Fossil SCM

Primative validation of request-supplied mime-types.

drh 2025-09-01 14:15 trunk
Commit ae8fc0e0b5e6f4c3b17ef74f8f660c0b709150940c8a9be4321cb632ce8c351f
1 file changed +18 -16
+18 -16
--- src/cgi.c
+++ src/cgi.c
@@ -241,11 +241,11 @@
241241
}
242242
243243
/*
244244
** Additional information used to form the HTTP reply
245245
*/
246
-static const char *zContentType = "text/html"; /* Content type of the reply */
246
+static const char *zReplyMimeType = "text/html"; /* Content type of the reply */
247247
static const char *zReplyStatus = "OK"; /* Reply status description */
248248
static int iReplyStatus = 200; /* Reply status code */
249249
static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
250250
static int rangeStart = 0; /* Start of Range: */
251251
static int rangeEnd = 0; /* End of Range: plus 1 */
@@ -256,11 +256,13 @@
256256
** The reply content type defaults to "text/html". It only needs to be
257257
** changed (by calling this routine) in the exceptional case where some
258258
** other content type is being returned.
259259
*/
260260
void cgi_set_content_type(const char *zType){
261
- zContentType = fossil_strdup(zType);
261
+ int i;
262
+ for(i=0; zType[i]>='-' && zType[i]<='z'; i++){}
263
+ zReplyMimeType = fossil_strndup(zType, i);
262264
}
263265
264266
/*
265267
** Erase any existing reply content. Replace is with a pNewContent.
266268
**
@@ -336,14 +338,14 @@
336338
if( g.fNoHttpCompress ) return 0;
337339
if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0;
338340
/* Maintenance note: this oddball structure is intended to make
339341
** adding new mimetypes to this list less of a performance hit than
340342
** doing a strcmp/glob over a growing set of compressible types. */
341
- switch(zContentType ? *zContentType : 0){
343
+ switch(zReplyMimeType ? *zReplyMimeType : 0){
342344
case (int)'a':
343
- if(0==fossil_strncmp("application/",zContentType,12)){
344
- const char * z = &zContentType[12];
345
+ if(0==fossil_strncmp("application/",zReplyMimeType,12)){
346
+ const char * z = &zReplyMimeType[12];
345347
switch(*z){
346348
case (int)'j':
347349
return fossil_strcmp("javascript", z)==0
348350
|| fossil_strcmp("json", z)==0;
349351
case (int)'w': return fossil_strcmp("wasm", z)==0;
@@ -354,14 +356,14 @@
354356
return sqlite3_strglob("*xml", z)==0;
355357
}
356358
}
357359
break;
358360
case (int)'i':
359
- return fossil_strcmp(zContentType, "image/svg+xml")==0
360
- || fossil_strcmp(zContentType, "image/vnd.microsoft.icon")==0;
361
+ return fossil_strcmp(zReplyMimeType, "image/svg+xml")==0
362
+ || fossil_strcmp(zReplyMimeType, "image/vnd.microsoft.icon")==0;
361363
case (int)'t':
362
- return fossil_strncmp(zContentType, "text/", 5)==0;
364
+ return fossil_strncmp(zReplyMimeType, "text/", 5)==0;
363365
}
364366
return 0;
365367
}
366368
367369
@@ -449,22 +451,22 @@
449451
}
450452
451453
/*
452454
** Given a Content-Type value, returns a string suitable for appending
453455
** to the Content-Type header for adding (or not) the "; charset=..."
454
-** part. It returns an empty string for most types or if zContentType
456
+** part. It returns an empty string for most types or if zReplyMimeType
455457
** is NULL.
456458
**
457459
** See forum post f60dece061c364d1 for the discussions which lead to
458460
** this. Previously we always appended the charset, but WASM loaders
459461
** are pedantic and refuse to load any responses which have a
460462
** charset. Also, adding a charset is not strictly appropriate for
461463
** most types (and not required for many others which may ostensibly
462464
** benefit from one, as detailed in that forum post).
463465
*/
464
-static const char * content_type_charset(const char *zContentType){
465
- if(0==fossil_strncmp(zContentType,"text/",5)){
466
+static const char * content_type_charset(const char *zReplyMimeType){
467
+ if(0==fossil_strncmp(zReplyMimeType,"text/",5)){
466468
return "; charset=utf-8";
467469
}
468470
return "";
469471
}
470472
@@ -500,11 +502,11 @@
500502
assert( rangeEnd==0 );
501503
blob_appendf(&hdr, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
502504
}
503505
if( etag_tag()[0]!=0
504506
&& iReplyStatus==200
505
- && strcmp(zContentType,"text/html")!=0
507
+ && strcmp(zReplyMimeType,"text/html")!=0
506508
){
507509
/* Do not cache HTML replies as those will have been generated and
508510
** will likely, therefore, contains a nonce and we want that nonce to
509511
** be different every time. */
510512
blob_appendf(&hdr, "ETag: \"%s\"\r\n", etag_tag());
@@ -542,13 +544,13 @@
542544
** These headers are probably best added by the web server hosting fossil as
543545
** a CGI script.
544546
*/
545547
546548
if( iReplyStatus!=304 ) {
547
- blob_appendf(&hdr, "Content-Type: %s%s\r\n", zContentType,
548
- content_type_charset(zContentType));
549
- if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
549
+ blob_appendf(&hdr, "Content-Type: %s%s\r\n", zReplyMimeType,
550
+ content_type_charset(zReplyMimeType));
551
+ if( fossil_strcmp(zReplyMimeType,"application/x-fossil")==0 ){
550552
cgi_combine_header_and_body();
551553
blob_compress(&cgiContent[0], &cgiContent[0]);
552554
}
553555
554556
if( is_gzippable() && iReplyStatus!=206 ){
@@ -2021,11 +2023,11 @@
20212023
char *z;
20222024
va_start(ap, zMsg);
20232025
z = vmprintf(zMsg, ap);
20242026
va_end(ap);
20252027
cgi_set_status(400, "Bad Request");
2026
- zContentType = "text/plain";
2028
+ zReplyMimeType = "text/plain";
20272029
if( g.zReqType==0 ) g.zReqType = "WWW";
20282030
if( g.zReqType[0]=='C' && PD("SERVER_SOFTWARE",0)!=0 ){
20292031
const char *zServer = PD("SERVER_SOFTWARE","");
20302032
cgi_printf("Bad CGI Request from \"%s\": %s\n",zServer,z);
20312033
}else{
20322034
--- src/cgi.c
+++ src/cgi.c
@@ -241,11 +241,11 @@
241 }
242
243 /*
244 ** Additional information used to form the HTTP reply
245 */
246 static const char *zContentType = "text/html"; /* Content type of the reply */
247 static const char *zReplyStatus = "OK"; /* Reply status description */
248 static int iReplyStatus = 200; /* Reply status code */
249 static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
250 static int rangeStart = 0; /* Start of Range: */
251 static int rangeEnd = 0; /* End of Range: plus 1 */
@@ -256,11 +256,13 @@
256 ** The reply content type defaults to "text/html". It only needs to be
257 ** changed (by calling this routine) in the exceptional case where some
258 ** other content type is being returned.
259 */
260 void cgi_set_content_type(const char *zType){
261 zContentType = fossil_strdup(zType);
 
 
262 }
263
264 /*
265 ** Erase any existing reply content. Replace is with a pNewContent.
266 **
@@ -336,14 +338,14 @@
336 if( g.fNoHttpCompress ) return 0;
337 if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0;
338 /* Maintenance note: this oddball structure is intended to make
339 ** adding new mimetypes to this list less of a performance hit than
340 ** doing a strcmp/glob over a growing set of compressible types. */
341 switch(zContentType ? *zContentType : 0){
342 case (int)'a':
343 if(0==fossil_strncmp("application/",zContentType,12)){
344 const char * z = &zContentType[12];
345 switch(*z){
346 case (int)'j':
347 return fossil_strcmp("javascript", z)==0
348 || fossil_strcmp("json", z)==0;
349 case (int)'w': return fossil_strcmp("wasm", z)==0;
@@ -354,14 +356,14 @@
354 return sqlite3_strglob("*xml", z)==0;
355 }
356 }
357 break;
358 case (int)'i':
359 return fossil_strcmp(zContentType, "image/svg+xml")==0
360 || fossil_strcmp(zContentType, "image/vnd.microsoft.icon")==0;
361 case (int)'t':
362 return fossil_strncmp(zContentType, "text/", 5)==0;
363 }
364 return 0;
365 }
366
367
@@ -449,22 +451,22 @@
449 }
450
451 /*
452 ** Given a Content-Type value, returns a string suitable for appending
453 ** to the Content-Type header for adding (or not) the "; charset=..."
454 ** part. It returns an empty string for most types or if zContentType
455 ** is NULL.
456 **
457 ** See forum post f60dece061c364d1 for the discussions which lead to
458 ** this. Previously we always appended the charset, but WASM loaders
459 ** are pedantic and refuse to load any responses which have a
460 ** charset. Also, adding a charset is not strictly appropriate for
461 ** most types (and not required for many others which may ostensibly
462 ** benefit from one, as detailed in that forum post).
463 */
464 static const char * content_type_charset(const char *zContentType){
465 if(0==fossil_strncmp(zContentType,"text/",5)){
466 return "; charset=utf-8";
467 }
468 return "";
469 }
470
@@ -500,11 +502,11 @@
500 assert( rangeEnd==0 );
501 blob_appendf(&hdr, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
502 }
503 if( etag_tag()[0]!=0
504 && iReplyStatus==200
505 && strcmp(zContentType,"text/html")!=0
506 ){
507 /* Do not cache HTML replies as those will have been generated and
508 ** will likely, therefore, contains a nonce and we want that nonce to
509 ** be different every time. */
510 blob_appendf(&hdr, "ETag: \"%s\"\r\n", etag_tag());
@@ -542,13 +544,13 @@
542 ** These headers are probably best added by the web server hosting fossil as
543 ** a CGI script.
544 */
545
546 if( iReplyStatus!=304 ) {
547 blob_appendf(&hdr, "Content-Type: %s%s\r\n", zContentType,
548 content_type_charset(zContentType));
549 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
550 cgi_combine_header_and_body();
551 blob_compress(&cgiContent[0], &cgiContent[0]);
552 }
553
554 if( is_gzippable() && iReplyStatus!=206 ){
@@ -2021,11 +2023,11 @@
2021 char *z;
2022 va_start(ap, zMsg);
2023 z = vmprintf(zMsg, ap);
2024 va_end(ap);
2025 cgi_set_status(400, "Bad Request");
2026 zContentType = "text/plain";
2027 if( g.zReqType==0 ) g.zReqType = "WWW";
2028 if( g.zReqType[0]=='C' && PD("SERVER_SOFTWARE",0)!=0 ){
2029 const char *zServer = PD("SERVER_SOFTWARE","");
2030 cgi_printf("Bad CGI Request from \"%s\": %s\n",zServer,z);
2031 }else{
2032
--- src/cgi.c
+++ src/cgi.c
@@ -241,11 +241,11 @@
241 }
242
243 /*
244 ** Additional information used to form the HTTP reply
245 */
246 static const char *zReplyMimeType = "text/html"; /* Content type of the reply */
247 static const char *zReplyStatus = "OK"; /* Reply status description */
248 static int iReplyStatus = 200; /* Reply status code */
249 static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
250 static int rangeStart = 0; /* Start of Range: */
251 static int rangeEnd = 0; /* End of Range: plus 1 */
@@ -256,11 +256,13 @@
256 ** The reply content type defaults to "text/html". It only needs to be
257 ** changed (by calling this routine) in the exceptional case where some
258 ** other content type is being returned.
259 */
260 void cgi_set_content_type(const char *zType){
261 int i;
262 for(i=0; zType[i]>='-' && zType[i]<='z'; i++){}
263 zReplyMimeType = fossil_strndup(zType, i);
264 }
265
266 /*
267 ** Erase any existing reply content. Replace is with a pNewContent.
268 **
@@ -336,14 +338,14 @@
338 if( g.fNoHttpCompress ) return 0;
339 if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0;
340 /* Maintenance note: this oddball structure is intended to make
341 ** adding new mimetypes to this list less of a performance hit than
342 ** doing a strcmp/glob over a growing set of compressible types. */
343 switch(zReplyMimeType ? *zReplyMimeType : 0){
344 case (int)'a':
345 if(0==fossil_strncmp("application/",zReplyMimeType,12)){
346 const char * z = &zReplyMimeType[12];
347 switch(*z){
348 case (int)'j':
349 return fossil_strcmp("javascript", z)==0
350 || fossil_strcmp("json", z)==0;
351 case (int)'w': return fossil_strcmp("wasm", z)==0;
@@ -354,14 +356,14 @@
356 return sqlite3_strglob("*xml", z)==0;
357 }
358 }
359 break;
360 case (int)'i':
361 return fossil_strcmp(zReplyMimeType, "image/svg+xml")==0
362 || fossil_strcmp(zReplyMimeType, "image/vnd.microsoft.icon")==0;
363 case (int)'t':
364 return fossil_strncmp(zReplyMimeType, "text/", 5)==0;
365 }
366 return 0;
367 }
368
369
@@ -449,22 +451,22 @@
451 }
452
453 /*
454 ** Given a Content-Type value, returns a string suitable for appending
455 ** to the Content-Type header for adding (or not) the "; charset=..."
456 ** part. It returns an empty string for most types or if zReplyMimeType
457 ** is NULL.
458 **
459 ** See forum post f60dece061c364d1 for the discussions which lead to
460 ** this. Previously we always appended the charset, but WASM loaders
461 ** are pedantic and refuse to load any responses which have a
462 ** charset. Also, adding a charset is not strictly appropriate for
463 ** most types (and not required for many others which may ostensibly
464 ** benefit from one, as detailed in that forum post).
465 */
466 static const char * content_type_charset(const char *zReplyMimeType){
467 if(0==fossil_strncmp(zReplyMimeType,"text/",5)){
468 return "; charset=utf-8";
469 }
470 return "";
471 }
472
@@ -500,11 +502,11 @@
502 assert( rangeEnd==0 );
503 blob_appendf(&hdr, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
504 }
505 if( etag_tag()[0]!=0
506 && iReplyStatus==200
507 && strcmp(zReplyMimeType,"text/html")!=0
508 ){
509 /* Do not cache HTML replies as those will have been generated and
510 ** will likely, therefore, contains a nonce and we want that nonce to
511 ** be different every time. */
512 blob_appendf(&hdr, "ETag: \"%s\"\r\n", etag_tag());
@@ -542,13 +544,13 @@
544 ** These headers are probably best added by the web server hosting fossil as
545 ** a CGI script.
546 */
547
548 if( iReplyStatus!=304 ) {
549 blob_appendf(&hdr, "Content-Type: %s%s\r\n", zReplyMimeType,
550 content_type_charset(zReplyMimeType));
551 if( fossil_strcmp(zReplyMimeType,"application/x-fossil")==0 ){
552 cgi_combine_header_and_body();
553 blob_compress(&cgiContent[0], &cgiContent[0]);
554 }
555
556 if( is_gzippable() && iReplyStatus!=206 ){
@@ -2021,11 +2023,11 @@
2023 char *z;
2024 va_start(ap, zMsg);
2025 z = vmprintf(zMsg, ap);
2026 va_end(ap);
2027 cgi_set_status(400, "Bad Request");
2028 zReplyMimeType = "text/plain";
2029 if( g.zReqType==0 ) g.zReqType = "WWW";
2030 if( g.zReqType[0]=='C' && PD("SERVER_SOFTWARE",0)!=0 ){
2031 const char *zServer = PD("SERVER_SOFTWARE","");
2032 cgi_printf("Bad CGI Request from \"%s\": %s\n",zServer,z);
2033 }else{
2034

Keyboard Shortcuts

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