Fossil SCM

Add support for SCGI via the --scgi command-line option to the "server" and "ui" and "http" commands.

drh 2013-08-13 18:15 trunk
Commit a2e7472d0fa04132edf6b425252cb76366334a7a
+68 -7
--- src/cgi.c
+++ src/cgi.c
@@ -812,10 +812,12 @@
812812
}
813813
}
814814
fputs(z, pLog);
815815
}
816816
817
+/* Forward declaration */
818
+static NORETURN void malformed_request(const char *zMsg);
817819
818820
/*
819821
** Initialize the query parameter database. Information is pulled from
820822
** the QUERY_STRING environment variable (if it exists), from standard
821823
** input if there is POST data, and from HTTP_COOKIE.
@@ -822,15 +824,31 @@
822824
*/
823825
void cgi_init(void){
824826
char *z;
825827
const char *zType;
826828
int len;
829
+ const char *zRequestUri = cgi_parameter("REQUEST_URI",0);
830
+ const char *zScriptName = cgi_parameter("SCRIPT_NAME",0);
831
+
827832
#ifdef FOSSIL_ENABLE_JSON
828833
json_main_bootstrap();
829834
#endif
830835
g.isHTTP = 1;
831836
cgi_destination(CGI_BODY);
837
+ if( zRequestUri==0 ) malformed_request("missing REQUEST_URI");
838
+ if( zScriptName==0 ) malformed_request("missing SCRIPT_NAME");
839
+ if( cgi_parameter("PATH_INFO",0)==0 ){
840
+ int i, j;
841
+ for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){}
842
+ if( zRequestUri[i]=='/' ){
843
+ for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
844
+ cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i));
845
+ }else{
846
+ malformed_request("cannot compute PATH_INFO from REQUEST_URI"
847
+ " and SCRIPT_NAME");
848
+ }
849
+ }
832850
833851
z = (char*)P("HTTP_COOKIE");
834852
if( z ){
835853
z = mprintf("%s",z);
836854
add_param_list(z, ';');
@@ -1092,14 +1110,14 @@
10921110
10931111
10941112
/*
10951113
** Send a reply indicating that the HTTP request was malformed
10961114
*/
1097
-static NORETURN void malformed_request(void){
1115
+static NORETURN void malformed_request(const char *zMsg){
10981116
cgi_set_status(501, "Not Implemented");
10991117
cgi_printf(
1100
- "<html><body>Unrecognized HTTP Request</body></html>\n"
1118
+ "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg
11011119
);
11021120
cgi_reply();
11031121
fossil_exit(0);
11041122
}
11051123
@@ -1187,29 +1205,30 @@
11871205
struct sockaddr_in remoteName;
11881206
socklen_t size = sizeof(struct sockaddr_in);
11891207
char zLine[2000]; /* A single line of input. */
11901208
g.fullHttpReply = 1;
11911209
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1192
- malformed_request();
1210
+ malformed_request("missing HTTP header");
11931211
}
11941212
blob_append(&g.httpHeader, zLine, -1);
11951213
cgi_trace(zLine);
11961214
zToken = extract_token(zLine, &z);
11971215
if( zToken==0 ){
1198
- malformed_request();
1216
+ malformed_request("malformed HTTP header");
11991217
}
12001218
if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
12011219
&& fossil_strcmp(zToken,"HEAD")!=0 ){
1202
- malformed_request();
1220
+ malformed_request("unsupported HTTP method");
12031221
}
12041222
cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
12051223
cgi_setenv("REQUEST_METHOD",zToken);
12061224
zToken = extract_token(z, &z);
12071225
if( zToken==0 ){
1208
- malformed_request();
1226
+ malformed_request("malformed URL in HTTP header");
12091227
}
12101228
cgi_setenv("REQUEST_URI", zToken);
1229
+ cgi_setenv("SCRIPT_NAME", "");
12111230
for(i=0; zToken[i] && zToken[i]!='?'; i++){}
12121231
if( zToken[i] ) zToken[i++] = 0;
12131232
cgi_setenv("PATH_INFO", zToken);
12141233
cgi_setenv("QUERY_STRING", &zToken[i]);
12151234
if( zIpAddr==0 &&
@@ -1269,16 +1288,57 @@
12691288
}
12701289
}
12711290
cgi_init();
12721291
cgi_trace(0);
12731292
}
1293
+
1294
+/*
1295
+** This routine handles a single SCGI request which is coming in on
1296
+** g.httpIn and which replies on g.httpOut
1297
+**
1298
+** The SCGI request is read from g.httpIn and is used to initialize
1299
+** entries in the cgi_parameter() hash, as if those entries were
1300
+** environment variables. A call to cgi_init() completes
1301
+** the setup. Once all the setup is finished, this procedure returns
1302
+** and subsequent code handles the actual generation of the webpage.
1303
+*/
1304
+void cgi_handle_scgi_request(void){
1305
+ char *zHdr;
1306
+ char *zToFree;
1307
+ int nHdr = 0;
1308
+ int nRead;
1309
+ int n, m;
1310
+ char c;
1311
+
1312
+ while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit(c) ){
1313
+ nHdr = nHdr*10 + c - '0';
1314
+ }
1315
+ if( nHdr<16 ) malformed_request("SCGI header too short");
1316
+ zToFree = zHdr = fossil_malloc(nHdr);
1317
+ nRead = (int)fread(zHdr, 1, nHdr, g.httpIn);
1318
+ if( nRead<nHdr ) malformed_request("cannot read entire SCGI header");
1319
+ nHdr = nRead;
1320
+ while( nHdr ){
1321
+ for(n=0; n<nHdr && zHdr[n]; n++){}
1322
+ for(m=n+1; m<nHdr && zHdr[m]; m++){}
1323
+ if( m>=nHdr ) malformed_request("SCGI header formatting error");
1324
+ cgi_set_parameter(zHdr, zHdr+n+1);
1325
+ zHdr += m+1;
1326
+ nHdr -= m+1;
1327
+ }
1328
+ fossil_free(zToFree);
1329
+ fgetc(g.httpIn); /* Read past the "," separating header from content */
1330
+ cgi_init();
1331
+}
1332
+
12741333
12751334
#if INTERFACE
12761335
/*
12771336
** Bitmap values for the flags parameter to cgi_http_server().
12781337
*/
12791338
#define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
1339
+#define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
12801340
12811341
#endif /* INTERFACE */
12821342
12831343
/*
12841344
** Maximum number of child processes that we can have running
@@ -1356,11 +1416,12 @@
13561416
}
13571417
}
13581418
if( iPort>mxPort ) return 1;
13591419
listen(listener,10);
13601420
if( iPort>mnPort ){
1361
- fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
1421
+ fossil_print("Listening for %s requests on TCP port %d\n",
1422
+ (flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
13621423
fflush(stdout);
13631424
}
13641425
if( zBrowser ){
13651426
zBrowser = mprintf(zBrowser, iPort);
13661427
if( system(zBrowser)<0 ){
13671428
--- src/cgi.c
+++ src/cgi.c
@@ -812,10 +812,12 @@
812 }
813 }
814 fputs(z, pLog);
815 }
816
 
 
817
818 /*
819 ** Initialize the query parameter database. Information is pulled from
820 ** the QUERY_STRING environment variable (if it exists), from standard
821 ** input if there is POST data, and from HTTP_COOKIE.
@@ -822,15 +824,31 @@
822 */
823 void cgi_init(void){
824 char *z;
825 const char *zType;
826 int len;
 
 
 
827 #ifdef FOSSIL_ENABLE_JSON
828 json_main_bootstrap();
829 #endif
830 g.isHTTP = 1;
831 cgi_destination(CGI_BODY);
 
 
 
 
 
 
 
 
 
 
 
 
 
832
833 z = (char*)P("HTTP_COOKIE");
834 if( z ){
835 z = mprintf("%s",z);
836 add_param_list(z, ';');
@@ -1092,14 +1110,14 @@
1092
1093
1094 /*
1095 ** Send a reply indicating that the HTTP request was malformed
1096 */
1097 static NORETURN void malformed_request(void){
1098 cgi_set_status(501, "Not Implemented");
1099 cgi_printf(
1100 "<html><body>Unrecognized HTTP Request</body></html>\n"
1101 );
1102 cgi_reply();
1103 fossil_exit(0);
1104 }
1105
@@ -1187,29 +1205,30 @@
1187 struct sockaddr_in remoteName;
1188 socklen_t size = sizeof(struct sockaddr_in);
1189 char zLine[2000]; /* A single line of input. */
1190 g.fullHttpReply = 1;
1191 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1192 malformed_request();
1193 }
1194 blob_append(&g.httpHeader, zLine, -1);
1195 cgi_trace(zLine);
1196 zToken = extract_token(zLine, &z);
1197 if( zToken==0 ){
1198 malformed_request();
1199 }
1200 if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
1201 && fossil_strcmp(zToken,"HEAD")!=0 ){
1202 malformed_request();
1203 }
1204 cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
1205 cgi_setenv("REQUEST_METHOD",zToken);
1206 zToken = extract_token(z, &z);
1207 if( zToken==0 ){
1208 malformed_request();
1209 }
1210 cgi_setenv("REQUEST_URI", zToken);
 
