Althttpd

Check-in [8d917cb10d]
Login

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 | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8d917cb10df3ad28c9662190cec397c18ecac3bd4338ae9b42dfc30fd17eab74
User & Date: drh 2024-10-10 16:21:28
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
Hide Diffs Unified Diffs Ignore Whitespace Patch

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
1259
1260
1261
1262
1263
1264
1265
1266
}

/*
** 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\r\n", 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){







|







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
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
/*
** 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\r\n",
                          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\r\n");
  }else{
    nOut += althttpd_printf("Connection: keep-alive\r\n");
  }
  nOut += DateTag("Date", now);
  statusSent = 1;
}

/*
** Check all of the files in the zIPShunDir directory.  Unlink any







|








|

|







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
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

/*
** Send a service-unavailable reply.
*/
static void ServiceUnavailable(int lineno){
  StartResponse("503 Service Unavailable");
  nOut += althttpd_printf(
    "Content-type: text/plain; charset=utf-8\r\n"
    "\r\n"

    "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\r\n"
    "\r\n"

    "<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\r\n"
    "\r\n"

    "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\"\r\n"
    "Content-type: text/html; charset=utf-8\r\n"
    "\r\n"

    "<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\r\n"
    "\r\n"

    "<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);
}







|
<
>



















|
<
>














|
<
>














|
|
<
>













|
<
>







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
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

/*
** 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\r\n"
    "\r\n"

    "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\r\n"
    "\r\n"

    "Web server malfunctioned; error number %d\n\n", linenum);
  if( zFormat ){
    nOut += althttpd_vprintf(zFormat, ap);
    althttpd_printf("\n");
    nOut++;
  }
  va_end(ap);







|
<
>














|
<
>







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
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
      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\r\n",
                   zHttpScheme, zServerName, zPath, zQuerySuffix);
  }else{
    nOut += althttpd_printf("Location: %s://%s:%s%s%s\r\n",
                   zHttpScheme, zServerName, zServerPort, zPath, zQuerySuffix);
  }
  if( finish ){
    nOut += althttpd_printf("Content-length: 0\r\n");
    nOut += althttpd_printf("\r\n");
    MakeLogEntry(0, lineno);
  }
  fflush(stdout);
}

/*
** This function treats its input as a base-64 string and returns the







|


|



|
<







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
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
  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\r\n", mxAge);
    nOut += althttpd_printf("ETag: \"%s\"\r\n", zETag);
    nOut += althttpd_printf("\r\n");
    fflush(stdout);
    MakeLogEntry(0, 470);  /* LOG: ETag Cache Hit */
    return 1;
  }
  if( rangeEnd<=0
   && zAcceptEncoding
   && strstr(zAcceptEncoding,"gzip")!=0







|
|
<







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
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
  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\r\n",
                    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\r\n");
    nOut += althttpd_printf("Cross-Origin-Embedder-Policy: require-corp\r\n");
  }
  nOut += althttpd_printf("Cache-Control: max-age=%d\r\n", mxAge);
  nOut += althttpd_printf("ETag: \"%s\"\r\n", zETag);
  nOut += althttpd_printf("Content-type: %s%s\r\n",zContentType,
                          bAddCharset ? "; charset=utf-8" : "");
  if( zEncoding ){
    nOut += althttpd_printf("Content-encoding: %s\r\n", zEncoding);
  }
  nOut += althttpd_printf("Content-length: %d\r\n\r\n",(int)pStat->st_size);
  fflush(stdout);
  if( strcmp(zMethod,"HEAD")==0 ){
    MakeLogEntry(0, 2); /* LOG: Normal HEAD reply */
    fclose(in);
    fflush(stdout);
    return 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
2618
2619
2620
2621
2622
2623
2624
2625

  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\r\n",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);







|







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
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
  /* 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\r\n",
                            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("\r\n\r\n");
  }else if( seenContentLength ){
    nOut += althttpd_printf("Content-length: %d\r\n\r\n", 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\r\n\r\n", (int)nRes);
      nOut += althttpd_fwrite(aRes, nRes, 1, stdout);
    }else{
      nOut += althttpd_printf("Content-length: 0\r\n\r\n");
    }
  }
  free(aRes);
  fclose(in);
}

/*







|












|

|














|


|







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
3054
3055

3056
3057
3058
3059
3060
3061
3062
3063

3064
3065
3066
3067
3068
3069
3070
   || strlen(zProtocol)!=8
   || i>9990
  ){
    zProtocol = 0;
    if( i<=9990 ){
      StartResponse("400 Bad Request");
      nOut += althttpd_printf(
        "Content-type: text/plain; charset=utf-8\r\n"
        "\r\n"

        "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\r\n"
        "\r\n"

        "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 */







|
<
>






|
<
>







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
3088
3089

3090
3091
3092
3093
3094
3095
3096
  /* 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\r\n"
      "\r\n"

      "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







|
<
>







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
3303
3304

3305
3306
3307
3308
3309
3310
3311

  /* 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\r\n"
        "\r\n"

        "Too much POST data\n"
      );
      MakeLogEntry(0, 270); /* LOG: Request too large */
      althttpd_exit(0);
    }
    rangeEnd = 0;
    zPostData = SafeMalloc( len+1 );







|
<
>







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 );