Check-in [aee7401958]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Implement an idle-timeout for windows.
Timelines: family | ancestors | descendants | both | idle-timeout
Files: files | file ages | folders
SHA3-256: aee7401958cf16b2707252ba67c5e496744532573e35f727e2876e50cba94bb7
User & Date: drh 2020-04-09 17:18:53.252
Context
2020-04-09
17:29
Branch closed. See this forum post for an explanation. Was: Fix a harmless compiler warning. Closed-Leaf check-in: eb750c284a user: drh tags: idle-timeout
17:18
Implement an idle-timeout for windows. check-in: aee7401958 user: drh tags: idle-timeout
16:34
Fix the build for windows. The idle-timeout is still not implemented in the Windows HTTP server, though. check-in: 1d7e2fa697 user: drh tags: idle-timeout
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/main.c.
2634
2635
2636
2637
2638
2639
2640
2641


2642
2643
2644
2645
2646
2647
2648
** by default.
**
** Options:
**   --baseurl URL       Use URL as the base (useful for reverse proxies)
**   --create            Create a new REPOSITORY if it does not already exist
**   --extroot DIR       Document root for the /ext extension mechanism
**   --files GLOBLIST    Comma-separated list of glob patterns for static files
**   --idle-timeout N    Exit if no HTTP requests received for N seconds


**   --localauth         enable automatic login for requests from localhost
**   --localhost         listen on 127.0.0.1 only (always true for "ui")
**   --https             Indicates that the input is coming through a reverse
**                       proxy that has already translated HTTPS into HTTP.
**   --max-latency N     Do not let any single HTTP request run for more than N
**                       seconds (only works on unix)
**   --nocompress        Do not compress HTTP replies







|
>
>







2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
** by default.
**
** Options:
**   --baseurl URL       Use URL as the base (useful for reverse proxies)
**   --create            Create a new REPOSITORY if it does not already exist
**   --extroot DIR       Document root for the /ext extension mechanism
**   --files GLOBLIST    Comma-separated list of glob patterns for static files
**   --idle-timeout N    Exit if no HTTP requests are received for N seconds. 
**                       "0" means never. 0 is default for the "server" 
**                       command and "60" is the default for the "ui" command.
**   --localauth         enable automatic login for requests from localhost
**   --localhost         listen on 127.0.0.1 only (always true for "ui")
**   --https             Indicates that the input is coming through a reverse
**                       proxy that has already translated HTTPS into HTTP.
**   --max-latency N     Do not let any single HTTP request run for more than N
**                       seconds (only works on unix)
**   --nocompress        Do not compress HTTP replies
Changes to src/winhttp.c.
197
198
199
200
201
202
203
204
205
206
207
208
209


210
211
212
213
214
215
216
217
218
219
220
221


222
223
224
225
226
227
228
229
230
231
232

233
234
235
236
237
238
239
  if( ds->s6!=INVALID_SOCKET && listen(ds->s6, SOMAXCONN)==SOCKET_ERROR ){
    return 0;
  }
  return 1;
};

/*
** Accepts connections on DualSocket.
*/
static void DualSocket_accept(DualSocket* pListen, DualSocket* pClient,
                              DualAddr* pClientAddr){
  fd_set rs;
  int rs_count = 0;


  assert( pListen!=NULL && pClient!=NULL && pClientAddr!= NULL );
  DualSocket_init(pClient);
  DualAddr_init(pClientAddr);
  FD_ZERO(&rs);
  if( pListen->s4!=INVALID_SOCKET ){
    FD_SET(pListen->s4, &rs);
    ++rs_count;
  }
  if( pListen->s6!=INVALID_SOCKET ){
    FD_SET(pListen->s6, &rs);
    ++rs_count;
  }


  if( select(rs_count, &rs, 0, 0, 0 /*blocking*/)==SOCKET_ERROR ){
    return;
  }
  if( FD_ISSET(pListen->s4, &rs) ){
    pClient->s4 = accept(pListen->s4, (struct sockaddr*)&pClientAddr->a4.addr,
                         &pClientAddr->a4.len);
  }
  if( FD_ISSET(pListen->s6, &rs) ){
    pClient->s6 = accept(pListen->s6, (struct sockaddr*)&pClientAddr->a6.addr,
                         &pClientAddr->a6.len);
  }

}

/*
** The HttpServer structure holds information about an instance of
** the HTTP server itself.
*/
typedef struct HttpServer HttpServer;







|

|



>
>












>
>
|
<
<








>







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226


227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  if( ds->s6!=INVALID_SOCKET && listen(ds->s6, SOMAXCONN)==SOCKET_ERROR ){
    return 0;
  }
  return 1;
};

