Fossil SCM

/fileedit now accepts 'fn' and 'ci' as undocumented aliases for 'filename' resp. 'checkin', for consistency with some other pages. style_emit_script_builtin() now includes a cache-buster on URLs (a prefix of the builtin content's MD5 hash).

stephan 2020-05-08 12:39 fileedit-ajaxify
Commit 3733293a0125a4dac7c4b2188789fd6b5f86cfa035eb98fab29f3c4b572bf066
2 files changed +42 -11 +15 -4
+42 -11
--- src/fileedit.c
+++ src/fileedit.c
@@ -1071,10 +1071,38 @@
10711071
return 0;
10721072
}
10731073
return 1;
10741074
}
10751075
1076
+
1077
+/*
1078
+** If zFn is not NULL, it is assigned the value of the first one of
1079
+** the "filename" or "fn" CGI parameters which is set.
1080
+**
1081
+** If zCi is not NULL, it is assigned the value of the first one of
1082
+** the "checkin" or "ci" CGI parameters which is set.
1083
+**
1084
+** If a parameter is not NULL, it will be assigned NULL if the
1085
+** corresponding parameter is not set.
1086
+**
1087
+** Returns the number of non-NULL values it assigns to arguments. Thus
1088
+** if passed (&x, NULL), it returns 1 if it assigns non-NULL to *x and
1089
+** 0 if it assigns NULL to *x.
1090
+*/
1091
+static int fileedit_get_fnci_args( const char **zFn, const char **zCi ){
1092
+ int rc = 0;
1093
+ if(zCi!=0){
1094
+ *zCi = PD("checkin",P("ci"));
1095
+ if( *zCi ) ++rc;
1096
+ }
1097
+ if(zFn!=0){
1098
+ *zFn = PD("filename",P("fn"));
1099
+ if (*zFn) ++rc;
1100
+ }
1101
+ return rc;
1102
+}
1103
+
10761104
/*
10771105
** Passed the values of the "checkin" and "filename" request
10781106
** properties, this function verifies that they are valid and
10791107
** populates:
10801108
**
@@ -1095,11 +1123,11 @@
10951123
int * vid,
10961124
const char * zFilename,
10971125
int * frid){
10981126
char * zCi = 0; /* fully-resolved checkin UUID */
10991127
char * zFileUuid; /* file UUID */
1100
-
1128
+
11011129
if(!fileedit_ajax_check_filename(zFilename)){
11021130
return 0;
11031131
}
11041132
*vid = symbolic_name_to_rid(zRev, "ci");
11051133
if(0==*vid){
@@ -1139,16 +1167,17 @@
11391167
**
11401168
** Responds with the raw content of the given page. On error it
11411169
** produces a JSON response as documented for fileedit_ajax_error().
11421170
*/
11431171
void fileedit_ajax_content(){
1144
- const char * zFilename = PD("filename",P("name"));
1145
- const char * zRev = P("checkin");
1172
+ const char * zFilename = 0;
1173
+ const char * zRev = 0;
11461174
int vid, frid;
11471175
Blob content = empty_blob;
11481176
const char * zMime;
11491177
1178
+ fileedit_get_fnci_args( &zFilename, &zRev );
11501179
if(!fileedit_ajax_boostrap()
11511180
|| !fileedit_ajax_setup_filerev(zRev, 0, &vid,
11521181
zFilename, &frid)){
11531182
return;
11541183
}
@@ -1187,17 +1216,18 @@
11871216
**
11881217
** Responds with the HTML content of the preview. On error it produces
11891218
** a JSON response as documented for fileedit_ajax_error().
11901219
*/
11911220
void fileedit_ajax_preview(){
1192
- const char * zFilename = PD("filename",P("name"));
1221
+ const char * zFilename = 0;
11931222
const char * zContent = P("content");
11941223
int renderMode = atoi(PD("render_mode","0"));
11951224
int ln = atoi(PD("ln","0"));
11961225
int iframeHeight = atoi(PD("iframe_height","40"));
11971226
Blob content = empty_blob;
11981227
1228
+ fileedit_get_fnci_args( &zFilename, 0 );
11991229
if(!fileedit_ajax_boostrap()
12001230
|| !fileedit_ajax_check_filename(zFilename)){
12011231
return;
12021232
}
12031233
cgi_set_content_type("text/html");
@@ -1230,18 +1260,19 @@
12301260
** Reminder: we only need the filename to perform valdiation
12311261
** against fileedit_is_editable(), else this route could be
12321262
** abused to get diffs against content disallowed by the
12331263
** whitelist.
12341264
*/
1235
- const char * zFilename = PD("filename",P("name"));
1236
- const char * zRev = P("checkin");
1265
+ const char * zFilename = 0;
1266
+ const char * zRev = 0;
12371267
const char * zContent = P("content");
12381268
char * zRevUuid = 0;
12391269
int isSbs = atoi(PD("sbs","0"));
12401270
int vid, frid;
12411271
Blob content = empty_blob;
12421272
1273
+ fileedit_get_fnci_args( &zFilename, &zRev );
12431274
if(!fileedit_ajax_boostrap()
12441275
|| !fileedit_ajax_setup_filerev(zRev, &zRevUuid, &vid,
12451276
zFilename, &frid)){
12461277
return;
12471278
}
@@ -1273,14 +1304,14 @@
12731304
char * zFileUuid = 0; /* UUID of file content */
12741305
const char * zFlag; /* generic flag */
12751306
int rc = 0, vid = 0, frid = 0; /* result code, checkin/file rids */
12761307
12771308
#define fail(EXPR) blob_appendf EXPR; goto end_fail
1278
- zFlag = PD("filename",P("name"));
1309
+ zFlag = PD("filename",P("fn"));
12791310
if(zFlag==0 || !*zFlag){
12801311
rc = 400;
1281
- fail((pErr,"Missing required 'file' parameter."));
1312
+ fail((pErr,"Missing required 'filename' parameter."));
12821313
}
12831314
p->zFilename = mprintf("%s",zFlag);
12841315
12851316
if(0==fileedit_is_editable(p->zFilename)){
12861317
rc = 403;
@@ -1288,14 +1319,14 @@
12881319
"by the [fileedit-glob] repository "
12891320
"setting.",
12901321
p->zFilename));
12911322
}
12921323
1293
- zFlag = P("checkin");
1324
+ zFlag = PD("checkin",P("ci"));
12941325
if(!zFlag){
12951326
rc = 400;
1296
- fail((pErr,"Missing required 'r' parameter."));
1327
+ fail((pErr,"Missing required 'checkin' parameter."));
12971328
}
12981329
vid = symbolic_name_to_rid(zFlag, "ci");
12991330
if(0==vid){
13001331
rc = 404;
13011332
fail((pErr,"Could not resolve checkin version."));
@@ -1420,11 +1451,11 @@
14201451
if(!fileedit_ajax_boostrap()){
14211452
goto end_cleanup;
14221453
}
14231454
db_begin_transaction();
14241455
CheckinMiniInfo_init(&cimi);
1425
- rc = fileedit_setup_cimi_from_p(&cimi,&err);
1456
+ rc = fileedit_setup_cimi_from_p(&cimi, &err);
14261457
if(0!=rc){
14271458
fileedit_ajax_error(rc,"%b",&err);
14281459
goto end_cleanup;
14291460
}
14301461
if(blob_size(&cimi.comment)==0){
14311462
--- src/fileedit.c
+++ src/fileedit.c
@@ -1071,10 +1071,38 @@
1071 return 0;
1072 }
1073 return 1;
1074 }
1075
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1076 /*
1077 ** Passed the values of the "checkin" and "filename" request
1078 ** properties, this function verifies that they are valid and
1079 ** populates:
1080 **
@@ -1095,11 +1123,11 @@
1095 int * vid,
1096 const char * zFilename,
1097 int * frid){
1098 char * zCi = 0; /* fully-resolved checkin UUID */
1099 char * zFileUuid; /* file UUID */
1100
1101 if(!fileedit_ajax_check_filename(zFilename)){
1102 return 0;
1103 }
1104 *vid = symbolic_name_to_rid(zRev, "ci");
1105 if(0==*vid){
@@ -1139,16 +1167,17 @@
1139 **
1140 ** Responds with the raw content of the given page. On error it
1141 ** produces a JSON response as documented for fileedit_ajax_error().
1142 */
1143 void fileedit_ajax_content(){
1144 const char * zFilename = PD("filename",P("name"));
1145 const char * zRev = P("checkin");
1146 int vid, frid;
1147 Blob content = empty_blob;
1148 const char * zMime;
1149
 
1150 if(!fileedit_ajax_boostrap()
1151 || !fileedit_ajax_setup_filerev(zRev, 0, &vid,
1152 zFilename, &frid)){
1153 return;
1154 }
@@ -1187,17 +1216,18 @@
1187 **
1188 ** Responds with the HTML content of the preview. On error it produces
1189 ** a JSON response as documented for fileedit_ajax_error().
1190 */
1191 void fileedit_ajax_preview(){
1192 const char * zFilename = PD("filename",P("name"));
1193 const char * zContent = P("content");
1194 int renderMode = atoi(PD("render_mode","0"));
1195 int ln = atoi(PD("ln","0"));
1196 int iframeHeight = atoi(PD("iframe_height","40"));
1197 Blob content = empty_blob;
1198
 
1199 if(!fileedit_ajax_boostrap()
1200 || !fileedit_ajax_check_filename(zFilename)){
1201 return;
1202 }
1203 cgi_set_content_type("text/html");
@@ -1230,18 +1260,19 @@
1230 ** Reminder: we only need the filename to perform valdiation
1231 ** against fileedit_is_editable(), else this route could be
1232 ** abused to get diffs against content disallowed by the
1233 ** whitelist.
1234 */
1235 const char * zFilename = PD("filename",P("name"));
1236 const char * zRev = P("checkin");
1237 const char * zContent = P("content");
1238 char * zRevUuid = 0;
1239 int isSbs = atoi(PD("sbs","0"));
1240 int vid, frid;
1241 Blob content = empty_blob;
1242
 
1243 if(!fileedit_ajax_boostrap()
1244 || !fileedit_ajax_setup_filerev(zRev, &zRevUuid, &vid,
1245 zFilename, &frid)){
1246 return;
1247 }
@@ -1273,14 +1304,14 @@
1273 char * zFileUuid = 0; /* UUID of file content */
1274 const char * zFlag; /* generic flag */
1275 int rc = 0, vid = 0, frid = 0; /* result code, checkin/file rids */
1276
1277 #define fail(EXPR) blob_appendf EXPR; goto end_fail
1278 zFlag = PD("filename",P("name"));
1279 if(zFlag==0 || !*zFlag){
1280 rc = 400;
1281 fail((pErr,"Missing required 'file' parameter."));
1282 }
1283 p->zFilename = mprintf("%s",zFlag);
1284
1285 if(0==fileedit_is_editable(p->zFilename)){
1286 rc = 403;
@@ -1288,14 +1319,14 @@
1288 "by the [fileedit-glob] repository "
1289 "setting.",
1290 p->zFilename));
1291 }
1292
1293 zFlag = P("checkin");
1294 if(!zFlag){
1295 rc = 400;
1296 fail((pErr,"Missing required 'r' parameter."));
1297 }
1298 vid = symbolic_name_to_rid(zFlag, "ci");
1299 if(0==vid){
1300 rc = 404;
1301 fail((pErr,"Could not resolve checkin version."));
@@ -1420,11 +1451,11 @@
1420 if(!fileedit_ajax_boostrap()){
1421 goto end_cleanup;
1422 }
1423 db_begin_transaction();
1424 CheckinMiniInfo_init(&cimi);
1425 rc = fileedit_setup_cimi_from_p(&cimi,&err);
1426 if(0!=rc){
1427 fileedit_ajax_error(rc,"%b",&err);
1428 goto end_cleanup;
1429 }
1430 if(blob_size(&cimi.comment)==0){
1431
--- src/fileedit.c
+++ src/fileedit.c
@@ -1071,10 +1071,38 @@
1071 return 0;
1072 }
1073 return 1;
1074 }
1075
1076
1077 /*
1078 ** If zFn is not NULL, it is assigned the value of the first one of
1079 ** the "filename" or "fn" CGI parameters which is set.
1080 **
1081 ** If zCi is not NULL, it is assigned the value of the first one of
1082 ** the "checkin" or "ci" CGI parameters which is set.
1083 **
1084 ** If a parameter is not NULL, it will be assigned NULL if the
1085 ** corresponding parameter is not set.
1086 **
1087 ** Returns the number of non-NULL values it assigns to arguments. Thus
1088 ** if passed (&x, NULL), it returns 1 if it assigns non-NULL to *x and
1089 ** 0 if it assigns NULL to *x.
1090 */
1091 static int fileedit_get_fnci_args( const char **zFn, const char **zCi ){
1092 int rc = 0;
1093 if(zCi!=0){
1094 *zCi = PD("checkin",P("ci"));
1095 if( *zCi ) ++rc;
1096 }
1097 if(zFn!=0){
1098 *zFn = PD("filename",P("fn"));
1099 if (*zFn) ++rc;
1100 }
1101 return rc;
1102 }
1103
1104 /*
1105 ** Passed the values of the "checkin" and "filename" request
1106 ** properties, this function verifies that they are valid and
1107 ** populates:
1108 **
@@ -1095,11 +1123,11 @@
1123 int * vid,
1124 const char * zFilename,
1125 int * frid){
1126 char * zCi = 0; /* fully-resolved checkin UUID */
1127 char * zFileUuid; /* file UUID */
1128
1129 if(!fileedit_ajax_check_filename(zFilename)){
1130 return 0;
1131 }
1132 *vid = symbolic_name_to_rid(zRev, "ci");
1133 if(0==*vid){
@@ -1139,16 +1167,17 @@
1167 **
1168 ** Responds with the raw content of the given page. On error it
1169 ** produces a JSON response as documented for fileedit_ajax_error().
1170 */
1171 void fileedit_ajax_content(){
1172 const char * zFilename = 0;
1173 const char * zRev = 0;
1174 int vid, frid;
1175 Blob content = empty_blob;
1176 const char * zMime;
1177
1178 fileedit_get_fnci_args( &zFilename, &zRev );
1179 if(!fileedit_ajax_boostrap()
1180 || !fileedit_ajax_setup_filerev(zRev, 0, &vid,
1181 zFilename, &frid)){
1182 return;
1183 }
@@ -1187,17 +1216,18 @@
1216 **
1217 ** Responds with the HTML content of the preview. On error it produces
1218 ** a JSON response as documented for fileedit_ajax_error().
1219 */
1220 void fileedit_ajax_preview(){
1221 const char * zFilename = 0;
1222 const char * zContent = P("content");
1223 int renderMode = atoi(PD("render_mode","0"));
1224 int ln = atoi(PD("ln","0"));
1225 int iframeHeight = atoi(PD("iframe_height","40"));
1226 Blob content = empty_blob;
1227
1228 fileedit_get_fnci_args( &zFilename, 0 );
1229 if(!fileedit_ajax_boostrap()
1230 || !fileedit_ajax_check_filename(zFilename)){
1231 return;
1232 }
1233 cgi_set_content_type("text/html");
@@ -1230,18 +1260,19 @@
1260 ** Reminder: we only need the filename to perform valdiation
1261 ** against fileedit_is_editable(), else this route could be
1262 ** abused to get diffs against content disallowed by the
1263 ** whitelist.
1264 */
1265 const char * zFilename = 0;
1266 const char * zRev = 0;
1267 const char * zContent = P("content");
1268 char * zRevUuid = 0;
1269 int isSbs = atoi(PD("sbs","0"));
1270 int vid, frid;
1271 Blob content = empty_blob;
1272
1273 fileedit_get_fnci_args( &zFilename, &zRev );
1274 if(!fileedit_ajax_boostrap()
1275 || !fileedit_ajax_setup_filerev(zRev, &zRevUuid, &vid,
1276 zFilename, &frid)){
1277 return;
1278 }
@@ -1273,14 +1304,14 @@
1304 char * zFileUuid = 0; /* UUID of file content */
1305 const char * zFlag; /* generic flag */
1306 int rc = 0, vid = 0, frid = 0; /* result code, checkin/file rids */
1307
1308 #define fail(EXPR) blob_appendf EXPR; goto end_fail
1309 zFlag = PD("filename",P("fn"));
1310 if(zFlag==0 || !*zFlag){
1311 rc = 400;
1312 fail((pErr,"Missing required 'filename' parameter."));
1313 }
1314 p->zFilename = mprintf("%s",zFlag);
1315
1316 if(0==fileedit_is_editable(p->zFilename)){
1317 rc = 403;
@@ -1288,14 +1319,14 @@
1319 "by the [fileedit-glob] repository "
1320 "setting.",
1321 p->zFilename));
1322 }
1323
1324 zFlag = PD("checkin",P("ci"));
1325 if(!zFlag){
1326 rc = 400;
1327 fail((pErr,"Missing required 'checkin' parameter."));
1328 }
1329 vid = symbolic_name_to_rid(zFlag, "ci");
1330 if(0==vid){
1331 rc = 404;
1332 fail((pErr,"Could not resolve checkin version."));
@@ -1420,11 +1451,11 @@
1451 if(!fileedit_ajax_boostrap()){
1452 goto end_cleanup;
1453 }
1454 db_begin_transaction();
1455 CheckinMiniInfo_init(&cimi);
1456 rc = fileedit_setup_cimi_from_p(&cimi, &err);
1457 if(0!=rc){
1458 fileedit_ajax_error(rc,"%b",&err);
1459 goto end_cleanup;
1460 }
1461 if(blob_size(&cimi.comment)==0){
1462
+15 -4
--- src/style.c
+++ src/style.c
@@ -1470,11 +1470,11 @@
14701470
if(asInline){
14711471
CX("%s\n", builtin_text("fossil.bootstrap.js"));
14721472
}
14731473
style_emit_script_tag(1,0);
14741474
if(asInline==0){
1475
- style_emit_script_tag(0,"builtin/fossil.bootstrap.js");
1475
+ style_emit_script_builtin("fossil.bootstrap.js", 0);
14761476
}
14771477
}
14781478
}
14791479
14801480
/*
@@ -1510,21 +1510,32 @@
15101510
15111511
/*
15121512
** Emits a script tag which uses content from a builtin script file.
15131513
**
15141514
** If asInline is true, it is emitted directly as an opening tag, the
1515
-** content of the zName builtin file, and a closing tag. If it is false,
1516
-** a script tag loading it via src=builtin/{{zName}} is emitted.
1515
+** content of the zName builtin file, and a closing tag.
1516
+**
1517
+** If it is false, a script tag loading it via
1518
+** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a prefix
1519
+** of the builtin content's md5 hash.
15171520
*/
15181521
void style_emit_script_builtin(char const * zName, int asInline){
15191522
if(asInline){
15201523
style_emit_script_tag(0,0);
15211524
CX("%s", builtin_text(zName));
15221525
style_emit_script_tag(1,0);
15231526
}else{
15241527
char * zFull = mprintf("builtin/%s",zName);
1525
- style_emit_script_tag(0,zFull);
1528
+ const char * zBuiltin = builtin_text(zName);
1529
+ const char * zHash = 0;
1530
+ if(zBuiltin!=0){
1531
+ md5sum_init();
1532
+ md5sum_step_text(zBuiltin,-1);
1533
+ zHash = md5sum_finish(0);
1534
+ }
1535
+ CX("<script src='%R/%T?cache=%.8s'></script>\n",zFull,
1536
+ zHash ? zHash : "MISSING");
15261537
fossil_free(zFull);
15271538
}
15281539
}
15291540
15301541
/*
15311542
--- src/style.c
+++ src/style.c
@@ -1470,11 +1470,11 @@
1470 if(asInline){
1471 CX("%s\n", builtin_text("fossil.bootstrap.js"));
1472 }
1473 style_emit_script_tag(1,0);
1474 if(asInline==0){
1475 style_emit_script_tag(0,"builtin/fossil.bootstrap.js");
1476 }
1477 }
1478 }
1479
1480 /*
@@ -1510,21 +1510,32 @@
1510
1511 /*
1512 ** Emits a script tag which uses content from a builtin script file.
1513 **
1514 ** If asInline is true, it is emitted directly as an opening tag, the
1515 ** content of the zName builtin file, and a closing tag. If it is false,
1516 ** a script tag loading it via src=builtin/{{zName}} is emitted.
 
 
 
1517 */
1518 void style_emit_script_builtin(char const * zName, int asInline){
1519 if(asInline){
1520 style_emit_script_tag(0,0);
1521 CX("%s", builtin_text(zName));
1522 style_emit_script_tag(1,0);
1523 }else{
1524 char * zFull = mprintf("builtin/%s",zName);
1525 style_emit_script_tag(0,zFull);
 
 
 
 
 
 
 
 
1526 fossil_free(zFull);
1527 }
1528 }
1529
1530 /*
1531
--- src/style.c
+++ src/style.c
@@ -1470,11 +1470,11 @@
1470 if(asInline){
1471 CX("%s\n", builtin_text("fossil.bootstrap.js"));
1472 }
1473 style_emit_script_tag(1,0);
1474 if(asInline==0){
1475 style_emit_script_builtin("fossil.bootstrap.js", 0);
1476 }
1477 }
1478 }
1479
1480 /*
@@ -1510,21 +1510,32 @@
1510
1511 /*
1512 ** Emits a script tag which uses content from a builtin script file.
1513 **
1514 ** If asInline is true, it is emitted directly as an opening tag, the
1515 ** content of the zName builtin file, and a closing tag.
1516 **
1517 ** If it is false, a script tag loading it via
1518 ** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a prefix
1519 ** of the builtin content's md5 hash.
1520 */
1521 void style_emit_script_builtin(char const * zName, int asInline){
1522 if(asInline){
1523 style_emit_script_tag(0,0);
1524 CX("%s", builtin_text(zName));
1525 style_emit_script_tag(1,0);
1526 }else{
1527 char * zFull = mprintf("builtin/%s",zName);
1528 const char * zBuiltin = builtin_text(zName);
1529 const char * zHash = 0;
1530 if(zBuiltin!=0){
1531 md5sum_init();
1532 md5sum_step_text(zBuiltin,-1);
1533 zHash = md5sum_finish(0);
1534 }
1535 CX("<script src='%R/%T?cache=%.8s'></script>\n",zFull,
1536 zHash ? zHash : "MISSING");
1537 fossil_free(zFull);
1538 }
1539 }
1540
1541 /*
1542

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button