1211 for(i=0; zToken[i] && zToken[i]!='?'; i++){}
1212 if( zToken[i] ) zToken[i++] = 0;
1213 cgi_setenv("PATH_INFO", zToken);
1214 cgi_setenv("QUERY_STRING", &zToken[i]);
1215 if( zIpAddr==0 &&
@@ -1269,16 +1288,57 @@
1269 }
1270 }
1271 cgi_init();
1272 cgi_trace(0);
1273 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1274
1275 #if INTERFACE
1276 /*
1277 ** Bitmap values for the flags parameter to cgi_http_server().
1278 */
1279 #define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
 
1280
1281 #endif /* INTERFACE */
1282
1283 /*
1284 ** Maximum number of child processes that we can have running
@@ -1356,11 +1416,12 @@
1356 }
1357 }
1358 if( iPort>mxPort ) return 1;
1359 listen(listener,10);
1360 if( iPort>mnPort ){
1361 fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
 
1362 fflush(stdout);
1363 }
1364 if( zBrowser ){
1365 zBrowser = mprintf(zBrowser, iPort);
1366 if( system(zBrowser)<0 ){
1367
--- src/cgi.c
+++ src/cgi.c
@@ -812,10 +812,12 @@
812 }
813 }
814 fputs(z, pLog);
815 }
816
817 /* Forward declaration */
818 static NORETURN void malformed_request(const char *zMsg);
819
820 /*
821 ** Initialize the query parameter database. Information is pulled from
822 ** the QUERY_STRING environment variable (if it exists), from standard
823 ** input if there is POST data, and from HTTP_COOKIE.
@@ -822,15 +824,31 @@
824 */
825 void cgi_init(void){
826 char *z;
827 const char *zType;
828 int len;
829 const char *zRequestUri = cgi_parameter("REQUEST_URI",0);
830 const char *zScriptName = cgi_parameter("SCRIPT_NAME",0);
831
832 #ifdef FOSSIL_ENABLE_JSON
833 json_main_bootstrap();
834 #endif
835 g.isHTTP = 1;
836 cgi_destination(CGI_BODY);
837 if( zRequestUri==0 ) malformed_request("missing REQUEST_URI");
838 if( zScriptName==0 ) malformed_request("missing SCRIPT_NAME");
839 if( cgi_parameter("PATH_INFO",0)==0 ){
840 int i, j;
841 for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){}
842 if( zRequestUri[i]=='/' ){
843 for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
844 cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i));
845 }else{
846 malformed_request("cannot compute PATH_INFO from REQUEST_URI"
847 " and SCRIPT_NAME");
848 }
849 }
850
851 z = (char*)P("HTTP_COOKIE");
852 if( z ){
853 z = mprintf("%s",z);
854 add_param_list(z, ';');
@@ -1092,14 +1110,14 @@
1110
1111
1112 /*
1113 ** Send a reply indicating that the HTTP request was malformed
1114 */
1115 static NORETURN void malformed_request(const char *zMsg){
1116 cgi_set_status(501, "Not Implemented");
1117 cgi_printf(
1118 "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg
1119 );
1120 cgi_reply();
1121 fossil_exit(0);
1122 }
1123
@@ -1187,29 +1205,30 @@
1205 struct sockaddr_in remoteName;
1206 socklen_t size = sizeof(struct sockaddr_in);
1207 char zLine[2000]; /* A single line of input. */
1208 g.fullHttpReply = 1;
1209 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1210 malformed_request("missing HTTP header");
1211 }
1212 blob_append(&g.httpHeader, zLine, -1);
1213 cgi_trace(zLine);
1214 zToken = extract_token(zLine, &z);
1215 if( zToken==0 ){
1216 malformed_request("malformed HTTP header");
1217 }
1218 if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
1219 && fossil_strcmp(zToken,"HEAD")!=0 ){
1220 malformed_request("unsupported HTTP method");
1221 }
1222 cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
1223 cgi_setenv("REQUEST_METHOD",zToken);
1224 zToken = extract_token(z, &z);
1225 if( zToken==0 ){
1226 malformed_request("malformed URL in HTTP header");
1227 }
1228 cgi_setenv("REQUEST_URI", zToken);
1229 cgi_setenv("SCRIPT_NAME", "");
1230 for(i=0; zToken[i] && zToken[i]!='?'; i++){}
1231 if( zToken[i] ) zToken[i++] = 0;
1232 cgi_setenv("PATH_INFO", zToken);
1233 cgi_setenv("QUERY_STRING", &zToken[i]);
1234 if( zIpAddr==0 &&
@@ -1269,16 +1288,57 @@
1288 }
1289 }
1290 cgi_init();
1291 cgi_trace(0);
1292 }
1293
1294 /*
1295 ** This routine handles a single SCGI request which is coming in on
1296 ** g.httpIn and which replies on g.httpOut
1297 **
1298 ** The SCGI request is read from g.httpIn and is used to initialize
1299 ** entries in the cgi_parameter() hash, as if those entries were
1300 ** environment variables. A call to cgi_init() completes
1301 ** the setup. Once all the setup is finished, this procedure returns
1302 ** and subsequent code handles the actual generation of the webpage.
1303 */
1304 void cgi_handle_scgi_request(void){
1305 char *zHdr;
1306 char *zToFree;
1307 int nHdr = 0;
1308 int nRead;
1309 int n, m;
1310 char c;
1311
1312 while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit(c) ){
1313 nHdr = nHdr*10 + c - '0';
1314 }
1315 if( nHdr<16 ) malformed_request("SCGI header too short");
1316 zToFree = zHdr = fossil_malloc(nHdr);
1317 nRead = (int)fread(zHdr, 1, nHdr, g.httpIn);
1318 if( nRead<nHdr ) malformed_request("cannot read entire SCGI header");
1319 nHdr = nRead;
1320 while( nHdr ){
1321 for(n=0; n<nHdr && zHdr[n]; n++){}
1322 for(m=n+1; m<nHdr && zHdr[m]; m++){}
1323 if( m>=nHdr ) malformed_request("SCGI header formatting error");
1324 cgi_set_parameter(zHdr, zHdr+n+1);
1325 zHdr += m+1;
1326 nHdr -= m+1;
1327 }
1328 fossil_free(zToFree);
1329 fgetc(g.httpIn); /* Read past the "," separating header from content */
1330 cgi_init();
1331 }
1332
1333
1334 #if INTERFACE
1335 /*
1336 ** Bitmap values for the flags parameter to cgi_http_server().
1337 */
1338 #define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
1339 #define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
1340
1341 #endif /* INTERFACE */
1342
1343 /*
1344 ** Maximum number of child processes that we can have running
@@ -1356,11 +1416,12 @@
1416 }
1417 }
1418 if( iPort>mxPort ) return 1;
1419 listen(listener,10);
1420 if( iPort>mnPort ){
1421 fossil_print("Listening for %s requests on TCP port %d\n",
1422 (flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
1423 fflush(stdout);
1424 }
1425 if( zBrowser ){
1426 zBrowser = mprintf(zBrowser, iPort);
1427 if( system(zBrowser)<0 ){
1428
+15 -2
--- src/main.c
+++ src/main.c
@@ -1636,19 +1636,21 @@
16361636
** --https signal a request coming in via https
16371637
** --nossl signal that no SSL connections are available
16381638
** --notfound URL use URL as "HTTP 404, object not found" page.
16391639
** --files GLOB comma-separate glob patterns for static file to serve
16401640
** --baseurl URL base URL (useful with reverse proxies)
1641
+** --scgi Interpret input as SCGI rather than HTTP
16411642
**
16421643
** See also: cgi, server, winsrv
16431644
*/
16441645
void cmd_http(void){
16451646
const char *zIpAddr;
16461647
const char *zNotFound;
16471648
const char *zHost;
16481649
const char *zAltBase;
16491650
const char *zFileGlob;
1651
+ int useSCGI;
16501652
16511653
/* The winhttp module passes the --files option as --files-urlenc with
16521654
** the argument being URL encoded, to avoid wildcard expansion in the
16531655
** shell. This option is for internal use and is undocumented.
16541656
*/
@@ -1661,10 +1663,11 @@
16611663
zFileGlob = find_option("files",0,1);
16621664
}
16631665
zNotFound = find_option("notfound", 0, 1);
16641666
g.useLocalauth = find_option("localauth", 0, 0)!=0;
16651667
g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
1668
+ useSCGI = find_option("scgi", 0, 0)!=0;
16661669
zAltBase = find_option("baseurl", 0, 1);
16671670
if( zAltBase ) set_base_url(zAltBase);
16681671
if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
16691672
zHost = find_option("host", 0, 1);
16701673
if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
@@ -1682,11 +1685,15 @@
16821685
g.httpOut = stdout;
16831686
zIpAddr = 0;
16841687
}
16851688
find_server_repository(0);
16861689
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1687
- cgi_handle_http_request(zIpAddr);
1690
+ if( useSCGI ){
1691
+ cgi_handle_scgi_request();
1692
+ }else{
1693
+ cgi_handle_http_request(zIpAddr);
1694
+ }
16881695
process_one_web_page(zNotFound, glob_create(zFileGlob));
16891696
}
16901697
16911698
/*
16921699
** Note that the following command is used by ssh:// processing.
@@ -1778,10 +1785,11 @@
17781785
** -P|--port TCPPORT listen to request on port TCPPORT
17791786
** --th-trace trace TH1 execution (for debugging purposes)
17801787
** --baseurl URL Use URL as the base (useful for reverse proxies)
17811788
** --notfound URL Redirect
17821789
** --files GLOBLIST Comma-separated list of glob patterns for static files
1790
+** --scgi Accept SCGI rather than HTTP
17831791
**
17841792
** See also: cgi, http, winsrv
17851793
*/
17861794
void cmd_webserver(void){
17871795
int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1804,10 +1812,11 @@
18041812
g.useLocalauth = find_option("localauth", 0, 0)!=0;
18051813
Th_InitTraceLog();
18061814
zPort = find_option("port", "P", 1);
18071815
zNotFound = find_option("notfound", 0, 1);
18081816
zAltBase = find_option("baseurl", 0, 1);
1817
+ if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
18091818
if( zAltBase ){
18101819
set_base_url(zAltBase);
18111820
}
18121821
if ( find_option("localhost", 0, 0)!=0 ){
18131822
flags |= HTTP_SERVER_LOCALHOST;
@@ -1868,11 +1877,15 @@
18681877
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
18691878
}
18701879
g.cgiOutput = 1;
18711880
find_server_repository(isUiCmd && zNotFound==0);
18721881
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1873
- cgi_handle_http_request(0);
1882
+ if( flags & HTTP_SERVER_SCGI ){
1883
+ cgi_handle_scgi_request();
1884
+ }else{
1885
+ cgi_handle_http_request(0);
1886
+ }
18741887
process_one_web_page(zNotFound, glob_create(zFileGlob));
18751888
#else
18761889
/* Win32 implementation */
18771890
if( isUiCmd ){
18781891
zBrowser = db_get("web-browser", "start");
18791892
--- src/main.c
+++ src/main.c
@@ -1636,19 +1636,21 @@
1636 ** --https signal a request coming in via https
1637 ** --nossl signal that no SSL connections are available
1638 ** --notfound URL use URL as "HTTP 404, object not found" page.
1639 ** --files GLOB comma-separate glob patterns for static file to serve
1640 ** --baseurl URL base URL (useful with reverse proxies)
 
1641 **
1642 ** See also: cgi, server, winsrv
1643 */
1644 void cmd_http(void){
1645 const char *zIpAddr;
1646 const char *zNotFound;
1647 const char *zHost;
1648 const char *zAltBase;
1649 const char *zFileGlob;
 
1650
1651 /* The winhttp module passes the --files option as --files-urlenc with
1652 ** the argument being URL encoded, to avoid wildcard expansion in the
1653 ** shell. This option is for internal use and is undocumented.
1654 */
@@ -1661,10 +1663,11 @@
1661 zFileGlob = find_option("files",0,1);
1662 }
1663 zNotFound = find_option("notfound", 0, 1);
1664 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1665 g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
 
1666 zAltBase = find_option("baseurl", 0, 1);
1667 if( zAltBase ) set_base_url(zAltBase);
1668 if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
1669 zHost = find_option("host", 0, 1);
1670 if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
@@ -1682,11 +1685,15 @@
1682 g.httpOut = stdout;
1683 zIpAddr = 0;
1684 }
1685 find_server_repository(0);
1686 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1687 cgi_handle_http_request(zIpAddr);
 
 
 
 
1688 process_one_web_page(zNotFound, glob_create(zFileGlob));
1689 }
1690
1691 /*
1692 ** Note that the following command is used by ssh:// processing.
@@ -1778,10 +1785,11 @@
1778 ** -P|--port TCPPORT listen to request on port TCPPORT
1779 ** --th-trace trace TH1 execution (for debugging purposes)
1780 ** --baseurl URL Use URL as the base (useful for reverse proxies)
1781 ** --notfound URL Redirect
1782 ** --files GLOBLIST Comma-separated list of glob patterns for static files
 
1783 **
1784 ** See also: cgi, http, winsrv
1785 */
1786 void cmd_webserver(void){
1787 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1804,10 +1812,11 @@
1804 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1805 Th_InitTraceLog();
1806 zPort = find_option("port", "P", 1);
1807 zNotFound = find_option("notfound", 0, 1);
1808 zAltBase = find_option("baseurl", 0, 1);
 
1809 if( zAltBase ){
1810 set_base_url(zAltBase);
1811 }
1812 if ( find_option("localhost", 0, 0)!=0 ){
1813 flags |= HTTP_SERVER_LOCALHOST;
@@ -1868,11 +1877,15 @@
1868 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
1869 }
1870 g.cgiOutput = 1;
1871 find_server_repository(isUiCmd && zNotFound==0);
1872 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1873 cgi_handle_http_request(0);
 
 
 
 
1874 process_one_web_page(zNotFound, glob_create(zFileGlob));
1875 #else
1876 /* Win32 implementation */
1877 if( isUiCmd ){
1878 zBrowser = db_get("web-browser", "start");
1879
--- src/main.c
+++ src/main.c
@@ -1636,19 +1636,21 @@
1636 ** --https signal a request coming in via https
1637 ** --nossl signal that no SSL connections are available
1638 ** --notfound URL use URL as "HTTP 404, object not found" page.
1639 ** --files GLOB comma-separate glob patterns for static file to serve
1640 ** --baseurl URL base URL (useful with reverse proxies)
1641 ** --scgi Interpret input as SCGI rather than HTTP
1642 **
1643 ** See also: cgi, server, winsrv
1644 */
1645 void cmd_http(void){
1646 const char *zIpAddr;
1647 const char *zNotFound;
1648 const char *zHost;
1649 const char *zAltBase;
1650 const char *zFileGlob;
1651 int useSCGI;
1652
1653 /* The winhttp module passes the --files option as --files-urlenc with
1654 ** the argument being URL encoded, to avoid wildcard expansion in the
1655 ** shell. This option is for internal use and is undocumented.
1656 */
@@ -1661,10 +1663,11 @@
1663 zFileGlob = find_option("files",0,1);
1664 }
1665 zNotFound = find_option("notfound", 0, 1);
1666 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1667 g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
1668 useSCGI = find_option("scgi", 0, 0)!=0;
1669 zAltBase = find_option("baseurl", 0, 1);
1670 if( zAltBase ) set_base_url(zAltBase);
1671 if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
1672 zHost = find_option("host", 0, 1);
1673 if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
@@ -1682,11 +1685,15 @@
1685 g.httpOut = stdout;
1686 zIpAddr = 0;
1687 }
1688 find_server_repository(0);
1689 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1690 if( useSCGI ){
1691 cgi_handle_scgi_request();
1692 }else{
1693 cgi_handle_http_request(zIpAddr);
1694 }
1695 process_one_web_page(zNotFound, glob_create(zFileGlob));
1696 }
1697
1698 /*
1699 ** Note that the following command is used by ssh:// processing.
@@ -1778,10 +1785,11 @@
1785 ** -P|--port TCPPORT listen to request on port TCPPORT
1786 ** --th-trace trace TH1 execution (for debugging purposes)
1787 ** --baseurl URL Use URL as the base (useful for reverse proxies)
1788 ** --notfound URL Redirect
1789 ** --files GLOBLIST Comma-separated list of glob patterns for static files
1790 ** --scgi Accept SCGI rather than HTTP
1791 **
1792 ** See also: cgi, http, winsrv
1793 */
1794 void cmd_webserver(void){
1795 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1804,10 +1812,11 @@
1812 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1813 Th_InitTraceLog();
1814 zPort = find_option("port", "P", 1);
1815 zNotFound = find_option("notfound", 0, 1);
1816 zAltBase = find_option("baseurl", 0, 1);
1817 if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
1818 if( zAltBase ){
1819 set_base_url(zAltBase);
1820 }
1821 if ( find_option("localhost", 0, 0)!=0 ){
1822 flags |= HTTP_SERVER_LOCALHOST;
@@ -1868,11 +1877,15 @@
1877 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
1878 }
1879 g.cgiOutput = 1;
1880 find_server_repository(isUiCmd && zNotFound==0);
1881 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1882 if( flags & HTTP_SERVER_SCGI ){
1883 cgi_handle_scgi_request();
1884 }else{
1885 cgi_handle_http_request(0);
1886 }
1887 process_one_web_page(zNotFound, glob_create(zFileGlob));
1888 #else
1889 /* Win32 implementation */
1890 if( isUiCmd ){
1891 zBrowser = db_get("web-browser", "start");
1892
+77 -3
--- src/winhttp.c
+++ src/winhttp.c
@@ -61,11 +61,11 @@
6161
}
6262
6363
/*
6464
** Process a single incoming HTTP request.
6565
*/
66
-static void win32_process_one_http_request(void *pAppData){
66
+static void win32_http_request(void *pAppData){
6767
HttpRequest *p = (HttpRequest*)pAppData;
6868
FILE *in = 0, *out = 0;
6969
int amt, got;
7070
int wanted = 0;
7171
char *z;
@@ -128,10 +128,73 @@
128128
closesocket(p->s);
129129
file_delete(zRequestFName);
130130
file_delete(zReplyFName);
131131
free(p);
132132
}
133
+
134
+/*
135
+** Process a single incoming SCGI request.
136
+*/
137
+static void win32_scgi_request(void *pAppData){
138
+ HttpRequest *p = (HttpRequest*)pAppData;
139
+ FILE *in = 0, *out = 0;
140
+ int amt, got, nHdr, i;
141
+ int wanted = 0;
142
+ char *z;
143
+ char zRequestFName[MAX_PATH];
144
+ char zReplyFName[MAX_PATH];
145
+ char zCmd[2000]; /* Command-line to process the request */
146
+ char zHdr[2000]; /* The SCGI request header */
147
+
148
+ sqlite3_snprintf(MAX_PATH, zRequestFName,
149
+ "%s_in%d.txt", zTempPrefix, p->id);
150
+ sqlite3_snprintf(MAX_PATH, zReplyFName,
151
+ "%s_out%d.txt", zTempPrefix, p->id);
152
+ out = fossil_fopen(zRequestFName, "wb");
153
+ if( out==0 ) goto end_request;
154
+ amt = 0;
155
+ got = recv(p->s, zHdr, sizeof(zHdr), 0);
156
+ if( got==SOCKET_ERROR ) goto end_request;
157
+ amt = fwrite(zHdr, 1, got, out);
158
+ nHdr = 0;
159
+ for(i=0; zHdr[i]>='0' && zHdr[i]<='9'; i++){
160
+ nHdr = 10*nHdr + zHdr[i] - '0';
161
+ }
162
+ wanted = nHdr + i + 1;
163
+ if( strcmp(zHdr+i+1, "CONTENT_LENGTH")==0 ){
164
+ wanted += atoi(zHdr+i+15);
165
+ }
166
+ while( wanted>amt ){
167
+ got = recv(p->s, zHdr, wanted<sizeof(zHdr) ? wanted : sizeof(zHdr), 0);
168
+ if( got<=0 ) break;
169
+ fwrite(zHdr, 1, got, out);
170
+ wanted += got;
171
+ }
172
+ fclose(out);
173
+ out = 0;
174
+ sqlite3_snprintf(sizeof(zCmd), zCmd,
175
+ "\"%s\" http \"%s\" %s %s %s --scgi --nossl%s",
176
+ g.nameOfExe, g.zRepositoryName, zRequestFName, zReplyFName,
177
+ inet_ntoa(p->addr.sin_addr), p->zOptions
178
+ );
179
+ fossil_system(zCmd);
180
+ in = fossil_fopen(zReplyFName, "rb");
181
+ if( in ){
182
+ while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
183
+ send(p->s, zHdr, got, 0);
184
+ }
185
+ }
186
+
187
+end_request:
188
+ if( out ) fclose(out);
189
+ if( in ) fclose(in);
190
+ closesocket(p->s);
191
+ file_delete(zRequestFName);
192
+ file_delete(zReplyFName);
193
+ free(p);
194
+}
195
+
133196
134197
/*
135198
** Start a listening socket and process incoming HTTP requests on
136199
** that socket.
137200
*/
@@ -206,11 +269,12 @@
206269
if( !GetTempPathW(MAX_PATH, zTmpPath) ){
207270
fossil_fatal("unable to get path to the temporary directory.");
208271
}
209272
zTempPrefix = mprintf("%sfossil_server_P%d_",
210273
fossil_unicode_to_utf8(zTmpPath), iPort);
211
- fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
274
+ fossil_print("Listening for %s requests on TCP port %d\n",
275
+ (flags&HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
212276
if( zBrowser ){
213277
zBrowser = mprintf(zBrowser, iPort);
214278
fossil_print("Launch webbrowser: %s\n", zBrowser);
215279
fossil_system(zBrowser);
216280
}
@@ -244,11 +308,15 @@
244308
p = fossil_malloc( sizeof(*p) );
245309
p->id = ++idCnt;
246310
p->s = client;
247311
p->addr = client_addr;
248312
p->zOptions = blob_str(&options);
249
- _beginthread(win32_process_one_http_request, 0, (void*)p);
313
+ if( flags & HTTP_SERVER_SCGI ){
314
+ _beginthread(win32_scgi_request, 0, (void*)p);
315
+ }else{
316
+ _beginthread(win32_http_request, 0, (void*)p);
317
+ }
250318
}
251319
closesocket(s);
252320
WSACleanup();
253321
}
254322
@@ -539,10 +607,14 @@
539607
**
540608
** Enables automatic login if the --localauth option is present
541609
** and the "localauth" setting is off and the connection is from
542610
** localhost.
543611
**
612
+** --scgi
613
+**
614
+** Create an SCGI server instead of an HTTP server
615
+**
544616
**
545617
** fossil winsrv delete ?SERVICE-NAME?
546618
**
547619
** Deletes a service. If the service is currently running, it will be
548620
** stopped first and then deleted.
@@ -592,10 +664,11 @@
592664
const char *zPort = find_option("port", "P", 1);
593665
const char *zNotFound = find_option("notfound", 0, 1);
594666
const char *zFileGlob = find_option("files", 0, 1);
595667
const char *zLocalAuth = find_option("localauth", 0, 0);
596668
const char *zRepository = find_option("repository", "R", 1);
669
+ int useSCGI = find_option("scgi", 0, 0)!=0;
597670
Blob binPath;
598671
599672
verify_all_options();
600673
if( g.argc==4 ){
601674
zSvcName = g.argv[3];
@@ -632,10 +705,11 @@
632705
db_close(0);
633706
/* Build the fully-qualified path to the service binary file. */
634707
blob_zero(&binPath);
635708
blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
636709
if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
710
+ if( useSCGI ) blob_appendf(&binPath, " --scgi");
637711
if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
638712
if( zFileGlob ) blob_appendf(&binPath, " --files-urlenc %T", zFileGlob);
639713
if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
640714
blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
641715
/* Create the service. */
642716
--- src/winhttp.c
+++ src/winhttp.c
@@ -61,11 +61,11 @@
61 }
62
63 /*
64 ** Process a single incoming HTTP request.
65 */
66 static void win32_process_one_http_request(void *pAppData){
67 HttpRequest *p = (HttpRequest*)pAppData;
68 FILE *in = 0, *out = 0;
69 int amt, got;
70 int wanted = 0;
71 char *z;
@@ -128,10 +128,73 @@
128 closesocket(p->s);
129 file_delete(zRequestFName);
130 file_delete(zReplyFName);
131 free(p);
132 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
134 /*
135 ** Start a listening socket and process incoming HTTP requests on
136 ** that socket.
137 */
@@ -206,11 +269,12 @@
206 if( !GetTempPathW(MAX_PATH, zTmpPath) ){
207 fossil_fatal("unable to get path to the temporary directory.");
208 }
209 zTempPrefix = mprintf("%sfossil_server_P%d_",
210 fossil_unicode_to_utf8(zTmpPath), iPort);
211 fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
 
212 if( zBrowser ){
213 zBrowser = mprintf(zBrowser, iPort);
214 fossil_print("Launch webbrowser: %s\n", zBrowser);
215 fossil_system(zBrowser);
216 }
@@ -244,11 +308,15 @@
244 p = fossil_malloc( sizeof(*p) );
245 p->id = ++idCnt;
246 p->s = client;
247 p->addr = client_addr;
248 p->zOptions = blob_str(&options);
249 _beginthread(win32_process_one_http_request, 0, (void*)p);
 
 
 
 
250 }
251 closesocket(s);
252 WSACleanup();
253 }
254
@@ -539,10 +607,14 @@
539 **
540 ** Enables automatic login if the --localauth option is present
541 ** and the "localauth" setting is off and the connection is from
542 ** localhost.
543 **
 
 
 
 
544 **
545 ** fossil winsrv delete ?SERVICE-NAME?
546 **
547 ** Deletes a service. If the service is currently running, it will be
548 ** stopped first and then deleted.
@@ -592,10 +664,11 @@
592 const char *zPort = find_option("port", "P", 1);
593 const char *zNotFound = find_option("notfound", 0, 1);
594 const char *zFileGlob = find_option("files", 0, 1);
595 const char *zLocalAuth = find_option("localauth", 0, 0);
596 const char *zRepository = find_option("repository", "R", 1);
 
