Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch signal-after-exit Excluding Merge-Ins
This is equivalent to a diff from c482a5e04d to 092234da85
2024-02-08
| ||
08:43 | Improve the handling of a signal after exit() is called, as that leads to undefined results in some libc implementations. We now keep track of whether exit() has been called and skip signal handling if a signal is triggered after that. ... (check-in: b60cc28c07 user: stephan tags: trunk) | |
2024-01-26
| ||
03:17 | Rework exit() calls so that Timeout() cannot be run after exit(). This is an attempt to work around the problem reported in /forumpost/9947114e61. ... (Closed-Leaf check-in: 092234da85 user: stephan tags: signal-after-exit) | |
2024-01-17
| ||
14:40 | Audit recent log changes, making improvements to comments. Add mention of the automatic content compression feature to the feature list in the main header comment. Identify ".md" files has text/plain. ... (check-in: c482a5e04d user: drh tags: trunk) | |
12:27 | Rename LOG_PID to ALTHTTPD_LOG_PID because LOG_PID is defined indirectly by syslog.h, causing it to always be defined on some builds. ... (check-in: a0a5f93c36 user: stephan tags: trunk) | |
Changes to althttpd.c.
︙ | ︙ | |||
462 463 464 465 466 467 468 469 470 471 | static char *zScgi = 0; /* Value of the SCGI env variable */ static int rangeStart = 0; /* Start of a Range: request */ static int rangeEnd = 0; /* End of a Range: request */ static int maxCpu = MAX_CPU; /* Maximum CPU time per process */ static int enableSAB = 0; /* Add reply header to enable ** SharedArrayBuffer */ static int inSignalHandler = 0; /* True if running a signal handler */ /* Forward reference */ static void Malfunction(int errNo, const char *zFormat, ...); | > < | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | static char *zScgi = 0; /* Value of the SCGI env variable */ static int rangeStart = 0; /* Start of a Range: request */ static int rangeEnd = 0; /* End of a Range: request */ static int maxCpu = MAX_CPU; /* Maximum CPU time per process */ static int enableSAB = 0; /* Add reply header to enable ** SharedArrayBuffer */ static int inSignalHandler = 0; /* True if running a signal handler */ static int isExiting = 0; /* True when althttpd_exit() has been called */ /* Forward reference */ static void Malfunction(int errNo, const char *zFormat, ...); #ifdef ENABLE_TLS #include <openssl/bio.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/x509.h> |
︙ | ︙ | |||
629 630 631 632 633 634 635 | /* forward references */ static int tls_init_conn(int iSocket); static void tls_close_conn(void); static void althttpd_fflush(FILE *f); /* | | > > | > > | | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 | /* forward references */ static int tls_init_conn(int iSocket); static void tls_close_conn(void); static void althttpd_fflush(FILE *f); /* ** Flush stdout then exit() with the given result code. This must ** always be used instead of exit() so that a corner case involving ** post-exit() signal handling via Timeout() can be accounted for. */ static void althttpd_exit(int iErrCode){ assert( isExiting == 0 ); isExiting = iErrCode ? iErrCode : 1; althttpd_fflush(stdout); tls_close_conn(); exit(iErrCode); } /* ** Mapping between CGI variable names and values stored in ** global variables. */ static struct { |
︙ | ︙ | |||
1465 1466 1467 1468 1469 1470 1471 | "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); | | | | | 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 | "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" "<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>\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){ |
︙ | ︙ | |||
1534 1535 1536 1537 1538 1539 1540 | "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 */ | | > > | | 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 | "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); exit(0); } /* ** Set the timeout in seconds. 0 means no-timeout. */ static void SetTimeout(int nSec, int lineNum){ if( useTimeout ){ nTimeoutLine = lineNum; alarm(nSec); } } /* ** This is called if we timeout or catch some other kind of signal. ** Log an error code which is 900+iSig and then quit. ** ** If called after althttpd_exit(), this is a no-op. */ static void Timeout(int iSig){ if( debugFlag==0 && isExiting==0 ){ if( zScript && zScript[0] ){ char zBuf[10]; zBuf[0] = '9'; zBuf[1] = '0' + (iSig/10)%10; zBuf[2] = '0' + iSig%10; zBuf[3] = 0; strcpy(zReplyStatus, zBuf); |
︙ | ︙ | |||
1581 1582 1583 1584 1585 1586 1587 | break; default: MakeLogEntry(0, 139); /* LOG: Unknown signal */ break; } --inSignalHandler; } | | | | | 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 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 1635 1636 1637 | break; default: MakeLogEntry(0, 139); /* LOG: Unknown signal */ break; } --inSignalHandler; } althttpd_exit(0); } } /* ** 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); MakeLogEntry(0, linenum); althttpd_exit(0); } /* ** Do a server redirect to the document specified. The document ** name not contain scheme or network location or the query string. ** It will be just the path. */ |
︙ | ︙ | |||
2309 2310 2311 2312 2313 2314 2315 | TlsServerConn *pServer = (TlsServerConn*)pServerArg; SSL_free(pServer->ssl); memset(pServer, 0, sizeof(TlsServerConn)); free(pServer); } static void tls_atexit(void){ | < < | 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 | TlsServerConn *pServer = (TlsServerConn*)pServerArg; SSL_free(pServer->ssl); memset(pServer, 0, sizeof(TlsServerConn)); free(pServer); } static void tls_atexit(void){ /* ** Shutting down TLS can lead to spurious hung processes on some ** platforms/builds. See the long discussion on this at: ** https://sqlite.org/althttpd/forumpost/4dc31619341ce947 */ if( inSignalHandler==0 && tlsState.sslCon!=0 ){ tls_close_server(tlsState.sslCon); tlsState.sslCon = NULL; } } #endif /* ENABLE_TLS */ /* ** Works like fgets(): ** |
︙ | ︙ | |||
2787 2788 2789 2790 2791 2792 2793 | zDir, getcwd(zBuf,999)); } rc = stat(zFallback, &statbuf); if( rc==0 && S_ISREG(statbuf.st_mode) && access(zFallback,R_OK)==0 ){ closeConnection = 1; rc = SendFile(zFallback, (int)strlen(zFallback), &statbuf); free(zFallback); | | | 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 | zDir, getcwd(zBuf,999)); } rc = stat(zFallback, &statbuf); if( rc==0 && S_ISREG(statbuf.st_mode) && access(zFallback,R_OK)==0 ){ closeConnection = 1; rc = SendFile(zFallback, (int)strlen(zFallback), &statbuf); free(zFallback); althttpd_exit(0); }else{ Malfunction(706, /* LOG: bad SCGI fallback */ "bad fallback file: \"%s\"\n", zFallback); } } Malfunction(707, /* LOG: Cannot open socket to SCGI */ "cannot open socket to SCGI server %s\n", |
︙ | ︙ | |||
3010 3011 3012 3013 3014 3015 3016 | tls_init_conn(socketId); /* Get the first line of the request and parse out the ** method, the script and the protocol. */ omitLog = 1; if( althttpd_fgets(zLine,sizeof(zLine),stdin)==0 ){ | | | 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 | tls_init_conn(socketId); /* Get the first line of the request and parse out the ** method, the script and the protocol. */ omitLog = 1; if( althttpd_fgets(zLine,sizeof(zLine),stdin)==0 ){ althttpd_exit(0); } clock_gettime(ALTHTTPD_CLOCK_ID, &tsBeginTime); gettimeofday(&beginTime, 0); omitLog = 0; nIn += (i = (int)strlen(zLine)); /* Parse the first line of the HTTP request */ |
︙ | ︙ | |||
3044 3045 3046 3047 3048 3049 3050 | 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 */ } | | | 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 | 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 */ while( zScript[1]=='/' ){ zScript++; zRealScript++; } if( forceClose ){ |
︙ | ︙ | |||
3069 3070 3071 3072 3073 3074 3075 | 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 */ | | | 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 | 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 ** the first line of the http request contains the magic string ** "FullHeaderLog" then write the complete header text into the ** file %s(zLogFile)-hdr. Overwrite the file. This is for protocol ** debugging only and is only enabled if althttpd is compiled with |
︙ | ︙ | |||
3269 3270 3271 3272 3273 3274 3275 | 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 */ | | | 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 | 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 ); SetTimeout(15 + len/2000, 803); /* LOG: Timeout POST data */ nPostData = althttpd_fread(zPostData,1,len,stdin); nIn += nPostData; } |
︙ | ︙ | |||
3524 3525 3526 3527 3528 3529 3530 | if( *cgienv[i].pzEnvValue ){ SetEnv(cgienv[i].zEnvName,*cgienv[i].pzEnvValue); } } /* Run the CGI program */ execl(zBaseFilename, zBaseFilename, (char*)0); | | | 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 | if( *cgienv[i].pzEnvValue ){ SetEnv(cgienv[i].zEnvName,*cgienv[i].pzEnvValue); } } /* Run the CGI program */ execl(zBaseFilename, zBaseFilename, (char*)0); althttpd_exit(0); /* Not reached */ } /* This parent process. The child has been started. ** Set up the CGI-to-althttp pipe on which to receive the reply */ close(px[1]); in = fdopen(px[0], "rb"); |
︙ | ︙ | |||
3603 3604 3605 3606 3607 3608 3609 | if( strlen(zPath)<=sizeof(zUrl)-1000 ){ while( zPath[0]=='/' ) zPath++; sprintf(zUrl, "http://localhost:%d/%s", iPort, zPath); for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ execlp(azBrowserProg[i], azBrowserProg[i], zUrl, (char*)0); } } | | | 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 | if( strlen(zPath)<=sizeof(zUrl)-1000 ){ while( zPath[0]=='/' ) zPath++; sprintf(zUrl, "http://localhost:%d/%s", iPort, zPath); for(i=0; i<sizeof(azBrowserProg)/sizeof(azBrowserProg[0]); i++){ execlp(azBrowserProg[i], azBrowserProg[i], zUrl, (char*)0); } } althttpd_exit(1); } #define MAX_PARALLEL 50 /* Number of simultaneous children */ /* ** All possible forms of an IP address. Needed to work around GCC strict ** aliasing rules. |
︙ | ︙ | |||
3681 3682 3683 3684 3685 3686 3687 | if( iPort>mxPort ){ if( mnPort==mxPort ){ fprintf(stderr,"unable to open listening socket on port %d\n", mnPort); }else{ fprintf(stderr,"unable to open listening socket on any" " port in the range %d..%d\n", mnPort, mxPort); } | | | | 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 | if( iPort>mxPort ){ if( mnPort==mxPort ){ fprintf(stderr,"unable to open listening socket on port %d\n", mnPort); }else{ fprintf(stderr,"unable to open listening socket on any" " port in the range %d..%d\n", mnPort, mxPort); } althttpd_exit(1); } if( iPort>mxPort ) return 1; listen(listener,10); printf("Listening for %s requests on TCP port %d\n", useHttps?"TLS-encrypted HTTPS":"HTTP", iPort); fflush(stdout); if( zPage ){ child = fork(); if( child!=0 ){ if( child>0 ) nchildren++; }else{ launch_web_browser(zPage, iPort); /* NOT REACHED */ althttpd_exit(1); } } while( 1 ){ if( nchildren>MAX_PARALLEL ){ /* Slow down if connections are arriving too fast */ sleep( nchildren-MAX_PARALLEL ); } |
︙ | ︙ | |||
3739 3740 3741 3742 3743 3744 3745 | /* Bury dead children */ while( (child = waitpid(0, 0, WNOHANG))>0 ){ /* printf("process %d ends\n", child); fflush(stdout); */ nchildren--; } } /* NOT REACHED */ | | | 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 | /* Bury dead children */ while( (child = waitpid(0, 0, WNOHANG))>0 ){ /* printf("process %d ends\n", child); fflush(stdout); */ nchildren--; } } /* NOT REACHED */ althttpd_exit(1); } int main(int argc, const char **argv){ int i; /* Loop counter */ const char *zPermUser = 0; /* Run daemon with this user's permissions */ int mnPort = 0; /* Range of TCP ports for server mode */ int mxPort = 0; |
︙ | ︙ | |||
3883 3884 3885 3886 3887 3888 3889 | if( strcmp(z, "-version")==0 ){ puts(SERVER_SOFTWARE_TLS); return 0; }else if( strcmp(z, "-datetest")==0 ){ TestParseRfc822Date(); printf("Ok\n"); | | | 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 | if( strcmp(z, "-version")==0 ){ puts(SERVER_SOFTWARE_TLS); return 0; }else if( strcmp(z, "-datetest")==0 ){ TestParseRfc822Date(); printf("Ok\n"); althttpd_exit(0); }else if( strcmp(z,"-remote-addr")==0 ){ /* Used for testing purposes only - to simulate a remote IP address when ** input is really coming from a disk file. */ zRemoteAddr = StrDup(zArg); }else { |
︙ | ︙ | |||
4019 4020 4021 4022 4023 4024 4025 | /* Process the input stream */ for(i=0; i<100; i++){ ProcessOneRequest(0, httpConnection); } ProcessOneRequest(1, httpConnection); tls_close_conn(); | | | 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 | /* Process the input stream */ for(i=0; i<100; i++){ ProcessOneRequest(0, httpConnection); } ProcessOneRequest(1, httpConnection); tls_close_conn(); althttpd_exit(0); } #if 0 /* Copy/paste the following text into SQLite to generate the xref ** table that describes all error codes. */ BEGIN; |
︙ | ︙ |