/*
** Accepts connections on DualSocket.  Return 
*/
static int DualSocket_accept(DualSocket* pListen, DualSocket* pClient,
                              DualAddr* pClientAddr){
  fd_set rs;
  int rs_count = 0;
  int rc = 0;
  struct timeval delay;
  assert( pListen!=NULL && pClient!=NULL && pClientAddr!= NULL );
  DualSocket_init(pClient);
  DualAddr_init(pClientAddr);
  FD_ZERO(&rs);
  if( pListen->s4!=INVALID_SOCKET ){
    FD_SET(pListen->s4, &rs);
    ++rs_count;
  }
  if( pListen->s6!=INVALID_SOCKET ){
    FD_SET(pListen->s6, &rs);
    ++rs_count;
  }
  delay.tv_sec = 2;
  delay.tv_usec = 0;
  rc = select(rs_count, &rs, 0, 0, &delay);


  if( FD_ISSET(pListen->s4, &rs) ){
    pClient->s4 = accept(pListen->s4, (struct sockaddr*)&pClientAddr->a4.addr,
                         &pClientAddr->a4.len);
  }
  if( FD_ISSET(pListen->s6, &rs) ){
    pClient->s6 = accept(pListen->s6, (struct sockaddr*)&pClientAddr->a6.addr,
                         &pClientAddr->a6.len);
  }
  return rc;
}

/*
** The HttpServer structure holds information about an instance of
** the HTTP server itself.
*/
typedef struct HttpServer HttpServer;
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534

