Fossil SCM
Implement an idle-timeout for windows.
Commit
aee7401958cf16b2707252ba67c5e496744532573e35f727e2876e50cba94bb7
Parent
1d7e2fa6971cf2c…
2 files changed
+3
-1
+22
-10
+3
-1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -2636,11 +2636,13 @@ | ||
| 2636 | 2636 | ** Options: |
| 2637 | 2637 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 2638 | 2638 | ** --create Create a new REPOSITORY if it does not already exist |
| 2639 | 2639 | ** --extroot DIR Document root for the /ext extension mechanism |
| 2640 | 2640 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 2641 | -** --idle-timeout N Exit if no HTTP requests received for N seconds | |
| 2641 | +** --idle-timeout N Exit if no HTTP requests are received for N seconds. | |
| 2642 | +** "0" means never. 0 is default for the "server" | |
| 2643 | +** command and "60" is the default for the "ui" command. | |
| 2642 | 2644 | ** --localauth enable automatic login for requests from localhost |
| 2643 | 2645 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2644 | 2646 | ** --https Indicates that the input is coming through a reverse |
| 2645 | 2647 | ** proxy that has already translated HTTPS into HTTP. |
| 2646 | 2648 | ** --max-latency N Do not let any single HTTP request run for more than N |
| 2647 | 2649 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -2636,11 +2636,13 @@ | |
| 2636 | ** Options: |
| 2637 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 2638 | ** --create Create a new REPOSITORY if it does not already exist |
| 2639 | ** --extroot DIR Document root for the /ext extension mechanism |
| 2640 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 2641 | ** --idle-timeout N Exit if no HTTP requests received for N seconds |
| 2642 | ** --localauth enable automatic login for requests from localhost |
| 2643 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2644 | ** --https Indicates that the input is coming through a reverse |
| 2645 | ** proxy that has already translated HTTPS into HTTP. |
| 2646 | ** --max-latency N Do not let any single HTTP request run for more than N |
| 2647 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -2636,11 +2636,13 @@ | |
| 2636 | ** Options: |
| 2637 | ** --baseurl URL Use URL as the base (useful for reverse proxies) |
| 2638 | ** --create Create a new REPOSITORY if it does not already exist |
| 2639 | ** --extroot DIR Document root for the /ext extension mechanism |
| 2640 | ** --files GLOBLIST Comma-separated list of glob patterns for static files |
| 2641 | ** --idle-timeout N Exit if no HTTP requests are received for N seconds. |
| 2642 | ** "0" means never. 0 is default for the "server" |
| 2643 | ** command and "60" is the default for the "ui" command. |
| 2644 | ** --localauth enable automatic login for requests from localhost |
| 2645 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2646 | ** --https Indicates that the input is coming through a reverse |
| 2647 | ** proxy that has already translated HTTPS into HTTP. |
| 2648 | ** --max-latency N Do not let any single HTTP request run for more than N |
| 2649 |
+22
-10
| --- src/winhttp.c | ||
| +++ src/winhttp.c | ||
| @@ -199,16 +199,18 @@ | ||
| 199 | 199 | } |
| 200 | 200 | return 1; |
| 201 | 201 | }; |
| 202 | 202 | |
| 203 | 203 | /* |
| 204 | -** Accepts connections on DualSocket. | |
| 204 | +** Accepts connections on DualSocket. Return | |
| 205 | 205 | */ |
| 206 | -static void DualSocket_accept(DualSocket* pListen, DualSocket* pClient, | |
| 206 | +static int DualSocket_accept(DualSocket* pListen, DualSocket* pClient, | |
| 207 | 207 | DualAddr* pClientAddr){ |
| 208 | 208 | fd_set rs; |
| 209 | 209 | int rs_count = 0; |
| 210 | + int rc = 0; | |
| 211 | + struct timeval delay; | |
| 210 | 212 | assert( pListen!=NULL && pClient!=NULL && pClientAddr!= NULL ); |
| 211 | 213 | DualSocket_init(pClient); |
| 212 | 214 | DualAddr_init(pClientAddr); |
| 213 | 215 | FD_ZERO(&rs); |
| 214 | 216 | if( pListen->s4!=INVALID_SOCKET ){ |
| @@ -217,21 +219,22 @@ | ||
| 217 | 219 | } |
| 218 | 220 | if( pListen->s6!=INVALID_SOCKET ){ |
| 219 | 221 | FD_SET(pListen->s6, &rs); |
| 220 | 222 | ++rs_count; |
| 221 | 223 | } |
| 222 | - if( select(rs_count, &rs, 0, 0, 0 /*blocking*/)==SOCKET_ERROR ){ | |
| 223 | - return; | |
| 224 | - } | |
| 224 | + delay.tv_sec = 2; | |
| 225 | + delay.tv_usec = 0; | |
| 226 | + rc = select(rs_count, &rs, 0, 0, &delay); | |
| 225 | 227 | if( FD_ISSET(pListen->s4, &rs) ){ |
| 226 | 228 | pClient->s4 = accept(pListen->s4, (struct sockaddr*)&pClientAddr->a4.addr, |
| 227 | 229 | &pClientAddr->a4.len); |
| 228 | 230 | } |
| 229 | 231 | if( FD_ISSET(pListen->s6, &rs) ){ |
| 230 | 232 | pClient->s6 = accept(pListen->s6, (struct sockaddr*)&pClientAddr->a6.addr, |
| 231 | 233 | &pClientAddr->a6.len); |
| 232 | 234 | } |
| 235 | + return rc; | |
| 233 | 236 | } |
| 234 | 237 | |
| 235 | 238 | /* |
| 236 | 239 | ** The HttpServer structure holds information about an instance of |
| 237 | 240 | ** the HTTP server itself. |
| @@ -514,16 +517,16 @@ | ||
| 514 | 517 | ** that socket. |
| 515 | 518 | */ |
| 516 | 519 | void win32_http_server( |
| 517 | 520 | int mnPort, int mxPort, /* Range of allowed TCP port numbers */ |
| 518 | 521 | const char *zBrowser, /* Command to launch browser. (Or NULL) */ |
| 519 | - const char *zStopper, /* Stop server when this file is exists (Or NULL) */ | |
| 522 | + const char *zStopper, /* Stop server when this file exists (Or NULL) */ | |
| 520 | 523 | const char *zBaseUrl, /* The --baseurl option, or NULL */ |
| 521 | 524 | const char *zNotFound, /* The --notfound option, or NULL */ |
| 522 | 525 | const char *zFileGlob, /* The --fileglob option, or NULL */ |
| 523 | 526 | const char *zIpAddr, /* Bind to this IP address, if not NULL */ |
| 524 | - int idleTimeout, /* Idle timeout in seconds. 0 means none */ | |
| 527 | + int iIdleTimeout, /* Idle timeout in seconds. 0 means none */ | |
| 525 | 528 | int flags /* One or more HTTP_SERVER_ flags */ |
| 526 | 529 | ){ |
| 527 | 530 | HANDLE hStoppedEvent; |
| 528 | 531 | WSADATA wd; |
| 529 | 532 | DualSocket ds; |
| @@ -530,10 +533,11 @@ | ||
| 530 | 533 | int idCnt = 0; |
| 531 | 534 | int iPort = mnPort; |
| 532 | 535 | Blob options; |
| 533 | 536 | wchar_t zTmpPath[MAX_PATH]; |
| 534 | 537 | const char *zSkin; |
| 538 | + time_t stopTime = 0; /* When to stop due to idle timeout */ | |
| 535 | 539 | #if USE_SEE |
| 536 | 540 | const char *zSavedKey = 0; |
| 537 | 541 | size_t savedKeySize = 0; |
| 538 | 542 | #endif |
| 539 | 543 | |
| @@ -554,11 +558,11 @@ | ||
| 554 | 558 | blob_appendf(&options, " --localauth"); |
| 555 | 559 | } |
| 556 | 560 | if( g.thTrace ){ |
| 557 | 561 | blob_appendf(&options, " --th-trace"); |
| 558 | 562 | } |
| 559 | - if( idleTimeout>0 ){ | |
| 563 | + if( iIdleTimeout>0 ){ | |
| 560 | 564 | blob_appendf(&options, " --keep-alive"); |
| 561 | 565 | } |
| 562 | 566 | if( flags & HTTP_SERVER_REPOLIST ){ |
| 563 | 567 | blob_appendf(&options, " --repolist"); |
| 564 | 568 | } |
| @@ -636,18 +640,23 @@ | ||
| 636 | 640 | _beginthread(win32_server_stopper, 0, (void*)pServer); |
| 637 | 641 | } |
| 638 | 642 | /* Set the service status to running and pass the listener socket to the |
| 639 | 643 | ** service handling procedures. */ |
| 640 | 644 | win32_http_service_running(&ds); |
| 645 | + if( iIdleTimeout>0 ) stopTime = time(0) + iIdleTimeout; | |
| 641 | 646 | for(;;){ |
| 642 | 647 | DualSocket client; |
| 643 | 648 | DualAddr client_addr; |
| 644 | 649 | HttpRequest *pRequest; |
| 645 | 650 | int wsaError; |
| 651 | + int nSock; | |
| 646 | 652 | |
| 647 | - DualSocket_accept(&ds, &client, &client_addr); | |
| 648 | - if( client.s4==INVALID_SOCKET && client.s6==INVALID_SOCKET ){ | |
| 653 | + nSock = DualSocket_accept(&ds, &client, &client_addr); | |
| 654 | + if( nSock==SOCKET_ERROR | |
| 655 | + && client.s4==INVALID_SOCKET | |
| 656 | + && client.s6==INVALID_SOCKET | |
| 657 | + ){ | |
| 649 | 658 | /* If the service control handler has closed the listener socket, |
| 650 | 659 | ** cleanup and return, otherwise report a fatal error. */ |
| 651 | 660 | wsaError = WSAGetLastError(); |
| 652 | 661 | DualSocket_close(&ds); |
| 653 | 662 | if( (wsaError==WSAEINTR) || (wsaError==WSAENOTSOCK) ){ |
| @@ -663,10 +672,11 @@ | ||
| 663 | 672 | pRequest->id = ++idCnt; |
| 664 | 673 | pRequest->s = client.s4; |
| 665 | 674 | memcpy(&pRequest->addr, &client_addr.a4, sizeof(client_addr.a4)); |
| 666 | 675 | pRequest->flags = flags; |
| 667 | 676 | pRequest->zOptions = blob_str(&options); |
| 677 | + if( iIdleTimeout>0 ) stopTime = time(0) + iIdleTimeout; | |
| 668 | 678 | if( flags & HTTP_SERVER_SCGI ){ |
| 669 | 679 | _beginthread(win32_scgi_request, 0, (void*)pRequest); |
| 670 | 680 | }else{ |
| 671 | 681 | _beginthread(win32_http_request, 0, (void*)pRequest); |
| 672 | 682 | } |
| @@ -676,16 +686,18 @@ | ||
| 676 | 686 | pRequest->id = ++idCnt; |
| 677 | 687 | pRequest->s = client.s6; |
| 678 | 688 | memcpy(&pRequest->addr, &client_addr.a6, sizeof(client_addr.a6)); |
| 679 | 689 | pRequest->flags = flags; |
| 680 | 690 | pRequest->zOptions = blob_str(&options); |
| 691 | + if( iIdleTimeout>0 ) stopTime = time(0) + iIdleTimeout; | |
| 681 | 692 | if( flags & HTTP_SERVER_SCGI ){ |
| 682 | 693 | _beginthread(win32_scgi_request, 0, (void*)pRequest); |
| 683 | 694 | }else{ |
| 684 | 695 | _beginthread(win32_http_request, 0, (void*)pRequest); |
| 685 | 696 | } |
| 686 | 697 | } |
| 698 | + if( iIdleTimeout>0 && stopTime<time(0) ) break; | |
| 687 | 699 | } |
| 688 | 700 | DualSocket_close(&ds); |
| 689 | 701 | WSACleanup(); |
| 690 | 702 | SetEvent(hStoppedEvent); |
| 691 | 703 | CloseHandle(hStoppedEvent); |
| 692 | 704 |
| --- src/winhttp.c | |
| +++ src/winhttp.c | |
| @@ -199,16 +199,18 @@ | |
| 199 | } |
| 200 | return 1; |
| 201 | }; |
| 202 | |
| 203 | /* |
| 204 | ** Accepts connections on DualSocket. |
| 205 | */ |
| 206 | static void DualSocket_accept(DualSocket* pListen, DualSocket* pClient, |
| 207 | DualAddr* pClientAddr){ |
| 208 | fd_set rs; |
| 209 | int rs_count = 0; |
| 210 | assert( pListen!=NULL && pClient!=NULL && pClientAddr!= NULL ); |
| 211 | DualSocket_init(pClient); |
| 212 | DualAddr_init(pClientAddr); |
| 213 | FD_ZERO(&rs); |
| 214 | if( pListen->s4!=INVALID_SOCKET ){ |
| @@ -217,21 +219,22 @@ | |
| 217 | } |
| 218 | if( pListen->s6!=INVALID_SOCKET ){ |
| 219 | FD_SET(pListen->s6, &rs); |
| 220 | ++rs_count; |
| 221 | } |
| 222 | if( select(rs_count, &rs, 0, 0, 0 /*blocking*/)==SOCKET_ERROR ){ |
| 223 | return; |
| 224 | } |
| 225 | if( FD_ISSET(pListen->s4, &rs) ){ |
| 226 | pClient->s4 = accept(pListen->s4, (struct sockaddr*)&pClientAddr->a4.addr, |
| 227 | &pClientAddr->a4.len); |
| 228 | } |
| 229 | if( FD_ISSET(pListen->s6, &rs) ){ |
| 230 | pClient->s6 = accept(pListen->s6, (struct sockaddr*)&pClientAddr->a6.addr, |
| 231 | &pClientAddr->a6.len); |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | /* |
| 236 | ** The HttpServer structure holds information about an instance of |
| 237 | ** the HTTP server itself. |
| @@ -514,16 +517,16 @@ | |
| 514 | ** that socket. |
| 515 | */ |
| 516 | void win32_http_server( |
| 517 | int mnPort, int mxPort, /* Range of allowed TCP port numbers */ |
| 518 | const char *zBrowser, /* Command to launch browser. (Or NULL) */ |
| 519 | const char *zStopper, /* Stop server when this file is exists (Or NULL) */ |
| 520 | const char *zBaseUrl, /* The --baseurl option, or NULL */ |
| 521 | const char *zNotFound, /* The --notfound option, or NULL */ |
| 522 | const char *zFileGlob, /* The --fileglob option, or NULL */ |
| 523 | const char *zIpAddr, /* Bind to this IP address, if not NULL */ |
| 524 | int idleTimeout, /* Idle timeout in seconds. 0 means none */ |
| 525 | int flags /* One or more HTTP_SERVER_ flags */ |
| 526 | ){ |
| 527 | HANDLE hStoppedEvent; |
| 528 | WSADATA wd; |
| 529 | DualSocket ds; |
| @@ -530,10 +533,11 @@ | |
| 530 | int idCnt = 0; |
| 531 | int iPort = mnPort; |
| 532 | Blob options; |
| 533 | wchar_t zTmpPath[MAX_PATH]; |
| 534 | const char *zSkin; |
| 535 | #if USE_SEE |
| 536 | const char *zSavedKey = 0; |
| 537 | size_t savedKeySize = 0; |
| 538 | #endif |
| 539 | |
| @@ -554,11 +558,11 @@ | |
| 554 | blob_appendf(&options, " --localauth"); |
| 555 | } |
| 556 | if( g.thTrace ){ |
| 557 | blob_appendf(&options, " --th-trace"); |
| 558 | } |
| 559 | if( idleTimeout>0 ){ |
| 560 | blob_appendf(&options, " --keep-alive"); |
| 561 | } |
| 562 | if( flags & HTTP_SERVER_REPOLIST ){ |
| 563 | blob_appendf(&options, " --repolist"); |
| 564 | } |
| @@ -636,18 +640,23 @@ | |
| 636 | _beginthread(win32_server_stopper, 0, (void*)pServer); |
| 637 | } |
| 638 | /* Set the service status to running and pass the listener socket to the |
| 639 | ** service handling procedures. */ |
| 640 | win32_http_service_running(&ds); |
| 641 | for(;;){ |
| 642 | DualSocket client; |
| 643 | DualAddr client_addr; |
| 644 | HttpRequest *pRequest; |
| 645 | int wsaError; |
| 646 | |
| 647 | DualSocket_accept(&ds, &client, &client_addr); |
| 648 | if( client.s4==INVALID_SOCKET && client.s6==INVALID_SOCKET ){ |
| 649 | /* If the service control handler has closed the listener socket, |
| 650 | ** cleanup and return, otherwise report a fatal error. */ |
| 651 | wsaError = WSAGetLastError(); |
| 652 | DualSocket_close(&ds); |
| 653 | if( (wsaError==WSAEINTR) || (wsaError==WSAENOTSOCK) ){ |
| @@ -663,10 +672,11 @@ | |
| 663 | pRequest->id = ++idCnt; |
| 664 | pRequest->s = client.s4; |
| 665 | memcpy(&pRequest->addr, &client_addr.a4, sizeof(client_addr.a4)); |
| 666 | pRequest->flags = flags; |
| 667 | pRequest->zOptions = blob_str(&options); |
| 668 | if( flags & HTTP_SERVER_SCGI ){ |
| 669 | _beginthread(win32_scgi_request, 0, (void*)pRequest); |
| 670 | }else{ |
| 671 | _beginthread(win32_http_request, 0, (void*)pRequest); |
| 672 | } |
| @@ -676,16 +686,18 @@ | |
| 676 | pRequest->id = ++idCnt; |
| 677 | pRequest->s = client.s6; |
| 678 | memcpy(&pRequest->addr, &client_addr.a6, sizeof(client_addr.a6)); |
| 679 | pRequest->flags = flags; |
| 680 | pRequest->zOptions = blob_str(&options); |
| 681 | if( flags & HTTP_SERVER_SCGI ){ |
| 682 | _beginthread(win32_scgi_request, 0, (void*)pRequest); |
| 683 | }else{ |
| 684 | _beginthread(win32_http_request, 0, (void*)pRequest); |
| 685 | } |
| 686 | } |
| 687 | } |
| 688 | DualSocket_close(&ds); |
| 689 | WSACleanup(); |
| 690 | SetEvent(hStoppedEvent); |
| 691 | CloseHandle(hStoppedEvent); |
| 692 |
| --- src/winhttp.c | |
| +++ src/winhttp.c | |
| @@ -199,16 +199,18 @@ | |
| 199 | } |
| 200 | return 1; |
| 201 | }; |
| 202 | |
| 203 | /* |
| 204 | ** Accepts connections on DualSocket. Return |
| 205 | */ |
| 206 | static int DualSocket_accept(DualSocket* pListen, DualSocket* pClient, |
| 207 | DualAddr* pClientAddr){ |
| 208 | fd_set rs; |
| 209 | int rs_count = 0; |
| 210 | int rc = 0; |
| 211 | struct timeval delay; |
| 212 | assert( pListen!=NULL && pClient!=NULL && pClientAddr!= NULL ); |
| 213 | DualSocket_init(pClient); |
| 214 | DualAddr_init(pClientAddr); |
| 215 | FD_ZERO(&rs); |
| 216 | if( pListen->s4!=INVALID_SOCKET ){ |
| @@ -217,21 +219,22 @@ | |
| 219 | } |
| 220 | if( pListen->s6!=INVALID_SOCKET ){ |
| 221 | FD_SET(pListen->s6, &rs); |
| 222 | ++rs_count; |
| 223 | } |
| 224 | delay.tv_sec = 2; |
| 225 | delay.tv_usec = 0; |
| 226 | rc = select(rs_count, &rs, 0, 0, &delay); |
| 227 | if( FD_ISSET(pListen->s4, &rs) ){ |
| 228 | pClient->s4 = accept(pListen->s4, (struct sockaddr*)&pClientAddr->a4.addr, |
| 229 | &pClientAddr->a4.len); |
| 230 | } |
| 231 | if( FD_ISSET(pListen->s6, &rs) ){ |
| 232 | pClient->s6 = accept(pListen->s6, (struct sockaddr*)&pClientAddr->a6.addr, |
| 233 | &pClientAddr->a6.len); |
| 234 | } |
| 235 | return rc; |
| 236 | } |
| 237 | |
| 238 | /* |
| 239 | ** The HttpServer structure holds information about an instance of |
| 240 | ** the HTTP server itself. |
| @@ -514,16 +517,16 @@ | |
| 517 | ** that socket. |
| 518 | */ |
| 519 | void win32_http_server( |
| 520 | int mnPort, int mxPort, /* Range of allowed TCP port numbers */ |
| 521 | const char *zBrowser, /* Command to launch browser. (Or NULL) */ |
| 522 | const char *zStopper, /* Stop server when this file exists (Or NULL) */ |
| 523 | const char *zBaseUrl, /* The --baseurl option, or NULL */ |
| 524 | const char *zNotFound, /* The --notfound option, or NULL */ |
| 525 | const char *zFileGlob, /* The --fileglob option, or NULL */ |
| 526 | const char *zIpAddr, /* Bind to this IP address, if not NULL */ |
| 527 | int iIdleTimeout, /* Idle timeout in seconds. 0 means none */ |
| 528 | int flags /* One or more HTTP_SERVER_ flags */ |
| 529 | ){ |
| 530 | HANDLE hStoppedEvent; |
| 531 | WSADATA wd; |
| 532 | DualSocket ds; |
| @@ -530,10 +533,11 @@ | |
| 533 | int idCnt = 0; |
| 534 | int iPort = mnPort; |
| 535 | Blob options; |
| 536 | wchar_t zTmpPath[MAX_PATH]; |
| 537 | const char *zSkin; |
| 538 | time_t stopTime = 0; /* When to stop due to idle timeout */ |
| 539 | #if USE_SEE |
| 540 | const char *zSavedKey = 0; |
| 541 | size_t savedKeySize = 0; |
| 542 | #endif |
| 543 | |
| @@ -554,11 +558,11 @@ | |
| 558 | blob_appendf(&options, " --localauth"); |
| 559 | } |
| 560 | if( g.thTrace ){ |
| 561 | blob_appendf(&options, " --th-trace"); |
| 562 | } |
| 563 | if( iIdleTimeout>0 ){ |
| 564 | blob_appendf(&options, " --keep-alive"); |
| 565 | } |
| 566 | if( flags & HTTP_SERVER_REPOLIST ){ |
| 567 | blob_appendf(&options, " --repolist"); |
| 568 | } |
| @@ -636,18 +640,23 @@ | |
| 640 | _beginthread(win32_server_stopper, 0, (void*)pServer); |
| 641 | } |
| 642 | /* Set the service status to running and pass the listener socket to the |
| 643 | ** service handling procedures. */ |
| 644 | win32_http_service_running(&ds); |
| 645 | if( iIdleTimeout>0 ) stopTime = time(0) + iIdleTimeout; |
| 646 | for(;;){ |
| 647 | DualSocket client; |
| 648 | DualAddr client_addr; |
| 649 | HttpRequest *pRequest; |
| 650 | int wsaError; |
| 651 | int nSock; |
| 652 | |
| 653 | nSock = DualSocket_accept(&ds, &client, &client_addr); |
| 654 | if( nSock==SOCKET_ERROR |
| 655 | && client.s4==INVALID_SOCKET |
| 656 | && client.s6==INVALID_SOCKET |
| 657 | ){ |
| 658 | /* If the service control handler has closed the listener socket, |
| 659 | ** cleanup and return, otherwise report a fatal error. */ |
| 660 | wsaError = WSAGetLastError(); |
| 661 | DualSocket_close(&ds); |
| 662 | if( (wsaError==WSAEINTR) || (wsaError==WSAENOTSOCK) ){ |
| @@ -663,10 +672,11 @@ | |
| 672 | pRequest->id = ++idCnt; |
| 673 | pRequest->s = client.s4; |
| 674 | memcpy(&pRequest->addr, &client_addr.a4, sizeof(client_addr.a4)); |
| 675 | pRequest->flags = flags; |
| 676 | pRequest->zOptions = blob_str(&options); |
| 677 | if( iIdleTimeout>0 ) stopTime = time(0) + iIdleTimeout; |
| 678 | if( flags & HTTP_SERVER_SCGI ){ |
| 679 | _beginthread(win32_scgi_request, 0, (void*)pRequest); |
| 680 | }else{ |
| 681 | _beginthread(win32_http_request, 0, (void*)pRequest); |
| 682 | } |
| @@ -676,16 +686,18 @@ | |
| 686 | pRequest->id = ++idCnt; |
| 687 | pRequest->s = client.s6; |
| 688 | memcpy(&pRequest->addr, &client_addr.a6, sizeof(client_addr.a6)); |
| 689 | pRequest->flags = flags; |
| 690 | pRequest->zOptions = blob_str(&options); |
| 691 | if( iIdleTimeout>0 ) stopTime = time(0) + iIdleTimeout; |
| 692 | if( flags & HTTP_SERVER_SCGI ){ |
| 693 | _beginthread(win32_scgi_request, 0, (void*)pRequest); |
| 694 | }else{ |
| 695 | _beginthread(win32_http_request, 0, (void*)pRequest); |
| 696 | } |
| 697 | } |
| 698 | if( iIdleTimeout>0 && stopTime<time(0) ) break; |
| 699 | } |
| 700 | DualSocket_close(&ds); |
| 701 | WSACleanup(); |
| 702 | SetEvent(hStoppedEvent); |
| 703 | CloseHandle(hStoppedEvent); |
| 704 |