| | @@ -84,10 +84,11 @@ |
| 84 | 84 | #endif |
| 85 | 85 | #include <time.h> |
| 86 | 86 | #include <stdio.h> |
| 87 | 87 | #include <stdlib.h> |
| 88 | 88 | #include <unistd.h> |
| 89 | +#include <assert.h> |
| 89 | 90 | #include "cgi.h" |
| 90 | 91 | #include "cygsup.h" |
| 91 | 92 | |
| 92 | 93 | #if INTERFACE |
| 93 | 94 | /* |
| | @@ -333,10 +334,79 @@ |
| 333 | 334 | if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0; |
| 334 | 335 | return strncmp(zContentType, "text/", 5)==0 |
| 335 | 336 | || sqlite3_strglob("application/*xml", zContentType)==0 |
| 336 | 337 | || sqlite3_strglob("application/*javascript", zContentType)==0; |
| 337 | 338 | } |
| 339 | + |
| 340 | + |
| 341 | +/* |
| 342 | +** The following routines read or write content from/to the wire for |
| 343 | +** an HTTP request. Depending on settings the content might be coming |
| 344 | +** from or going to a socket, or a file, or it might come from or go |
| 345 | +** to an SSL decoder/encoder. |
| 346 | +*/ |
| 347 | +/* |
| 348 | +** Works like fgets(): |
| 349 | +** |
| 350 | +** Read a single line of input into s[]. Ensure that s[] is zero-terminated. |
| 351 | +** The s[] buffer is size bytes and so at most size-1 bytes will be read. |
| 352 | +** |
| 353 | +** Return a pointer to s[] on success, or NULL at end-of-input. |
| 354 | +*/ |
| 355 | +static char *cgi_fgets(char *s, int size){ |
| 356 | + if( !g.httpUseSSL ){ |
| 357 | + return fgets(s, size, g.httpIn); |
| 358 | + } |
| 359 | + assert( !"SSL Server not yet implemented" ); |
| 360 | +} |
| 361 | + |
| 362 | +/* Works like fread(): |
| 363 | +** |
| 364 | +** Read as many as bytes of content as we can, up to a maximum of nmemb |
| 365 | +** bytes. Return the number of bytes read. Return -1 if there is no |
| 366 | +** further input or if an I/O error occurs. |
| 367 | +*/ |
| 368 | +size_t cgi_fread(void *ptr, size_t nmemb){ |
| 369 | + if( !g.httpUseSSL ){ |
| 370 | + return fread(ptr, 1, nmemb, g.httpIn); |
| 371 | + } |
| 372 | + assert( !"SSL Server not yet implemented" ); |
| 373 | +} |
| 374 | + |
| 375 | +/* Works like feof(): |
| 376 | +** |
| 377 | +** Return true if end-of-input has been reached. |
| 378 | +*/ |
| 379 | +int cgi_feof(void){ |
| 380 | + if( !g.httpUseSSL ){ |
| 381 | + return feof(g.httpIn); |
| 382 | + } |
| 383 | + assert( !"SSL Server not yet implemented" ); |
| 384 | +} |
| 385 | + |
| 386 | +/* Works like fwrite(): |
| 387 | +** |
| 388 | +** Try to output nmemb bytes of content. Return the number of |
| 389 | +** bytes actually written. |
| 390 | +*/ |
| 391 | +static size_t cgi_fwrite(void *ptr, size_t nmemb){ |
| 392 | + if( !g.httpUseSSL ){ |
| 393 | + return fwrite(ptr, 1, nmemb, g.httpOut); |
| 394 | + } |
| 395 | + assert( !"SSL Server not yet implemented" ); |
| 396 | +} |
| 397 | + |
| 398 | +/* Works like fflush(): |
| 399 | +** |
| 400 | +** Make sure I/O has completed. |
| 401 | +*/ |
| 402 | +static void cgi_fflush(void){ |
| 403 | + if( !g.httpUseSSL ){ |
| 404 | + fflush(g.httpOut); |
| 405 | + } |
| 406 | +} |
| 407 | + |
| 338 | 408 | |
| 339 | 409 | /* |
| 340 | 410 | ** Generate the reply to a web request. The output might be an |
| 341 | 411 | ** full HTTP response, or a CGI response, depending on how things have |
| 342 | 412 | ** be set up. |
| | @@ -436,11 +506,11 @@ |
| 436 | 506 | blob_appendf(&hdr, "Content-Length: %d\r\n", total_size); |
| 437 | 507 | }else{ |
| 438 | 508 | total_size = 0; |
| 439 | 509 | } |
| 440 | 510 | blob_appendf(&hdr, "\r\n"); |
| 441 | | - fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), g.httpOut); |
| 511 | + cgi_fwrite(blob_buffer(&hdr), blob_size(&hdr)); |
| 442 | 512 | blob_reset(&hdr); |
| 443 | 513 | if( total_size>0 |
| 444 | 514 | && iReplyStatus!=304 |
| 445 | 515 | && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0 |
| 446 | 516 | ){ |
| | @@ -452,17 +522,17 @@ |
| 452 | 522 | }else{ |
| 453 | 523 | int n = size - rangeStart; |
| 454 | 524 | if( n>total_size ){ |
| 455 | 525 | n = total_size; |
| 456 | 526 | } |
| 457 | | - fwrite(blob_buffer(&cgiContent[i])+rangeStart, 1, n, g.httpOut); |
| 527 | + cgi_fwrite(blob_buffer(&cgiContent[i])+rangeStart, n); |
| 458 | 528 | rangeStart = 0; |
| 459 | 529 | total_size -= n; |
| 460 | 530 | } |
| 461 | 531 | } |
| 462 | 532 | } |
| 463 | | - fflush(g.httpOut); |
| 533 | + cgi_fflush(); |
| 464 | 534 | CGIDEBUG(("-------- END cgi ---------\n")); |
| 465 | 535 | |
| 466 | 536 | /* After the webpage has been sent, do any useful background |
| 467 | 537 | ** processing. |
| 468 | 538 | */ |
| | @@ -1262,18 +1332,19 @@ |
| 1262 | 1332 | g.zContentType = zType; |
| 1263 | 1333 | } |
| 1264 | 1334 | blob_zero(&g.cgiIn); |
| 1265 | 1335 | if( len>0 && zType ){ |
| 1266 | 1336 | if( fossil_strcmp(zType, "application/x-fossil")==0 ){ |
| 1267 | | - if( blob_read_from_channel(&g.cgiIn, g.httpIn, len)!=len ){ |
| 1337 | + if( blob_read_from_cgi(&g.cgiIn, len)!=len ){ |
| 1268 | 1338 | malformed_request("CGI content-length mismatch"); |
| 1269 | 1339 | } |
| 1270 | 1340 | blob_uncompress(&g.cgiIn, &g.cgiIn); |
| 1271 | 1341 | } |
| 1272 | 1342 | #ifdef FOSSIL_ENABLE_JSON |
| 1273 | | - else if( noJson==0 && g.json.isJsonMode!=0 |
| 1343 | + else if( noJson==0 && g.json.isJsonMode!=0 |
| 1274 | 1344 | && json_can_consume_content_type(zType)!=0 ){ |
| 1345 | + assert( !g.httpUseSSL ); |
| 1275 | 1346 | cgi_parse_POST_JSON(g.httpIn, (unsigned int)len); |
| 1276 | 1347 | /* |
| 1277 | 1348 | Potential TODOs: |
| 1278 | 1349 | |
| 1279 | 1350 | 1) If parsing fails, immediately return an error response |
| | @@ -1281,11 +1352,11 @@ |
| 1281 | 1352 | */ |
| 1282 | 1353 | cgi_set_content_type(json_guess_content_type()); |
| 1283 | 1354 | } |
| 1284 | 1355 | #endif /* FOSSIL_ENABLE_JSON */ |
| 1285 | 1356 | else{ |
| 1286 | | - blob_read_from_channel(&g.cgiIn, g.httpIn, len); |
| 1357 | + blob_read_from_cgi(&g.cgiIn, len); |
| 1287 | 1358 | } |
| 1288 | 1359 | } |
| 1289 | 1360 | } |
| 1290 | 1361 | |
| 1291 | 1362 | /* |
| | @@ -1799,11 +1870,11 @@ |
| 1799 | 1870 | char *z, *zToken; |
| 1800 | 1871 | int i; |
| 1801 | 1872 | const char *zScheme = "http"; |
| 1802 | 1873 | char zLine[2000]; /* A single line of input. */ |
| 1803 | 1874 | g.fullHttpReply = 1; |
| 1804 | | - if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 1875 | + if( cgi_fgets(zLine, sizeof(zLine))==0 ){ |
| 1805 | 1876 | malformed_request("missing HTTP header"); |
| 1806 | 1877 | } |
| 1807 | 1878 | blob_append(&g.httpHeader, zLine, -1); |
| 1808 | 1879 | cgi_trace(zLine); |
| 1809 | 1880 | zToken = extract_token(zLine, &z); |
| | @@ -1837,11 +1908,11 @@ |
| 1837 | 1908 | } |
| 1838 | 1909 | |
| 1839 | 1910 | |
| 1840 | 1911 | /* Get all the optional fields that follow the first line. |
| 1841 | 1912 | */ |
| 1842 | | - while( fgets(zLine,sizeof(zLine),g.httpIn) ){ |
| 1913 | + while( cgi_fgets(zLine,sizeof(zLine)) ){ |
| 1843 | 1914 | char *zFieldName; |
| 1844 | 1915 | char *zVal; |
| 1845 | 1916 | |
| 1846 | 1917 | cgi_trace(zLine); |
| 1847 | 1918 | blob_append(&g.httpHeader, zLine, -1); |
| | @@ -1916,10 +1987,11 @@ |
| 1916 | 1987 | char *z, *zToken; |
| 1917 | 1988 | const char *zType = 0; |
| 1918 | 1989 | int i, content_length = 0; |
| 1919 | 1990 | char zLine[2000]; /* A single line of input. */ |
| 1920 | 1991 | |
| 1992 | + assert( !g.httpUseSSL ); |
| 1921 | 1993 | #ifdef FOSSIL_ENABLE_JSON |
| 1922 | 1994 | if( nCycles==0 ){ json_bootstrap_early(); } |
| 1923 | 1995 | #endif |
| 1924 | 1996 | if( zIpAddr ){ |
| 1925 | 1997 | if( nCycles==0 ){ |
| | @@ -2057,10 +2129,11 @@ |
| 2057 | 2129 | /* |
| 2058 | 2130 | ** This routine handles the old fossil SSH probes |
| 2059 | 2131 | */ |
| 2060 | 2132 | char *cgi_handle_ssh_probes(char *zLine, int zSize, char *z, char *zToken){ |
| 2061 | 2133 | /* Start looking for probes */ |
| 2134 | + assert( !g.httpUseSSL ); |
| 2062 | 2135 | while( fossil_strcmp(zToken, "echo")==0 ){ |
| 2063 | 2136 | zToken = extract_token(z, &z); |
| 2064 | 2137 | if( zToken==0 ){ |
| 2065 | 2138 | malformed_request("malformed probe"); |
| 2066 | 2139 | } |
| | @@ -2094,10 +2167,11 @@ |
| 2094 | 2167 | */ |
| 2095 | 2168 | void cgi_handle_ssh_transport(const char *zCmd){ |
| 2096 | 2169 | char *z, *zToken; |
| 2097 | 2170 | char zLine[2000]; /* A single line of input. */ |
| 2098 | 2171 | |
| 2172 | + assert( !g.httpUseSSL ); |
| 2099 | 2173 | /* look for second newline of transport_flip */ |
| 2100 | 2174 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 2101 | 2175 | malformed_request("incorrect transport_flip"); |
| 2102 | 2176 | } |
| 2103 | 2177 | cgi_trace(zLine); |
| | @@ -2143,10 +2217,11 @@ |
| 2143 | 2217 | char *zToFree; |
| 2144 | 2218 | int nHdr = 0; |
| 2145 | 2219 | int nRead; |
| 2146 | 2220 | int c, n, m; |
| 2147 | 2221 | |
| 2222 | + assert( !g.httpUseSSL ); |
| 2148 | 2223 | while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit((char)c) ){ |
| 2149 | 2224 | nHdr = nHdr*10 + (char)c - '0'; |
| 2150 | 2225 | } |
| 2151 | 2226 | if( nHdr<16 ) malformed_request("SCGI header too short"); |
| 2152 | 2227 | zToFree = zHdr = fossil_malloc(nHdr); |
| 2153 | 2228 | |