Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Send bare \n instead of \r\n for all HTTP reply headers. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
8d917cb10df3ad28c9662190cec397c1 |
User & Date: | drh 2024-10-10 16:21:28.920 |
Context
2024-10-11
| ||
10:35 | Add a copyright release form. ... (check-in: f6ad09182f user: drh tags: trunk) | |
2024-10-10
| ||
16:21 | Send bare \n instead of \r\n for all HTTP reply headers. ... (check-in: 8d917cb10d user: drh tags: trunk) | |
2024-09-30
| ||
17:38 | Fix the --enable-sab command-line option so that it only consumes a single argument from the command-line, not two. ... (check-in: e2bfd75a40 user: drh tags: trunk) | |
Changes
Changes to althttpd.c.
︙ | ︙ | |||
386 387 388 389 390 391 392 393 394 395 396 397 398 399 | #ifdef _POSIX_MONOTONIC_CLOCK # define ALTHTTPD_CLOCK_ID CLOCK_MONOTONIC #else # define ALTHTTPD_CLOCK_ID CLOCK_REALTIME /* noting that this can jump if the system time changes */ #endif /* ** We record most of the state information as global variables. This ** saves having to pass information to subroutines as parameters, and ** makes the executable smaller... */ static const char *zRoot = 0; /* Root directory of the website */ static char *zPostData= 0; /* POST data */ | > > > > > | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 | #ifdef _POSIX_MONOTONIC_CLOCK # define ALTHTTPD_CLOCK_ID CLOCK_MONOTONIC #else # define ALTHTTPD_CLOCK_ID CLOCK_REALTIME /* noting that this can jump if the system time changes */ #endif /* ** Change CRNL to be the string "\r\n" for strict compliance with HTTP. */ #define CRNL "\n" /* ** We record most of the state information as global variables. This ** saves having to pass information to subroutines as parameters, and ** makes the executable smaller... */ static const char *zRoot = 0; /* Root directory of the website */ static char *zPostData= 0; /* POST data */ |
︙ | ︙ | |||
1252 1253 1254 1255 1256 1257 1258 | } /* ** Print a date tag in the header. The name of the tag is zTag. ** The date is determined from the unix timestamp given. */ static int DateTag(const char *zTag, time_t t){ | | | 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 | } /* ** Print a date tag in the header. The name of the tag is zTag. ** The date is determined from the unix timestamp given. */ static int DateTag(const char *zTag, time_t t){ return althttpd_printf("%s: %s" CRNL, zTag, Rfc822Date(t)); } /* ** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return ** a Unix epoch time. <= zero is returned on failure. */ time_t ParseRfc822Date(const char *zDate){ |
︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 | /* ** Print the first line of a response followed by the server type. */ static void StartResponse(const char *zResultCode){ time_t now; time(&now); if( statusSent ) return; | | | | | 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 | /* ** Print the first line of a response followed by the server type. */ static void StartResponse(const char *zResultCode){ time_t now; time(&now); if( statusSent ) return; nOut += althttpd_printf("%s %s" CRNL, zProtocol ? zProtocol : "HTTP/1.1", zResultCode); strncpy(zReplyStatus, zResultCode, 3); zReplyStatus[3] = 0; if( zReplyStatus[0]>='4' ){ closeConnection = 1; } if( closeConnection ){ nOut += althttpd_printf("Connection: close" CRNL); }else{ nOut += althttpd_printf("Connection: keep-alive" CRNL); } nOut += DateTag("Date", now); statusSent = 1; } /* ** Check all of the files in the zIPShunDir directory. Unlink any |
︙ | ︙ | |||
1469 1470 1471 1472 1473 1474 1475 | /* ** Send a service-unavailable reply. */ static void ServiceUnavailable(int lineno){ StartResponse("503 Service Unavailable"); nOut += althttpd_printf( | | < > | < > | < > | | < > | < > | 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 | /* ** Send a service-unavailable reply. */ static void ServiceUnavailable(int lineno){ StartResponse("503 Service Unavailable"); nOut += althttpd_printf( "Content-type: text/plain; charset=utf-8" CRNL CRNL "Service to IP address %s temporarily blocked due to abuse\n", zRemoteAddr ); closeConnection = 1; MakeLogEntry(0, lineno); althttpd_exit(0); } /* ** Tell the client that there is no such document */ static void NotFound(int lineno){ if( LikelyHackAttempt() ){ BlockIPAddress(); ServiceUnavailable(lineno); } UnlinkExpiredIPBlockers(); StartResponse("404 Not Found"); nOut += althttpd_printf( "Content-type: text/html; charset=utf-8" CRNL CRNL "<html><head><title lineno=\"%d\">Not Found</title></head>\n" "<body><h1>Document Not Found</h1>\n" "The document %s is not available on this server\n" "</body></html>\n", lineno, zScript); MakeLogEntry(0, lineno); althttpd_exit(0); } /* ** Tell the client that they are not welcomed here. */ static void Forbidden(int lineno){ StartResponse("403 Forbidden"); nOut += althttpd_printf( "Content-type: text/plain; charset=utf-8" CRNL CRNL "Access denied\n" ); closeConnection = 1; MakeLogEntry(0, lineno); althttpd_exit(0); } /* ** Tell the client that authorization is required to access the ** document. */ static void NotAuthorized(const char *zRealm){ StartResponse("401 Authorization Required"); nOut += althttpd_printf( "WWW-Authenticate: Basic realm=\"%s\"" CRNL "Content-type: text/html; charset=utf-8" CRNL CRNL "<head><title>Not Authorized</title></head>\n" "<body><h1>401 Not Authorized</h1>\n" "A login and password are required for this document\n" "</body>\n", zRealm); MakeLogEntry(0, 110); /* LOG: Not authorized */ } /* ** Tell the client that there is an error in the script. */ static void CgiError(void){ StartResponse("500 Error"); nOut += althttpd_printf( "Content-type: text/html; charset=utf-8" CRNL CRNL "<head><title>CGI Program Error</title></head>\n" "<body><h1>CGI Program Error</h1>\n" "The CGI program %s generated an error\n" "</body>\n", zScript); MakeLogEntry(0, 120); /* LOG: CGI Error */ althttpd_exit(0); } |
︙ | ︙ | |||
1603 1604 1605 1606 1607 1608 1609 | /* ** Tell the client that there is an error in the script. */ static void CgiScriptWritable(void){ StartResponse("500 CGI Configuration Error"); nOut += althttpd_printf( | | < > | < > | 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 | /* ** Tell the client that there is an error in the script. */ static void CgiScriptWritable(void){ StartResponse("500 CGI Configuration Error"); nOut += althttpd_printf( "Content-type: text/plain; charset=utf-8" CRNL CRNL "The CGI program %s is writable by users other than its owner.\n", zRealScript); MakeLogEntry(0, 140); /* LOG: CGI script is writable */ althttpd_exit(0); } /* ** Tell the client that the server malfunctioned. */ void Malfunction(int linenum, const char *zFormat, ...){ va_list ap; va_start(ap, zFormat); StartResponse("500 Server Malfunction"); nOut += althttpd_printf( "Content-type: text/plain; charset=utf-8" CRNL CRNL "Web server malfunctioned; error number %d\n\n", linenum); if( zFormat ){ nOut += althttpd_vprintf(zFormat, ap); althttpd_printf("\n"); nOut++; } va_end(ap); |
︙ | ︙ | |||
1650 1651 1652 1653 1654 1655 1656 | StartResponse("308 Permanent Redirect"); break; default: StartResponse("302 Temporary Redirect"); break; } if( zServerPort==0 || zServerPort[0]==0 || strcmp(zServerPort,"80")==0 ){ | | | | < | 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 | StartResponse("308 Permanent Redirect"); break; default: StartResponse("302 Temporary Redirect"); break; } if( zServerPort==0 || zServerPort[0]==0 || strcmp(zServerPort,"80")==0 ){ nOut += althttpd_printf("Location: %s://%s%s%s" CRNL, zHttpScheme, zServerName, zPath, zQuerySuffix); }else{ nOut += althttpd_printf("Location: %s://%s:%s%s%s" CRNL, zHttpScheme, zServerName, zServerPort, zPath, zQuerySuffix); } if( finish ){ nOut += althttpd_printf("Content-length: 0" CRNL CRNL); MakeLogEntry(0, lineno); } fflush(stdout); } /* ** This function treats its input as a base-64 string and returns the |
︙ | ︙ | |||
2481 2482 2483 2484 2485 2486 2487 | if( CompareEtags(zIfNoneMatch,zETag)==0 || (zIfModifiedSince!=0 && (t = ParseRfc822Date(zIfModifiedSince))>0 && t>=pStat->st_mtime) ){ StartResponse("304 Not Modified"); nOut += DateTag("Last-Modified", pStat->st_mtime); | | | < | 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 | if( CompareEtags(zIfNoneMatch,zETag)==0 || (zIfModifiedSince!=0 && (t = ParseRfc822Date(zIfModifiedSince))>0 && t>=pStat->st_mtime) ){ StartResponse("304 Not Modified"); nOut += DateTag("Last-Modified", pStat->st_mtime); nOut += althttpd_printf("Cache-Control: max-age=%d" CRNL, mxAge); nOut += althttpd_printf("ETag: \"%s\"" CRNL CRNL, zETag); fflush(stdout); MakeLogEntry(0, 470); /* LOG: ETag Cache Hit */ return 1; } if( rangeEnd<=0 && zAcceptEncoding && strstr(zAcceptEncoding,"gzip")!=0 |
︙ | ︙ | |||
2513 2514 2515 2516 2517 2518 2519 | in = fopen(zFile,"rb"); if( in==0 ) NotFound(480); /* LOG: fopen() failed for static content */ if( rangeEnd>0 && rangeStart<pStat->st_size ){ StartResponse("206 Partial Content"); if( rangeEnd>=pStat->st_size ){ rangeEnd = pStat->st_size-1; } | | | | | | | | | | 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 | in = fopen(zFile,"rb"); if( in==0 ) NotFound(480); /* LOG: fopen() failed for static content */ if( rangeEnd>0 && rangeStart<pStat->st_size ){ StartResponse("206 Partial Content"); if( rangeEnd>=pStat->st_size ){ rangeEnd = pStat->st_size-1; } nOut += althttpd_printf("Content-Range: bytes %d-%d/%d" CRNL, rangeStart, rangeEnd, (int)pStat->st_size); pStat->st_size = rangeEnd + 1 - rangeStart; }else{ StartResponse("200 OK"); rangeStart = 0; } nOut += DateTag("Last-Modified", pStat->st_mtime); if( enableSAB ){ /* The following two HTTP reply headers are required if javascript ** is to make use of SharedArrayBuffer */ nOut += althttpd_printf("Cross-Origin-Opener-Policy: same-origin" CRNL); nOut += althttpd_printf("Cross-Origin-Embedder-Policy: require-corp" CRNL); } nOut += althttpd_printf("Cache-Control: max-age=%d" CRNL, mxAge); nOut += althttpd_printf("ETag: \"%s\"" CRNL, zETag); nOut += althttpd_printf("Content-type: %s%s" CRNL,zContentType, bAddCharset ? "; charset=utf-8" : ""); if( zEncoding ){ nOut += althttpd_printf("Content-encoding: %s" CRNL, zEncoding); } nOut += althttpd_printf("Content-length: %d" CRNL CRNL,(int)pStat->st_size); fflush(stdout); if( strcmp(zMethod,"HEAD")==0 ){ MakeLogEntry(0, 2); /* LOG: Normal HEAD reply */ fclose(in); fflush(stdout); return 1; } |
︙ | ︙ | |||
2611 2612 2613 2614 2615 2616 2617 | while( fgets(zLine,sizeof(zLine),in) && !isspace((unsigned char)zLine[0]) ){ if( strncasecmp(zLine,"Location:",9)==0 ){ StartResponse("302 Redirect"); RemoveNewline(zLine); z = &zLine[10]; while( isspace(*(unsigned char*)z) ){ z++; } | | | 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 | while( fgets(zLine,sizeof(zLine),in) && !isspace((unsigned char)zLine[0]) ){ if( strncasecmp(zLine,"Location:",9)==0 ){ StartResponse("302 Redirect"); RemoveNewline(zLine); z = &zLine[10]; while( isspace(*(unsigned char*)z) ){ z++; } nOut += althttpd_printf("Location: %s" CRNL,z); rangeEnd = 0; }else if( strncasecmp(zLine,"Status:",7)==0 ){ int i; for(i=7; isspace((unsigned char)zLine[i]); i++){} strncpy(zReplyStatus, &zLine[i], 3); zReplyStatus[3] = 0; iStatus = atoi(zReplyStatus); |
︙ | ︙ | |||
2657 2658 2659 2660 2661 2662 2663 | /* Copy everything else thru without change or analysis. */ if( rangeEnd>0 && seenContentLength && rangeStart<contentLength ){ StartResponse("206 Partial Content"); if( rangeEnd>=contentLength ){ rangeEnd = contentLength-1; } | | | | | | | 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 | /* Copy everything else thru without change or analysis. */ if( rangeEnd>0 && seenContentLength && rangeStart<contentLength ){ StartResponse("206 Partial Content"); if( rangeEnd>=contentLength ){ rangeEnd = contentLength-1; } nOut += althttpd_printf("Content-Range: bytes %d-%d/%d" CRNL, rangeStart, rangeEnd, contentLength); contentLength = rangeEnd + 1 - rangeStart; }else{ StartResponse("200 OK"); } if( nRes>0 ){ aRes[nRes] = 0; althttpd_fwrite(aRes, nRes, 1, stdout); nOut += nRes; nRes = 0; } if( iStatus==304 ){ nOut += althttpd_printf(CRNL CRNL); }else if( seenContentLength ){ nOut += althttpd_printf("Content-length: %d" CRNL CRNL, contentLength); xferBytes(in, stdout, contentLength, rangeStart); }else{ while( (c = getc(in))!=EOF ){ if( nRes>=nMalloc ){ nMalloc = nMalloc*2 + 1000; aRes = realloc(aRes, nMalloc+1); if( aRes==0 ){ Malfunction(610, "Out of memory: %d bytes", nMalloc); /* LOG: OOM */ } } aRes[nRes++] = c; } if( nRes ){ aRes[nRes] = 0; nOut += althttpd_printf("Content-length: %d" CRNL CRNL, (int)nRes); nOut += althttpd_fwrite(aRes, nRes, 1, stdout); }else{ nOut += althttpd_printf("Content-length: 0" CRNL CRNL); } } free(aRes); fclose(in); } /* |
︙ | ︙ | |||
3047 3048 3049 3050 3051 3052 3053 | || strlen(zProtocol)!=8 || i>9990 ){ zProtocol = 0; if( i<=9990 ){ StartResponse("400 Bad Request"); nOut += althttpd_printf( | | < > | < > | 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 | || strlen(zProtocol)!=8 || i>9990 ){ zProtocol = 0; if( i<=9990 ){ StartResponse("400 Bad Request"); nOut += althttpd_printf( "Content-type: text/plain; charset=utf-8" CRNL CRNL "This server does not understand the requested protocol\n" ); MakeLogEntry(0, 200); /* LOG: bad protocol in HTTP header */ }else{ StartResponse("414 URI Too Long"); nOut += althttpd_printf( "Content-type: text/plain; charset=utf-8" CRNL CRNL "URI too long\n" ); MakeLogEntry(0, 201); /* LOG: bad protocol in HTTP header */ } althttpd_exit(0); } if( zScript[0]!='/' ) NotFound(210); /* LOG: Empty request URI */ |
︙ | ︙ | |||
3081 3082 3083 3084 3085 3086 3087 | /* This very simple server only understands the GET, POST ** and HEAD methods */ if( strcmp(zMethod,"GET")!=0 && strcmp(zMethod,"POST")!=0 && strcmp(zMethod,"HEAD")!=0 ){ StartResponse("501 Not Implemented"); nOut += althttpd_printf( | | < > | 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 | /* This very simple server only understands the GET, POST ** and HEAD methods */ if( strcmp(zMethod,"GET")!=0 && strcmp(zMethod,"POST")!=0 && strcmp(zMethod,"HEAD")!=0 ){ StartResponse("501 Not Implemented"); nOut += althttpd_printf( "Content-type: text/plain; charset=utf-8" CRNL CRNL "The %s method is not implemented on this server.\n", zMethod); MakeLogEntry(0, 220); /* LOG: Unknown request method */ althttpd_exit(0); } /* If there is a log file (if zLogFile!=0) and if the pathname in |
︙ | ︙ | |||
3296 3297 3298 3299 3300 3301 3302 | /* Create either a memory buffer to hold the POST query data */ if( zMethod[0]=='P' && zContentLength!=0 ){ size_t len = atoi(zContentLength); if( len>MAX_CONTENT_LENGTH ){ StartResponse("500 Request too large"); nOut += althttpd_printf( | | < > | 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 | /* Create either a memory buffer to hold the POST query data */ if( zMethod[0]=='P' && zContentLength!=0 ){ size_t len = atoi(zContentLength); if( len>MAX_CONTENT_LENGTH ){ StartResponse("500 Request too large"); nOut += althttpd_printf( "Content-type: text/plain; charset=utf-8" CRNL CRNL "Too much POST data\n" ); MakeLogEntry(0, 270); /* LOG: Request too large */ althttpd_exit(0); } rangeEnd = 0; zPostData = SafeMalloc( len+1 ); |
︙ | ︙ |