535
536
537
538
539
540
541
/*
** Start a listening socket and process incoming HTTP requests on
** that socket.
*/
void win32_http_server(
  int mnPort, int mxPort,   /* Range of allowed TCP port numbers */
  const char *zBrowser,     /* Command to launch browser.  (Or NULL) */
  const char *zStopper,     /* Stop server when this file is exists (Or NULL) */
  const char *zBaseUrl,     /* The --baseurl option, or NULL */
  const char *zNotFound,    /* The --notfound option, or NULL */
  const char *zFileGlob,    /* The --fileglob option, or NULL */
  const char *zIpAddr,      /* Bind to this IP address, if not NULL */
  int idleTimeout,          /* Idle timeout in seconds.  0 means none */
  int flags                 /* One or more HTTP_SERVER_ flags */
){
  HANDLE hStoppedEvent;
  WSADATA wd;
  DualSocket ds;
  int idCnt = 0;
  int iPort = mnPort;
  Blob options;
  wchar_t zTmpPath[MAX_PATH];
  const char *zSkin;

#if USE_SEE
  const char *zSavedKey = 0;
  size_t savedKeySize = 0;
#endif

  blob_zero(&options);
  if( PB("HTTPS") ){







|




|










>







515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
/*
** Start a listening socket and process incoming HTTP requests on
** that socket.
*/
void win32_http_server(
  int mnPort, int mxPort,   /* Range of allowed TCP port numbers */
  const char *zBrowser,     /* Command to launch browser.  (Or NULL) */
  const char *zStopper,     /* Stop server when this file exists (Or NULL) */
  const char *zBaseUrl,     /* The --baseurl option, or NULL */
  const char *zNotFound,    /* The --notfound option, or NULL */
  const char *zFileGlob,    /* The --fileglob option, or NULL */
  const char *zIpAddr,      /* Bind to this IP address, if not NULL */
  int iIdleTimeout,         /* Idle timeout in seconds.  0 means none */
  int flags                 /* One or more HTTP_SERVER_ flags */
){
  HANDLE hStoppedEvent;
  WSADATA wd;
  DualSocket ds;
  int idCnt = 0;
  int iPort = mnPort;
  Blob options;
  wchar_t zTmpPath[MAX_PATH];
  const char *zSkin;
  time_t stopTime = 0;      /* When to stop due to idle timeout */
#if USE_SEE
  const char *zSavedKey = 0;
  size_t savedKeySize = 0;
#endif

  blob_zero(&options);
  if( PB("HTTPS") ){
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
  }
  if( g.useLocalauth ){
    blob_appendf(&options, " --localauth");
  }
  if( g.thTrace ){
    blob_appendf(&options, " --th-trace");
  }
  if( idleTimeout>0 ){
    blob_appendf(&options, " --keep-alive");
  }
  if( flags & HTTP_SERVER_REPOLIST ){
    blob_appendf(&options, " --repolist");
  }
  zSkin = skin_in_use();
  if( zSkin ){







|







556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
  }
  if( g.useLocalauth ){
    blob_appendf(&options, " --localauth");
  }
  if( g.thTrace ){
    blob_appendf(&options, " --th-trace");
  }
  if( iIdleTimeout>0 ){
    blob_appendf(&options, " --keep-alive");
  }
  if( flags & HTTP_SERVER_REPOLIST ){
    blob_appendf(&options, " --repolist");
  }
  zSkin = skin_in_use();
  if( zSkin ){
634
635
636
637
638
639
640

641
642
643
644
645

646
647


648

649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667

668
669
670
671
672
673
674
675
676
677
678
679
680

681
682
683
684
685
686

687
688
689
690
691
692
693
    pServer->listener = ds;
    file_delete(zStopper);
    _beginthread(win32_server_stopper, 0, (void*)pServer);
  }
  /* Set the service status to running and pass the listener socket to the
  ** service handling procedures. */
  win32_http_service_running(&ds);

  for(;;){
    DualSocket client;
    DualAddr client_addr;
    HttpRequest *pRequest;
    int wsaError;


    DualSocket_accept(&ds, &client, &client_addr);


    if( client.s4==INVALID_SOCKET && client.s6==INVALID_SOCKET ){

      /* If the service control handler has closed the listener socket,
      ** cleanup and return, otherwise report a fatal error. */
      wsaError =  WSAGetLastError();
      DualSocket_close(&ds);
      if( (wsaError==WSAEINTR) || (wsaError==WSAENOTSOCK) ){
        WSACleanup();
        return;
      }else{
        WSACleanup();
        fossil_panic("error from accept()");
      }
    }
    if( client.s4!=INVALID_SOCKET ){
      pRequest = fossil_malloc(sizeof(HttpRequest));
      pRequest->id = ++idCnt;
      pRequest->s = client.s4;
      memcpy(&pRequest->addr, &client_addr.a4, sizeof(client_addr.a4));
      pRequest->flags = flags;
      pRequest->zOptions = blob_str(&options);

      if( flags & HTTP_SERVER_SCGI ){
        _beginthread(win32_scgi_request, 0, (void*)pRequest);
      }else{
        _beginthread(win32_http_request, 0, (void*)pRequest);
      }
    }
    if( client.s6!=INVALID_SOCKET ){
      pRequest = fossil_malloc(sizeof(HttpRequest));
      pRequest->id = ++idCnt;
      pRequest->s = client.s6;
      memcpy(&pRequest->addr, &client_addr.a6, sizeof(client_addr.a6));
      pRequest->flags = flags;
      pRequest->zOptions = blob_str(&options);

      if( flags & HTTP_SERVER_SCGI ){
        _beginthread(win32_scgi_request, 0, (void*)pRequest);
      }else{
        _beginthread(win32_http_request, 0, (void*)pRequest);
      }
    }

  }
  DualSocket_close(&ds);
  WSACleanup();
  SetEvent(hStoppedEvent);
  CloseHandle(hStoppedEvent);
}








>





>

|
>
>
|
>



















>













>






>







638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
    pServer->listener = ds;
    file_delete(zStopper);
    _beginthread(win32_server_stopper, 0, (void*)pServer);
  }
  /* Set the service status to running and pass the listener socket to the
  ** service handling procedures. */
  win32_http_service_running(&ds);
  if( iIdleTimeout>0 ) stopTime = time(0) + iIdleTimeout;
  for(;;){
    DualSocket client;
    DualAddr client_addr;
    HttpRequest *pRequest;
    int wsaError;
    int nSock;

    nSock = DualSocket_accept(&ds, &client, &client_addr);
    if( nSock==SOCKET_ERROR
     && client.s4==INVALID_SOCKET
     && client.s6==INVALID_SOCKET
    ){
      /* If the service control handler has closed the listener socket,
      ** cleanup and return, otherwise report a fatal error. */
      wsaError =  WSAGetLastError();
      DualSocket_close(&ds);
      if( (wsaError==WSAEINTR) || (wsaError==WSAENOTSOCK) ){
        WSACleanup();
        return;
      }else{
        WSACleanup();
        fossil_panic("error from accept()");
      }
    }
    if( client.s4!=INVALID_SOCKET ){
      pRequest = fossil_malloc(sizeof(HttpRequest));
      pRequest->id = ++idCnt;
      pRequest->s = client.s4;
      memcpy(&pRequest->addr, &client_addr.a4, sizeof(client_addr.a4));
      pRequest->flags = flags;
      pRequest->zOptions = blob_str(&options);
      if( iIdleTimeout>0 ) stopTime = time(0) + iIdleTimeout;
      if( flags & HTTP_SERVER_SCGI ){
        _beginthread(win32_scgi_request, 0, (void*)pRequest);
      }else{
        _beginthread(win32_http_request, 0, (void*)pRequest);
      }
    }
    if( client.s6!=INVALID_SOCKET ){
      pRequest = fossil_malloc(sizeof(HttpRequest));
      pRequest->id = ++idCnt;
      pRequest->s = client.s6;
      memcpy(&pRequest->addr, &client_addr.a6, sizeof(client_addr.a6));
      pRequest->flags = flags;
      pRequest->zOptions = blob_str(&options);
      if( iIdleTimeout>0 ) stopTime = time(0) + iIdleTimeout;
      if( flags & HTTP_SERVER_SCGI ){
        _beginthread(win32_scgi_request, 0, (void*)pRequest);
      }else{
        _beginthread(win32_http_request, 0, (void*)pRequest);
      }
    }
    if( iIdleTimeout>0 && stopTime<time(0) ) break;
  }
  DualSocket_close(&ds);
  WSACleanup();
  SetEvent(hStoppedEvent);
  CloseHandle(hStoppedEvent);
}