597 Blob binPath;
598
599 verify_all_options();
600 if( g.argc==4 ){
601 zSvcName = g.argv[3];
@@ -632,10 +705,11 @@
632 db_close(0);
633 /* Build the fully-qualified path to the service binary file. */
634 blob_zero(&binPath);
635 blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
636 if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
 
637 if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
638 if( zFileGlob ) blob_appendf(&binPath, " --files-urlenc %T", zFileGlob);
639 if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
640 blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
641 /* Create the service. */
642
--- src/winhttp.c
+++ src/winhttp.c
@@ -61,11 +61,11 @@
61 }
62
63 /*
64 ** Process a single incoming HTTP request.
65 */
66 static void win32_http_request(void *pAppData){
67 HttpRequest *p = (HttpRequest*)pAppData;
68 FILE *in = 0, *out = 0;
69 int amt, got;
70 int wanted = 0;
71 char *z;
@@ -128,10 +128,73 @@
128 closesocket(p->s);
129 file_delete(zRequestFName);
130 file_delete(zReplyFName);
131 free(p);
132 }
133
134 /*
135 ** Process a single incoming SCGI request.
136 */
137 static void win32_scgi_request(void *pAppData){
138 HttpRequest *p = (HttpRequest*)pAppData;
139 FILE *in = 0, *out = 0;
140 int amt, got, nHdr, i;
141 int wanted = 0;
142 char *z;
143 char zRequestFName[MAX_PATH];
144 char zReplyFName[MAX_PATH];
145 char zCmd[2000]; /* Command-line to process the request */
146 char zHdr[2000]; /* The SCGI request header */
147
148 sqlite3_snprintf(MAX_PATH, zRequestFName,
149 "%s_in%d.txt", zTempPrefix, p->id);
150 sqlite3_snprintf(MAX_PATH, zReplyFName,
151 "%s_out%d.txt", zTempPrefix, p->id);
152 out = fossil_fopen(zRequestFName, "wb");
153 if( out==0 ) goto end_request;
154 amt = 0;
155 got = recv(p->s, zHdr, sizeof(zHdr), 0);
156 if( got==SOCKET_ERROR ) goto end_request;
157 amt = fwrite(zHdr, 1, got, out);
158 nHdr = 0;
159 for(i=0; zHdr[i]>='0' && zHdr[i]<='9'; i++){
160 nHdr = 10*nHdr + zHdr[i] - '0';
161 }
162 wanted = nHdr + i + 1;
163 if( strcmp(zHdr+i+1, "CONTENT_LENGTH")==0 ){
164 wanted += atoi(zHdr+i+15);
165 }
166 while( wanted>amt ){
167 got = recv(p->s, zHdr, wanted<sizeof(zHdr) ? wanted : sizeof(zHdr), 0);
168 if( got<=0 ) break;
169 fwrite(zHdr, 1, got, out);
170 wanted += got;
171 }
172 fclose(out);
173 out = 0;
174 sqlite3_snprintf(sizeof(zCmd), zCmd,
175 "\"%s\" http \"%s\" %s %s %s --scgi --nossl%s",
176 g.nameOfExe, g.zRepositoryName, zRequestFName, zReplyFName,
177 inet_ntoa(p->addr.sin_addr), p->zOptions
178 );
179 fossil_system(zCmd);
180 in = fossil_fopen(zReplyFName, "rb");
181 if( in ){
182 while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
183 send(p->s, zHdr, got, 0);
184 }
185 }
186
187 end_request:
188 if( out ) fclose(out);
189 if( in ) fclose(in);
190 closesocket(p->s);
191 file_delete(zRequestFName);
192 file_delete(zReplyFName);
193 free(p);
194 }
195
196
197 /*
198 ** Start a listening socket and process incoming HTTP requests on
199 ** that socket.
200 */
@@ -206,11 +269,12 @@
269 if( !GetTempPathW(MAX_PATH, zTmpPath) ){
270 fossil_fatal("unable to get path to the temporary directory.");
271 }
272 zTempPrefix = mprintf("%sfossil_server_P%d_",
273 fossil_unicode_to_utf8(zTmpPath), iPort);
274 fossil_print("Listening for %s requests on TCP port %d\n",
275 (flags&HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
276 if( zBrowser ){
277 zBrowser = mprintf(zBrowser, iPort);
278 fossil_print("Launch webbrowser: %s\n", zBrowser);
279 fossil_system(zBrowser);
280 }
@@ -244,11 +308,15 @@
308 p = fossil_malloc( sizeof(*p) );
309 p->id = ++idCnt;
310 p->s = client;
311 p->addr = client_addr;
312 p->zOptions = blob_str(&options);
313 if( flags & HTTP_SERVER_SCGI ){
314 _beginthread(win32_scgi_request, 0, (void*)p);
315 }else{
316 _beginthread(win32_http_request, 0, (void*)p);
317 }
318 }
319 closesocket(s);
320 WSACleanup();
321 }
322
@@ -539,10 +607,14 @@
607 **
608 ** Enables automatic login if the --localauth option is present
609 ** and the "localauth" setting is off and the connection is from
610 ** localhost.
611 **
612 ** --scgi
613 **
614 ** Create an SCGI server instead of an HTTP server
615 **
616 **
617 ** fossil winsrv delete ?SERVICE-NAME?
618 **
619 ** Deletes a service. If the service is currently running, it will be
620 ** stopped first and then deleted.
@@ -592,10 +664,11 @@
664 const char *zPort = find_option("port", "P", 1);
665 const char *zNotFound = find_option("notfound", 0, 1);
666 const char *zFileGlob = find_option("files", 0, 1);
667 const char *zLocalAuth = find_option("localauth", 0, 0);
668 const char *zRepository = find_option("repository", "R", 1);
669 int useSCGI = find_option("scgi", 0, 0)!=0;
670 Blob binPath;
671
672 verify_all_options();
673 if( g.argc==4 ){
674 zSvcName = g.argv[3];
@@ -632,10 +705,11 @@
705 db_close(0);
706 /* Build the fully-qualified path to the service binary file. */
707 blob_zero(&binPath);
708 blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
709 if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
710 if( useSCGI ) blob_appendf(&binPath, " --scgi");
711 if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
712 if( zFileGlob ) blob_appendf(&binPath, " --files-urlenc %T", zFileGlob);
713 if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
714 blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
715 /* Create the service. */
716
+2 -2
--- www/index.wiki
+++ www/index.wiki
@@ -91,13 +91,13 @@
9191
for all network communications, meaning that it works fine from behind
9292
restrictive firewalls. The protocol is
9393
[./stats.wiki | bandwidth efficient] to the point that Fossil can be
9494
used comfortably over a dial-up internet connection.
9595
96
- 6. <b>CGI Enabled</b> -
96
+ 6. <b>CGI and SCGI Enabled</b> -
9797
No server is required to use fossil. But a
98
- server does make collaboration easier. Fossil supports three different
98
+ server does make collaboration easier. Fossil supports four different
9999
yet simple [./quickstart.wiki#serversetup | server configurations].
100100
The most popular is a 2-line CGI script. This is the approach
101101
used by the [./selfhost.wiki | self-hosting fossil repositories].
102102
103103
7. <b>Robust &amp; Reliable</b> -
104104
--- www/index.wiki
+++ www/index.wiki
@@ -91,13 +91,13 @@
91 for all network communications, meaning that it works fine from behind
92 restrictive firewalls. The protocol is
93 [./stats.wiki | bandwidth efficient] to the point that Fossil can be
94 used comfortably over a dial-up internet connection.
95
96 6. <b>CGI Enabled</b> -
97 No server is required to use fossil. But a
98 server does make collaboration easier. Fossil supports three different
99 yet simple [./quickstart.wiki#serversetup | server configurations].
100 The most popular is a 2-line CGI script. This is the approach
101 used by the [./selfhost.wiki | self-hosting fossil repositories].
102
103 7. <b>Robust &amp; Reliable</b> -
104
--- www/index.wiki
+++ www/index.wiki
@@ -91,13 +91,13 @@
91 for all network communications, meaning that it works fine from behind
92 restrictive firewalls. The protocol is
93 [./stats.wiki | bandwidth efficient] to the point that Fossil can be
94 used comfortably over a dial-up internet connection.
95
96 6. <b>CGI and SCGI Enabled</b> -
97 No server is required to use fossil. But a
98 server does make collaboration easier. Fossil supports four different
99 yet simple [./quickstart.wiki#serversetup | server configurations].
100 The most popular is a 2-line CGI script. This is the approach
101 used by the [./selfhost.wiki | self-hosting fossil repositories].
102
103 7. <b>Robust &amp; Reliable</b> -
104
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -309,10 +309,13 @@
309309
server. For cross-machine collaboration, use the <b>server</b> command,
310310
which binds on all IP addresses and does not try to start a web browser.
311311
You can omit the <i>repository-filename</i> if you are within
312312
a checked-out local tree. The <b>server</b> uses port 8080 by default
313313
but you can specify a different port using the <b>-port</b> option.</p>
314
+
315
+ <p>The same commands can be used with the --scgi option to run
316
+ [./scgi.wiki | SCGI] from Nginx, if desired.</p>
314317
315318
<p>Command-line servers like this are useful when two people want
316319
to share a repository on temporary or ad-hoc basis. For a more
317320
permanent installation, you should use either the CGI server or the
318321
inetd server.
319322
320323
ADDED www/scgi.wiki
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -309,10 +309,13 @@
309 server. For cross-machine collaboration, use the <b>server</b> command,
310 which binds on all IP addresses and does not try to start a web browser.
311 You can omit the <i>repository-filename</i> if you are within
312 a checked-out local tree. The <b>server</b> uses port 8080 by default
313 but you can specify a different port using the <b>-port</b> option.</p>
 
 
 
314
315 <p>Command-line servers like this are useful when two people want
316 to share a repository on temporary or ad-hoc basis. For a more
317 permanent installation, you should use either the CGI server or the
318 inetd server.
319
320 DDED www/scgi.wiki
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -309,10 +309,13 @@
309 server. For cross-machine collaboration, use the <b>server</b> command,
310 which binds on all IP addresses and does not try to start a web browser.
311 You can omit the <i>repository-filename</i> if you are within
312 a checked-out local tree. The <b>server</b> uses port 8080 by default
313 but you can specify a different port using the <b>-port</b> option.</p>
314
315 <p>The same commands can be used with the --scgi option to run
316 [./scgi.wiki | SCGI] from Nginx, if desired.</p>
317
318 <p>Command-line servers like this are useful when two people want
319 to share a repository on temporary or ad-hoc basis. For a more
320 permanent installation, you should use either the CGI server or the
321 inetd server.
322
323 DDED www/scgi.wiki
--- a/www/scgi.wiki
+++ b/www/scgi.wiki
@@ -0,0 +1,22 @@
1
+<title>Fossil SCGI</title>
2
+
3
+To run Fossil using SCGI, start the [/help/server|fossil server] command
4
+with the --scgi command-line option. You will probably also want to
5
+specific an alternative TCP/IP port usiblockquote>ing --port. For example:
6
+
7
+<pr</blockquote>
8
+
9
+Then configure your SCGI-aware web-server to send SCGI requests to port
10
+9000 on the machine where Fossil is running. A typical configuratiblockquote><pre>
11
+location ~ ^/demo_project/ {
12
+ include scgi_params;
13
+ scgi_pass localhost:9000;
14
+ scgi_param SCRIPT_NAME "/demo_project";
15
+ scgi</blockquotgi_param HTTPS "on";
16
+}
17
+</pre>
18
+
19
+NoteO or SCRIPT_NAME
20
+variables via SCGI, but Fossil needs one or the other. So the configuration
21
+above needs to add SCRIPT_N an
22
+error.
--- a/www/scgi.wiki
+++ b/www/scgi.wiki
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/www/scgi.wiki
+++ b/www/scgi.wiki
@@ -0,0 +1,22 @@
1 <title>Fossil SCGI</title>
2
3 To run Fossil using SCGI, start the [/help/server|fossil server] command
4 with the --scgi command-line option. You will probably also want to
5 specific an alternative TCP/IP port usiblockquote>ing --port. For example:
6
7 <pr</blockquote>
8
9 Then configure your SCGI-aware web-server to send SCGI requests to port
10 9000 on the machine where Fossil is running. A typical configuratiblockquote><pre>
11 location ~ ^/demo_project/ {
12 include scgi_params;
13 scgi_pass localhost:9000;
14 scgi_param SCRIPT_NAME "/demo_project";
15 scgi</blockquotgi_param HTTPS "on";
16 }
17 </pre>
18
19 NoteO or SCRIPT_NAME
20 variables via SCGI, but Fossil needs one or the other. So the configuration
21 above needs to add SCRIPT_N an
22 error.

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button