Fossil SCM
Primative validation of request-supplied mime-types.
Commit
ae8fc0e0b5e6f4c3b17ef74f8f660c0b709150940c8a9be4321cb632ce8c351f
Parent
55c972103ffc130…
1 file changed
+18
-16
+18
-16
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -241,11 +241,11 @@ | ||
| 241 | 241 | } |
| 242 | 242 | |
| 243 | 243 | /* |
| 244 | 244 | ** Additional information used to form the HTTP reply |
| 245 | 245 | */ |
| 246 | -static const char *zContentType = "text/html"; /* Content type of the reply */ | |
| 246 | +static const char *zReplyMimeType = "text/html"; /* Content type of the reply */ | |
| 247 | 247 | static const char *zReplyStatus = "OK"; /* Reply status description */ |
| 248 | 248 | static int iReplyStatus = 200; /* Reply status code */ |
| 249 | 249 | static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */ |
| 250 | 250 | static int rangeStart = 0; /* Start of Range: */ |
| 251 | 251 | static int rangeEnd = 0; /* End of Range: plus 1 */ |
| @@ -256,11 +256,13 @@ | ||
| 256 | 256 | ** The reply content type defaults to "text/html". It only needs to be |
| 257 | 257 | ** changed (by calling this routine) in the exceptional case where some |
| 258 | 258 | ** other content type is being returned. |
| 259 | 259 | */ |
| 260 | 260 | 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); | |
| 262 | 264 | } |
| 263 | 265 | |
| 264 | 266 | /* |
| 265 | 267 | ** Erase any existing reply content. Replace is with a pNewContent. |
| 266 | 268 | ** |
| @@ -336,14 +338,14 @@ | ||
| 336 | 338 | if( g.fNoHttpCompress ) return 0; |
| 337 | 339 | if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0; |
| 338 | 340 | /* Maintenance note: this oddball structure is intended to make |
| 339 | 341 | ** adding new mimetypes to this list less of a performance hit than |
| 340 | 342 | ** doing a strcmp/glob over a growing set of compressible types. */ |
| 341 | - switch(zContentType ? *zContentType : 0){ | |
| 343 | + switch(zReplyMimeType ? *zReplyMimeType : 0){ | |
| 342 | 344 | 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]; | |
| 345 | 347 | switch(*z){ |
| 346 | 348 | case (int)'j': |
| 347 | 349 | return fossil_strcmp("javascript", z)==0 |
| 348 | 350 | || fossil_strcmp("json", z)==0; |
| 349 | 351 | case (int)'w': return fossil_strcmp("wasm", z)==0; |
| @@ -354,14 +356,14 @@ | ||
| 354 | 356 | return sqlite3_strglob("*xml", z)==0; |
| 355 | 357 | } |
| 356 | 358 | } |
| 357 | 359 | break; |
| 358 | 360 | 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; | |
| 361 | 363 | case (int)'t': |
| 362 | - return fossil_strncmp(zContentType, "text/", 5)==0; | |
| 364 | + return fossil_strncmp(zReplyMimeType, "text/", 5)==0; | |
| 363 | 365 | } |
| 364 | 366 | return 0; |
| 365 | 367 | } |
| 366 | 368 | |
| 367 | 369 | |
| @@ -449,22 +451,22 @@ | ||
| 449 | 451 | } |
| 450 | 452 | |
| 451 | 453 | /* |
| 452 | 454 | ** Given a Content-Type value, returns a string suitable for appending |
| 453 | 455 | ** 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 | |
| 455 | 457 | ** is NULL. |
| 456 | 458 | ** |
| 457 | 459 | ** See forum post f60dece061c364d1 for the discussions which lead to |
| 458 | 460 | ** this. Previously we always appended the charset, but WASM loaders |
| 459 | 461 | ** are pedantic and refuse to load any responses which have a |
| 460 | 462 | ** charset. Also, adding a charset is not strictly appropriate for |
| 461 | 463 | ** most types (and not required for many others which may ostensibly |
| 462 | 464 | ** benefit from one, as detailed in that forum post). |
| 463 | 465 | */ |
| 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)){ | |
| 466 | 468 | return "; charset=utf-8"; |
| 467 | 469 | } |
| 468 | 470 | return ""; |
| 469 | 471 | } |
| 470 | 472 | |
| @@ -500,11 +502,11 @@ | ||
| 500 | 502 | assert( rangeEnd==0 ); |
| 501 | 503 | blob_appendf(&hdr, "Status: %d %s\r\n", iReplyStatus, zReplyStatus); |
| 502 | 504 | } |
| 503 | 505 | if( etag_tag()[0]!=0 |
| 504 | 506 | && iReplyStatus==200 |
| 505 | - && strcmp(zContentType,"text/html")!=0 | |
| 507 | + && strcmp(zReplyMimeType,"text/html")!=0 | |
| 506 | 508 | ){ |
| 507 | 509 | /* Do not cache HTML replies as those will have been generated and |
| 508 | 510 | ** will likely, therefore, contains a nonce and we want that nonce to |
| 509 | 511 | ** be different every time. */ |
| 510 | 512 | blob_appendf(&hdr, "ETag: \"%s\"\r\n", etag_tag()); |
| @@ -542,13 +544,13 @@ | ||
| 542 | 544 | ** These headers are probably best added by the web server hosting fossil as |
| 543 | 545 | ** a CGI script. |
| 544 | 546 | */ |
| 545 | 547 | |
| 546 | 548 | 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 ){ | |
| 550 | 552 | cgi_combine_header_and_body(); |
| 551 | 553 | blob_compress(&cgiContent[0], &cgiContent[0]); |
| 552 | 554 | } |
| 553 | 555 | |
| 554 | 556 | if( is_gzippable() && iReplyStatus!=206 ){ |
| @@ -2021,11 +2023,11 @@ | ||
| 2021 | 2023 | char *z; |
| 2022 | 2024 | va_start(ap, zMsg); |
| 2023 | 2025 | z = vmprintf(zMsg, ap); |
| 2024 | 2026 | va_end(ap); |
| 2025 | 2027 | cgi_set_status(400, "Bad Request"); |
| 2026 | - zContentType = "text/plain"; | |
| 2028 | + zReplyMimeType = "text/plain"; | |
| 2027 | 2029 | if( g.zReqType==0 ) g.zReqType = "WWW"; |
| 2028 | 2030 | if( g.zReqType[0]=='C' && PD("SERVER_SOFTWARE",0)!=0 ){ |
| 2029 | 2031 | const char *zServer = PD("SERVER_SOFTWARE",""); |
| 2030 | 2032 | cgi_printf("Bad CGI Request from \"%s\": %s\n",zServer,z); |
| 2031 | 2033 | }else{ |
| 2032 | 2034 |
| --- 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 |