Index: althttpd.c ================================================================== --- althttpd.c +++ althttpd.c @@ -464,14 +464,14 @@ 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 #include @@ -631,16 +631,20 @@ static int tls_init_conn(int iSocket); static void tls_close_conn(void); static void althttpd_fflush(FILE *f); /* -** Flush the buffer then exit. +** 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(void){ +static void althttpd_exit(int iErrCode){ + assert( isExiting == 0 ); + isExiting = iErrCode ? iErrCode : 1; althttpd_fflush(stdout); tls_close_conn(); - exit(0); + exit(iErrCode); } /* ** Mapping between CGI variable names and values stored in ** global variables. @@ -1467,11 +1471,11 @@ "Service to IP address %s temporarily blocked due to abuse\n", zRemoteAddr ); closeConnection = 1; MakeLogEntry(0, lineno); - althttpd_exit(); + althttpd_exit(0); } /* ** Tell the client that there is no such document */ @@ -1488,11 +1492,11 @@ "Not Found\n" "

Document Not Found

\n" "The document %s is not available on this server\n" "\n", lineno, zScript); MakeLogEntry(0, lineno); - althttpd_exit(); + althttpd_exit(0); } /* ** Tell the client that they are not welcomed here. */ @@ -1503,11 +1507,11 @@ "\r\n" "Access denied\n" ); closeConnection = 1; MakeLogEntry(0, lineno); - althttpd_exit(); + althttpd_exit(0); } /* ** Tell the client that authorization is required to access the ** document. @@ -1536,11 +1540,11 @@ "CGI Program Error\n" "

CGI Program Error

\n" "The CGI program %s generated an error\n" "\n", zScript); MakeLogEntry(0, 120); /* LOG: CGI Error */ - althttpd_exit(); + althttpd_exit(0); exit(0); } /* ** Set the timeout in seconds. 0 means no-timeout. @@ -1553,13 +1557,15 @@ } /* ** 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 ){ + 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; @@ -1583,11 +1589,11 @@ MakeLogEntry(0, 139); /* LOG: Unknown signal */ break; } --inSignalHandler; } - exit(0); + althttpd_exit(0); } } /* ** Tell the client that there is an error in the script. @@ -1598,11 +1604,11 @@ "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(); + althttpd_exit(0); } /* ** Tell the client that the server malfunctioned. */ @@ -1619,11 +1625,11 @@ althttpd_printf("\n"); nOut++; } va_end(ap); MakeLogEntry(0, linenum); - althttpd_exit(); + althttpd_exit(0); } /* ** Do a server redirect to the document specified. The document ** name not contain scheme or network location or the query string. @@ -2311,21 +2317,19 @@ memset(pServer, 0, sizeof(TlsServerConn)); free(pServer); } static void tls_atexit(void){ -#if 0 /* ** 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 } #endif /* ENABLE_TLS */ /* @@ -2789,11 +2793,11 @@ 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(); + althttpd_exit(0); }else{ Malfunction(706, /* LOG: bad SCGI fallback */ "bad fallback file: \"%s\"\n", zFallback); } } @@ -3012,11 +3016,11 @@ /* 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 ){ - exit(0); + althttpd_exit(0); } clock_gettime(ALTHTTPD_CLOCK_ID, &tsBeginTime); gettimeofday(&beginTime, 0); omitLog = 0; nIn += (i = (int)strlen(zLine)); @@ -3046,11 +3050,11 @@ "\r\n" "URI too long\n" ); MakeLogEntry(0, 201); /* LOG: bad protocol in HTTP header */ } - althttpd_exit(); + althttpd_exit(0); } if( zScript[0]!='/' ) NotFound(210); /* LOG: Empty request URI */ while( zScript[1]=='/' ){ zScript++; zRealScript++; @@ -3071,11 +3075,11 @@ "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(); + 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 @@ -3271,11 +3275,11 @@ "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(); + 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); @@ -3526,11 +3530,11 @@ } } /* Run the CGI program */ execl(zBaseFilename, zBaseFilename, (char*)0); - exit(0); /* Not reached */ + 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 */ @@ -3605,11 +3609,11 @@ sprintf(zUrl, "http://localhost:%d/%s", iPort, zPath); for(i=0; imxPort ) return 1; listen(listener,10); printf("Listening for %s requests on TCP port %d\n", useHttps?"TLS-encrypted HTTPS":"HTTP", iPort); @@ -3697,11 +3701,11 @@ if( child!=0 ){ if( child>0 ) nchildren++; }else{ launch_web_browser(zPage, iPort); /* NOT REACHED */ - exit(1); + althttpd_exit(1); } } while( 1 ){ if( nchildren>MAX_PARALLEL ){ /* Slow down if connections are arriving too fast */ @@ -3741,11 +3745,11 @@ /* printf("process %d ends\n", child); fflush(stdout); */ nchildren--; } } /* NOT REACHED */ - exit(1); + 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 */ @@ -3885,11 +3889,11 @@ return 0; }else if( strcmp(z, "-datetest")==0 ){ TestParseRfc822Date(); printf("Ok\n"); - exit(0); + 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); @@ -4021,11 +4025,11 @@ for(i=0; i<100; i++){ ProcessOneRequest(0, httpConnection); } ProcessOneRequest(1, httpConnection); tls_close_conn(); - exit(0); + althttpd_exit(0); } #if 0 /* Copy/paste the following text into SQLite to generate the xref ** table that describes all error codes.