Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Modifications to the "fossil ui" idle timeout feature: (0) Make the Javascript work with IE (lacking the `fetch()' function) (1) Ensure the Javascript keep-alive polling interval is lower than the idle timeout (2) Add the short form `-t' as an alias for the `--idle-timeout' command-line option, since it is now always required to enable legacy behavior. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | idle-time-suggestions |
Files: | files | file ages | folders |
SHA3-256: |
fae4ae058d92d47b6c9cd3be63854b4a |
User & Date: | florian 2020-04-10 14:02:00 |
Context
2020-04-10
| ||
14:02 | Modifications to the "fossil ui" idle timeout feature: (0) Make the Javascript work with IE (lacking the `fetch()' function) (1) Ensure the Javascript keep-alive polling interval is lower than the idle timeout (2) Add the short form `-t' as an alias for the `--idle-timeout' command-line option, since it is now always required to enable legacy behavior. ... (Closed-Leaf check-in: fae4ae05 user: florian tags: idle-time-suggestions) | |
2020-04-09
| ||
17:29 | Branch closed. See this forum post for an explanation. Was: Fix a harmless compiler warning. ... (Closed-Leaf check-in: eb750c28 user: drh tags: idle-timeout) | |
Changes
Changes to src/main.c.
︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 211 212 213 214 | int xlinkClusterOnly; /* Set when cloning. Only process clusters */ int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ char *ckinLockFail; /* Check-in lock failure received from server */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ UrlData url; /* Information about current URL */ const char *zLogin; /* Login name. NULL or "" if not logged in. */ const char *zSSLIdentity; /* Value of --ssl-identity option, filename of ** SSL client identity */ | > > > | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | int xlinkClusterOnly; /* Set when cloning. Only process clusters */ int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ char *ckinLockFail; /* Check-in lock failure received from server */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %W */ int iHTTPdIdleTimeout; /* Auto-shutdown the HTTP server after an idle timeout ** of N seconds without HTTP requests; disabled if set ** to 0 (default). */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ UrlData url; /* Information about current URL */ const char *zLogin; /* Login name. NULL or "" if not logged in. */ const char *zSSLIdentity; /* Value of --ssl-identity option, filename of ** SSL client identity */ |
︙ | ︙ | |||
2369 2370 2371 2372 2373 2374 2375 | ** --baseurl URL base URL (useful with reverse proxies) ** --extroot DIR document root for the /ext extension mechanism ** --files GLOB comma-separate glob patterns for static file to serve ** --host NAME specify hostname of the server ** --https signal a request coming in via https ** --in FILE Take input from FILE instead of standard input ** --ipaddr ADDR Assume the request comes from the given IP address | | > | 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 | ** --baseurl URL base URL (useful with reverse proxies) ** --extroot DIR document root for the /ext extension mechanism ** --files GLOB comma-separate glob patterns for static file to serve ** --host NAME specify hostname of the server ** --https signal a request coming in via https ** --in FILE Take input from FILE instead of standard input ** --ipaddr ADDR Assume the request comes from the given IP address ** --keep-alive N Add "keep alive" script in HTML to poll every N seconds ** --localauth enable automatic login for local connections ** --nocompress do not compress HTTP replies ** --nodelay omit backoffice processing if it would delay process exit ** --nojail drop root privilege but do not enter the chroot jail ** --nossl signal that no SSL connections are available ** --notfound URL use URL as "HTTP 404, object not found" page. ** --out FILE write results to FILE instead of to standard output ** --repolist If REPOSITORY is directory, URL "/" lists all repos ** --scgi Interpret input as SCGI rather than HTTP ** --skin LABEL Use override skin LABEL ** --th-trace trace TH1 execution (for debugging purposes) ** --usepidkey Use saved encryption key from parent process. This is ** only necessary when using SEE on Windows. ** ** See also: cgi, server, winsrv */ void cmd_http(void){ const char *zIpAddr = 0; const char *zNotFound; const char *zHost; const char *zKeepAliveTimeout; const char *zAltBase; const char *zFileGlob; const char *zInFile; const char *zOutFile; int useSCGI; int noJail; int allowRepoList; |
︙ | ︙ | |||
2449 2450 2451 2452 2453 2454 2455 | if( zAltBase ) set_base_url(zAltBase); if( find_option("https",0,0)!=0 ){ zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */ cgi_replace_parameter("HTTPS","on"); } zHost = find_option("host", 0, 1); if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost); | | > > | 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 | if( zAltBase ) set_base_url(zAltBase); if( find_option("https",0,0)!=0 ){ zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */ cgi_replace_parameter("HTTPS","on"); } zHost = find_option("host", 0, 1); if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost); zKeepAliveTimeout = find_option("keep-alive", 0, 1); if( zKeepAliveTimeout ) g.iHTTPdIdleTimeout = atoi(zKeepAliveTimeout); #if defined(_WIN32) && USE_SEE zPidKey = find_option("usepidkey", 0, 1); if( zPidKey ){ DWORD processId = 0; LPVOID pAddress = NULL; SIZE_T nSize = 0; |
︙ | ︙ | |||
2630 2631 2632 2633 2634 2635 2636 | ** having to log in. This can be disabled by turning off the "localauth" ** setting. Automatic login for the "server" command is available if the ** --localauth option is present and the "localauth" setting is off and the ** connection is from localhost. The "ui" command also enables --repolist ** by default. ** ** Options: | | | | | | | | | | | | | | | | | | | | | | | | | | | | 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 | ** having to log in. This can be disabled by turning off the "localauth" ** setting. Automatic login for the "server" command is available if the ** --localauth option is present and the "localauth" setting is off and the ** connection is from localhost. The "ui" command also enables --repolist ** 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 ** -t|--idle-timeout N Exit if no HTTP requests are received for N seconds. ** "0" means never. "0" is the 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 ** --nojail Drop root privileges but do not enter the chroot jail ** --nossl signal that no SSL connections are available (Always ** set by default for the "ui" command) ** --notfound URL Redirect ** --page PAGE Start "ui" on PAGE. ex: --page "timeline?y=ci" ** -P|--port TCPPORT listen to request on port TCPPORT ** --th-trace trace TH1 execution (for debugging purposes) ** --repolist If REPOSITORY is dir, URL "/" lists repos. ** --scgi Accept SCGI rather than HTTP ** --skin LABEL Use override skin LABEL ** --usepidkey Use saved encryption key from parent process. This is ** only necessary when using SEE on Windows. ** ** See also: cgi, http, winsrv */ void cmd_webserver(void){ int iPort, mxPort; /* Range of TCP ports allowed */ const char *zPort; /* Value of the --port option */ const char *zBrowser; /* Name of web browser program */ |
︙ | ︙ | |||
2677 2678 2679 2680 2681 2682 2683 | #endif int allowRepoList; /* List repositories on URL "/" */ const char *zAltBase; /* Argument to the --baseurl option */ const char *zFileGlob; /* Static content must match this */ char *zIpAddr = 0; /* Bind to this IP address */ int fCreate = 0; /* The --create flag */ const char *zIdleTimeout; /* Value of the --idle-timeout flag */ | < | 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 | #endif int allowRepoList; /* List repositories on URL "/" */ const char *zAltBase; /* Argument to the --baseurl option */ const char *zFileGlob; /* Static content must match this */ char *zIpAddr = 0; /* Bind to this IP address */ int fCreate = 0; /* The --create flag */ const char *zIdleTimeout; /* Value of the --idle-timeout flag */ const char *zInitPage = 0; /* Start on this page. --page option */ #if defined(_WIN32) && USE_SEE const char *zPidKey; #endif #if defined(_WIN32) const char *zStopperFile; /* Name of file used to terminate server */ |
︙ | ︙ | |||
2711 2712 2713 2714 2715 2716 2717 | #endif g.useLocalauth = find_option("localauth", 0, 0)!=0; Th_InitTraceLog(); zPort = find_option("port", "P", 1); isUiCmd = g.argv[1][0]=='u'; if( isUiCmd ){ zInitPage = find_option("page", 0, 1); | | | | | 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 | #endif g.useLocalauth = find_option("localauth", 0, 0)!=0; Th_InitTraceLog(); zPort = find_option("port", "P", 1); isUiCmd = g.argv[1][0]=='u'; if( isUiCmd ){ zInitPage = find_option("page", 0, 1); g.iHTTPdIdleTimeout = 60; } zIdleTimeout = find_option("idle-timeout", "t", 1); if( zIdleTimeout ){ g.iHTTPdIdleTimeout = atoi(zIdleTimeout); } zNotFound = find_option("notfound", 0, 1); allowRepoList = find_option("repolist",0,0)!=0; if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1; zAltBase = find_option("baseurl", 0, 1); fCreate = find_option("create",0,0)!=0; |
︙ | ︙ | |||
2815 2816 2817 2818 2819 2820 2821 | zBrowserCmd = mprintf("%s http://%s:%%d/%s &", zBrowser, zIpAddr, zInitPage); } } if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; db_close(1); | | | 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 | zBrowserCmd = mprintf("%s http://%s:%%d/%s &", zBrowser, zIpAddr, zInitPage); } } if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY; if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; db_close(1); if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){ fossil_fatal("unable to listen on TCP socket %d", iPort); } /* For the parent process, the cgi_http_server() command above never ** returns (except in the case of an error). Instead, for each incoming ** client connection, a child process is created, file descriptors 0 ** and 1 are bound to that connection, and the child returns. ** |
︙ | ︙ | |||
2855 2856 2857 2858 2859 2860 2861 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); } if( flags & HTTP_SERVER_SCGI ){ cgi_handle_scgi_request(); }else{ cgi_handle_http_request(0); } | | | 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); } if( flags & HTTP_SERVER_SCGI ){ cgi_handle_scgi_request(); }else{ cgi_handle_http_request(0); } process_one_web_page(zNotFound, glob_create(zFileGlob), allowRepoList); if( g.fAnyTrace ){ fprintf(stderr, "/***** Webpage finished in subprocess %d *****/\n", getpid()); } #else /* Win32 implementation */ |
︙ | ︙ | |||
2884 2885 2886 2887 2888 2889 2890 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; db_close(1); if( allowRepoList ){ flags |= HTTP_SERVER_REPOLIST; } if( win32_http_service(iPort, zAltBase, zNotFound, zFileGlob, flags) ){ win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, | | | 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 | if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT; db_close(1); if( allowRepoList ){ flags |= HTTP_SERVER_REPOLIST; } if( win32_http_service(iPort, zAltBase, zNotFound, zFileGlob, flags) ){ win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zAltBase, zNotFound, zFileGlob, zIpAddr, flags); } #endif } /* ** COMMAND: test-echo ** |
︙ | ︙ |
Changes to src/style.c.
︙ | ︙ | |||
767 768 769 770 771 772 773 774 775 776 777 778 779 780 | cgi_append_content(builtin_text(azJsToLoad[i]),-1); } if( blob_size(&blobOnLoad)>0 ){ @ window.onload = function(){ cgi_append_content(blob_buffer(&blobOnLoad), blob_size(&blobOnLoad)); cgi_append_content("\n}\n", -1); } @ </script> } /* ** Extra JS to run after all content is loaded. */ void style_js_onload(const char *zFormat, ...){ | > > > > > > > > > > > > > > > | 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | cgi_append_content(builtin_text(azJsToLoad[i]),-1); } if( blob_size(&blobOnLoad)>0 ){ @ window.onload = function(){ cgi_append_content(blob_buffer(&blobOnLoad), blob_size(&blobOnLoad)); cgi_append_content("\n}\n", -1); } if( g.iHTTPdIdleTimeout>0 ){ /* This javascript runs on web-pages that need to periodically send ** a keep-alive HTTP request back to the server. This is typically ** used with the "fossil ui" command with a --idle-timeout set. The ** HTTP server will stop if it does not receive a new HTTP request ** within some time interval (60 seconds). This script keeps sending ** new HTTP requests every 20 seconds or so to keep the server running ** while the page is still viewable. */ /* TODO: move to separate function, or to built-in file enhanced to handle ** the g.iHTTPdIdleTimeout variable? */ @ setInterval(function(){ @ var xhr=new XMLHttpRequest();xhr.open('GET','/noop',true);xhr.send(); @ },%d((g.iHTTPdIdleTimeout-1)*1000+100)); } @ </script> } /* ** Extra JS to run after all content is loaded. */ void style_js_onload(const char *zFormat, ...){ |
︙ | ︙ |
Changes to src/winhttp.c.
︙ | ︙ | |||
520 521 522 523 524 525 526 | 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 */ | < | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 | 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 flags /* One or more HTTP_SERVER_ flags */ ){ HANDLE hStoppedEvent; WSADATA wd; DualSocket ds; int idCnt = 0; int iPort = mnPort; |
︙ | ︙ | |||
556 557 558 559 560 561 562 | } if( g.useLocalauth ){ blob_appendf(&options, " --localauth"); } if( g.thTrace ){ blob_appendf(&options, " --th-trace"); } | | | | 555 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( g.iHTTPdIdleTimeout>0 ){ blob_appendf(&options, " --keep-alive %d", g.iHTTPdIdleTimeout); } if( flags & HTTP_SERVER_REPOLIST ){ blob_appendf(&options, " --repolist"); } zSkin = skin_in_use(); if( zSkin ){ blob_appendf(&options, " --skin %s", zSkin); |
︙ | ︙ | |||
638 639 640 641 642 643 644 | 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); | | | 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | 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( g.iHTTPdIdleTimeout>0 ) stopTime = time(0) + g.iHTTPdIdleTimeout; for(;;){ DualSocket client; DualAddr client_addr; HttpRequest *pRequest; int wsaError; int nSock; |
︙ | ︙ | |||
670 671 672 673 674 675 676 | 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); | | | | | 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 | 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( g.iHTTPdIdleTimeout>0 ) stopTime = time(0) + g.iHTTPdIdleTimeout; 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( g.iHTTPdIdleTimeout>0 ) stopTime = time(0) + g.iHTTPdIdleTimeout; if( flags & HTTP_SERVER_SCGI ){ _beginthread(win32_scgi_request, 0, (void*)pRequest); }else{ _beginthread(win32_http_request, 0, (void*)pRequest); } } if( g.iHTTPdIdleTimeout>0 && stopTime<time(0) ) break; } DualSocket_close(&ds); WSACleanup(); SetEvent(hStoppedEvent); CloseHandle(hStoppedEvent); } |
︙ | ︙ |