Fossil SCM

Merge in all new development from trunk.

andybradford 2013-08-16 03:25 ssh-test-http merge
Commit 535cba9158f23dfd6a0c803c3be08ca8b4ddf1e2
+63 -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,26 @@
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
+ for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
843
+ cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i));
844
+ }
832845
833846
z = (char*)P("HTTP_COOKIE");
834847
if( z ){
835848
z = mprintf("%s",z);
836849
add_param_list(z, ';');
@@ -1092,14 +1105,14 @@
10921105
10931106
10941107
/*
10951108
** Send a reply indicating that the HTTP request was malformed
10961109
*/
1097
-static NORETURN void malformed_request(void){
1110
+static NORETURN void malformed_request(const char *zMsg){
10981111
cgi_set_status(501, "Not Implemented");
10991112
cgi_printf(
1100
- "<html><body>Unrecognized HTTP Request</body></html>\n"
1113
+ "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg
11011114
);
11021115
cgi_reply();
11031116
fossil_exit(0);
11041117
}
11051118
@@ -1187,29 +1200,30 @@
11871200
struct sockaddr_in remoteName;
11881201
socklen_t size = sizeof(struct sockaddr_in);
11891202
char zLine[2000]; /* A single line of input. */
11901203
g.fullHttpReply = 1;
11911204
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1192
- malformed_request();
1205
+ malformed_request("missing HTTP header");
11931206
}
11941207
blob_append(&g.httpHeader, zLine, -1);
11951208
cgi_trace(zLine);
11961209
zToken = extract_token(zLine, &z);
11971210
if( zToken==0 ){
1198
- malformed_request();
1211
+ malformed_request("malformed HTTP header");
11991212
}
12001213
if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
12011214
&& fossil_strcmp(zToken,"HEAD")!=0 ){
1202
- malformed_request();
1215
+ malformed_request("unsupported HTTP method");
12031216
}
12041217
cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
12051218
cgi_setenv("REQUEST_METHOD",zToken);
12061219
zToken = extract_token(z, &z);
12071220
if( zToken==0 ){
1208
- malformed_request();
1221
+ malformed_request("malformed URL in HTTP header");
12091222
}
12101223
cgi_setenv("REQUEST_URI", zToken);
1224
+ cgi_setenv("SCRIPT_NAME", "");
12111225
for(i=0; zToken[i] && zToken[i]!='?'; i++){}
12121226
if( zToken[i] ) zToken[i++] = 0;
12131227
cgi_setenv("PATH_INFO", zToken);
12141228
cgi_setenv("QUERY_STRING", &zToken[i]);
12151229
if( zIpAddr==0 &&
@@ -1269,16 +1283,57 @@
12691283
}
12701284
}
12711285
cgi_init();
12721286
cgi_trace(0);
12731287
}
1288
+
1289
+/*
1290
+** This routine handles a single SCGI request which is coming in on
1291
+** g.httpIn and which replies on g.httpOut
1292
+**
1293
+** The SCGI request is read from g.httpIn and is used to initialize
1294
+** entries in the cgi_parameter() hash, as if those entries were
1295
+** environment variables. A call to cgi_init() completes
1296
+** the setup. Once all the setup is finished, this procedure returns
1297
+** and subsequent code handles the actual generation of the webpage.
1298
+*/
1299
+void cgi_handle_scgi_request(void){
1300
+ char *zHdr;
1301
+ char *zToFree;
1302
+ int nHdr = 0;
1303
+ int nRead;
1304
+ int n, m;
1305
+ char c;
1306
+
1307
+ while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit(c) ){
1308
+ nHdr = nHdr*10 + c - '0';
1309
+ }
1310
+ if( nHdr<16 ) malformed_request("SCGI header too short");
1311
+ zToFree = zHdr = fossil_malloc(nHdr);
1312
+ nRead = (int)fread(zHdr, 1, nHdr, g.httpIn);
1313
+ if( nRead<nHdr ) malformed_request("cannot read entire SCGI header");
1314
+ nHdr = nRead;
1315
+ while( nHdr ){
1316
+ for(n=0; n<nHdr && zHdr[n]; n++){}
1317
+ for(m=n+1; m<nHdr && zHdr[m]; m++){}
1318
+ if( m>=nHdr ) malformed_request("SCGI header formatting error");
1319
+ cgi_set_parameter(zHdr, zHdr+n+1);
1320
+ zHdr += m+1;
1321
+ nHdr -= m+1;
1322
+ }
1323
+ fossil_free(zToFree);
1324
+ fgetc(g.httpIn); /* Read past the "," separating header from content */
1325
+ cgi_init();
1326
+}
1327
+
12741328
12751329
#if INTERFACE
12761330
/*
12771331
** Bitmap values for the flags parameter to cgi_http_server().
12781332
*/
12791333
#define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
1334
+#define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
12801335
12811336
#endif /* INTERFACE */
12821337
12831338
/*
12841339
** Maximum number of child processes that we can have running
@@ -1356,11 +1411,12 @@
13561411
}
13571412
}
13581413
if( iPort>mxPort ) return 1;
13591414
listen(listener,10);
13601415
if( iPort>mnPort ){
1361
- fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
1416
+ fossil_print("Listening for %s requests on TCP port %d\n",
1417
+ (flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
13621418
fflush(stdout);
13631419
}
13641420
if( zBrowser ){
13651421
zBrowser = mprintf(zBrowser, iPort);
13661422
if( system(zBrowser)<0 ){
13671423
--- 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,26 @@
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 +1105,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 +1200,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 +1283,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 +1411,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,26 @@
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 for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
843 cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i));
844 }
845
846 z = (char*)P("HTTP_COOKIE");
847 if( z ){
848 z = mprintf("%s",z);
849 add_param_list(z, ';');
@@ -1092,14 +1105,14 @@
1105
1106
1107 /*
1108 ** Send a reply indicating that the HTTP request was malformed
1109 */
1110 static NORETURN void malformed_request(const char *zMsg){
1111 cgi_set_status(501, "Not Implemented");
1112 cgi_printf(
1113 "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg
1114 );
1115 cgi_reply();
1116 fossil_exit(0);
1117 }
1118
@@ -1187,29 +1200,30 @@
1200 struct sockaddr_in remoteName;
1201 socklen_t size = sizeof(struct sockaddr_in);
1202 char zLine[2000]; /* A single line of input. */
1203 g.fullHttpReply = 1;
1204 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1205 malformed_request("missing HTTP header");
1206 }
1207 blob_append(&g.httpHeader, zLine, -1);
1208 cgi_trace(zLine);
1209 zToken = extract_token(zLine, &z);
1210 if( zToken==0 ){
1211 malformed_request("malformed HTTP header");
1212 }
1213 if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
1214 && fossil_strcmp(zToken,"HEAD")!=0 ){
1215 malformed_request("unsupported HTTP method");
1216 }
1217 cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
1218 cgi_setenv("REQUEST_METHOD",zToken);
1219 zToken = extract_token(z, &z);
1220 if( zToken==0 ){
1221 malformed_request("malformed URL in HTTP header");
1222 }
1223 cgi_setenv("REQUEST_URI", zToken);
1224 cgi_setenv("SCRIPT_NAME", "");
1225 for(i=0; zToken[i] && zToken[i]!='?'; i++){}
1226 if( zToken[i] ) zToken[i++] = 0;
1227 cgi_setenv("PATH_INFO", zToken);
1228 cgi_setenv("QUERY_STRING", &zToken[i]);
1229 if( zIpAddr==0 &&
@@ -1269,16 +1283,57 @@
1283 }
1284 }
1285 cgi_init();
1286 cgi_trace(0);
1287 }
1288
1289 /*
1290 ** This routine handles a single SCGI request which is coming in on
1291 ** g.httpIn and which replies on g.httpOut
1292 **
1293 ** The SCGI request is read from g.httpIn and is used to initialize
1294 ** entries in the cgi_parameter() hash, as if those entries were
1295 ** environment variables. A call to cgi_init() completes
1296 ** the setup. Once all the setup is finished, this procedure returns
1297 ** and subsequent code handles the actual generation of the webpage.
1298 */
1299 void cgi_handle_scgi_request(void){
1300 char *zHdr;
1301 char *zToFree;
1302 int nHdr = 0;
1303 int nRead;
1304 int n, m;
1305 char c;
1306
1307 while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit(c) ){
1308 nHdr = nHdr*10 + c - '0';
1309 }
1310 if( nHdr<16 ) malformed_request("SCGI header too short");
1311 zToFree = zHdr = fossil_malloc(nHdr);
1312 nRead = (int)fread(zHdr, 1, nHdr, g.httpIn);
1313 if( nRead<nHdr ) malformed_request("cannot read entire SCGI header");
1314 nHdr = nRead;
1315 while( nHdr ){
1316 for(n=0; n<nHdr && zHdr[n]; n++){}
1317 for(m=n+1; m<nHdr && zHdr[m]; m++){}
1318 if( m>=nHdr ) malformed_request("SCGI header formatting error");
1319 cgi_set_parameter(zHdr, zHdr+n+1);
1320 zHdr += m+1;
1321 nHdr -= m+1;
1322 }
1323 fossil_free(zToFree);
1324 fgetc(g.httpIn); /* Read past the "," separating header from content */
1325 cgi_init();
1326 }
1327
1328
1329 #if INTERFACE
1330 /*
1331 ** Bitmap values for the flags parameter to cgi_http_server().
1332 */
1333 #define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
1334 #define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
1335
1336 #endif /* INTERFACE */
1337
1338 /*
1339 ** Maximum number of child processes that we can have running
@@ -1356,11 +1411,12 @@
1411 }
1412 }
1413 if( iPort>mxPort ) return 1;
1414 listen(listener,10);
1415 if( iPort>mnPort ){
1416 fossil_print("Listening for %s requests on TCP port %d\n",
1417 (flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
1418 fflush(stdout);
1419 }
1420 if( zBrowser ){
1421 zBrowser = mprintf(zBrowser, iPort);
1422 if( system(zBrowser)<0 ){
1423
+63 -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,26 @@
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
+ for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
843
+ cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i));
844
+ }
832845
833846
z = (char*)P("HTTP_COOKIE");
834847
if( z ){
835848
z = mprintf("%s",z);
836849
add_param_list(z, ';');
@@ -1092,14 +1105,14 @@
10921105
10931106
10941107
/*
10951108
** Send a reply indicating that the HTTP request was malformed
10961109
*/
1097
-static NORETURN void malformed_request(void){
1110
+static NORETURN void malformed_request(const char *zMsg){
10981111
cgi_set_status(501, "Not Implemented");
10991112
cgi_printf(
1100
- "<html><body>Unrecognized HTTP Request</body></html>\n"
1113
+ "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg
11011114
);
11021115
cgi_reply();
11031116
fossil_exit(0);
11041117
}
11051118
@@ -1187,29 +1200,30 @@
11871200
struct sockaddr_in remoteName;
11881201
socklen_t size = sizeof(struct sockaddr_in);
11891202
char zLine[2000]; /* A single line of input. */
11901203
g.fullHttpReply = 1;
11911204
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1192
- malformed_request();
1205
+ malformed_request("missing HTTP header");
11931206
}
11941207
blob_append(&g.httpHeader, zLine, -1);
11951208
cgi_trace(zLine);
11961209
zToken = extract_token(zLine, &z);
11971210
if( zToken==0 ){
1198
- malformed_request();
1211
+ malformed_request("malformed HTTP header");
11991212
}
12001213
if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
12011214
&& fossil_strcmp(zToken,"HEAD")!=0 ){
1202
- malformed_request();
1215
+ malformed_request("unsupported HTTP method");
12031216
}
12041217
cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
12051218
cgi_setenv("REQUEST_METHOD",zToken);
12061219
zToken = extract_token(z, &z);
12071220
if( zToken==0 ){
1208
- malformed_request();
1221
+ malformed_request("malformed URL in HTTP header");
12091222
}
12101223
cgi_setenv("REQUEST_URI", zToken);
1224
+ cgi_setenv("SCRIPT_NAME", "");
12111225
for(i=0; zToken[i] && zToken[i]!='?'; i++){}
12121226
if( zToken[i] ) zToken[i++] = 0;
12131227
cgi_setenv("PATH_INFO", zToken);
12141228
cgi_setenv("QUERY_STRING", &zToken[i]);
12151229
if( zIpAddr==0 &&
@@ -1269,16 +1283,57 @@
12691283
}
12701284
}
12711285
cgi_init();
12721286
cgi_trace(0);
12731287
}
1288
+
1289
+/*
1290
+** This routine handles a single SCGI request which is coming in on
1291
+** g.httpIn and which replies on g.httpOut
1292
+**
1293
+** The SCGI request is read from g.httpIn and is used to initialize
1294
+** entries in the cgi_parameter() hash, as if those entries were
1295
+** environment variables. A call to cgi_init() completes
1296
+** the setup. Once all the setup is finished, this procedure returns
1297
+** and subsequent code handles the actual generation of the webpage.
1298
+*/
1299
+void cgi_handle_scgi_request(void){
1300
+ char *zHdr;
1301
+ char *zToFree;
1302
+ int nHdr = 0;
1303
+ int nRead;
1304
+ int n, m;
1305
+ char c;
1306
+
1307
+ while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit(c) ){
1308
+ nHdr = nHdr*10 + c - '0';
1309
+ }
1310
+ if( nHdr<16 ) malformed_request("SCGI header too short");
1311
+ zToFree = zHdr = fossil_malloc(nHdr);
1312
+ nRead = (int)fread(zHdr, 1, nHdr, g.httpIn);
1313
+ if( nRead<nHdr ) malformed_request("cannot read entire SCGI header");
1314
+ nHdr = nRead;
1315
+ while( nHdr ){
1316
+ for(n=0; n<nHdr && zHdr[n]; n++){}
1317
+ for(m=n+1; m<nHdr && zHdr[m]; m++){}
1318
+ if( m>=nHdr ) malformed_request("SCGI header formatting error");
1319
+ cgi_set_parameter(zHdr, zHdr+n+1);
1320
+ zHdr += m+1;
1321
+ nHdr -= m+1;
1322
+ }
1323
+ fossil_free(zToFree);
1324
+ fgetc(g.httpIn); /* Read past the "," separating header from content */
1325
+ cgi_init();
1326
+}
1327
+
12741328
12751329
#if INTERFACE
12761330
/*
12771331
** Bitmap values for the flags parameter to cgi_http_server().
12781332
*/
12791333
#define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
1334
+#define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
12801335
12811336
#endif /* INTERFACE */
12821337
12831338
/*
12841339
** Maximum number of child processes that we can have running
@@ -1356,11 +1411,12 @@
13561411
}
13571412
}
13581413
if( iPort>mxPort ) return 1;
13591414
listen(listener,10);
13601415
if( iPort>mnPort ){
1361
- fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
1416
+ fossil_print("Listening for %s requests on TCP port %d\n",
1417
+ (flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
13621418
fflush(stdout);
13631419
}
13641420
if( zBrowser ){
13651421
zBrowser = mprintf(zBrowser, iPort);
13661422
if( system(zBrowser)<0 ){
13671423
--- 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,26 @@
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 +1105,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 +1200,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 +1283,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 +1411,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,26 @@
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 for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
843 cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i));
844 }
845
846 z = (char*)P("HTTP_COOKIE");
847 if( z ){
848 z = mprintf("%s",z);
849 add_param_list(z, ';');
@@ -1092,14 +1105,14 @@
1105
1106
1107 /*
1108 ** Send a reply indicating that the HTTP request was malformed
1109 */
1110 static NORETURN void malformed_request(const char *zMsg){
1111 cgi_set_status(501, "Not Implemented");
1112 cgi_printf(
1113 "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg
1114 );
1115 cgi_reply();
1116 fossil_exit(0);
1117 }
1118
@@ -1187,29 +1200,30 @@
1200 struct sockaddr_in remoteName;
1201 socklen_t size = sizeof(struct sockaddr_in);
1202 char zLine[2000]; /* A single line of input. */
1203 g.fullHttpReply = 1;
1204 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1205 malformed_request("missing HTTP header");
1206 }
1207 blob_append(&g.httpHeader, zLine, -1);
1208 cgi_trace(zLine);
1209 zToken = extract_token(zLine, &z);
1210 if( zToken==0 ){
1211 malformed_request("malformed HTTP header");
1212 }
1213 if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
1214 && fossil_strcmp(zToken,"HEAD")!=0 ){
1215 malformed_request("unsupported HTTP method");
1216 }
1217 cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
1218 cgi_setenv("REQUEST_METHOD",zToken);
1219 zToken = extract_token(z, &z);
1220 if( zToken==0 ){
1221 malformed_request("malformed URL in HTTP header");
1222 }
1223 cgi_setenv("REQUEST_URI", zToken);
1224 cgi_setenv("SCRIPT_NAME", "");
1225 for(i=0; zToken[i] && zToken[i]!='?'; i++){}
1226 if( zToken[i] ) zToken[i++] = 0;
1227 cgi_setenv("PATH_INFO", zToken);
1228 cgi_setenv("QUERY_STRING", &zToken[i]);
1229 if( zIpAddr==0 &&
@@ -1269,16 +1283,57 @@
1283 }
1284 }
1285 cgi_init();
1286 cgi_trace(0);
1287 }
1288
1289 /*
1290 ** This routine handles a single SCGI request which is coming in on
1291 ** g.httpIn and which replies on g.httpOut
1292 **
1293 ** The SCGI request is read from g.httpIn and is used to initialize
1294 ** entries in the cgi_parameter() hash, as if those entries were
1295 ** environment variables. A call to cgi_init() completes
1296 ** the setup. Once all the setup is finished, this procedure returns
1297 ** and subsequent code handles the actual generation of the webpage.
1298 */
1299 void cgi_handle_scgi_request(void){
1300 char *zHdr;
1301 char *zToFree;
1302 int nHdr = 0;
1303 int nRead;
1304 int n, m;
1305 char c;
1306
1307 while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit(c) ){
1308 nHdr = nHdr*10 + c - '0';
1309 }
1310 if( nHdr<16 ) malformed_request("SCGI header too short");
1311 zToFree = zHdr = fossil_malloc(nHdr);
1312 nRead = (int)fread(zHdr, 1, nHdr, g.httpIn);
1313 if( nRead<nHdr ) malformed_request("cannot read entire SCGI header");
1314 nHdr = nRead;
1315 while( nHdr ){
1316 for(n=0; n<nHdr && zHdr[n]; n++){}
1317 for(m=n+1; m<nHdr && zHdr[m]; m++){}
1318 if( m>=nHdr ) malformed_request("SCGI header formatting error");
1319 cgi_set_parameter(zHdr, zHdr+n+1);
1320 zHdr += m+1;
1321 nHdr -= m+1;
1322 }
1323 fossil_free(zToFree);
1324 fgetc(g.httpIn); /* Read past the "," separating header from content */
1325 cgi_init();
1326 }
1327
1328
1329 #if INTERFACE
1330 /*
1331 ** Bitmap values for the flags parameter to cgi_http_server().
1332 */
1333 #define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
1334 #define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
1335
1336 #endif /* INTERFACE */
1337
1338 /*
1339 ** Maximum number of child processes that we can have running
@@ -1356,11 +1411,12 @@
1411 }
1412 }
1413 if( iPort>mxPort ) return 1;
1414 listen(listener,10);
1415 if( iPort>mnPort ){
1416 fossil_print("Listening for %s requests on TCP port %d\n",
1417 (flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
1418 fflush(stdout);
1419 }
1420 if( zBrowser ){
1421 zBrowser = mprintf(zBrowser, iPort);
1422 if( system(zBrowser)<0 ){
1423
+6 -1
--- src/checkin.c
+++ src/checkin.c
@@ -1526,10 +1526,15 @@
15261526
blob_append(&comment, zComment, -1);
15271527
}else if( zComFile ){
15281528
blob_zero(&comment);
15291529
blob_read_from_file(&comment, zComFile);
15301530
blob_to_utf8_no_bom(&comment, 1);
1531
+ }else if(dryRunFlag){
1532
+ blob_zero(&comment);
1533
+ blob_append(&comment, "Dry-run mode - no comment provided.", -1)
1534
+ /* Comment needed to avoid downstream assertion. */
1535
+ ;
15311536
}else{
15321537
char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'");
15331538
prepare_commit_comment(&comment, zInit, &sCiInfo, vid);
15341539
if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
15351540
blob_zero(&ans);
@@ -1722,11 +1727,11 @@
17221727
int nrid;
17231728
17241729
blob_zero(&ctrl);
17251730
zDate = date_in_standard_format(sCiInfo.zDateOvrd ? sCiInfo.zDateOvrd : "now");
17261731
blob_appendf(&ctrl, "D %s\n", zDate);
1727
- blob_appendf(&ctrl, "T +closed %s\n", zIntegrateUuid);
1732
+ blob_appendf(&ctrl, "T +closed %s by\\smerge\\s--integrate\n", zIntegrateUuid);
17281733
blob_appendf(&ctrl, "U %F\n", sCiInfo.zUserOvrd ? sCiInfo.zUserOvrd : g.zLogin);
17291734
md5sum_blob(&ctrl, &cksum);
17301735
blob_appendf(&ctrl, "Z %b\n", &cksum);
17311736
nrid = content_put(&ctrl);
17321737
manifest_crosslink(nrid, &ctrl);
17331738
--- src/checkin.c
+++ src/checkin.c
@@ -1526,10 +1526,15 @@
1526 blob_append(&comment, zComment, -1);
1527 }else if( zComFile ){
1528 blob_zero(&comment);
1529 blob_read_from_file(&comment, zComFile);
1530 blob_to_utf8_no_bom(&comment, 1);
 
 
 
 
 
1531 }else{
1532 char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'");
1533 prepare_commit_comment(&comment, zInit, &sCiInfo, vid);
1534 if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
1535 blob_zero(&ans);
@@ -1722,11 +1727,11 @@
1722 int nrid;
1723
1724 blob_zero(&ctrl);
1725 zDate = date_in_standard_format(sCiInfo.zDateOvrd ? sCiInfo.zDateOvrd : "now");
1726 blob_appendf(&ctrl, "D %s\n", zDate);
1727 blob_appendf(&ctrl, "T +closed %s\n", zIntegrateUuid);
1728 blob_appendf(&ctrl, "U %F\n", sCiInfo.zUserOvrd ? sCiInfo.zUserOvrd : g.zLogin);
1729 md5sum_blob(&ctrl, &cksum);
1730 blob_appendf(&ctrl, "Z %b\n", &cksum);
1731 nrid = content_put(&ctrl);
1732 manifest_crosslink(nrid, &ctrl);
1733
--- src/checkin.c
+++ src/checkin.c
@@ -1526,10 +1526,15 @@
1526 blob_append(&comment, zComment, -1);
1527 }else if( zComFile ){
1528 blob_zero(&comment);
1529 blob_read_from_file(&comment, zComFile);
1530 blob_to_utf8_no_bom(&comment, 1);
1531 }else if(dryRunFlag){
1532 blob_zero(&comment);
1533 blob_append(&comment, "Dry-run mode - no comment provided.", -1)
1534 /* Comment needed to avoid downstream assertion. */
1535 ;
1536 }else{
1537 char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'");
1538 prepare_commit_comment(&comment, zInit, &sCiInfo, vid);
1539 if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
1540 blob_zero(&ans);
@@ -1722,11 +1727,11 @@
1727 int nrid;
1728
1729 blob_zero(&ctrl);
1730 zDate = date_in_standard_format(sCiInfo.zDateOvrd ? sCiInfo.zDateOvrd : "now");
1731 blob_appendf(&ctrl, "D %s\n", zDate);
1732 blob_appendf(&ctrl, "T +closed %s by\\smerge\\s--integrate\n", zIntegrateUuid);
1733 blob_appendf(&ctrl, "U %F\n", sCiInfo.zUserOvrd ? sCiInfo.zUserOvrd : g.zLogin);
1734 md5sum_blob(&ctrl, &cksum);
1735 blob_appendf(&ctrl, "Z %b\n", &cksum);
1736 nrid = content_put(&ctrl);
1737 manifest_crosslink(nrid, &ctrl);
1738
+14
--- src/clone.c
+++ src/clone.c
@@ -84,10 +84,24 @@
8484
**
8585
** Usage: %fossil clone ?OPTIONS? URL FILENAME
8686
**
8787
** Make a clone of a repository specified by URL in the local
8888
** file named FILENAME.
89
+**
90
+** URL must be in one of the following form: ([...] mean optional)
91
+** HTTP/HTTPS protocol:
92
+** http[s]://[userid[:password]@]host[:port][/path]
93
+**
94
+** SSH protocol:
95
+** ssh://[userid[:password]@]host[:port]/path/to/repo.fossil\\
96
+** [?fossil=path/to/fossil.exe]
97
+**
98
+** Filesystem:
99
+** [file://]path/to/repo.fossil
100
+**
101
+** Note: For ssh and filesystem, path must have an extra leading
102
+** '/' to use an absolute path.
89103
**
90104
** By default, your current login name is used to create the default
91105
** admin user. This can be overridden using the -A|--admin-user
92106
** parameter.
93107
**
94108
--- src/clone.c
+++ src/clone.c
@@ -84,10 +84,24 @@
84 **
85 ** Usage: %fossil clone ?OPTIONS? URL FILENAME
86 **
87 ** Make a clone of a repository specified by URL in the local
88 ** file named FILENAME.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89 **
90 ** By default, your current login name is used to create the default
91 ** admin user. This can be overridden using the -A|--admin-user
92 ** parameter.
93 **
94
--- src/clone.c
+++ src/clone.c
@@ -84,10 +84,24 @@
84 **
85 ** Usage: %fossil clone ?OPTIONS? URL FILENAME
86 **
87 ** Make a clone of a repository specified by URL in the local
88 ** file named FILENAME.
89 **
90 ** URL must be in one of the following form: ([...] mean optional)
91 ** HTTP/HTTPS protocol:
92 ** http[s]://[userid[:password]@]host[:port][/path]
93 **
94 ** SSH protocol:
95 ** ssh://[userid[:password]@]host[:port]/path/to/repo.fossil\\
96 ** [?fossil=path/to/fossil.exe]
97 **
98 ** Filesystem:
99 ** [file://]path/to/repo.fossil
100 **
101 ** Note: For ssh and filesystem, path must have an extra leading
102 ** '/' to use an absolute path.
103 **
104 ** By default, your current login name is used to create the default
105 ** admin user. This can be overridden using the -A|--admin-user
106 ** parameter.
107 **
108
+14
--- src/clone.c
+++ src/clone.c
@@ -84,10 +84,24 @@
8484
**
8585
** Usage: %fossil clone ?OPTIONS? URL FILENAME
8686
**
8787
** Make a clone of a repository specified by URL in the local
8888
** file named FILENAME.
89
+**
90
+** URL must be in one of the following form: ([...] mean optional)
91
+** HTTP/HTTPS protocol:
92
+** http[s]://[userid[:password]@]host[:port][/path]
93
+**
94
+** SSH protocol:
95
+** ssh://[userid[:password]@]host[:port]/path/to/repo.fossil\\
96
+** [?fossil=path/to/fossil.exe]
97
+**
98
+** Filesystem:
99
+** [file://]path/to/repo.fossil
100
+**
101
+** Note: For ssh and filesystem, path must have an extra leading
102
+** '/' to use an absolute path.
89103
**
90104
** By default, your current login name is used to create the default
91105
** admin user. This can be overridden using the -A|--admin-user
92106
** parameter.
93107
**
94108
--- src/clone.c
+++ src/clone.c
@@ -84,10 +84,24 @@
84 **
85 ** Usage: %fossil clone ?OPTIONS? URL FILENAME
86 **
87 ** Make a clone of a repository specified by URL in the local
88 ** file named FILENAME.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89 **
90 ** By default, your current login name is used to create the default
91 ** admin user. This can be overridden using the -A|--admin-user
92 ** parameter.
93 **
94
--- src/clone.c
+++ src/clone.c
@@ -84,10 +84,24 @@
84 **
85 ** Usage: %fossil clone ?OPTIONS? URL FILENAME
86 **
87 ** Make a clone of a repository specified by URL in the local
88 ** file named FILENAME.
89 **
90 ** URL must be in one of the following form: ([...] mean optional)
91 ** HTTP/HTTPS protocol:
92 ** http[s]://[userid[:password]@]host[:port][/path]
93 **
94 ** SSH protocol:
95 ** ssh://[userid[:password]@]host[:port]/path/to/repo.fossil\\
96 ** [?fossil=path/to/fossil.exe]
97 **
98 ** Filesystem:
99 ** [file://]path/to/repo.fossil
100 **
101 ** Note: For ssh and filesystem, path must have an extra leading
102 ** '/' to use an absolute path.
103 **
104 ** By default, your current login name is used to create the default
105 ** admin user. This can be overridden using the -A|--admin-user
106 ** parameter.
107 **
108
--- src/content.c
+++ src/content.c
@@ -27,11 +27,10 @@
2727
static struct {
2828
i64 szTotal; /* Total size of all entries in the cache */
2929
int n; /* Current number of cache entries */
3030
int nAlloc; /* Number of slots allocated in a[] */
3131
int nextAge; /* Age counter for implementing LRU */
32
- int skipCnt; /* Used to limit entries expelled from cache */
3332
struct cacheLine { /* One instance of this for each cache entry */
3433
int rid; /* Artifact id */
3534
int age; /* Age. Newer is larger */
3635
Blob content; /* Content of the artifact */
3736
} *a; /* The positive cache */
@@ -492,11 +491,10 @@
492491
493492
assert( g.repositoryOpen );
494493
assert( pBlob!=0 );
495494
assert( srcId==0 || zUuid!=0 );
496495
if( zUuid==0 ){
497
- assert( pBlob!=0 );
498496
assert( nBlob==0 );
499497
sha1sum_blob(pBlob, &hash);
500498
}else{
501499
blob_init(&hash, zUuid, -1);
502500
}
503501
--- src/content.c
+++ src/content.c
@@ -27,11 +27,10 @@
27 static struct {
28 i64 szTotal; /* Total size of all entries in the cache */
29 int n; /* Current number of cache entries */
30 int nAlloc; /* Number of slots allocated in a[] */
31 int nextAge; /* Age counter for implementing LRU */
32 int skipCnt; /* Used to limit entries expelled from cache */
33 struct cacheLine { /* One instance of this for each cache entry */
34 int rid; /* Artifact id */
35 int age; /* Age. Newer is larger */
36 Blob content; /* Content of the artifact */
37 } *a; /* The positive cache */
@@ -492,11 +491,10 @@
492
493 assert( g.repositoryOpen );
494 assert( pBlob!=0 );
495 assert( srcId==0 || zUuid!=0 );
496 if( zUuid==0 ){
497 assert( pBlob!=0 );
498 assert( nBlob==0 );
499 sha1sum_blob(pBlob, &hash);
500 }else{
501 blob_init(&hash, zUuid, -1);
502 }
503
--- src/content.c
+++ src/content.c
@@ -27,11 +27,10 @@
27 static struct {
28 i64 szTotal; /* Total size of all entries in the cache */
29 int n; /* Current number of cache entries */
30 int nAlloc; /* Number of slots allocated in a[] */
31 int nextAge; /* Age counter for implementing LRU */
 
32 struct cacheLine { /* One instance of this for each cache entry */
33 int rid; /* Artifact id */
34 int age; /* Age. Newer is larger */
35 Blob content; /* Content of the artifact */
36 } *a; /* The positive cache */
@@ -492,11 +491,10 @@
491
492 assert( g.repositoryOpen );
493 assert( pBlob!=0 );
494 assert( srcId==0 || zUuid!=0 );
495 if( zUuid==0 ){
 
496 assert( nBlob==0 );
497 sha1sum_blob(pBlob, &hash);
498 }else{
499 blob_init(&hash, zUuid, -1);
500 }
501
+1 -1
--- src/diff.c
+++ src/diff.c
@@ -1310,11 +1310,11 @@
13101310
sbsWriteText(&s, &B[b+j], SBS_TXTB);
13111311
}
13121312
}
13131313
13141314
if( s.escHtml && blob_size(s.apCols[SBS_LNA])>0 ){
1315
- blob_append(pOut, "<table class=\"sbsdiffcols\" width=\"90%\"><tr>\n", -1);
1315
+ blob_append(pOut, "<table class=\"sbsdiffcols\"><tr>\n", -1);
13161316
for(i=SBS_LNA; i<=SBS_TXTB; i++){
13171317
sbsWriteColumn(pOut, s.apCols[i], i);
13181318
blob_reset(s.apCols[i]);
13191319
}
13201320
blob_append(pOut, "</tr></table>\n", -1);
13211321
--- src/diff.c
+++ src/diff.c
@@ -1310,11 +1310,11 @@
1310 sbsWriteText(&s, &B[b+j], SBS_TXTB);
1311 }
1312 }
1313
1314 if( s.escHtml && blob_size(s.apCols[SBS_LNA])>0 ){
1315 blob_append(pOut, "<table class=\"sbsdiffcols\" width=\"90%\"><tr>\n", -1);
1316 for(i=SBS_LNA; i<=SBS_TXTB; i++){
1317 sbsWriteColumn(pOut, s.apCols[i], i);
1318 blob_reset(s.apCols[i]);
1319 }
1320 blob_append(pOut, "</tr></table>\n", -1);
1321
--- src/diff.c
+++ src/diff.c
@@ -1310,11 +1310,11 @@
1310 sbsWriteText(&s, &B[b+j], SBS_TXTB);
1311 }
1312 }
1313
1314 if( s.escHtml && blob_size(s.apCols[SBS_LNA])>0 ){
1315 blob_append(pOut, "<table class=\"sbsdiffcols\"><tr>\n", -1);
1316 for(i=SBS_LNA; i<=SBS_TXTB; i++){
1317 sbsWriteColumn(pOut, s.apCols[i], i);
1318 blob_reset(s.apCols[i]);
1319 }
1320 blob_append(pOut, "</tr></table>\n", -1);
1321
+1 -1
--- src/glob.c
+++ src/glob.c
@@ -252,11 +252,11 @@
252252
**
253253
** PATTERN is a comma- and whitespace-separated list of optionally
254254
** quoted glob patterns. Show which of the STRINGs that follow match
255255
** the PATTERN.
256256
**
257
-** If PATTERN begins with "@" the the rest of the pattern is understood
257
+** If PATTERN begins with "@" the rest of the pattern is understood
258258
** to be a setting name (such as binary-glob, crln-glob, or encoding-glob)
259259
** and the value of that setting is used as the actually glob pattern.
260260
*/
261261
void glob_test_cmd(void){
262262
Glob *pGlob;
263263
--- src/glob.c
+++ src/glob.c
@@ -252,11 +252,11 @@
252 **
253 ** PATTERN is a comma- and whitespace-separated list of optionally
254 ** quoted glob patterns. Show which of the STRINGs that follow match
255 ** the PATTERN.
256 **
257 ** If PATTERN begins with "@" the the rest of the pattern is understood
258 ** to be a setting name (such as binary-glob, crln-glob, or encoding-glob)
259 ** and the value of that setting is used as the actually glob pattern.
260 */
261 void glob_test_cmd(void){
262 Glob *pGlob;
263
--- src/glob.c
+++ src/glob.c
@@ -252,11 +252,11 @@
252 **
253 ** PATTERN is a comma- and whitespace-separated list of optionally
254 ** quoted glob patterns. Show which of the STRINGs that follow match
255 ** the PATTERN.
256 **
257 ** If PATTERN begins with "@" the rest of the pattern is understood
258 ** to be a setting name (such as binary-glob, crln-glob, or encoding-glob)
259 ** and the value of that setting is used as the actually glob pattern.
260 */
261 void glob_test_cmd(void){
262 Glob *pGlob;
263
+1 -1
--- src/graph.c
+++ src/graph.c
@@ -198,11 +198,11 @@
198198
pRow->zBranch = persistBranchName(p, zBranch);
199199
if( zUuid==0 ) zUuid = "";
200200
sqlite3_snprintf(sizeof(pRow->zUuid), pRow->zUuid, "%s", zUuid);
201201
pRow->isLeaf = isLeaf;
202202
memset(pRow->aiRiser, -1, sizeof(pRow->aiRiser));
203
- if( zBgClr==0 || zBgClr[0]==0 ) zBgClr = "white";
203
+ if( zBgClr==0 ) zBgClr = "";
204204
pRow->zBgClr = persistBranchName(p, zBgClr);
205205
memcpy(pRow->aParent, aParent, sizeof(aParent[0])*nParent);
206206
if( p->pFirst==0 ){
207207
p->pFirst = pRow;
208208
}else{
209209
--- src/graph.c
+++ src/graph.c
@@ -198,11 +198,11 @@
198 pRow->zBranch = persistBranchName(p, zBranch);
199 if( zUuid==0 ) zUuid = "";
200 sqlite3_snprintf(sizeof(pRow->zUuid), pRow->zUuid, "%s", zUuid);
201 pRow->isLeaf = isLeaf;
202 memset(pRow->aiRiser, -1, sizeof(pRow->aiRiser));
203 if( zBgClr==0 || zBgClr[0]==0 ) zBgClr = "white";
204 pRow->zBgClr = persistBranchName(p, zBgClr);
205 memcpy(pRow->aParent, aParent, sizeof(aParent[0])*nParent);
206 if( p->pFirst==0 ){
207 p->pFirst = pRow;
208 }else{
209
--- src/graph.c
+++ src/graph.c
@@ -198,11 +198,11 @@
198 pRow->zBranch = persistBranchName(p, zBranch);
199 if( zUuid==0 ) zUuid = "";
200 sqlite3_snprintf(sizeof(pRow->zUuid), pRow->zUuid, "%s", zUuid);
201 pRow->isLeaf = isLeaf;
202 memset(pRow->aiRiser, -1, sizeof(pRow->aiRiser));
203 if( zBgClr==0 ) zBgClr = "";
204 pRow->zBgClr = persistBranchName(p, zBgClr);
205 memcpy(pRow->aParent, aParent, sizeof(aParent[0])*nParent);
206 if( p->pFirst==0 ){
207 p->pFirst = pRow;
208 }else{
209
+1 -1
--- src/json.c
+++ src/json.c
@@ -2004,11 +2004,11 @@
20042004
** whose final entry MUST have a NULL name value or results
20052005
** are undefined.
20062006
**
20072007
** The list is appended to pOut. The number of items (not bytes)
20082008
** appended are returned. If filterByMode is non-0 then the result
2009
-** list will contain only commands which are able to run in the the
2009
+** list will contain only commands which are able to run in the
20102010
** current run mode (CLI vs. HTTP).
20112011
*/
20122012
static int json_pagedefs_to_string(JsonPageDef const * zPages,
20132013
Blob * pOut, int filterByMode){
20142014
int i = 0;
20152015
--- src/json.c
+++ src/json.c
@@ -2004,11 +2004,11 @@
2004 ** whose final entry MUST have a NULL name value or results
2005 ** are undefined.
2006 **
2007 ** The list is appended to pOut. The number of items (not bytes)
2008 ** appended are returned. If filterByMode is non-0 then the result
2009 ** list will contain only commands which are able to run in the the
2010 ** current run mode (CLI vs. HTTP).
2011 */
2012 static int json_pagedefs_to_string(JsonPageDef const * zPages,
2013 Blob * pOut, int filterByMode){
2014 int i = 0;
2015
--- src/json.c
+++ src/json.c
@@ -2004,11 +2004,11 @@
2004 ** whose final entry MUST have a NULL name value or results
2005 ** are undefined.
2006 **
2007 ** The list is appended to pOut. The number of items (not bytes)
2008 ** appended are returned. If filterByMode is non-0 then the result
2009 ** list will contain only commands which are able to run in the
2010 ** current run mode (CLI vs. HTTP).
2011 */
2012 static int json_pagedefs_to_string(JsonPageDef const * zPages,
2013 Blob * pOut, int filterByMode){
2014 int i = 0;
2015
+1 -1
--- src/json.c
+++ src/json.c
@@ -2004,11 +2004,11 @@
20042004
** whose final entry MUST have a NULL name value or results
20052005
** are undefined.
20062006
**
20072007
** The list is appended to pOut. The number of items (not bytes)
20082008
** appended are returned. If filterByMode is non-0 then the result
2009
-** list will contain only commands which are able to run in the the
2009
+** list will contain only commands which are able to run in the
20102010
** current run mode (CLI vs. HTTP).
20112011
*/
20122012
static int json_pagedefs_to_string(JsonPageDef const * zPages,
20132013
Blob * pOut, int filterByMode){
20142014
int i = 0;
20152015
--- src/json.c
+++ src/json.c
@@ -2004,11 +2004,11 @@
2004 ** whose final entry MUST have a NULL name value or results
2005 ** are undefined.
2006 **
2007 ** The list is appended to pOut. The number of items (not bytes)
2008 ** appended are returned. If filterByMode is non-0 then the result
2009 ** list will contain only commands which are able to run in the the
2010 ** current run mode (CLI vs. HTTP).
2011 */
2012 static int json_pagedefs_to_string(JsonPageDef const * zPages,
2013 Blob * pOut, int filterByMode){
2014 int i = 0;
2015
--- src/json.c
+++ src/json.c
@@ -2004,11 +2004,11 @@
2004 ** whose final entry MUST have a NULL name value or results
2005 ** are undefined.
2006 **
2007 ** The list is appended to pOut. The number of items (not bytes)
2008 ** appended are returned. If filterByMode is non-0 then the result
2009 ** list will contain only commands which are able to run in the
2010 ** current run mode (CLI vs. HTTP).
2011 */
2012 static int json_pagedefs_to_string(JsonPageDef const * zPages,
2013 Blob * pOut, int filterByMode){
2014 int i = 0;
2015
+18 -12
--- src/login.c
+++ src/login.c
@@ -391,24 +391,24 @@
391391
for(i=0; zAgent[i]; i++){
392392
if( prefix_match("bot", zAgent+i) ) return 0;
393393
if( prefix_match("spider", zAgent+i) ) return 0;
394394
if( prefix_match("crawl", zAgent+i) ) return 0;
395395
/* If a URI appears in the User-Agent, it is probably a bot */
396
- if( memcmp("http", zAgent+i,4)==0 ) return 0;
396
+ if( strncmp("http", zAgent+i,4)==0 ) return 0;
397397
}
398
- if( memcmp(zAgent, "Mozilla/", 8)==0 ){
398
+ if( strncmp(zAgent, "Mozilla/", 8)==0 ){
399399
if( atoi(&zAgent[8])<4 ) return 0; /* Many bots advertise as Mozilla/3 */
400400
if( strglob("*Firefox/[1-9]*", zAgent) ) return 1;
401401
if( strglob("*Chrome/[1-9]*", zAgent) ) return 1;
402402
if( strglob("*(compatible;?MSIE?[1789]*", zAgent) ) return 1;
403403
if( strglob("*AppleWebKit/[1-9]*(KHTML*", zAgent) ) return 1;
404404
return 0;
405405
}
406
- if( memcmp(zAgent, "Opera/", 6)==0 ) return 1;
407
- if( memcmp(zAgent, "Safari/", 7)==0 ) return 1;
408
- if( memcmp(zAgent, "Lynx/", 5)==0 ) return 1;
409
- if( memcmp(zAgent, "NetSurf/", 8)==0 ) return 1;
406
+ if( strncmp(zAgent, "Opera/", 6)==0 ) return 1;
407
+ if( strncmp(zAgent, "Safari/", 7)==0 ) return 1;
408
+ if( strncmp(zAgent, "Lynx/", 5)==0 ) return 1;
409
+ if( strncmp(zAgent, "NetSurf/", 8)==0 ) return 1;
410410
return 0;
411411
}
412412
413413
/*
414414
** COMMAND: test-ishuman
@@ -598,11 +598,11 @@
598598
@ </table>
599599
@ <script type="text/JavaScript">
600600
@ gebi('u').focus()
601601
@ function chngAction(form){
602602
if( g.sslNotAvailable==0
603
- && memcmp(g.zBaseURL,"https:",6)!=0
603
+ && strncmp(g.zBaseURL,"https:",6)!=0
604604
&& db_get_boolean("https-login",0)
605605
){
606606
char *zSSL = mprintf("https:%s", &g.zBaseURL[5]);
607607
@ if( form.u.value!="anonymous" ){
608608
@ form.action = "%h(zSSL)/login";
@@ -763,14 +763,17 @@
763763
}
764764
765765
/*
766766
** This routine examines the login cookie to see if it exists and
767767
** is valid. If the login cookie checks out, it then sets global
768
-** variables appropriately. Global variables set include g.userUid
769
-** and g.zLogin and the g.perm family of permission booleans.
768
+** variables appropriately.
770769
**
771
-** If the
770
+** g.userUid Database USER.UID value. Might be -1 for "nobody"
771
+** g.zLogin Database USER.LOGIN value. NULL for user "nobody"
772
+** g.perm Permissions granted to this user
773
+** g.isHuman True if the user is human, not a spider or robot
774
+**
772775
*/
773776
void login_check_credentials(void){
774777
int uid = 0; /* User id */
775778
const char *zCookie; /* Text of the login cookie */
776779
const char *zIpAddr; /* Raw IP address of the requestor */
@@ -799,10 +802,11 @@
799802
){
800803
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
801804
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
802805
zCap = "sx";
803806
g.noPswd = 1;
807
+ g.isHuman = 1;
804808
sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost");
805809
}
806810
807811
/* Check the login cookie to see if it matches a known valid user.
808812
*/
@@ -907,10 +911,11 @@
907911
*/
908912
g.userUid = uid;
909913
if( fossil_strcmp(g.zLogin,"nobody")==0 ){
910914
g.zLogin = 0;
911915
}
916
+ g.isHuman = g.zLogin==0 ? isHuman(P("HTTP_USER_AGENT")) : 1;
912917
913918
/* Set the capabilities */
914919
login_replace_capabilities(zCap, 0);
915920
login_set_anon_nobody_capabilities();
916921
@@ -918,13 +923,14 @@
918923
** who do not have the "h" permission as long as their UserAgent string
919924
** makes it appear that they are human. Check to see if auto-hyperlink is
920925
** enabled for this repository and make appropriate adjustments to the
921926
** permission flags if it is.
922927
*/
923
- if( zCap[0] && !g.perm.Hyperlink
928
+ if( zCap[0]
929
+ && !g.perm.Hyperlink
930
+ && g.isHuman
924931
&& db_get_boolean("auto-hyperlink",1)
925
- && isHuman(P("HTTP_USER_AGENT"))
926932
){
927933
g.perm.Hyperlink = 1;
928934
g.javascriptHyperlink = 1;
929935
}
930936
931937
--- src/login.c
+++ src/login.c
@@ -391,24 +391,24 @@
391 for(i=0; zAgent[i]; i++){
392 if( prefix_match("bot", zAgent+i) ) return 0;
393 if( prefix_match("spider", zAgent+i) ) return 0;
394 if( prefix_match("crawl", zAgent+i) ) return 0;
395 /* If a URI appears in the User-Agent, it is probably a bot */
396 if( memcmp("http", zAgent+i,4)==0 ) return 0;
397 }
398 if( memcmp(zAgent, "Mozilla/", 8)==0 ){
399 if( atoi(&zAgent[8])<4 ) return 0; /* Many bots advertise as Mozilla/3 */
400 if( strglob("*Firefox/[1-9]*", zAgent) ) return 1;
401 if( strglob("*Chrome/[1-9]*", zAgent) ) return 1;
402 if( strglob("*(compatible;?MSIE?[1789]*", zAgent) ) return 1;
403 if( strglob("*AppleWebKit/[1-9]*(KHTML*", zAgent) ) return 1;
404 return 0;
405 }
406 if( memcmp(zAgent, "Opera/", 6)==0 ) return 1;
407 if( memcmp(zAgent, "Safari/", 7)==0 ) return 1;
408 if( memcmp(zAgent, "Lynx/", 5)==0 ) return 1;
409 if( memcmp(zAgent, "NetSurf/", 8)==0 ) return 1;
410 return 0;
411 }
412
413 /*
414 ** COMMAND: test-ishuman
@@ -598,11 +598,11 @@
598 @ </table>
599 @ <script type="text/JavaScript">
600 @ gebi('u').focus()
601 @ function chngAction(form){
602 if( g.sslNotAvailable==0
603 && memcmp(g.zBaseURL,"https:",6)!=0
604 && db_get_boolean("https-login",0)
605 ){
606 char *zSSL = mprintf("https:%s", &g.zBaseURL[5]);
607 @ if( form.u.value!="anonymous" ){
608 @ form.action = "%h(zSSL)/login";
@@ -763,14 +763,17 @@
763 }
764
765 /*
766 ** This routine examines the login cookie to see if it exists and
767 ** is valid. If the login cookie checks out, it then sets global
768 ** variables appropriately. Global variables set include g.userUid
769 ** and g.zLogin and the g.perm family of permission booleans.
770 **
771 ** If the
 
 
 
 
772 */
773 void login_check_credentials(void){
774 int uid = 0; /* User id */
775 const char *zCookie; /* Text of the login cookie */
776 const char *zIpAddr; /* Raw IP address of the requestor */
@@ -799,10 +802,11 @@
799 ){
800 uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
801 g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
802 zCap = "sx";
803 g.noPswd = 1;
 
804 sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost");
805 }
806
807 /* Check the login cookie to see if it matches a known valid user.
808 */
@@ -907,10 +911,11 @@
907 */
908 g.userUid = uid;
909 if( fossil_strcmp(g.zLogin,"nobody")==0 ){
910 g.zLogin = 0;
911 }
 
912
913 /* Set the capabilities */
914 login_replace_capabilities(zCap, 0);
915 login_set_anon_nobody_capabilities();
916
@@ -918,13 +923,14 @@
918 ** who do not have the "h" permission as long as their UserAgent string
919 ** makes it appear that they are human. Check to see if auto-hyperlink is
920 ** enabled for this repository and make appropriate adjustments to the
921 ** permission flags if it is.
922 */
923 if( zCap[0] && !g.perm.Hyperlink
 
 
924 && db_get_boolean("auto-hyperlink",1)
925 && isHuman(P("HTTP_USER_AGENT"))
926 ){
927 g.perm.Hyperlink = 1;
928 g.javascriptHyperlink = 1;
929 }
930
931
--- src/login.c
+++ src/login.c
@@ -391,24 +391,24 @@
391 for(i=0; zAgent[i]; i++){
392 if( prefix_match("bot", zAgent+i) ) return 0;
393 if( prefix_match("spider", zAgent+i) ) return 0;
394 if( prefix_match("crawl", zAgent+i) ) return 0;
395 /* If a URI appears in the User-Agent, it is probably a bot */
396 if( strncmp("http", zAgent+i,4)==0 ) return 0;
397 }
398 if( strncmp(zAgent, "Mozilla/", 8)==0 ){
399 if( atoi(&zAgent[8])<4 ) return 0; /* Many bots advertise as Mozilla/3 */
400 if( strglob("*Firefox/[1-9]*", zAgent) ) return 1;
401 if( strglob("*Chrome/[1-9]*", zAgent) ) return 1;
402 if( strglob("*(compatible;?MSIE?[1789]*", zAgent) ) return 1;
403 if( strglob("*AppleWebKit/[1-9]*(KHTML*", zAgent) ) return 1;
404 return 0;
405 }
406 if( strncmp(zAgent, "Opera/", 6)==0 ) return 1;
407 if( strncmp(zAgent, "Safari/", 7)==0 ) return 1;
408 if( strncmp(zAgent, "Lynx/", 5)==0 ) return 1;
409 if( strncmp(zAgent, "NetSurf/", 8)==0 ) return 1;
410 return 0;
411 }
412
413 /*
414 ** COMMAND: test-ishuman
@@ -598,11 +598,11 @@
598 @ </table>
599 @ <script type="text/JavaScript">
600 @ gebi('u').focus()
601 @ function chngAction(form){
602 if( g.sslNotAvailable==0
603 && strncmp(g.zBaseURL,"https:",6)!=0
604 && db_get_boolean("https-login",0)
605 ){
606 char *zSSL = mprintf("https:%s", &g.zBaseURL[5]);
607 @ if( form.u.value!="anonymous" ){
608 @ form.action = "%h(zSSL)/login";
@@ -763,14 +763,17 @@
763 }
764
765 /*
766 ** This routine examines the login cookie to see if it exists and
767 ** is valid. If the login cookie checks out, it then sets global
768 ** variables appropriately.
 
769 **
770 ** g.userUid Database USER.UID value. Might be -1 for "nobody"
771 ** g.zLogin Database USER.LOGIN value. NULL for user "nobody"
772 ** g.perm Permissions granted to this user
773 ** g.isHuman True if the user is human, not a spider or robot
774 **
775 */
776 void login_check_credentials(void){
777 int uid = 0; /* User id */
778 const char *zCookie; /* Text of the login cookie */
779 const char *zIpAddr; /* Raw IP address of the requestor */
@@ -799,10 +802,11 @@
802 ){
803 uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
804 g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
805 zCap = "sx";
806 g.noPswd = 1;
807 g.isHuman = 1;
808 sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost");
809 }
810
811 /* Check the login cookie to see if it matches a known valid user.
812 */
@@ -907,10 +911,11 @@
911 */
912 g.userUid = uid;
913 if( fossil_strcmp(g.zLogin,"nobody")==0 ){
914 g.zLogin = 0;
915 }
916 g.isHuman = g.zLogin==0 ? isHuman(P("HTTP_USER_AGENT")) : 1;
917
918 /* Set the capabilities */
919 login_replace_capabilities(zCap, 0);
920 login_set_anon_nobody_capabilities();
921
@@ -918,13 +923,14 @@
923 ** who do not have the "h" permission as long as their UserAgent string
924 ** makes it appear that they are human. Check to see if auto-hyperlink is
925 ** enabled for this repository and make appropriate adjustments to the
926 ** permission flags if it is.
927 */
928 if( zCap[0]
929 && !g.perm.Hyperlink
930 && g.isHuman
931 && db_get_boolean("auto-hyperlink",1)
 
932 ){
933 g.perm.Hyperlink = 1;
934 g.javascriptHyperlink = 1;
935 }
936
937
+16 -2
--- src/main.c
+++ src/main.c
@@ -185,10 +185,11 @@
185185
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
186186
** SSL client identity */
187187
int useLocalauth; /* No login required if from 127.0.0.1 */
188188
int noPswd; /* Logged in without password (on 127.0.0.1) */
189189
int userUid; /* Integer user id */
190
+ int isHuman; /* True if access by a human, not a spider or bot */
190191
191192
/* Information used to populate the RCVFROM table */
192193
int rcvid; /* The rcvid. 0 if not yet defined. */
193194
char *zIpAddr; /* The remote IP address */
194195
char *zNonce; /* The nonce used for login */
@@ -1639,19 +1640,21 @@
16391640
** --https signal a request coming in via https
16401641
** --nossl signal that no SSL connections are available
16411642
** --notfound URL use URL as "HTTP 404, object not found" page.
16421643
** --files GLOB comma-separate glob patterns for static file to serve
16431644
** --baseurl URL base URL (useful with reverse proxies)
1645
+** --scgi Interpret input as SCGI rather than HTTP
16441646
**
16451647
** See also: cgi, server, winsrv
16461648
*/
16471649
void cmd_http(void){
16481650
const char *zIpAddr;
16491651
const char *zNotFound;
16501652
const char *zHost;
16511653
const char *zAltBase;
16521654
const char *zFileGlob;
1655
+ int useSCGI;
16531656
16541657
/* The winhttp module passes the --files option as --files-urlenc with
16551658
** the argument being URL encoded, to avoid wildcard expansion in the
16561659
** shell. This option is for internal use and is undocumented.
16571660
*/
@@ -1664,10 +1667,11 @@
16641667
zFileGlob = find_option("files",0,1);
16651668
}
16661669
zNotFound = find_option("notfound", 0, 1);
16671670
g.useLocalauth = find_option("localauth", 0, 0)!=0;
16681671
g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
1672
+ useSCGI = find_option("scgi", 0, 0)!=0;
16691673
zAltBase = find_option("baseurl", 0, 1);
16701674
if( zAltBase ) set_base_url(zAltBase);
16711675
if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
16721676
zHost = find_option("host", 0, 1);
16731677
if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
@@ -1688,11 +1692,15 @@
16881692
if( zIpAddr==0 ){
16891693
zIpAddr = cgi_ssh_remote_addr(0);
16901694
}
16911695
find_server_repository(0);
16921696
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1693
- cgi_handle_http_request(zIpAddr);
1697
+ if( useSCGI ){
1698
+ cgi_handle_scgi_request();
1699
+ }else{
1700
+ cgi_handle_http_request(zIpAddr);
1701
+ }
16941702
process_one_web_page(zNotFound, glob_create(zFileGlob));
16951703
}
16961704
16971705
/*
16981706
** Note that the following command is used by ssh:// processing.
@@ -1784,10 +1792,11 @@
17841792
** -P|--port TCPPORT listen to request on port TCPPORT
17851793
** --th-trace trace TH1 execution (for debugging purposes)
17861794
** --baseurl URL Use URL as the base (useful for reverse proxies)
17871795
** --notfound URL Redirect
17881796
** --files GLOBLIST Comma-separated list of glob patterns for static files
1797
+** --scgi Accept SCGI rather than HTTP
17891798
**
17901799
** See also: cgi, http, winsrv
17911800
*/
17921801
void cmd_webserver(void){
17931802
int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1810,10 +1819,11 @@
18101819
g.useLocalauth = find_option("localauth", 0, 0)!=0;
18111820
Th_InitTraceLog();
18121821
zPort = find_option("port", "P", 1);
18131822
zNotFound = find_option("notfound", 0, 1);
18141823
zAltBase = find_option("baseurl", 0, 1);
1824
+ if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
18151825
if( zAltBase ){
18161826
set_base_url(zAltBase);
18171827
}
18181828
if ( find_option("localhost", 0, 0)!=0 ){
18191829
flags |= HTTP_SERVER_LOCALHOST;
@@ -1874,11 +1884,15 @@
18741884
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
18751885
}
18761886
g.cgiOutput = 1;
18771887
find_server_repository(isUiCmd && zNotFound==0);
18781888
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1879
- cgi_handle_http_request(0);
1889
+ if( flags & HTTP_SERVER_SCGI ){
1890
+ cgi_handle_scgi_request();
1891
+ }else{
1892
+ cgi_handle_http_request(0);
1893
+ }
18801894
process_one_web_page(zNotFound, glob_create(zFileGlob));
18811895
#else
18821896
/* Win32 implementation */
18831897
if( isUiCmd ){
18841898
zBrowser = db_get("web-browser", "start");
18851899
--- src/main.c
+++ src/main.c
@@ -185,10 +185,11 @@
185 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
186 ** SSL client identity */
187 int useLocalauth; /* No login required if from 127.0.0.1 */
188 int noPswd; /* Logged in without password (on 127.0.0.1) */
189 int userUid; /* Integer user id */
 
190
191 /* Information used to populate the RCVFROM table */
192 int rcvid; /* The rcvid. 0 if not yet defined. */
193 char *zIpAddr; /* The remote IP address */
194 char *zNonce; /* The nonce used for login */
@@ -1639,19 +1640,21 @@
1639 ** --https signal a request coming in via https
1640 ** --nossl signal that no SSL connections are available
1641 ** --notfound URL use URL as "HTTP 404, object not found" page.
1642 ** --files GLOB comma-separate glob patterns for static file to serve
1643 ** --baseurl URL base URL (useful with reverse proxies)
 
1644 **
1645 ** See also: cgi, server, winsrv
1646 */
1647 void cmd_http(void){
1648 const char *zIpAddr;
1649 const char *zNotFound;
1650 const char *zHost;
1651 const char *zAltBase;
1652 const char *zFileGlob;
 
1653
1654 /* The winhttp module passes the --files option as --files-urlenc with
1655 ** the argument being URL encoded, to avoid wildcard expansion in the
1656 ** shell. This option is for internal use and is undocumented.
1657 */
@@ -1664,10 +1667,11 @@
1664 zFileGlob = find_option("files",0,1);
1665 }
1666 zNotFound = find_option("notfound", 0, 1);
1667 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1668 g.sslNotAvailable = find_option("nossl", 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);
@@ -1688,11 +1692,15 @@
1688 if( zIpAddr==0 ){
1689 zIpAddr = cgi_ssh_remote_addr(0);
1690 }
1691 find_server_repository(0);
1692 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1693 cgi_handle_http_request(zIpAddr);
 
 
 
 
1694 process_one_web_page(zNotFound, glob_create(zFileGlob));
1695 }
1696
1697 /*
1698 ** Note that the following command is used by ssh:// processing.
@@ -1784,10 +1792,11 @@
1784 ** -P|--port TCPPORT listen to request on port TCPPORT
1785 ** --th-trace trace TH1 execution (for debugging purposes)
1786 ** --baseurl URL Use URL as the base (useful for reverse proxies)
1787 ** --notfound URL Redirect
1788 ** --files GLOBLIST Comma-separated list of glob patterns for static files
 
1789 **
1790 ** See also: cgi, http, winsrv
1791 */
1792 void cmd_webserver(void){
1793 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1810,10 +1819,11 @@
1810 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1811 Th_InitTraceLog();
1812 zPort = find_option("port", "P", 1);
1813 zNotFound = find_option("notfound", 0, 1);
1814 zAltBase = find_option("baseurl", 0, 1);
 
1815 if( zAltBase ){
1816 set_base_url(zAltBase);
1817 }
1818 if ( find_option("localhost", 0, 0)!=0 ){
1819 flags |= HTTP_SERVER_LOCALHOST;
@@ -1874,11 +1884,15 @@
1874 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
1875 }
1876 g.cgiOutput = 1;
1877 find_server_repository(isUiCmd && zNotFound==0);
1878 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1879 cgi_handle_http_request(0);
 
 
 
 
1880 process_one_web_page(zNotFound, glob_create(zFileGlob));
1881 #else
1882 /* Win32 implementation */
1883 if( isUiCmd ){
1884 zBrowser = db_get("web-browser", "start");
1885
--- src/main.c
+++ src/main.c
@@ -185,10 +185,11 @@
185 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
186 ** SSL client identity */
187 int useLocalauth; /* No login required if from 127.0.0.1 */
188 int noPswd; /* Logged in without password (on 127.0.0.1) */
189 int userUid; /* Integer user id */
190 int isHuman; /* True if access by a human, not a spider or bot */
191
192 /* Information used to populate the RCVFROM table */
193 int rcvid; /* The rcvid. 0 if not yet defined. */
194 char *zIpAddr; /* The remote IP address */
195 char *zNonce; /* The nonce used for login */
@@ -1639,19 +1640,21 @@
1640 ** --https signal a request coming in via https
1641 ** --nossl signal that no SSL connections are available
1642 ** --notfound URL use URL as "HTTP 404, object not found" page.
1643 ** --files GLOB comma-separate glob patterns for static file to serve
1644 ** --baseurl URL base URL (useful with reverse proxies)
1645 ** --scgi Interpret input as SCGI rather than HTTP
1646 **
1647 ** See also: cgi, server, winsrv
1648 */
1649 void cmd_http(void){
1650 const char *zIpAddr;
1651 const char *zNotFound;
1652 const char *zHost;
1653 const char *zAltBase;
1654 const char *zFileGlob;
1655 int useSCGI;
1656
1657 /* The winhttp module passes the --files option as --files-urlenc with
1658 ** the argument being URL encoded, to avoid wildcard expansion in the
1659 ** shell. This option is for internal use and is undocumented.
1660 */
@@ -1664,10 +1667,11 @@
1667 zFileGlob = find_option("files",0,1);
1668 }
1669 zNotFound = find_option("notfound", 0, 1);
1670 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1671 g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
1672 useSCGI = find_option("scgi", 0, 0)!=0;
1673 zAltBase = find_option("baseurl", 0, 1);
1674 if( zAltBase ) set_base_url(zAltBase);
1675 if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
1676 zHost = find_option("host", 0, 1);
1677 if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
@@ -1688,11 +1692,15 @@
1692 if( zIpAddr==0 ){
1693 zIpAddr = cgi_ssh_remote_addr(0);
1694 }
1695 find_server_repository(0);
1696 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1697 if( useSCGI ){
1698 cgi_handle_scgi_request();
1699 }else{
1700 cgi_handle_http_request(zIpAddr);
1701 }
1702 process_one_web_page(zNotFound, glob_create(zFileGlob));
1703 }
1704
1705 /*
1706 ** Note that the following command is used by ssh:// processing.
@@ -1784,10 +1792,11 @@
1792 ** -P|--port TCPPORT listen to request on port TCPPORT
1793 ** --th-trace trace TH1 execution (for debugging purposes)
1794 ** --baseurl URL Use URL as the base (useful for reverse proxies)
1795 ** --notfound URL Redirect
1796 ** --files GLOBLIST Comma-separated list of glob patterns for static files
1797 ** --scgi Accept SCGI rather than HTTP
1798 **
1799 ** See also: cgi, http, winsrv
1800 */
1801 void cmd_webserver(void){
1802 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1810,10 +1819,11 @@
1819 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1820 Th_InitTraceLog();
1821 zPort = find_option("port", "P", 1);
1822 zNotFound = find_option("notfound", 0, 1);
1823 zAltBase = find_option("baseurl", 0, 1);
1824 if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
1825 if( zAltBase ){
1826 set_base_url(zAltBase);
1827 }
1828 if ( find_option("localhost", 0, 0)!=0 ){
1829 flags |= HTTP_SERVER_LOCALHOST;
@@ -1874,11 +1884,15 @@
1884 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
1885 }
1886 g.cgiOutput = 1;
1887 find_server_repository(isUiCmd && zNotFound==0);
1888 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1889 if( flags & HTTP_SERVER_SCGI ){
1890 cgi_handle_scgi_request();
1891 }else{
1892 cgi_handle_http_request(0);
1893 }
1894 process_one_web_page(zNotFound, glob_create(zFileGlob));
1895 #else
1896 /* Win32 implementation */
1897 if( isUiCmd ){
1898 zBrowser = db_get("web-browser", "start");
1899
+16 -2
--- src/main.c
+++ src/main.c
@@ -185,10 +185,11 @@
185185
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
186186
** SSL client identity */
187187
int useLocalauth; /* No login required if from 127.0.0.1 */
188188
int noPswd; /* Logged in without password (on 127.0.0.1) */
189189
int userUid; /* Integer user id */
190
+ int isHuman; /* True if access by a human, not a spider or bot */
190191
191192
/* Information used to populate the RCVFROM table */
192193
int rcvid; /* The rcvid. 0 if not yet defined. */
193194
char *zIpAddr; /* The remote IP address */
194195
char *zNonce; /* The nonce used for login */
@@ -1639,19 +1640,21 @@
16391640
** --https signal a request coming in via https
16401641
** --nossl signal that no SSL connections are available
16411642
** --notfound URL use URL as "HTTP 404, object not found" page.
16421643
** --files GLOB comma-separate glob patterns for static file to serve
16431644
** --baseurl URL base URL (useful with reverse proxies)
1645
+** --scgi Interpret input as SCGI rather than HTTP
16441646
**
16451647
** See also: cgi, server, winsrv
16461648
*/
16471649
void cmd_http(void){
16481650
const char *zIpAddr;
16491651
const char *zNotFound;
16501652
const char *zHost;
16511653
const char *zAltBase;
16521654
const char *zFileGlob;
1655
+ int useSCGI;
16531656
16541657
/* The winhttp module passes the --files option as --files-urlenc with
16551658
** the argument being URL encoded, to avoid wildcard expansion in the
16561659
** shell. This option is for internal use and is undocumented.
16571660
*/
@@ -1664,10 +1667,11 @@
16641667
zFileGlob = find_option("files",0,1);
16651668
}
16661669
zNotFound = find_option("notfound", 0, 1);
16671670
g.useLocalauth = find_option("localauth", 0, 0)!=0;
16681671
g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
1672
+ useSCGI = find_option("scgi", 0, 0)!=0;
16691673
zAltBase = find_option("baseurl", 0, 1);
16701674
if( zAltBase ) set_base_url(zAltBase);
16711675
if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
16721676
zHost = find_option("host", 0, 1);
16731677
if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
@@ -1688,11 +1692,15 @@
16881692
if( zIpAddr==0 ){
16891693
zIpAddr = cgi_ssh_remote_addr(0);
16901694
}
16911695
find_server_repository(0);
16921696
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1693
- cgi_handle_http_request(zIpAddr);
1697
+ if( useSCGI ){
1698
+ cgi_handle_scgi_request();
1699
+ }else{
1700
+ cgi_handle_http_request(zIpAddr);
1701
+ }
16941702
process_one_web_page(zNotFound, glob_create(zFileGlob));
16951703
}
16961704
16971705
/*
16981706
** Note that the following command is used by ssh:// processing.
@@ -1784,10 +1792,11 @@
17841792
** -P|--port TCPPORT listen to request on port TCPPORT
17851793
** --th-trace trace TH1 execution (for debugging purposes)
17861794
** --baseurl URL Use URL as the base (useful for reverse proxies)
17871795
** --notfound URL Redirect
17881796
** --files GLOBLIST Comma-separated list of glob patterns for static files
1797
+** --scgi Accept SCGI rather than HTTP
17891798
**
17901799
** See also: cgi, http, winsrv
17911800
*/
17921801
void cmd_webserver(void){
17931802
int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1810,10 +1819,11 @@
18101819
g.useLocalauth = find_option("localauth", 0, 0)!=0;
18111820
Th_InitTraceLog();
18121821
zPort = find_option("port", "P", 1);
18131822
zNotFound = find_option("notfound", 0, 1);
18141823
zAltBase = find_option("baseurl", 0, 1);
1824
+ if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
18151825
if( zAltBase ){
18161826
set_base_url(zAltBase);
18171827
}
18181828
if ( find_option("localhost", 0, 0)!=0 ){
18191829
flags |= HTTP_SERVER_LOCALHOST;
@@ -1874,11 +1884,15 @@
18741884
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
18751885
}
18761886
g.cgiOutput = 1;
18771887
find_server_repository(isUiCmd && zNotFound==0);
18781888
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1879
- cgi_handle_http_request(0);
1889
+ if( flags & HTTP_SERVER_SCGI ){
1890
+ cgi_handle_scgi_request();
1891
+ }else{
1892
+ cgi_handle_http_request(0);
1893
+ }
18801894
process_one_web_page(zNotFound, glob_create(zFileGlob));
18811895
#else
18821896
/* Win32 implementation */
18831897
if( isUiCmd ){
18841898
zBrowser = db_get("web-browser", "start");
18851899
--- src/main.c
+++ src/main.c
@@ -185,10 +185,11 @@
185 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
186 ** SSL client identity */
187 int useLocalauth; /* No login required if from 127.0.0.1 */
188 int noPswd; /* Logged in without password (on 127.0.0.1) */
189 int userUid; /* Integer user id */
 
190
191 /* Information used to populate the RCVFROM table */
192 int rcvid; /* The rcvid. 0 if not yet defined. */
193 char *zIpAddr; /* The remote IP address */
194 char *zNonce; /* The nonce used for login */
@@ -1639,19 +1640,21 @@
1639 ** --https signal a request coming in via https
1640 ** --nossl signal that no SSL connections are available
1641 ** --notfound URL use URL as "HTTP 404, object not found" page.
1642 ** --files GLOB comma-separate glob patterns for static file to serve
1643 ** --baseurl URL base URL (useful with reverse proxies)
 
1644 **
1645 ** See also: cgi, server, winsrv
1646 */
1647 void cmd_http(void){
1648 const char *zIpAddr;
1649 const char *zNotFound;
1650 const char *zHost;
1651 const char *zAltBase;
1652 const char *zFileGlob;
 
1653
1654 /* The winhttp module passes the --files option as --files-urlenc with
1655 ** the argument being URL encoded, to avoid wildcard expansion in the
1656 ** shell. This option is for internal use and is undocumented.
1657 */
@@ -1664,10 +1667,11 @@
1664 zFileGlob = find_option("files",0,1);
1665 }
1666 zNotFound = find_option("notfound", 0, 1);
1667 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1668 g.sslNotAvailable = find_option("nossl", 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);
@@ -1688,11 +1692,15 @@
1688 if( zIpAddr==0 ){
1689 zIpAddr = cgi_ssh_remote_addr(0);
1690 }
1691 find_server_repository(0);
1692 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1693 cgi_handle_http_request(zIpAddr);
 
 
 
 
1694 process_one_web_page(zNotFound, glob_create(zFileGlob));
1695 }
1696
1697 /*
1698 ** Note that the following command is used by ssh:// processing.
@@ -1784,10 +1792,11 @@
1784 ** -P|--port TCPPORT listen to request on port TCPPORT
1785 ** --th-trace trace TH1 execution (for debugging purposes)
1786 ** --baseurl URL Use URL as the base (useful for reverse proxies)
1787 ** --notfound URL Redirect
1788 ** --files GLOBLIST Comma-separated list of glob patterns for static files
 
1789 **
1790 ** See also: cgi, http, winsrv
1791 */
1792 void cmd_webserver(void){
1793 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1810,10 +1819,11 @@
1810 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1811 Th_InitTraceLog();
1812 zPort = find_option("port", "P", 1);
1813 zNotFound = find_option("notfound", 0, 1);
1814 zAltBase = find_option("baseurl", 0, 1);
 
1815 if( zAltBase ){
1816 set_base_url(zAltBase);
1817 }
1818 if ( find_option("localhost", 0, 0)!=0 ){
1819 flags |= HTTP_SERVER_LOCALHOST;
@@ -1874,11 +1884,15 @@
1874 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
1875 }
1876 g.cgiOutput = 1;
1877 find_server_repository(isUiCmd && zNotFound==0);
1878 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1879 cgi_handle_http_request(0);
 
 
 
 
1880 process_one_web_page(zNotFound, glob_create(zFileGlob));
1881 #else
1882 /* Win32 implementation */
1883 if( isUiCmd ){
1884 zBrowser = db_get("web-browser", "start");
1885
--- src/main.c
+++ src/main.c
@@ -185,10 +185,11 @@
185 const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
186 ** SSL client identity */
187 int useLocalauth; /* No login required if from 127.0.0.1 */
188 int noPswd; /* Logged in without password (on 127.0.0.1) */
189 int userUid; /* Integer user id */
190 int isHuman; /* True if access by a human, not a spider or bot */
191
192 /* Information used to populate the RCVFROM table */
193 int rcvid; /* The rcvid. 0 if not yet defined. */
194 char *zIpAddr; /* The remote IP address */
195 char *zNonce; /* The nonce used for login */
@@ -1639,19 +1640,21 @@
1640 ** --https signal a request coming in via https
1641 ** --nossl signal that no SSL connections are available
1642 ** --notfound URL use URL as "HTTP 404, object not found" page.
1643 ** --files GLOB comma-separate glob patterns for static file to serve
1644 ** --baseurl URL base URL (useful with reverse proxies)
1645 ** --scgi Interpret input as SCGI rather than HTTP
1646 **
1647 ** See also: cgi, server, winsrv
1648 */
1649 void cmd_http(void){
1650 const char *zIpAddr;
1651 const char *zNotFound;
1652 const char *zHost;
1653 const char *zAltBase;
1654 const char *zFileGlob;
1655 int useSCGI;
1656
1657 /* The winhttp module passes the --files option as --files-urlenc with
1658 ** the argument being URL encoded, to avoid wildcard expansion in the
1659 ** shell. This option is for internal use and is undocumented.
1660 */
@@ -1664,10 +1667,11 @@
1667 zFileGlob = find_option("files",0,1);
1668 }
1669 zNotFound = find_option("notfound", 0, 1);
1670 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1671 g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
1672 useSCGI = find_option("scgi", 0, 0)!=0;
1673 zAltBase = find_option("baseurl", 0, 1);
1674 if( zAltBase ) set_base_url(zAltBase);
1675 if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
1676 zHost = find_option("host", 0, 1);
1677 if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
@@ -1688,11 +1692,15 @@
1692 if( zIpAddr==0 ){
1693 zIpAddr = cgi_ssh_remote_addr(0);
1694 }
1695 find_server_repository(0);
1696 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1697 if( useSCGI ){
1698 cgi_handle_scgi_request();
1699 }else{
1700 cgi_handle_http_request(zIpAddr);
1701 }
1702 process_one_web_page(zNotFound, glob_create(zFileGlob));
1703 }
1704
1705 /*
1706 ** Note that the following command is used by ssh:// processing.
@@ -1784,10 +1792,11 @@
1792 ** -P|--port TCPPORT listen to request on port TCPPORT
1793 ** --th-trace trace TH1 execution (for debugging purposes)
1794 ** --baseurl URL Use URL as the base (useful for reverse proxies)
1795 ** --notfound URL Redirect
1796 ** --files GLOBLIST Comma-separated list of glob patterns for static files
1797 ** --scgi Accept SCGI rather than HTTP
1798 **
1799 ** See also: cgi, http, winsrv
1800 */
1801 void cmd_webserver(void){
1802 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1810,10 +1819,11 @@
1819 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1820 Th_InitTraceLog();
1821 zPort = find_option("port", "P", 1);
1822 zNotFound = find_option("notfound", 0, 1);
1823 zAltBase = find_option("baseurl", 0, 1);
1824 if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
1825 if( zAltBase ){
1826 set_base_url(zAltBase);
1827 }
1828 if ( find_option("localhost", 0, 0)!=0 ){
1829 flags |= HTTP_SERVER_LOCALHOST;
@@ -1874,11 +1884,15 @@
1884 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
1885 }
1886 g.cgiOutput = 1;
1887 find_server_repository(isUiCmd && zNotFound==0);
1888 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1889 if( flags & HTTP_SERVER_SCGI ){
1890 cgi_handle_scgi_request();
1891 }else{
1892 cgi_handle_http_request(0);
1893 }
1894 process_one_web_page(zNotFound, glob_create(zFileGlob));
1895 #else
1896 /* Win32 implementation */
1897 if( isUiCmd ){
1898 zBrowser = db_get("web-browser", "start");
1899
+12 -4
--- src/manifest.c
+++ src/manifest.c
@@ -660,11 +660,11 @@
660660
}
661661
662662
/*
663663
** P <uuid> ...
664664
**
665
- ** Specify one or more other artifacts where are the parents of
665
+ ** Specify one or more other artifacts which are the parents of
666666
** this artifact. The first parent is the primary parent. All
667667
** others are parents by merge.
668668
*/
669669
case 'P': {
670670
while( (zUuid = next_token(&x, &sz))!=0 ){
@@ -783,11 +783,11 @@
783783
** Identify the user who created this control file by their
784784
** login. Only one U line is allowed. Prohibited in clusters.
785785
** If the user name is omitted, take that to be "anonymous".
786786
*/
787787
case 'U': {
788
- if( p->zUser!=0 ) SYNTAX("more than on U-card");
788
+ if( p->zUser!=0 ) SYNTAX("more than one U-card");
789789
p->zUser = next_token(&x, 0);
790790
if( p->zUser==0 ){
791791
p->zUser = "anonymous";
792792
}else{
793793
defossilize(p->zUser);
@@ -1965,13 +1965,21 @@
19651965
}else if( memcmp(zName, "+sym-",5)==0 ){
19661966
blob_appendf(&comment, " Add tag \"%h\".", &zName[5]);
19671967
}else if( memcmp(zName, "-sym-",5)==0 ){
19681968
blob_appendf(&comment, " Cancel tag \"%h\".", &zName[5]);
19691969
}else if( strcmp(zName, "+closed")==0 ){
1970
- blob_appendf(&comment, " Marked \"Closed\".");
1970
+ blob_append(&comment, " Marked \"Closed\"", -1);
1971
+ if( zValue && *zValue ){
1972
+ blob_appendf(&comment, " with note \"%h\"", zValue);
1973
+ }
1974
+ blob_append(&comment, ".", 1);
19711975
}else if( strcmp(zName, "-closed")==0 ){
1972
- blob_appendf(&comment, " Removed the \"Closed\" mark.");
1976
+ blob_append(&comment, " Removed the \"Closed\" mark", -1);
1977
+ if( zValue && *zValue ){
1978
+ blob_appendf(&comment, " with note \"%h\"", zValue);
1979
+ }
1980
+ blob_append(&comment, ".", 1);
19731981
}else {
19741982
if( zName[0]=='-' ){
19751983
blob_appendf(&comment, " Cancel \"%h\"", &zName[1]);
19761984
}else if( zName[0]=='+' ){
19771985
blob_appendf(&comment, " Add \"%h\"", &zName[1]);
19781986
--- src/manifest.c
+++ src/manifest.c
@@ -660,11 +660,11 @@
660 }
661
662 /*
663 ** P <uuid> ...
664 **
665 ** Specify one or more other artifacts where are the parents of
666 ** this artifact. The first parent is the primary parent. All
667 ** others are parents by merge.
668 */
669 case 'P': {
670 while( (zUuid = next_token(&x, &sz))!=0 ){
@@ -783,11 +783,11 @@
783 ** Identify the user who created this control file by their
784 ** login. Only one U line is allowed. Prohibited in clusters.
785 ** If the user name is omitted, take that to be "anonymous".
786 */
787 case 'U': {
788 if( p->zUser!=0 ) SYNTAX("more than on U-card");
789 p->zUser = next_token(&x, 0);
790 if( p->zUser==0 ){
791 p->zUser = "anonymous";
792 }else{
793 defossilize(p->zUser);
@@ -1965,13 +1965,21 @@
1965 }else if( memcmp(zName, "+sym-",5)==0 ){
1966 blob_appendf(&comment, " Add tag \"%h\".", &zName[5]);
1967 }else if( memcmp(zName, "-sym-",5)==0 ){
1968 blob_appendf(&comment, " Cancel tag \"%h\".", &zName[5]);
1969 }else if( strcmp(zName, "+closed")==0 ){
1970 blob_appendf(&comment, " Marked \"Closed\".");
 
 
 
 
1971 }else if( strcmp(zName, "-closed")==0 ){
1972 blob_appendf(&comment, " Removed the \"Closed\" mark.");
 
 
 
 
1973 }else {
1974 if( zName[0]=='-' ){
1975 blob_appendf(&comment, " Cancel \"%h\"", &zName[1]);
1976 }else if( zName[0]=='+' ){
1977 blob_appendf(&comment, " Add \"%h\"", &zName[1]);
1978
--- src/manifest.c
+++ src/manifest.c
@@ -660,11 +660,11 @@
660 }
661
662 /*
663 ** P <uuid> ...
664 **
665 ** Specify one or more other artifacts which are the parents of
666 ** this artifact. The first parent is the primary parent. All
667 ** others are parents by merge.
668 */
669 case 'P': {
670 while( (zUuid = next_token(&x, &sz))!=0 ){
@@ -783,11 +783,11 @@
783 ** Identify the user who created this control file by their
784 ** login. Only one U line is allowed. Prohibited in clusters.
785 ** If the user name is omitted, take that to be "anonymous".
786 */
787 case 'U': {
788 if( p->zUser!=0 ) SYNTAX("more than one U-card");
789 p->zUser = next_token(&x, 0);
790 if( p->zUser==0 ){
791 p->zUser = "anonymous";
792 }else{
793 defossilize(p->zUser);
@@ -1965,13 +1965,21 @@
1965 }else if( memcmp(zName, "+sym-",5)==0 ){
1966 blob_appendf(&comment, " Add tag \"%h\".", &zName[5]);
1967 }else if( memcmp(zName, "-sym-",5)==0 ){
1968 blob_appendf(&comment, " Cancel tag \"%h\".", &zName[5]);
1969 }else if( strcmp(zName, "+closed")==0 ){
1970 blob_append(&comment, " Marked \"Closed\"", -1);
1971 if( zValue && *zValue ){
1972 blob_appendf(&comment, " with note \"%h\"", zValue);
1973 }
1974 blob_append(&comment, ".", 1);
1975 }else if( strcmp(zName, "-closed")==0 ){
1976 blob_append(&comment, " Removed the \"Closed\" mark", -1);
1977 if( zValue && *zValue ){
1978 blob_appendf(&comment, " with note \"%h\"", zValue);
1979 }
1980 blob_append(&comment, ".", 1);
1981 }else {
1982 if( zName[0]=='-' ){
1983 blob_appendf(&comment, " Cancel \"%h\"", &zName[1]);
1984 }else if( zName[0]=='+' ){
1985 blob_appendf(&comment, " Add \"%h\"", &zName[1]);
1986
+71 -56
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -656,11 +656,11 @@
656656
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657657
** [sqlite_version()] and [sqlite_source_id()].
658658
*/
659659
#define SQLITE_VERSION "3.8.0"
660660
#define SQLITE_VERSION_NUMBER 3008000
661
-#define SQLITE_SOURCE_ID "2013-08-06 07:45:08 924f7e4d7a8fa2fe9100836663f3733b6e1a9084"
661
+#define SQLITE_SOURCE_ID "2013-08-15 22:40:21 f2d175f975cd0be63425424ec322a98fb650019e"
662662
663663
/*
664664
** CAPI3REF: Run-Time Library Version Numbers
665665
** KEYWORDS: sqlite3_version, sqlite3_sourceid
666666
**
@@ -7780,11 +7780,11 @@
77807780
#endif
77817781
77827782
#if 0
77837783
} /* End of the 'extern "C"' block */
77847784
#endif
7785
-#endif
7785
+#endif /* _SQLITE3_H_ */
77867786
77877787
/*
77887788
** 2010 August 30
77897789
**
77907790
** The author disclaims copyright to this source code. In place of
@@ -11214,11 +11214,11 @@
1121411214
** subqueries looking for a match.
1121511215
*/
1121611216
struct NameContext {
1121711217
Parse *pParse; /* The parser */
1121811218
SrcList *pSrcList; /* One or more tables used to resolve names */
11219
- ExprList *pEList; /* Optional list of named expressions */
11219
+ ExprList *pEList; /* Optional list of result-set columns */
1122011220
AggInfo *pAggInfo; /* Information about aggregates at this level */
1122111221
NameContext *pNext; /* Next outer name context. NULL for outermost */
1122211222
int nRef; /* Number of names resolved by this context */
1122311223
int nErr; /* Number of errors encountered while resolving names */
1122411224
u8 ncFlags; /* Zero or more NC_* flags defined below */
@@ -11229,13 +11229,11 @@
1122911229
*/
1123011230
#define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */
1123111231
#define NC_HasAgg 0x02 /* One or more aggregate functions seen */
1123211232
#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
1123311233
#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
11234
-#define NC_AsMaybe 0x10 /* Resolve to AS terms of the result set only
11235
- ** if no other resolution is available */
11236
-#define NC_PartIdx 0x20 /* True if resolving a partial index WHERE */
11234
+#define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */
1123711235
1123811236
/*
1123911237
** An instance of the following structure contains all information
1124011238
** needed to generate code for a single SELECT statement.
1124111239
**
@@ -17231,17 +17229,17 @@
1723117229
u8 *aCtrl;
1723217230
1723317231
} mem5;
1723417232
1723517233
/*
17236
-** Access the static variable through a macro for SQLITE_OMIT_WSD
17234
+** Access the static variable through a macro for SQLITE_OMIT_WSD.
1723717235
*/
1723817236
#define mem5 GLOBAL(struct Mem5Global, mem5)
1723917237
1724017238
/*
1724117239
** Assuming mem5.zPool is divided up into an array of Mem5Link
17242
-** structures, return a pointer to the idx-th such lik.
17240
+** structures, return a pointer to the idx-th such link.
1724317241
*/
1724417242
#define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.szAtom]))
1724517243
1724617244
/*
1724717245
** Unlink the chunk at mem5.aPool[i] from list it is currently
@@ -17333,11 +17331,11 @@
1733317331
1733417332
/*
1733517333
** Return a block of memory of at least nBytes in size.
1733617334
** Return NULL if unable. Return NULL if nBytes==0.
1733717335
**
17338
-** The caller guarantees that nByte positive.
17336
+** The caller guarantees that nByte is positive.
1733917337
**
1734017338
** The caller has obtained a mutex prior to invoking this
1734117339
** routine so there is never any chance that two or more
1734217340
** threads can be in this routine at the same time.
1734317341
*/
@@ -17455,11 +17453,11 @@
1745517453
}
1745617454
memsys5Link(iBlock, iLogsize);
1745717455
}
1745817456
1745917457
/*
17460
-** Allocate nBytes of memory
17458
+** Allocate nBytes of memory.
1746117459
*/
1746217460
static void *memsys5Malloc(int nBytes){
1746317461
sqlite3_int64 *p = 0;
1746417462
if( nBytes>0 ){
1746517463
memsys5Enter();
@@ -74041,22 +74039,23 @@
7404174039
**
7404274040
** The reason for suppressing the TK_AS term when the expression is a simple
7404374041
** column reference is so that the column reference will be recognized as
7404474042
** usable by indices within the WHERE clause processing logic.
7404574043
**
74046
-** Hack: The TK_AS operator is inhibited if zType[0]=='G'. This means
74044
+** The TK_AS operator is inhibited if zType[0]=='G'. This means
7404774045
** that in a GROUP BY clause, the expression is evaluated twice. Hence:
7404874046
**
7404974047
** SELECT random()%5 AS x, count(*) FROM tab GROUP BY x
7405074048
**
7405174049
** Is equivalent to:
7405274050
**
7405374051
** SELECT random()%5 AS x, count(*) FROM tab GROUP BY random()%5
7405474052
**
7405574053
** The result of random()%5 in the GROUP BY clause is probably different
74056
-** from the result in the result-set. We might fix this someday. Or
74057
-** then again, we might not...
74054
+** from the result in the result-set. On the other hand Standard SQL does
74055
+** not allow the GROUP BY clause to contain references to result-set columns.
74056
+** So this should never come up in well-formed queries.
7405874057
**
7405974058
** If the reference is followed by a COLLATE operator, then make sure
7406074059
** the COLLATE operator is preserved. For example:
7406174060
**
7406274061
** SELECT a+b, c+d FROM t1 ORDER BY 1 COLLATE nocase;
@@ -74382,14 +74381,20 @@
7438274381
**
7438374382
** In cases like this, replace pExpr with a copy of the expression that
7438474383
** forms the result set entry ("a+b" in the example) and return immediately.
7438574384
** Note that the expression in the result set should have already been
7438674385
** resolved by the time the WHERE clause is resolved.
74386
+ **
74387
+ ** The ability to use an output result-set column in the WHERE, GROUP BY,
74388
+ ** or HAVING clauses, or as part of a larger expression in the ORDRE BY
74389
+ ** clause is not standard SQL. This is a (goofy) SQLite extension, that
74390
+ ** is supported for backwards compatibility only. TO DO: Issue a warning
74391
+ ** on sqlite3_log() whenever the capability is used.
7438774392
*/
7438874393
if( (pEList = pNC->pEList)!=0
7438974394
&& zTab==0
74390
- && ((pNC->ncFlags & NC_AsMaybe)==0 || cnt==0)
74395
+ && cnt==0
7439174396
){
7439274397
for(j=0; j<pEList->nExpr; j++){
7439374398
char *zAs = pEList->a[j].zName;
7439474399
if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
7439574400
Expr *pOrig;
@@ -74947,11 +74952,11 @@
7494774952
}
7494874953
7494974954
/*
7495074955
** Check every term in the ORDER BY or GROUP BY clause pOrderBy of
7495174956
** the SELECT statement pSelect. If any term is reference to a
74952
-** result set expression (as determined by the ExprList.a.iCol field)
74957
+** result set expression (as determined by the ExprList.a.iOrderByCol field)
7495374958
** then convert that term into a copy of the corresponding result set
7495474959
** column.
7495574960
**
7495674961
** If any errors are detected, add an error message to pParse and
7495774962
** return non-zero. Return zero if no errors are seen.
@@ -74995,11 +75000,11 @@
7499575000
**
7499675001
** This routine resolves each term of the clause into an expression.
7499775002
** If the order-by term is an integer I between 1 and N (where N is the
7499875003
** number of columns in the result set of the SELECT) then the expression
7499975004
** in the resolution is a copy of the I-th result-set expression. If
75000
-** the order-by term is an identify that corresponds to the AS-name of
75005
+** the order-by term is an identifier that corresponds to the AS-name of
7500175006
** a result-set expression, then the term resolves to a copy of the
7500275007
** result-set expression. Otherwise, the expression is resolved in
7500375008
** the usual way - using sqlite3ResolveExprNames().
7500475009
**
7500575010
** This routine returns the number of errors. If errors occur, then
@@ -75021,20 +75026,23 @@
7502175026
if( pOrderBy==0 ) return 0;
7502275027
nResult = pSelect->pEList->nExpr;
7502375028
pParse = pNC->pParse;
7502475029
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
7502575030
Expr *pE = pItem->pExpr;
75026
- iCol = resolveAsName(pParse, pSelect->pEList, pE);
75027
- if( iCol>0 ){
75028
- /* If an AS-name match is found, mark this ORDER BY column as being
75029
- ** a copy of the iCol-th result-set column. The subsequent call to
75030
- ** sqlite3ResolveOrderGroupBy() will convert the expression to a
75031
- ** copy of the iCol-th result-set expression. */
75032
- pItem->iOrderByCol = (u16)iCol;
75033
- continue;
75034
- }
75035
- if( sqlite3ExprIsInteger(sqlite3ExprSkipCollate(pE), &iCol) ){
75031
+ Expr *pE2 = sqlite3ExprSkipCollate(pE);
75032
+ if( zType[0]!='G' ){
75033
+ iCol = resolveAsName(pParse, pSelect->pEList, pE2);
75034
+ if( iCol>0 ){
75035
+ /* If an AS-name match is found, mark this ORDER BY column as being
75036
+ ** a copy of the iCol-th result-set column. The subsequent call to
75037
+ ** sqlite3ResolveOrderGroupBy() will convert the expression to a
75038
+ ** copy of the iCol-th result-set expression. */
75039
+ pItem->iOrderByCol = (u16)iCol;
75040
+ continue;
75041
+ }
75042
+ }
75043
+ if( sqlite3ExprIsInteger(pE2, &iCol) ){
7503675044
/* The ORDER BY term is an integer constant. Again, set the column
7503775045
** number so that sqlite3ResolveOrderGroupBy() will convert the
7503875046
** order-by term to a copy of the result-set expression */
7503975047
if( iCol<1 || iCol>0xffff ){
7504075048
resolveOutOfRangeError(pParse, zType, i+1, nResult);
@@ -75173,23 +75181,21 @@
7517375181
if( p->pHaving && !pGroupBy ){
7517475182
sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
7517575183
return WRC_Abort;
7517675184
}
7517775185
75178
- /* Add the expression list to the name-context before parsing the
75186
+ /* Add the output column list to the name-context before parsing the
7517975187
** other expressions in the SELECT statement. This is so that
7518075188
** expressions in the WHERE clause (etc.) can refer to expressions by
7518175189
** aliases in the result set.
7518275190
**
7518375191
** Minor point: If this is the case, then the expression will be
7518475192
** re-evaluated for each reference to it.
7518575193
*/
7518675194
sNC.pEList = p->pEList;
75187
- sNC.ncFlags |= NC_AsMaybe;
7518875195
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
7518975196
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
75190
- sNC.ncFlags &= ~NC_AsMaybe;
7519175197
7519275198
/* The ORDER BY and GROUP BY clauses may not refer to terms in
7519375199
** outer queries
7519475200
*/
7519575201
sNC.pNext = 0;
@@ -77134,19 +77140,21 @@
7713477140
assert( !isRowid );
7713577141
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
7713677142
dest.affSdst = (u8)affinity;
7713777143
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
7713877144
pExpr->x.pSelect->iLimit = 0;
77145
+ testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
7713977146
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
7714077147
sqlite3DbFree(pParse->db, pKeyInfo);
7714177148
return 0;
7714277149
}
7714377150
pEList = pExpr->x.pSelect->pEList;
77144
- if( pKeyInfo && ALWAYS(pEList!=0 && pEList->nExpr>0) ){
77145
- pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
77146
- pEList->a[0].pExpr);
77147
- }
77151
+ assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
77152
+ assert( pEList!=0 );
77153
+ assert( pEList->nExpr>0 );
77154
+ pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
77155
+ pEList->a[0].pExpr);
7714877156
}else if( ALWAYS(pExpr->x.pList!=0) ){
7714977157
/* Case 2: expr IN (exprlist)
7715077158
**
7715177159
** For each expression, build an index key from the evaluation and
7715277160
** store it in the temporary table. If <expr> is a column, then use
@@ -104711,11 +104719,11 @@
104711104719
# define WHERETRACE_ENABLED 1
104712104720
#else
104713104721
# define WHERETRACE(K,X)
104714104722
#endif
104715104723
104716
-/* Forward reference
104724
+/* Forward references
104717104725
*/
104718104726
typedef struct WhereClause WhereClause;
104719104727
typedef struct WhereMaskSet WhereMaskSet;
104720104728
typedef struct WhereOrInfo WhereOrInfo;
104721104729
typedef struct WhereAndInfo WhereAndInfo;
@@ -104733,18 +104741,19 @@
104733104741
** maximum cost for ordinary tables is 64*(2**63) which becomes 6900.
104734104742
** (Virtual tables can return a larger cost, but let's assume they do not.)
104735104743
** So all costs can be stored in a 16-bit unsigned integer without risk
104736104744
** of overflow.
104737104745
**
104738
-** Costs are estimates, so don't go to the computational trouble to compute
104739
-** 10*log2(X) exactly. Instead, a close estimate is used. Any value of
104740
-** X<=1 is stored as 0. X=2 is 10. X=3 is 16. X=1000 is 99. etc.
104746
+** Costs are estimates, so no effort is made to compute 10*log2(X) exactly.
104747
+** Instead, a close estimate is used. Any value of X<=1 is stored as 0.
104748
+** X=2 is 10. X=3 is 16. X=1000 is 99. etc.
104741104749
**
104742104750
** The tool/wherecosttest.c source file implements a command-line program
104743
-** that will convert between WhereCost to integers and do addition and
104744
-** multiplication on WhereCost values. That command-line program is a
104745
-** useful utility to have around when working with this module.
104751
+** that will convert WhereCosts to integers, convert integers to WhereCosts
104752
+** and do addition and multiplication on WhereCost values. The wherecosttest
104753
+** command-line program is a useful utility to have around when working with
104754
+** this module.
104746104755
*/
104747104756
typedef unsigned short int WhereCost;
104748104757
104749104758
/*
104750104759
** This object contains information needed to implement a single nested
@@ -104843,12 +104852,12 @@
104843104852
WhereCost rRun; /* Cost of running this subquery */
104844104853
WhereCost nOut; /* Number of outputs for this subquery */
104845104854
};
104846104855
104847104856
/* The WhereOrSet object holds a set of possible WhereOrCosts that
104848
-** correspond to the subquery(s) of OR-clause processing. At most
104849
-** favorable N_OR_COST elements are retained.
104857
+** correspond to the subquery(s) of OR-clause processing. Only the
104858
+** best N_OR_COST elements are retained.
104850104859
*/
104851104860
#define N_OR_COST 3
104852104861
struct WhereOrSet {
104853104862
u16 n; /* Number of valid a[] entries */
104854104863
WhereOrCost a[N_OR_COST]; /* Set of best costs */
@@ -104910,13 +104919,13 @@
104910104919
**
104911104920
** A WhereTerm might also be two or more subterms connected by OR:
104912104921
**
104913104922
** (t1.X <op> <expr>) OR (t1.Y <op> <expr>) OR ....
104914104923
**
104915
-** In this second case, wtFlag as the TERM_ORINFO set and eOperator==WO_OR
104924
+** In this second case, wtFlag has the TERM_ORINFO bit set and eOperator==WO_OR
104916104925
** and the WhereTerm.u.pOrInfo field points to auxiliary information that
104917
-** is collected about the
104926
+** is collected about the OR clause.
104918104927
**
104919104928
** If a term in the WHERE clause does not match either of the two previous
104920104929
** categories, then eOperator==0. The WhereTerm.pExpr field is still set
104921104930
** to the original subexpression content and wtFlags is set up appropriately
104922104931
** but no other fields in the WhereTerm object are meaningful.
@@ -105424,11 +105433,11 @@
105424105433
assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
105425105434
pMaskSet->ix[pMaskSet->n++] = iCursor;
105426105435
}
105427105436
105428105437
/*
105429
-** These routine walk (recursively) an expression tree and generates
105438
+** These routines walk (recursively) an expression tree and generate
105430105439
** a bitmask indicating which tables are used in that expression
105431105440
** tree.
105432105441
*/
105433105442
static Bitmask exprListTableUsage(WhereMaskSet*, ExprList*);
105434105443
static Bitmask exprSelectTableUsage(WhereMaskSet*, Select*);
@@ -105941,14 +105950,14 @@
105941105950
** u.pAndInfo set to a dynamically allocated WhereAndTerm object.
105942105951
**
105943105952
** From another point of view, "indexable" means that the subterm could
105944105953
** potentially be used with an index if an appropriate index exists.
105945105954
** This analysis does not consider whether or not the index exists; that
105946
-** is something the bestIndex() routine will determine. This analysis
105947
-** only looks at whether subterms appropriate for indexing exist.
105955
+** is decided elsewhere. This analysis only looks at whether subterms
105956
+** appropriate for indexing exist.
105948105957
**
105949
-** All examples A through E above all satisfy case 2. But if a term
105958
+** All examples A through E above satisfy case 2. But if a term
105950105959
** also statisfies case 1 (such as B) we know that the optimizer will
105951105960
** always prefer case 1, so in that case we pretend that case 2 is not
105952105961
** satisfied.
105953105962
**
105954105963
** It might be the case that multiple tables are indexable. For example,
@@ -106611,11 +106620,11 @@
106611106620
106612106621
return 0;
106613106622
}
106614106623
106615106624
/*
106616
-** The (an approximate) sum of two WhereCosts. This computation is
106625
+** Find (an approximate) sum of two WhereCosts. This computation is
106617106626
** not a simple "+" operator because WhereCost is stored as a logarithmic
106618106627
** value.
106619106628
**
106620106629
*/
106621106630
static WhereCost whereCostAdd(WhereCost a, WhereCost b){
@@ -115614,10 +115623,13 @@
115614115623
** without blocking.
115615115624
*/
115616115625
SQLITE_API int sqlite3_initialize(void){
115617115626
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
115618115627
int rc; /* Result code */
115628
+#ifdef SQLITE_EXTRA_INIT
115629
+ int bRunExtraInit = 0; /* Extra initialization needed */
115630
+#endif
115619115631
115620115632
#ifdef SQLITE_OMIT_WSD
115621115633
rc = sqlite3_wsd_init(4096, 24);
115622115634
if( rc!=SQLITE_OK ){
115623115635
return rc;
@@ -115711,10 +115723,13 @@
115711115723
}
115712115724
if( rc==SQLITE_OK ){
115713115725
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
115714115726
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
115715115727
sqlite3GlobalConfig.isInit = 1;
115728
+#ifdef SQLITE_EXTRA_INIT
115729
+ bRunExtraInit = 1;
115730
+#endif
115716115731
}
115717115732
sqlite3GlobalConfig.inProgress = 0;
115718115733
}
115719115734
sqlite3_mutex_leave(sqlite3GlobalConfig.pInitMutex);
115720115735
@@ -115751,11 +115766,11 @@
115751115766
115752115767
/* Do extra initialization steps requested by the SQLITE_EXTRA_INIT
115753115768
** compile-time option.
115754115769
*/
115755115770
#ifdef SQLITE_EXTRA_INIT
115756
- if( rc==SQLITE_OK && sqlite3GlobalConfig.isInit ){
115771
+ if( bRunExtraInit ){
115757115772
int SQLITE_EXTRA_INIT(const char*);
115758115773
rc = SQLITE_EXTRA_INIT(0);
115759115774
}
115760115775
#endif
115761115776
@@ -115939,12 +115954,12 @@
115939115954
** run.
115940115955
*/
115941115956
memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m));
115942115957
}else{
115943115958
/* The heap pointer is not NULL, then install one of the
115944
- ** mem5.c/mem3.c methods. If neither ENABLE_MEMSYS3 nor
115945
- ** ENABLE_MEMSYS5 is defined, return an error.
115959
+ ** mem5.c/mem3.c methods. The enclosing #if guarantees at
115960
+ ** least one of these methods is currently enabled.
115946115961
*/
115947115962
#ifdef SQLITE_ENABLE_MEMSYS3
115948115963
sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3();
115949115964
#endif
115950115965
#ifdef SQLITE_ENABLE_MEMSYS5
@@ -115959,11 +115974,11 @@
115959115974
sqlite3GlobalConfig.szLookaside = va_arg(ap, int);
115960115975
sqlite3GlobalConfig.nLookaside = va_arg(ap, int);
115961115976
break;
115962115977
}
115963115978
115964
- /* Record a pointer to the logger funcction and its first argument.
115979
+ /* Record a pointer to the logger function and its first argument.
115965115980
** The default is NULL. Logging is disabled if the function pointer is
115966115981
** NULL.
115967115982
*/
115968115983
case SQLITE_CONFIG_LOG: {
115969115984
/* MSVC is picky about pulling func ptrs from va lists.
@@ -117675,24 +117690,24 @@
117675117690
117676117691
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
117677117692
zFile = sqlite3_malloc(nByte);
117678117693
if( !zFile ) return SQLITE_NOMEM;
117679117694
117695
+ iIn = 5;
117696
+#ifndef SQLITE_ALLOW_URI_AUTHORITY
117680117697
/* Discard the scheme and authority segments of the URI. */
117681117698
if( zUri[5]=='/' && zUri[6]=='/' ){
117682117699
iIn = 7;
117683117700
while( zUri[iIn] && zUri[iIn]!='/' ) iIn++;
117684
-
117685117701
if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){
117686117702
*pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s",
117687117703
iIn-7, &zUri[7]);
117688117704
rc = SQLITE_ERROR;
117689117705
goto parse_uri_out;
117690117706
}
117691
- }else{
117692
- iIn = 5;
117693117707
}
117708
+#endif
117694117709
117695117710
/* Copy the filename and any query parameters into the zFile buffer.
117696117711
** Decode %HH escape codes along the way.
117697117712
**
117698117713
** Within this loop, variable eState may be set to 0, 1 or 2, depending
117699117714
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -656,11 +656,11 @@
656 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657 ** [sqlite_version()] and [sqlite_source_id()].
658 */
659 #define SQLITE_VERSION "3.8.0"
660 #define SQLITE_VERSION_NUMBER 3008000
661 #define SQLITE_SOURCE_ID "2013-08-06 07:45:08 924f7e4d7a8fa2fe9100836663f3733b6e1a9084"
662
663 /*
664 ** CAPI3REF: Run-Time Library Version Numbers
665 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
666 **
@@ -7780,11 +7780,11 @@
7780 #endif
7781
7782 #if 0
7783 } /* End of the 'extern "C"' block */
7784 #endif
7785 #endif
7786
7787 /*
7788 ** 2010 August 30
7789 **
7790 ** The author disclaims copyright to this source code. In place of
@@ -11214,11 +11214,11 @@
11214 ** subqueries looking for a match.
11215 */
11216 struct NameContext {
11217 Parse *pParse; /* The parser */
11218 SrcList *pSrcList; /* One or more tables used to resolve names */
11219 ExprList *pEList; /* Optional list of named expressions */
11220 AggInfo *pAggInfo; /* Information about aggregates at this level */
11221 NameContext *pNext; /* Next outer name context. NULL for outermost */
11222 int nRef; /* Number of names resolved by this context */
11223 int nErr; /* Number of errors encountered while resolving names */
11224 u8 ncFlags; /* Zero or more NC_* flags defined below */
@@ -11229,13 +11229,11 @@
11229 */
11230 #define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */
11231 #define NC_HasAgg 0x02 /* One or more aggregate functions seen */
11232 #define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
11233 #define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
11234 #define NC_AsMaybe 0x10 /* Resolve to AS terms of the result set only
11235 ** if no other resolution is available */
11236 #define NC_PartIdx 0x20 /* True if resolving a partial index WHERE */
11237
11238 /*
11239 ** An instance of the following structure contains all information
11240 ** needed to generate code for a single SELECT statement.
11241 **
@@ -17231,17 +17229,17 @@
17231 u8 *aCtrl;
17232
17233 } mem5;
17234
17235 /*
17236 ** Access the static variable through a macro for SQLITE_OMIT_WSD
17237 */
17238 #define mem5 GLOBAL(struct Mem5Global, mem5)
17239
17240 /*
17241 ** Assuming mem5.zPool is divided up into an array of Mem5Link
17242 ** structures, return a pointer to the idx-th such lik.
17243 */
17244 #define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.szAtom]))
17245
17246 /*
17247 ** Unlink the chunk at mem5.aPool[i] from list it is currently
@@ -17333,11 +17331,11 @@
17333
17334 /*
17335 ** Return a block of memory of at least nBytes in size.
17336 ** Return NULL if unable. Return NULL if nBytes==0.
17337 **
17338 ** The caller guarantees that nByte positive.
17339 **
17340 ** The caller has obtained a mutex prior to invoking this
17341 ** routine so there is never any chance that two or more
17342 ** threads can be in this routine at the same time.
17343 */
@@ -17455,11 +17453,11 @@
17455 }
17456 memsys5Link(iBlock, iLogsize);
17457 }
17458
17459 /*
17460 ** Allocate nBytes of memory
17461 */
17462 static void *memsys5Malloc(int nBytes){
17463 sqlite3_int64 *p = 0;
17464 if( nBytes>0 ){
17465 memsys5Enter();
@@ -74041,22 +74039,23 @@
74041 **
74042 ** The reason for suppressing the TK_AS term when the expression is a simple
74043 ** column reference is so that the column reference will be recognized as
74044 ** usable by indices within the WHERE clause processing logic.
74045 **
74046 ** Hack: The TK_AS operator is inhibited if zType[0]=='G'. This means
74047 ** that in a GROUP BY clause, the expression is evaluated twice. Hence:
74048 **
74049 ** SELECT random()%5 AS x, count(*) FROM tab GROUP BY x
74050 **
74051 ** Is equivalent to:
74052 **
74053 ** SELECT random()%5 AS x, count(*) FROM tab GROUP BY random()%5
74054 **
74055 ** The result of random()%5 in the GROUP BY clause is probably different
74056 ** from the result in the result-set. We might fix this someday. Or
74057 ** then again, we might not...
 
74058 **
74059 ** If the reference is followed by a COLLATE operator, then make sure
74060 ** the COLLATE operator is preserved. For example:
74061 **
74062 ** SELECT a+b, c+d FROM t1 ORDER BY 1 COLLATE nocase;
@@ -74382,14 +74381,20 @@
74382 **
74383 ** In cases like this, replace pExpr with a copy of the expression that
74384 ** forms the result set entry ("a+b" in the example) and return immediately.
74385 ** Note that the expression in the result set should have already been
74386 ** resolved by the time the WHERE clause is resolved.
 
 
 
 
 
 
74387 */
74388 if( (pEList = pNC->pEList)!=0
74389 && zTab==0
74390 && ((pNC->ncFlags & NC_AsMaybe)==0 || cnt==0)
74391 ){
74392 for(j=0; j<pEList->nExpr; j++){
74393 char *zAs = pEList->a[j].zName;
74394 if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
74395 Expr *pOrig;
@@ -74947,11 +74952,11 @@
74947 }
74948
74949 /*
74950 ** Check every term in the ORDER BY or GROUP BY clause pOrderBy of
74951 ** the SELECT statement pSelect. If any term is reference to a
74952 ** result set expression (as determined by the ExprList.a.iCol field)
74953 ** then convert that term into a copy of the corresponding result set
74954 ** column.
74955 **
74956 ** If any errors are detected, add an error message to pParse and
74957 ** return non-zero. Return zero if no errors are seen.
@@ -74995,11 +75000,11 @@
74995 **
74996 ** This routine resolves each term of the clause into an expression.
74997 ** If the order-by term is an integer I between 1 and N (where N is the
74998 ** number of columns in the result set of the SELECT) then the expression
74999 ** in the resolution is a copy of the I-th result-set expression. If
75000 ** the order-by term is an identify that corresponds to the AS-name of
75001 ** a result-set expression, then the term resolves to a copy of the
75002 ** result-set expression. Otherwise, the expression is resolved in
75003 ** the usual way - using sqlite3ResolveExprNames().
75004 **
75005 ** This routine returns the number of errors. If errors occur, then
@@ -75021,20 +75026,23 @@
75021 if( pOrderBy==0 ) return 0;
75022 nResult = pSelect->pEList->nExpr;
75023 pParse = pNC->pParse;
75024 for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
75025 Expr *pE = pItem->pExpr;
75026 iCol = resolveAsName(pParse, pSelect->pEList, pE);
75027 if( iCol>0 ){
75028 /* If an AS-name match is found, mark this ORDER BY column as being
75029 ** a copy of the iCol-th result-set column. The subsequent call to
75030 ** sqlite3ResolveOrderGroupBy() will convert the expression to a
75031 ** copy of the iCol-th result-set expression. */
75032 pItem->iOrderByCol = (u16)iCol;
75033 continue;
75034 }
75035 if( sqlite3ExprIsInteger(sqlite3ExprSkipCollate(pE), &iCol) ){
 
 
 
75036 /* The ORDER BY term is an integer constant. Again, set the column
75037 ** number so that sqlite3ResolveOrderGroupBy() will convert the
75038 ** order-by term to a copy of the result-set expression */
75039 if( iCol<1 || iCol>0xffff ){
75040 resolveOutOfRangeError(pParse, zType, i+1, nResult);
@@ -75173,23 +75181,21 @@
75173 if( p->pHaving && !pGroupBy ){
75174 sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
75175 return WRC_Abort;
75176 }
75177
75178 /* Add the expression list to the name-context before parsing the
75179 ** other expressions in the SELECT statement. This is so that
75180 ** expressions in the WHERE clause (etc.) can refer to expressions by
75181 ** aliases in the result set.
75182 **
75183 ** Minor point: If this is the case, then the expression will be
75184 ** re-evaluated for each reference to it.
75185 */
75186 sNC.pEList = p->pEList;
75187 sNC.ncFlags |= NC_AsMaybe;
75188 if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
75189 if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
75190 sNC.ncFlags &= ~NC_AsMaybe;
75191
75192 /* The ORDER BY and GROUP BY clauses may not refer to terms in
75193 ** outer queries
75194 */
75195 sNC.pNext = 0;
@@ -77134,19 +77140,21 @@
77134 assert( !isRowid );
77135 sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
77136 dest.affSdst = (u8)affinity;
77137 assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
77138 pExpr->x.pSelect->iLimit = 0;
 
77139 if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
77140 sqlite3DbFree(pParse->db, pKeyInfo);
77141 return 0;
77142 }
77143 pEList = pExpr->x.pSelect->pEList;
77144 if( pKeyInfo && ALWAYS(pEList!=0 && pEList->nExpr>0) ){
77145 pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
77146 pEList->a[0].pExpr);
77147 }
 
77148 }else if( ALWAYS(pExpr->x.pList!=0) ){
77149 /* Case 2: expr IN (exprlist)
77150 **
77151 ** For each expression, build an index key from the evaluation and
77152 ** store it in the temporary table. If <expr> is a column, then use
@@ -104711,11 +104719,11 @@
104711 # define WHERETRACE_ENABLED 1
104712 #else
104713 # define WHERETRACE(K,X)
104714 #endif
104715
104716 /* Forward reference
104717 */
104718 typedef struct WhereClause WhereClause;
104719 typedef struct WhereMaskSet WhereMaskSet;
104720 typedef struct WhereOrInfo WhereOrInfo;
104721 typedef struct WhereAndInfo WhereAndInfo;
@@ -104733,18 +104741,19 @@
104733 ** maximum cost for ordinary tables is 64*(2**63) which becomes 6900.
104734 ** (Virtual tables can return a larger cost, but let's assume they do not.)
104735 ** So all costs can be stored in a 16-bit unsigned integer without risk
104736 ** of overflow.
104737 **
104738 ** Costs are estimates, so don't go to the computational trouble to compute
104739 ** 10*log2(X) exactly. Instead, a close estimate is used. Any value of
104740 ** X<=1 is stored as 0. X=2 is 10. X=3 is 16. X=1000 is 99. etc.
104741 **
104742 ** The tool/wherecosttest.c source file implements a command-line program
104743 ** that will convert between WhereCost to integers and do addition and
104744 ** multiplication on WhereCost values. That command-line program is a
104745 ** useful utility to have around when working with this module.
 
104746 */
104747 typedef unsigned short int WhereCost;
104748
104749 /*
104750 ** This object contains information needed to implement a single nested
@@ -104843,12 +104852,12 @@
104843 WhereCost rRun; /* Cost of running this subquery */
104844 WhereCost nOut; /* Number of outputs for this subquery */
104845 };
104846
104847 /* The WhereOrSet object holds a set of possible WhereOrCosts that
104848 ** correspond to the subquery(s) of OR-clause processing. At most
104849 ** favorable N_OR_COST elements are retained.
104850 */
104851 #define N_OR_COST 3
104852 struct WhereOrSet {
104853 u16 n; /* Number of valid a[] entries */
104854 WhereOrCost a[N_OR_COST]; /* Set of best costs */
@@ -104910,13 +104919,13 @@
104910 **
104911 ** A WhereTerm might also be two or more subterms connected by OR:
104912 **
104913 ** (t1.X <op> <expr>) OR (t1.Y <op> <expr>) OR ....
104914 **
104915 ** In this second case, wtFlag as the TERM_ORINFO set and eOperator==WO_OR
104916 ** and the WhereTerm.u.pOrInfo field points to auxiliary information that
104917 ** is collected about the
104918 **
104919 ** If a term in the WHERE clause does not match either of the two previous
104920 ** categories, then eOperator==0. The WhereTerm.pExpr field is still set
104921 ** to the original subexpression content and wtFlags is set up appropriately
104922 ** but no other fields in the WhereTerm object are meaningful.
@@ -105424,11 +105433,11 @@
105424 assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
105425 pMaskSet->ix[pMaskSet->n++] = iCursor;
105426 }
105427
105428 /*
105429 ** These routine walk (recursively) an expression tree and generates
105430 ** a bitmask indicating which tables are used in that expression
105431 ** tree.
105432 */
105433 static Bitmask exprListTableUsage(WhereMaskSet*, ExprList*);
105434 static Bitmask exprSelectTableUsage(WhereMaskSet*, Select*);
@@ -105941,14 +105950,14 @@
105941 ** u.pAndInfo set to a dynamically allocated WhereAndTerm object.
105942 **
105943 ** From another point of view, "indexable" means that the subterm could
105944 ** potentially be used with an index if an appropriate index exists.
105945 ** This analysis does not consider whether or not the index exists; that
105946 ** is something the bestIndex() routine will determine. This analysis
105947 ** only looks at whether subterms appropriate for indexing exist.
105948 **
105949 ** All examples A through E above all satisfy case 2. But if a term
105950 ** also statisfies case 1 (such as B) we know that the optimizer will
105951 ** always prefer case 1, so in that case we pretend that case 2 is not
105952 ** satisfied.
105953 **
105954 ** It might be the case that multiple tables are indexable. For example,
@@ -106611,11 +106620,11 @@
106611
106612 return 0;
106613 }
106614
106615 /*
106616 ** The (an approximate) sum of two WhereCosts. This computation is
106617 ** not a simple "+" operator because WhereCost is stored as a logarithmic
106618 ** value.
106619 **
106620 */
106621 static WhereCost whereCostAdd(WhereCost a, WhereCost b){
@@ -115614,10 +115623,13 @@
115614 ** without blocking.
115615 */
115616 SQLITE_API int sqlite3_initialize(void){
115617 MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
115618 int rc; /* Result code */
 
 
 
115619
115620 #ifdef SQLITE_OMIT_WSD
115621 rc = sqlite3_wsd_init(4096, 24);
115622 if( rc!=SQLITE_OK ){
115623 return rc;
@@ -115711,10 +115723,13 @@
115711 }
115712 if( rc==SQLITE_OK ){
115713 sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
115714 sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
115715 sqlite3GlobalConfig.isInit = 1;
 
 
 
115716 }
115717 sqlite3GlobalConfig.inProgress = 0;
115718 }
115719 sqlite3_mutex_leave(sqlite3GlobalConfig.pInitMutex);
115720
@@ -115751,11 +115766,11 @@
115751
115752 /* Do extra initialization steps requested by the SQLITE_EXTRA_INIT
115753 ** compile-time option.
115754 */
115755 #ifdef SQLITE_EXTRA_INIT
115756 if( rc==SQLITE_OK && sqlite3GlobalConfig.isInit ){
115757 int SQLITE_EXTRA_INIT(const char*);
115758 rc = SQLITE_EXTRA_INIT(0);
115759 }
115760 #endif
115761
@@ -115939,12 +115954,12 @@
115939 ** run.
115940 */
115941 memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m));
115942 }else{
115943 /* The heap pointer is not NULL, then install one of the
115944 ** mem5.c/mem3.c methods. If neither ENABLE_MEMSYS3 nor
115945 ** ENABLE_MEMSYS5 is defined, return an error.
115946 */
115947 #ifdef SQLITE_ENABLE_MEMSYS3
115948 sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3();
115949 #endif
115950 #ifdef SQLITE_ENABLE_MEMSYS5
@@ -115959,11 +115974,11 @@
115959 sqlite3GlobalConfig.szLookaside = va_arg(ap, int);
115960 sqlite3GlobalConfig.nLookaside = va_arg(ap, int);
115961 break;
115962 }
115963
115964 /* Record a pointer to the logger funcction and its first argument.
115965 ** The default is NULL. Logging is disabled if the function pointer is
115966 ** NULL.
115967 */
115968 case SQLITE_CONFIG_LOG: {
115969 /* MSVC is picky about pulling func ptrs from va lists.
@@ -117675,24 +117690,24 @@
117675
117676 for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
117677 zFile = sqlite3_malloc(nByte);
117678 if( !zFile ) return SQLITE_NOMEM;
117679
 
 
117680 /* Discard the scheme and authority segments of the URI. */
117681 if( zUri[5]=='/' && zUri[6]=='/' ){
117682 iIn = 7;
117683 while( zUri[iIn] && zUri[iIn]!='/' ) iIn++;
117684
117685 if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){
117686 *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s",
117687 iIn-7, &zUri[7]);
117688 rc = SQLITE_ERROR;
117689 goto parse_uri_out;
117690 }
117691 }else{
117692 iIn = 5;
117693 }
 
117694
117695 /* Copy the filename and any query parameters into the zFile buffer.
117696 ** Decode %HH escape codes along the way.
117697 **
117698 ** Within this loop, variable eState may be set to 0, 1 or 2, depending
117699
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -656,11 +656,11 @@
656 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657 ** [sqlite_version()] and [sqlite_source_id()].
658 */
659 #define SQLITE_VERSION "3.8.0"
660 #define SQLITE_VERSION_NUMBER 3008000
661 #define SQLITE_SOURCE_ID "2013-08-15 22:40:21 f2d175f975cd0be63425424ec322a98fb650019e"
662
663 /*
664 ** CAPI3REF: Run-Time Library Version Numbers
665 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
666 **
@@ -7780,11 +7780,11 @@
7780 #endif
7781
7782 #if 0
7783 } /* End of the 'extern "C"' block */
7784 #endif
7785 #endif /* _SQLITE3_H_ */
7786
7787 /*
7788 ** 2010 August 30
7789 **
7790 ** The author disclaims copyright to this source code. In place of
@@ -11214,11 +11214,11 @@
11214 ** subqueries looking for a match.
11215 */
11216 struct NameContext {
11217 Parse *pParse; /* The parser */
11218 SrcList *pSrcList; /* One or more tables used to resolve names */
11219 ExprList *pEList; /* Optional list of result-set columns */
11220 AggInfo *pAggInfo; /* Information about aggregates at this level */
11221 NameContext *pNext; /* Next outer name context. NULL for outermost */
11222 int nRef; /* Number of names resolved by this context */
11223 int nErr; /* Number of errors encountered while resolving names */
11224 u8 ncFlags; /* Zero or more NC_* flags defined below */
@@ -11229,13 +11229,11 @@
11229 */
11230 #define NC_AllowAgg 0x01 /* Aggregate functions are allowed here */
11231 #define NC_HasAgg 0x02 /* One or more aggregate functions seen */
11232 #define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
11233 #define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
11234 #define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */
 
 
11235
11236 /*
11237 ** An instance of the following structure contains all information
11238 ** needed to generate code for a single SELECT statement.
11239 **
@@ -17231,17 +17229,17 @@
17229 u8 *aCtrl;
17230
17231 } mem5;
17232
17233 /*
17234 ** Access the static variable through a macro for SQLITE_OMIT_WSD.
17235 */
17236 #define mem5 GLOBAL(struct Mem5Global, mem5)
17237
17238 /*
17239 ** Assuming mem5.zPool is divided up into an array of Mem5Link
17240 ** structures, return a pointer to the idx-th such link.
17241 */
17242 #define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.szAtom]))
17243
17244 /*
17245 ** Unlink the chunk at mem5.aPool[i] from list it is currently
@@ -17333,11 +17331,11 @@
17331
17332 /*
17333 ** Return a block of memory of at least nBytes in size.
17334 ** Return NULL if unable. Return NULL if nBytes==0.
17335 **
17336 ** The caller guarantees that nByte is positive.
17337 **
17338 ** The caller has obtained a mutex prior to invoking this
17339 ** routine so there is never any chance that two or more
17340 ** threads can be in this routine at the same time.
17341 */
@@ -17455,11 +17453,11 @@
17453 }
17454 memsys5Link(iBlock, iLogsize);
17455 }
17456
17457 /*
17458 ** Allocate nBytes of memory.
17459 */
17460 static void *memsys5Malloc(int nBytes){
17461 sqlite3_int64 *p = 0;
17462 if( nBytes>0 ){
17463 memsys5Enter();
@@ -74041,22 +74039,23 @@
74039 **
74040 ** The reason for suppressing the TK_AS term when the expression is a simple
74041 ** column reference is so that the column reference will be recognized as
74042 ** usable by indices within the WHERE clause processing logic.
74043 **
74044 ** The TK_AS operator is inhibited if zType[0]=='G'. This means
74045 ** that in a GROUP BY clause, the expression is evaluated twice. Hence:
74046 **
74047 ** SELECT random()%5 AS x, count(*) FROM tab GROUP BY x
74048 **
74049 ** Is equivalent to:
74050 **
74051 ** SELECT random()%5 AS x, count(*) FROM tab GROUP BY random()%5
74052 **
74053 ** The result of random()%5 in the GROUP BY clause is probably different
74054 ** from the result in the result-set. On the other hand Standard SQL does
74055 ** not allow the GROUP BY clause to contain references to result-set columns.
74056 ** So this should never come up in well-formed queries.
74057 **
74058 ** If the reference is followed by a COLLATE operator, then make sure
74059 ** the COLLATE operator is preserved. For example:
74060 **
74061 ** SELECT a+b, c+d FROM t1 ORDER BY 1 COLLATE nocase;
@@ -74382,14 +74381,20 @@
74381 **
74382 ** In cases like this, replace pExpr with a copy of the expression that
74383 ** forms the result set entry ("a+b" in the example) and return immediately.
74384 ** Note that the expression in the result set should have already been
74385 ** resolved by the time the WHERE clause is resolved.
74386 **
74387 ** The ability to use an output result-set column in the WHERE, GROUP BY,
74388 ** or HAVING clauses, or as part of a larger expression in the ORDRE BY
74389 ** clause is not standard SQL. This is a (goofy) SQLite extension, that
74390 ** is supported for backwards compatibility only. TO DO: Issue a warning
74391 ** on sqlite3_log() whenever the capability is used.
74392 */
74393 if( (pEList = pNC->pEList)!=0
74394 && zTab==0
74395 && cnt==0
74396 ){
74397 for(j=0; j<pEList->nExpr; j++){
74398 char *zAs = pEList->a[j].zName;
74399 if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
74400 Expr *pOrig;
@@ -74947,11 +74952,11 @@
74952 }
74953
74954 /*
74955 ** Check every term in the ORDER BY or GROUP BY clause pOrderBy of
74956 ** the SELECT statement pSelect. If any term is reference to a
74957 ** result set expression (as determined by the ExprList.a.iOrderByCol field)
74958 ** then convert that term into a copy of the corresponding result set
74959 ** column.
74960 **
74961 ** If any errors are detected, add an error message to pParse and
74962 ** return non-zero. Return zero if no errors are seen.
@@ -74995,11 +75000,11 @@
75000 **
75001 ** This routine resolves each term of the clause into an expression.
75002 ** If the order-by term is an integer I between 1 and N (where N is the
75003 ** number of columns in the result set of the SELECT) then the expression
75004 ** in the resolution is a copy of the I-th result-set expression. If
75005 ** the order-by term is an identifier that corresponds to the AS-name of
75006 ** a result-set expression, then the term resolves to a copy of the
75007 ** result-set expression. Otherwise, the expression is resolved in
75008 ** the usual way - using sqlite3ResolveExprNames().
75009 **
75010 ** This routine returns the number of errors. If errors occur, then
@@ -75021,20 +75026,23 @@
75026 if( pOrderBy==0 ) return 0;
75027 nResult = pSelect->pEList->nExpr;
75028 pParse = pNC->pParse;
75029 for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
75030 Expr *pE = pItem->pExpr;
75031 Expr *pE2 = sqlite3ExprSkipCollate(pE);
75032 if( zType[0]!='G' ){
75033 iCol = resolveAsName(pParse, pSelect->pEList, pE2);
75034 if( iCol>0 ){
75035 /* If an AS-name match is found, mark this ORDER BY column as being
75036 ** a copy of the iCol-th result-set column. The subsequent call to
75037 ** sqlite3ResolveOrderGroupBy() will convert the expression to a
75038 ** copy of the iCol-th result-set expression. */
75039 pItem->iOrderByCol = (u16)iCol;
75040 continue;
75041 }
75042 }
75043 if( sqlite3ExprIsInteger(pE2, &iCol) ){
75044 /* The ORDER BY term is an integer constant. Again, set the column
75045 ** number so that sqlite3ResolveOrderGroupBy() will convert the
75046 ** order-by term to a copy of the result-set expression */
75047 if( iCol<1 || iCol>0xffff ){
75048 resolveOutOfRangeError(pParse, zType, i+1, nResult);
@@ -75173,23 +75181,21 @@
75181 if( p->pHaving && !pGroupBy ){
75182 sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
75183 return WRC_Abort;
75184 }
75185
75186 /* Add the output column list to the name-context before parsing the
75187 ** other expressions in the SELECT statement. This is so that
75188 ** expressions in the WHERE clause (etc.) can refer to expressions by
75189 ** aliases in the result set.
75190 **
75191 ** Minor point: If this is the case, then the expression will be
75192 ** re-evaluated for each reference to it.
75193 */
75194 sNC.pEList = p->pEList;
 
75195 if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
75196 if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
 
75197
75198 /* The ORDER BY and GROUP BY clauses may not refer to terms in
75199 ** outer queries
75200 */
75201 sNC.pNext = 0;
@@ -77134,19 +77140,21 @@
77140 assert( !isRowid );
77141 sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
77142 dest.affSdst = (u8)affinity;
77143 assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
77144 pExpr->x.pSelect->iLimit = 0;
77145 testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
77146 if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
77147 sqlite3DbFree(pParse->db, pKeyInfo);
77148 return 0;
77149 }
77150 pEList = pExpr->x.pSelect->pEList;
77151 assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
77152 assert( pEList!=0 );
77153 assert( pEList->nExpr>0 );
77154 pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
77155 pEList->a[0].pExpr);
77156 }else if( ALWAYS(pExpr->x.pList!=0) ){
77157 /* Case 2: expr IN (exprlist)
77158 **
77159 ** For each expression, build an index key from the evaluation and
77160 ** store it in the temporary table. If <expr> is a column, then use
@@ -104711,11 +104719,11 @@
104719 # define WHERETRACE_ENABLED 1
104720 #else
104721 # define WHERETRACE(K,X)
104722 #endif
104723
104724 /* Forward references
104725 */
104726 typedef struct WhereClause WhereClause;
104727 typedef struct WhereMaskSet WhereMaskSet;
104728 typedef struct WhereOrInfo WhereOrInfo;
104729 typedef struct WhereAndInfo WhereAndInfo;
@@ -104733,18 +104741,19 @@
104741 ** maximum cost for ordinary tables is 64*(2**63) which becomes 6900.
104742 ** (Virtual tables can return a larger cost, but let's assume they do not.)
104743 ** So all costs can be stored in a 16-bit unsigned integer without risk
104744 ** of overflow.
104745 **
104746 ** Costs are estimates, so no effort is made to compute 10*log2(X) exactly.
104747 ** Instead, a close estimate is used. Any value of X<=1 is stored as 0.
104748 ** X=2 is 10. X=3 is 16. X=1000 is 99. etc.
104749 **
104750 ** The tool/wherecosttest.c source file implements a command-line program
104751 ** that will convert WhereCosts to integers, convert integers to WhereCosts
104752 ** and do addition and multiplication on WhereCost values. The wherecosttest
104753 ** command-line program is a useful utility to have around when working with
104754 ** this module.
104755 */
104756 typedef unsigned short int WhereCost;
104757
104758 /*
104759 ** This object contains information needed to implement a single nested
@@ -104843,12 +104852,12 @@
104852 WhereCost rRun; /* Cost of running this subquery */
104853 WhereCost nOut; /* Number of outputs for this subquery */
104854 };
104855
104856 /* The WhereOrSet object holds a set of possible WhereOrCosts that
104857 ** correspond to the subquery(s) of OR-clause processing. Only the
104858 ** best N_OR_COST elements are retained.
104859 */
104860 #define N_OR_COST 3
104861 struct WhereOrSet {
104862 u16 n; /* Number of valid a[] entries */
104863 WhereOrCost a[N_OR_COST]; /* Set of best costs */
@@ -104910,13 +104919,13 @@
104919 **
104920 ** A WhereTerm might also be two or more subterms connected by OR:
104921 **
104922 ** (t1.X <op> <expr>) OR (t1.Y <op> <expr>) OR ....
104923 **
104924 ** In this second case, wtFlag has the TERM_ORINFO bit set and eOperator==WO_OR
104925 ** and the WhereTerm.u.pOrInfo field points to auxiliary information that
104926 ** is collected about the OR clause.
104927 **
104928 ** If a term in the WHERE clause does not match either of the two previous
104929 ** categories, then eOperator==0. The WhereTerm.pExpr field is still set
104930 ** to the original subexpression content and wtFlags is set up appropriately
104931 ** but no other fields in the WhereTerm object are meaningful.
@@ -105424,11 +105433,11 @@
105433 assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
105434 pMaskSet->ix[pMaskSet->n++] = iCursor;
105435 }
105436
105437 /*
105438 ** These routines walk (recursively) an expression tree and generate
105439 ** a bitmask indicating which tables are used in that expression
105440 ** tree.
105441 */
105442 static Bitmask exprListTableUsage(WhereMaskSet*, ExprList*);
105443 static Bitmask exprSelectTableUsage(WhereMaskSet*, Select*);
@@ -105941,14 +105950,14 @@
105950 ** u.pAndInfo set to a dynamically allocated WhereAndTerm object.
105951 **
105952 ** From another point of view, "indexable" means that the subterm could
105953 ** potentially be used with an index if an appropriate index exists.
105954 ** This analysis does not consider whether or not the index exists; that
105955 ** is decided elsewhere. This analysis only looks at whether subterms
105956 ** appropriate for indexing exist.
105957 **
105958 ** All examples A through E above satisfy case 2. But if a term
105959 ** also statisfies case 1 (such as B) we know that the optimizer will
105960 ** always prefer case 1, so in that case we pretend that case 2 is not
105961 ** satisfied.
105962 **
105963 ** It might be the case that multiple tables are indexable. For example,
@@ -106611,11 +106620,11 @@
106620
106621 return 0;
106622 }
106623
106624 /*
106625 ** Find (an approximate) sum of two WhereCosts. This computation is
106626 ** not a simple "+" operator because WhereCost is stored as a logarithmic
106627 ** value.
106628 **
106629 */
106630 static WhereCost whereCostAdd(WhereCost a, WhereCost b){
@@ -115614,10 +115623,13 @@
115623 ** without blocking.
115624 */
115625 SQLITE_API int sqlite3_initialize(void){
115626 MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
115627 int rc; /* Result code */
115628 #ifdef SQLITE_EXTRA_INIT
115629 int bRunExtraInit = 0; /* Extra initialization needed */
115630 #endif
115631
115632 #ifdef SQLITE_OMIT_WSD
115633 rc = sqlite3_wsd_init(4096, 24);
115634 if( rc!=SQLITE_OK ){
115635 return rc;
@@ -115711,10 +115723,13 @@
115723 }
115724 if( rc==SQLITE_OK ){
115725 sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
115726 sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
115727 sqlite3GlobalConfig.isInit = 1;
115728 #ifdef SQLITE_EXTRA_INIT
115729 bRunExtraInit = 1;
115730 #endif
115731 }
115732 sqlite3GlobalConfig.inProgress = 0;
115733 }
115734 sqlite3_mutex_leave(sqlite3GlobalConfig.pInitMutex);
115735
@@ -115751,11 +115766,11 @@
115766
115767 /* Do extra initialization steps requested by the SQLITE_EXTRA_INIT
115768 ** compile-time option.
115769 */
115770 #ifdef SQLITE_EXTRA_INIT
115771 if( bRunExtraInit ){
115772 int SQLITE_EXTRA_INIT(const char*);
115773 rc = SQLITE_EXTRA_INIT(0);
115774 }
115775 #endif
115776
@@ -115939,12 +115954,12 @@
115954 ** run.
115955 */
115956 memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m));
115957 }else{
115958 /* The heap pointer is not NULL, then install one of the
115959 ** mem5.c/mem3.c methods. The enclosing #if guarantees at
115960 ** least one of these methods is currently enabled.
115961 */
115962 #ifdef SQLITE_ENABLE_MEMSYS3
115963 sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3();
115964 #endif
115965 #ifdef SQLITE_ENABLE_MEMSYS5
@@ -115959,11 +115974,11 @@
115974 sqlite3GlobalConfig.szLookaside = va_arg(ap, int);
115975 sqlite3GlobalConfig.nLookaside = va_arg(ap, int);
115976 break;
115977 }
115978
115979 /* Record a pointer to the logger function and its first argument.
115980 ** The default is NULL. Logging is disabled if the function pointer is
115981 ** NULL.
115982 */
115983 case SQLITE_CONFIG_LOG: {
115984 /* MSVC is picky about pulling func ptrs from va lists.
@@ -117675,24 +117690,24 @@
117690
117691 for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
117692 zFile = sqlite3_malloc(nByte);
117693 if( !zFile ) return SQLITE_NOMEM;
117694
117695 iIn = 5;
117696 #ifndef SQLITE_ALLOW_URI_AUTHORITY
117697 /* Discard the scheme and authority segments of the URI. */
117698 if( zUri[5]=='/' && zUri[6]=='/' ){
117699 iIn = 7;
117700 while( zUri[iIn] && zUri[iIn]!='/' ) iIn++;
 
117701 if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){
117702 *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s",
117703 iIn-7, &zUri[7]);
117704 rc = SQLITE_ERROR;
117705 goto parse_uri_out;
117706 }
 
 
117707 }
117708 #endif
117709
117710 /* Copy the filename and any query parameters into the zFile buffer.
117711 ** Decode %HH escape codes along the way.
117712 **
117713 ** Within this loop, variable eState may be set to 0, 1 or 2, depending
117714
+2 -2
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.8.0"
111111
#define SQLITE_VERSION_NUMBER 3008000
112
-#define SQLITE_SOURCE_ID "2013-08-06 07:45:08 924f7e4d7a8fa2fe9100836663f3733b6e1a9084"
112
+#define SQLITE_SOURCE_ID "2013-08-15 22:40:21 f2d175f975cd0be63425424ec322a98fb650019e"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
@@ -7231,11 +7231,11 @@
72317231
#endif
72327232
72337233
#ifdef __cplusplus
72347234
} /* End of the 'extern "C"' block */
72357235
#endif
7236
-#endif
7236
+#endif /* _SQLITE3_H_ */
72377237
72387238
/*
72397239
** 2010 August 30
72407240
**
72417241
** The author disclaims copyright to this source code. In place of
72427242
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.0"
111 #define SQLITE_VERSION_NUMBER 3008000
112 #define SQLITE_SOURCE_ID "2013-08-06 07:45:08 924f7e4d7a8fa2fe9100836663f3733b6e1a9084"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -7231,11 +7231,11 @@
7231 #endif
7232
7233 #ifdef __cplusplus
7234 } /* End of the 'extern "C"' block */
7235 #endif
7236 #endif
7237
7238 /*
7239 ** 2010 August 30
7240 **
7241 ** The author disclaims copyright to this source code. In place of
7242
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.8.0"
111 #define SQLITE_VERSION_NUMBER 3008000
112 #define SQLITE_SOURCE_ID "2013-08-15 22:40:21 f2d175f975cd0be63425424ec322a98fb650019e"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -7231,11 +7231,11 @@
7231 #endif
7232
7233 #ifdef __cplusplus
7234 } /* End of the 'extern "C"' block */
7235 #endif
7236 #endif /* _SQLITE3_H_ */
7237
7238 /*
7239 ** 2010 August 30
7240 **
7241 ** The author disclaims copyright to this source code. In place of
7242
+14 -2
--- src/style.c
+++ src/style.c
@@ -112,11 +112,11 @@
112112
if( nHref>=nHrefAlloc ){
113113
nHrefAlloc = nHrefAlloc*2 + 10;
114114
aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
115115
}
116116
aHref[nHref++] = zUrl;
117
- return mprintf("<a %s id='a%d'>", zExtra, nHref);
117
+ return mprintf("<a %s id='a%d' href='%R/honeypot'>", zExtra, nHref);
118118
}
119119
char *href(const char *zFormat, ...){
120120
char *zUrl;
121121
va_list ap;
122122
va_start(ap, zFormat);
@@ -130,11 +130,11 @@
130130
if( nHref>=nHrefAlloc ){
131131
nHrefAlloc = nHrefAlloc*2 + 10;
132132
aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
133133
}
134134
aHref[nHref++] = zUrl;
135
- return mprintf("<a id='a%d'>", nHref);
135
+ return mprintf("<a id='a%d' href='%R/honeypot'>", nHref);
136136
}
137137
138138
/*
139139
** Generate <form method="post" action=ARG>. The ARG value is inserted
140140
** by javascript.
@@ -972,10 +972,11 @@
972972
@ margin-top: 3px;
973973
@ line-height: 100%;
974974
},
975975
{ "table.sbsdiffcols",
976976
"side-by-side diff display (column-based)",
977
+ @ width: 90%;
977978
@ border-spacing: 0;
978979
@ font-size: xx-small;
979980
},
980981
{ "table.sbsdiffcols td",
981982
"sbs diff table cell",
@@ -1176,10 +1177,11 @@
11761177
if( login_has_capability(&c, 1) ) zCap[i++] = c;
11771178
}
11781179
zCap[i] = 0;
11791180
@ g.userUid = %d(g.userUid)<br />
11801181
@ g.zLogin = %h(g.zLogin)<br />
1182
+ @ g.isHuman = %d(g.isHuman)<br />
11811183
@ capabilities = %s(zCap)<br />
11821184
@ <hr>
11831185
P("HTTP_USER_AGENT");
11841186
cgi_print_all(showAll);
11851187
if( showAll && blob_size(&g.httpHeader)>0 ){
@@ -1192,5 +1194,15 @@
11921194
const char *zRedir = P("redirect");
11931195
if( zRedir ) cgi_redirect(zRedir);
11941196
}
11951197
style_footer();
11961198
}
1199
+
1200
+/*
1201
+** This page is a honeypot for spiders and bots.
1202
+**
1203
+** WEBPAGE: honeypot
1204
+*/
1205
+void honeypot_page(void){
1206
+ cgi_set_status(403, "Forbidden");
1207
+ @ <p>Access by spiders and robots is forbidden</p>
1208
+}
11971209
--- src/style.c
+++ src/style.c
@@ -112,11 +112,11 @@
112 if( nHref>=nHrefAlloc ){
113 nHrefAlloc = nHrefAlloc*2 + 10;
114 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
115 }
116 aHref[nHref++] = zUrl;
117 return mprintf("<a %s id='a%d'>", zExtra, nHref);
118 }
119 char *href(const char *zFormat, ...){
120 char *zUrl;
121 va_list ap;
122 va_start(ap, zFormat);
@@ -130,11 +130,11 @@
130 if( nHref>=nHrefAlloc ){
131 nHrefAlloc = nHrefAlloc*2 + 10;
132 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
133 }
134 aHref[nHref++] = zUrl;
135 return mprintf("<a id='a%d'>", nHref);
136 }
137
138 /*
139 ** Generate <form method="post" action=ARG>. The ARG value is inserted
140 ** by javascript.
@@ -972,10 +972,11 @@
972 @ margin-top: 3px;
973 @ line-height: 100%;
974 },
975 { "table.sbsdiffcols",
976 "side-by-side diff display (column-based)",
 
977 @ border-spacing: 0;
978 @ font-size: xx-small;
979 },
980 { "table.sbsdiffcols td",
981 "sbs diff table cell",
@@ -1176,10 +1177,11 @@
1176 if( login_has_capability(&c, 1) ) zCap[i++] = c;
1177 }
1178 zCap[i] = 0;
1179 @ g.userUid = %d(g.userUid)<br />
1180 @ g.zLogin = %h(g.zLogin)<br />
 
1181 @ capabilities = %s(zCap)<br />
1182 @ <hr>
1183 P("HTTP_USER_AGENT");
1184 cgi_print_all(showAll);
1185 if( showAll && blob_size(&g.httpHeader)>0 ){
@@ -1192,5 +1194,15 @@
1192 const char *zRedir = P("redirect");
1193 if( zRedir ) cgi_redirect(zRedir);
1194 }
1195 style_footer();
1196 }
 
 
 
 
 
 
 
 
 
 
1197
--- src/style.c
+++ src/style.c
@@ -112,11 +112,11 @@
112 if( nHref>=nHrefAlloc ){
113 nHrefAlloc = nHrefAlloc*2 + 10;
114 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
115 }
116 aHref[nHref++] = zUrl;
117 return mprintf("<a %s id='a%d' href='%R/honeypot'>", zExtra, nHref);
118 }
119 char *href(const char *zFormat, ...){
120 char *zUrl;
121 va_list ap;
122 va_start(ap, zFormat);
@@ -130,11 +130,11 @@
130 if( nHref>=nHrefAlloc ){
131 nHrefAlloc = nHrefAlloc*2 + 10;
132 aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
133 }
134 aHref[nHref++] = zUrl;
135 return mprintf("<a id='a%d' href='%R/honeypot'>", nHref);
136 }
137
138 /*
139 ** Generate <form method="post" action=ARG>. The ARG value is inserted
140 ** by javascript.
@@ -972,10 +972,11 @@
972 @ margin-top: 3px;
973 @ line-height: 100%;
974 },
975 { "table.sbsdiffcols",
976 "side-by-side diff display (column-based)",
977 @ width: 90%;
978 @ border-spacing: 0;
979 @ font-size: xx-small;
980 },
981 { "table.sbsdiffcols td",
982 "sbs diff table cell",
@@ -1176,10 +1177,11 @@
1177 if( login_has_capability(&c, 1) ) zCap[i++] = c;
1178 }
1179 zCap[i] = 0;
1180 @ g.userUid = %d(g.userUid)<br />
1181 @ g.zLogin = %h(g.zLogin)<br />
1182 @ g.isHuman = %d(g.isHuman)<br />
1183 @ capabilities = %s(zCap)<br />
1184 @ <hr>
1185 P("HTTP_USER_AGENT");
1186 cgi_print_all(showAll);
1187 if( showAll && blob_size(&g.httpHeader)>0 ){
@@ -1192,5 +1194,15 @@
1194 const char *zRedir = P("redirect");
1195 if( zRedir ) cgi_redirect(zRedir);
1196 }
1197 style_footer();
1198 }
1199
1200 /*
1201 ** This page is a honeypot for spiders and bots.
1202 **
1203 ** WEBPAGE: honeypot
1204 */
1205 void honeypot_page(void){
1206 cgi_set_status(403, "Forbidden");
1207 @ <p>Access by spiders and robots is forbidden</p>
1208 }
1209
+9 -5
--- src/sync.c
+++ src/sync.c
@@ -154,10 +154,12 @@
154154
** Usage: %fossil pull ?URL? ?options?
155155
**
156156
** Pull changes from a remote repository into the local repository.
157157
** Use the "-R REPO" or "--repository REPO" command-line options
158158
** to specify an alternative repository file.
159
+**
160
+** See clone usage for possible URL formats.
159161
**
160162
** If the URL is not specified, then the URL from the most recent
161163
** clone, push, pull, remote-url, or sync command is used.
162164
**
163165
** The URL specified normally becomes the new "remote-url" used for
@@ -183,10 +185,12 @@
183185
** Usage: %fossil push ?URL? ?options?
184186
**
185187
** Push changes in the local repository over into a remote repository.
186188
** Use the "-R REPO" or "--repository REPO" command-line options
187189
** to specify an alternative repository file.
190
+**
191
+** See clone usage for possible URL formats.
188192
**
189193
** If the URL is not specified, then the URL from the most recent
190194
** clone, push, pull, remote-url, or sync command is used.
191195
**
192196
** The URL specified normally becomes the new "remote-url" used for
@@ -218,16 +222,14 @@
218222
** Synchronize the local repository with a remote repository. This is
219223
** the equivalent of running both "push" and "pull" at the same time.
220224
** Use the "-R REPO" or "--repository REPO" command-line options
221225
** to specify an alternative repository file.
222226
**
223
-** If a user-id and password are required, specify them as follows:
227
+** See clone usage for possible URL formats.
224228
**
225
-** http://userid:[email protected]:1234/path
226
-**
227
-** If the URL is not specified, then the URL from the most recent successful
228
-** clone, push, pull, remote-url, or sync command is used.
229
+** If the URL is not specified, then the URL from the most recent
230
+** successful clone, push, pull, remote-url, or sync command is used.
229231
**
230232
** The URL specified normally becomes the new "remote-url" used for
231233
** subsequent push, pull, and sync operations. However, the "--once"
232234
** command-line option makes the URL a one-time-use URL that is not
233235
** saved.
@@ -258,10 +260,12 @@
258260
**
259261
** The remote-url is set automatically by a "clone" command or by any
260262
** "sync", "push", or "pull" command that specifies an explicit URL.
261263
** The default remote-url is used by auto-syncing and by "sync", "push",
262264
** "pull" that omit the server URL.
265
+**
266
+** See clone usage for possible URL formats.
263267
**
264268
** See also: clone, push, pull, sync
265269
*/
266270
void remote_url_cmd(void){
267271
char *zUrl;
268272
--- src/sync.c
+++ src/sync.c
@@ -154,10 +154,12 @@
154 ** Usage: %fossil pull ?URL? ?options?
155 **
156 ** Pull changes from a remote repository into the local repository.
157 ** Use the "-R REPO" or "--repository REPO" command-line options
158 ** to specify an alternative repository file.
 
 
159 **
160 ** If the URL is not specified, then the URL from the most recent
161 ** clone, push, pull, remote-url, or sync command is used.
162 **
163 ** The URL specified normally becomes the new "remote-url" used for
@@ -183,10 +185,12 @@
183 ** Usage: %fossil push ?URL? ?options?
184 **
185 ** Push changes in the local repository over into a remote repository.
186 ** Use the "-R REPO" or "--repository REPO" command-line options
187 ** to specify an alternative repository file.
 
 
188 **
189 ** If the URL is not specified, then the URL from the most recent
190 ** clone, push, pull, remote-url, or sync command is used.
191 **
192 ** The URL specified normally becomes the new "remote-url" used for
@@ -218,16 +222,14 @@
218 ** Synchronize the local repository with a remote repository. This is
219 ** the equivalent of running both "push" and "pull" at the same time.
220 ** Use the "-R REPO" or "--repository REPO" command-line options
221 ** to specify an alternative repository file.
222 **
223 ** If a user-id and password are required, specify them as follows:
224 **
225 ** http://userid:[email protected]:1234/path
226 **
227 ** If the URL is not specified, then the URL from the most recent successful
228 ** clone, push, pull, remote-url, or sync command is used.
229 **
230 ** The URL specified normally becomes the new "remote-url" used for
231 ** subsequent push, pull, and sync operations. However, the "--once"
232 ** command-line option makes the URL a one-time-use URL that is not
233 ** saved.
@@ -258,10 +260,12 @@
258 **
259 ** The remote-url is set automatically by a "clone" command or by any
260 ** "sync", "push", or "pull" command that specifies an explicit URL.
261 ** The default remote-url is used by auto-syncing and by "sync", "push",
262 ** "pull" that omit the server URL.
 
 
263 **
264 ** See also: clone, push, pull, sync
265 */
266 void remote_url_cmd(void){
267 char *zUrl;
268
--- src/sync.c
+++ src/sync.c
@@ -154,10 +154,12 @@
154 ** Usage: %fossil pull ?URL? ?options?
155 **
156 ** Pull changes from a remote repository into the local repository.
157 ** Use the "-R REPO" or "--repository REPO" command-line options
158 ** to specify an alternative repository file.
159 **
160 ** See clone usage for possible URL formats.
161 **
162 ** If the URL is not specified, then the URL from the most recent
163 ** clone, push, pull, remote-url, or sync command is used.
164 **
165 ** The URL specified normally becomes the new "remote-url" used for
@@ -183,10 +185,12 @@
185 ** Usage: %fossil push ?URL? ?options?
186 **
187 ** Push changes in the local repository over into a remote repository.
188 ** Use the "-R REPO" or "--repository REPO" command-line options
189 ** to specify an alternative repository file.
190 **
191 ** See clone usage for possible URL formats.
192 **
193 ** If the URL is not specified, then the URL from the most recent
194 ** clone, push, pull, remote-url, or sync command is used.
195 **
196 ** The URL specified normally becomes the new "remote-url" used for
@@ -218,16 +222,14 @@
222 ** Synchronize the local repository with a remote repository. This is
223 ** the equivalent of running both "push" and "pull" at the same time.
224 ** Use the "-R REPO" or "--repository REPO" command-line options
225 ** to specify an alternative repository file.
226 **
227 ** See clone usage for possible URL formats.
228 **
229 ** If the URL is not specified, then the URL from the most recent
230 ** successful clone, push, pull, remote-url, or sync command is used.
 
 
231 **
232 ** The URL specified normally becomes the new "remote-url" used for
233 ** subsequent push, pull, and sync operations. However, the "--once"
234 ** command-line option makes the URL a one-time-use URL that is not
235 ** saved.
@@ -258,10 +260,12 @@
260 **
261 ** The remote-url is set automatically by a "clone" command or by any
262 ** "sync", "push", or "pull" command that specifies an explicit URL.
263 ** The default remote-url is used by auto-syncing and by "sync", "push",
264 ** "pull" that omit the server URL.
265 **
266 ** See clone usage for possible URL formats.
267 **
268 ** See also: clone, push, pull, sync
269 */
270 void remote_url_cmd(void){
271 char *zUrl;
272
+9 -5
--- src/sync.c
+++ src/sync.c
@@ -154,10 +154,12 @@
154154
** Usage: %fossil pull ?URL? ?options?
155155
**
156156
** Pull changes from a remote repository into the local repository.
157157
** Use the "-R REPO" or "--repository REPO" command-line options
158158
** to specify an alternative repository file.
159
+**
160
+** See clone usage for possible URL formats.
159161
**
160162
** If the URL is not specified, then the URL from the most recent
161163
** clone, push, pull, remote-url, or sync command is used.
162164
**
163165
** The URL specified normally becomes the new "remote-url" used for
@@ -183,10 +185,12 @@
183185
** Usage: %fossil push ?URL? ?options?
184186
**
185187
** Push changes in the local repository over into a remote repository.
186188
** Use the "-R REPO" or "--repository REPO" command-line options
187189
** to specify an alternative repository file.
190
+**
191
+** See clone usage for possible URL formats.
188192
**
189193
** If the URL is not specified, then the URL from the most recent
190194
** clone, push, pull, remote-url, or sync command is used.
191195
**
192196
** The URL specified normally becomes the new "remote-url" used for
@@ -218,16 +222,14 @@
218222
** Synchronize the local repository with a remote repository. This is
219223
** the equivalent of running both "push" and "pull" at the same time.
220224
** Use the "-R REPO" or "--repository REPO" command-line options
221225
** to specify an alternative repository file.
222226
**
223
-** If a user-id and password are required, specify them as follows:
227
+** See clone usage for possible URL formats.
224228
**
225
-** http://userid:[email protected]:1234/path
226
-**
227
-** If the URL is not specified, then the URL from the most recent successful
228
-** clone, push, pull, remote-url, or sync command is used.
229
+** If the URL is not specified, then the URL from the most recent
230
+** successful clone, push, pull, remote-url, or sync command is used.
229231
**
230232
** The URL specified normally becomes the new "remote-url" used for
231233
** subsequent push, pull, and sync operations. However, the "--once"
232234
** command-line option makes the URL a one-time-use URL that is not
233235
** saved.
@@ -258,10 +260,12 @@
258260
**
259261
** The remote-url is set automatically by a "clone" command or by any
260262
** "sync", "push", or "pull" command that specifies an explicit URL.
261263
** The default remote-url is used by auto-syncing and by "sync", "push",
262264
** "pull" that omit the server URL.
265
+**
266
+** See clone usage for possible URL formats.
263267
**
264268
** See also: clone, push, pull, sync
265269
*/
266270
void remote_url_cmd(void){
267271
char *zUrl;
268272
--- src/sync.c
+++ src/sync.c
@@ -154,10 +154,12 @@
154 ** Usage: %fossil pull ?URL? ?options?
155 **
156 ** Pull changes from a remote repository into the local repository.
157 ** Use the "-R REPO" or "--repository REPO" command-line options
158 ** to specify an alternative repository file.
 
 
159 **
160 ** If the URL is not specified, then the URL from the most recent
161 ** clone, push, pull, remote-url, or sync command is used.
162 **
163 ** The URL specified normally becomes the new "remote-url" used for
@@ -183,10 +185,12 @@
183 ** Usage: %fossil push ?URL? ?options?
184 **
185 ** Push changes in the local repository over into a remote repository.
186 ** Use the "-R REPO" or "--repository REPO" command-line options
187 ** to specify an alternative repository file.
 
 
188 **
189 ** If the URL is not specified, then the URL from the most recent
190 ** clone, push, pull, remote-url, or sync command is used.
191 **
192 ** The URL specified normally becomes the new "remote-url" used for
@@ -218,16 +222,14 @@
218 ** Synchronize the local repository with a remote repository. This is
219 ** the equivalent of running both "push" and "pull" at the same time.
220 ** Use the "-R REPO" or "--repository REPO" command-line options
221 ** to specify an alternative repository file.
222 **
223 ** If a user-id and password are required, specify them as follows:
224 **
225 ** http://userid:[email protected]:1234/path
226 **
227 ** If the URL is not specified, then the URL from the most recent successful
228 ** clone, push, pull, remote-url, or sync command is used.
229 **
230 ** The URL specified normally becomes the new "remote-url" used for
231 ** subsequent push, pull, and sync operations. However, the "--once"
232 ** command-line option makes the URL a one-time-use URL that is not
233 ** saved.
@@ -258,10 +260,12 @@
258 **
259 ** The remote-url is set automatically by a "clone" command or by any
260 ** "sync", "push", or "pull" command that specifies an explicit URL.
261 ** The default remote-url is used by auto-syncing and by "sync", "push",
262 ** "pull" that omit the server URL.
 
 
263 **
264 ** See also: clone, push, pull, sync
265 */
266 void remote_url_cmd(void){
267 char *zUrl;
268
--- src/sync.c
+++ src/sync.c
@@ -154,10 +154,12 @@
154 ** Usage: %fossil pull ?URL? ?options?
155 **
156 ** Pull changes from a remote repository into the local repository.
157 ** Use the "-R REPO" or "--repository REPO" command-line options
158 ** to specify an alternative repository file.
159 **
160 ** See clone usage for possible URL formats.
161 **
162 ** If the URL is not specified, then the URL from the most recent
163 ** clone, push, pull, remote-url, or sync command is used.
164 **
165 ** The URL specified normally becomes the new "remote-url" used for
@@ -183,10 +185,12 @@
185 ** Usage: %fossil push ?URL? ?options?
186 **
187 ** Push changes in the local repository over into a remote repository.
188 ** Use the "-R REPO" or "--repository REPO" command-line options
189 ** to specify an alternative repository file.
190 **
191 ** See clone usage for possible URL formats.
192 **
193 ** If the URL is not specified, then the URL from the most recent
194 ** clone, push, pull, remote-url, or sync command is used.
195 **
196 ** The URL specified normally becomes the new "remote-url" used for
@@ -218,16 +222,14 @@
222 ** Synchronize the local repository with a remote repository. This is
223 ** the equivalent of running both "push" and "pull" at the same time.
224 ** Use the "-R REPO" or "--repository REPO" command-line options
225 ** to specify an alternative repository file.
226 **
227 ** See clone usage for possible URL formats.
228 **
229 ** If the URL is not specified, then the URL from the most recent
230 ** successful clone, push, pull, remote-url, or sync command is used.
 
 
231 **
232 ** The URL specified normally becomes the new "remote-url" used for
233 ** subsequent push, pull, and sync operations. However, the "--once"
234 ** command-line option makes the URL a one-time-use URL that is not
235 ** saved.
@@ -258,10 +260,12 @@
260 **
261 ** The remote-url is set automatically by a "clone" command or by any
262 ** "sync", "push", or "pull" command that specifies an explicit URL.
263 ** The default remote-url is used by auto-syncing and by "sync", "push",
264 ** "pull" that omit the server URL.
265 **
266 ** See clone usage for possible URL formats.
267 **
268 ** See also: clone, push, pull, sync
269 */
270 void remote_url_cmd(void){
271 char *zUrl;
272
+21 -16
--- src/timeline.c
+++ src/timeline.c
@@ -649,10 +649,15 @@
649649
cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
650650
}
651651
cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
652652
graph_free(pGraph);
653653
@ var canvasDiv = gebi("canvas");
654
+ @ var canvasStyle = window.getComputedStyle(canvasDiv,null);
655
+ @ var lineColor = canvasStyle.getPropertyValue('color') || 'black';
656
+ @ var bgColor = canvasStyle.getPropertyValue('background-color') || 'white';
657
+ @ if( bgColor=='transparent' ) bgColor = 'white';
658
+ @ var boxColor = lineColor;
654659
@ function drawBox(color,x0,y0,x1,y1){
655660
@ var n = document.createElement("div");
656661
@ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
657662
@ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
658663
@ var w = x1-x0+1;
@@ -689,38 +694,38 @@
689694
@ }while( obj = obj.offsetParent );
690695
@ }
691696
@ return left;
692697
@ }
693698
@ function drawUpArrow(x,y0,y1){
694
- @ drawBox("black",x,y0,x+1,y1);
699
+ @ drawBox(lineColor,x,y0,x+1,y1);
695700
@ if( y0+10>=y1 ){
696
- @ drawBox("black",x-1,y0+1,x+2,y0+2);
697
- @ drawBox("black",x-2,y0+3,x+3,y0+4);
701
+ @ drawBox(lineColor,x-1,y0+1,x+2,y0+2);
702
+ @ drawBox(lineColor,x-2,y0+3,x+3,y0+4);
698703
@ }else{
699
- @ drawBox("black",x-1,y0+2,x+2,y0+4);
700
- @ drawBox("black",x-2,y0+5,x+3,y0+7);
704
+ @ drawBox(lineColor,x-1,y0+2,x+2,y0+4);
705
+ @ drawBox(lineColor,x-2,y0+5,x+3,y0+7);
701706
@ }
702707
@ }
703708
@ function drawThinArrow(y,xFrom,xTo){
704709
@ if( xFrom<xTo ){
705
- @ drawBox("black",xFrom,y,xTo,y);
706
- @ drawBox("black",xTo-3,y-1,xTo-2,y+1);
707
- @ drawBox("black",xTo-4,y-2,xTo-4,y+2);
710
+ @ drawBox(lineColor,xFrom,y,xTo,y);
711
+ @ drawBox(lineColor,xTo-3,y-1,xTo-2,y+1);
712
+ @ drawBox(lineColor,xTo-4,y-2,xTo-4,y+2);
708713
@ }else{
709
- @ drawBox("black",xTo,y,xFrom,y);
710
- @ drawBox("black",xTo+2,y-1,xTo+3,y+1);
711
- @ drawBox("black",xTo+4,y-2,xTo+4,y+2);
714
+ @ drawBox(lineColor,xTo,y,xFrom,y);
715
+ @ drawBox(lineColor,xTo+2,y-1,xTo+3,y+1);
716
+ @ drawBox(lineColor,xTo+4,y-2,xTo+4,y+2);
712717
@ }
713718
@ }
714719
@ function drawThinLine(x0,y0,x1,y1){
715
- @ drawBox("black",x0,y0,x1,y1);
720
+ @ drawBox(lineColor,x0,y0,x1,y1);
716721
@ }
717722
@ function drawNode(p, left, btm){
718
- @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
719
- @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
723
+ @ drawBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6);
724
+ @ drawBox(p.bg||bgColor,p.x-4,p.y-4,p.x+5,p.y+5);
720725
@ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
721
- @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
726
+ @ if( p.f&1 ) drawBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2);
722727
if( !omitDescenders ){
723728
@ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
724729
@ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
725730
}
726731
@ if( p.mo>0 ){
@@ -740,11 +745,11 @@
740745
@ for(var i=0; i<n; i+=2){
741746
@ var x1 = p.au[i]*railPitch + left;
742747
@ var x0 = x1>p.x ? p.x+7 : p.x-6;
743748
@ var u = rowinfo[p.au[i+1]-1];
744749
@ if(u.id<p.id){
745
- @ drawBox("black",x0,p.y,x1,p.y+1);
750
+ @ drawBox(lineColor,x0,p.y,x1,p.y+1);
746751
@ drawUpArrow(x1, u.y+6, p.y);
747752
@ }else{
748753
@ drawBox("#600000",x0,p.y,x1,p.y+1);
749754
@ drawBox("#600000",x1-1,p.y,x1,u.y+1);
750755
@ drawBox("#600000",x1,u.y,u.x-6,u.y+1);
751756
--- src/timeline.c
+++ src/timeline.c
@@ -649,10 +649,15 @@
649 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
650 }
651 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
652 graph_free(pGraph);
653 @ var canvasDiv = gebi("canvas");
 
 
 
 
 
654 @ function drawBox(color,x0,y0,x1,y1){
655 @ var n = document.createElement("div");
656 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
657 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
658 @ var w = x1-x0+1;
@@ -689,38 +694,38 @@
689 @ }while( obj = obj.offsetParent );
690 @ }
691 @ return left;
692 @ }
693 @ function drawUpArrow(x,y0,y1){
694 @ drawBox("black",x,y0,x+1,y1);
695 @ if( y0+10>=y1 ){
696 @ drawBox("black",x-1,y0+1,x+2,y0+2);
697 @ drawBox("black",x-2,y0+3,x+3,y0+4);
698 @ }else{
699 @ drawBox("black",x-1,y0+2,x+2,y0+4);
700 @ drawBox("black",x-2,y0+5,x+3,y0+7);
701 @ }
702 @ }
703 @ function drawThinArrow(y,xFrom,xTo){
704 @ if( xFrom<xTo ){
705 @ drawBox("black",xFrom,y,xTo,y);
706 @ drawBox("black",xTo-3,y-1,xTo-2,y+1);
707 @ drawBox("black",xTo-4,y-2,xTo-4,y+2);
708 @ }else{
709 @ drawBox("black",xTo,y,xFrom,y);
710 @ drawBox("black",xTo+2,y-1,xTo+3,y+1);
711 @ drawBox("black",xTo+4,y-2,xTo+4,y+2);
712 @ }
713 @ }
714 @ function drawThinLine(x0,y0,x1,y1){
715 @ drawBox("black",x0,y0,x1,y1);
716 @ }
717 @ function drawNode(p, left, btm){
718 @ drawBox("black",p.x-5,p.y-5,p.x+6,p.y+6);
719 @ drawBox(p.bg,p.x-4,p.y-4,p.x+5,p.y+5);
720 @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
721 @ if( p.f&1 ) drawBox("black",p.x-1,p.y-1,p.x+2,p.y+2);
722 if( !omitDescenders ){
723 @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
724 @ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
725 }
726 @ if( p.mo>0 ){
@@ -740,11 +745,11 @@
740 @ for(var i=0; i<n; i+=2){
741 @ var x1 = p.au[i]*railPitch + left;
742 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
743 @ var u = rowinfo[p.au[i+1]-1];
744 @ if(u.id<p.id){
745 @ drawBox("black",x0,p.y,x1,p.y+1);
746 @ drawUpArrow(x1, u.y+6, p.y);
747 @ }else{
748 @ drawBox("#600000",x0,p.y,x1,p.y+1);
749 @ drawBox("#600000",x1-1,p.y,x1,u.y+1);
750 @ drawBox("#600000",x1,u.y,u.x-6,u.y+1);
751
--- src/timeline.c
+++ src/timeline.c
@@ -649,10 +649,15 @@
649 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
650 }
651 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
652 graph_free(pGraph);
653 @ var canvasDiv = gebi("canvas");
654 @ var canvasStyle = window.getComputedStyle(canvasDiv,null);
655 @ var lineColor = canvasStyle.getPropertyValue('color') || 'black';
656 @ var bgColor = canvasStyle.getPropertyValue('background-color') || 'white';
657 @ if( bgColor=='transparent' ) bgColor = 'white';
658 @ var boxColor = lineColor;
659 @ function drawBox(color,x0,y0,x1,y1){
660 @ var n = document.createElement("div");
661 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
662 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
663 @ var w = x1-x0+1;
@@ -689,38 +694,38 @@
694 @ }while( obj = obj.offsetParent );
695 @ }
696 @ return left;
697 @ }
698 @ function drawUpArrow(x,y0,y1){
699 @ drawBox(lineColor,x,y0,x+1,y1);
700 @ if( y0+10>=y1 ){
701 @ drawBox(lineColor,x-1,y0+1,x+2,y0+2);
702 @ drawBox(lineColor,x-2,y0+3,x+3,y0+4);
703 @ }else{
704 @ drawBox(lineColor,x-1,y0+2,x+2,y0+4);
705 @ drawBox(lineColor,x-2,y0+5,x+3,y0+7);
706 @ }
707 @ }
708 @ function drawThinArrow(y,xFrom,xTo){
709 @ if( xFrom<xTo ){
710 @ drawBox(lineColor,xFrom,y,xTo,y);
711 @ drawBox(lineColor,xTo-3,y-1,xTo-2,y+1);
712 @ drawBox(lineColor,xTo-4,y-2,xTo-4,y+2);
713 @ }else{
714 @ drawBox(lineColor,xTo,y,xFrom,y);
715 @ drawBox(lineColor,xTo+2,y-1,xTo+3,y+1);
716 @ drawBox(lineColor,xTo+4,y-2,xTo+4,y+2);
717 @ }
718 @ }
719 @ function drawThinLine(x0,y0,x1,y1){
720 @ drawBox(lineColor,x0,y0,x1,y1);
721 @ }
722 @ function drawNode(p, left, btm){
723 @ drawBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6);
724 @ drawBox(p.bg||bgColor,p.x-4,p.y-4,p.x+5,p.y+5);
725 @ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
726 @ if( p.f&1 ) drawBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2);
727 if( !omitDescenders ){
728 @ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
729 @ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
730 }
731 @ if( p.mo>0 ){
@@ -740,11 +745,11 @@
745 @ for(var i=0; i<n; i+=2){
746 @ var x1 = p.au[i]*railPitch + left;
747 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
748 @ var u = rowinfo[p.au[i+1]-1];
749 @ if(u.id<p.id){
750 @ drawBox(lineColor,x0,p.y,x1,p.y+1);
751 @ drawUpArrow(x1, u.y+6, p.y);
752 @ }else{
753 @ drawBox("#600000",x0,p.y,x1,p.y+1);
754 @ drawBox("#600000",x1-1,p.y,x1,u.y+1);
755 @ drawBox("#600000",x1,u.y,u.x-6,u.y+1);
756
+76 -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,72 @@
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 zRequestFName[MAX_PATH];
143
+ char zReplyFName[MAX_PATH];
144
+ char zCmd[2000]; /* Command-line to process the request */
145
+ char zHdr[2000]; /* The SCGI request header */
146
+
147
+ sqlite3_snprintf(MAX_PATH, zRequestFName,
148
+ "%s_in%d.txt", zTempPrefix, p->id);
149
+ sqlite3_snprintf(MAX_PATH, zReplyFName,
150
+ "%s_out%d.txt", zTempPrefix, p->id);
151
+ out = fossil_fopen(zRequestFName, "wb");
152
+ if( out==0 ) goto end_request;
153
+ amt = 0;
154
+ got = recv(p->s, zHdr, sizeof(zHdr), 0);
155
+ if( got==SOCKET_ERROR ) goto end_request;
156
+ amt = fwrite(zHdr, 1, got, out);
157
+ nHdr = 0;
158
+ for(i=0; zHdr[i]>='0' && zHdr[i]<='9'; i++){
159
+ nHdr = 10*nHdr + zHdr[i] - '0';
160
+ }
161
+ wanted = nHdr + i + 1;
162
+ if( strcmp(zHdr+i+1, "CONTENT_LENGTH")==0 ){
163
+ wanted += atoi(zHdr+i+15);
164
+ }
165
+ while( wanted>amt ){
166
+ got = recv(p->s, zHdr, wanted<sizeof(zHdr) ? wanted : sizeof(zHdr), 0);
167
+ if( got<=0 ) break;
168
+ fwrite(zHdr, 1, got, out);
169
+ wanted += got;
170
+ }
171
+ fclose(out);
172
+ out = 0;
173
+ sqlite3_snprintf(sizeof(zCmd), zCmd,
174
+ "\"%s\" http \"%s\" %s %s %s --scgi --nossl%s",
175
+ g.nameOfExe, g.zRepositoryName, zRequestFName, zReplyFName,
176
+ inet_ntoa(p->addr.sin_addr), p->zOptions
177
+ );
178
+ fossil_system(zCmd);
179
+ in = fossil_fopen(zReplyFName, "rb");
180
+ if( in ){
181
+ while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
182
+ send(p->s, zHdr, got, 0);
183
+ }
184
+ }
185
+
186
+end_request:
187
+ if( out ) fclose(out);
188
+ if( in ) fclose(in);
189
+ closesocket(p->s);
190
+ file_delete(zRequestFName);
191
+ file_delete(zReplyFName);
192
+ free(p);
193
+}
194
+
133195
134196
/*
135197
** Start a listening socket and process incoming HTTP requests on
136198
** that socket.
137199
*/
@@ -206,11 +268,12 @@
206268
if( !GetTempPathW(MAX_PATH, zTmpPath) ){
207269
fossil_fatal("unable to get path to the temporary directory.");
208270
}
209271
zTempPrefix = mprintf("%sfossil_server_P%d_",
210272
fossil_unicode_to_utf8(zTmpPath), iPort);
211
- fossil_print("Listening for HTTP requests on TCP port %d\n", iPort);
273
+ fossil_print("Listening for %s requests on TCP port %d\n",
274
+ (flags&HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
212275
if( zBrowser ){
213276
zBrowser = mprintf(zBrowser, iPort);
214277
fossil_print("Launch webbrowser: %s\n", zBrowser);
215278
fossil_system(zBrowser);
216279
}
@@ -244,11 +307,15 @@
244307
p = fossil_malloc( sizeof(*p) );
245308
p->id = ++idCnt;
246309
p->s = client;
247310
p->addr = client_addr;
248311
p->zOptions = blob_str(&options);
249
- _beginthread(win32_process_one_http_request, 0, (void*)p);
312
+ if( flags & HTTP_SERVER_SCGI ){
313
+ _beginthread(win32_scgi_request, 0, (void*)p);
314
+ }else{
315
+ _beginthread(win32_http_request, 0, (void*)p);
316
+ }
250317
}
251318
closesocket(s);
252319
WSACleanup();
253320
}
254321
@@ -539,10 +606,14 @@
539606
**
540607
** Enables automatic login if the --localauth option is present
541608
** and the "localauth" setting is off and the connection is from
542609
** localhost.
543610
**
611
+** --scgi
612
+**
613
+** Create an SCGI server instead of an HTTP server
614
+**
544615
**
545616
** fossil winsrv delete ?SERVICE-NAME?
546617
**
547618
** Deletes a service. If the service is currently running, it will be
548619
** stopped first and then deleted.
@@ -592,10 +663,11 @@
592663
const char *zPort = find_option("port", "P", 1);
593664
const char *zNotFound = find_option("notfound", 0, 1);
594665
const char *zFileGlob = find_option("files", 0, 1);
595666
const char *zLocalAuth = find_option("localauth", 0, 0);
596667
const char *zRepository = find_option("repository", "R", 1);
668
+ int useSCGI = find_option("scgi", 0, 0)!=0;
597669
Blob binPath;
598670
599671
verify_all_options();
600672
if( g.argc==4 ){
601673
zSvcName = g.argv[3];
@@ -632,10 +704,11 @@
632704
db_close(0);
633705
/* Build the fully-qualified path to the service binary file. */
634706
blob_zero(&binPath);
635707
blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
636708
if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
709
+ if( useSCGI ) blob_appendf(&binPath, " --scgi");
637710
if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
638711
if( zFileGlob ) blob_appendf(&binPath, " --files-urlenc %T", zFileGlob);
639712
if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
640713
blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
641714
/* Create the service. */
642715
--- 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,72 @@
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 +268,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 +307,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 +606,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 +663,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 +704,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,72 @@
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 zRequestFName[MAX_PATH];
143 char zReplyFName[MAX_PATH];
144 char zCmd[2000]; /* Command-line to process the request */
145 char zHdr[2000]; /* The SCGI request header */
146
147 sqlite3_snprintf(MAX_PATH, zRequestFName,
148 "%s_in%d.txt", zTempPrefix, p->id);
149 sqlite3_snprintf(MAX_PATH, zReplyFName,
150 "%s_out%d.txt", zTempPrefix, p->id);
151 out = fossil_fopen(zRequestFName, "wb");
152 if( out==0 ) goto end_request;
153 amt = 0;
154 got = recv(p->s, zHdr, sizeof(zHdr), 0);
155 if( got==SOCKET_ERROR ) goto end_request;
156 amt = fwrite(zHdr, 1, got, out);
157 nHdr = 0;
158 for(i=0; zHdr[i]>='0' && zHdr[i]<='9'; i++){
159 nHdr = 10*nHdr + zHdr[i] - '0';
160 }
161 wanted = nHdr + i + 1;
162 if( strcmp(zHdr+i+1, "CONTENT_LENGTH")==0 ){
163 wanted += atoi(zHdr+i+15);
164 }
165 while( wanted>amt ){
166 got = recv(p->s, zHdr, wanted<sizeof(zHdr) ? wanted : sizeof(zHdr), 0);
167 if( got<=0 ) break;
168 fwrite(zHdr, 1, got, out);
169 wanted += got;
170 }
171 fclose(out);
172 out = 0;
173 sqlite3_snprintf(sizeof(zCmd), zCmd,
174 "\"%s\" http \"%s\" %s %s %s --scgi --nossl%s",
175 g.nameOfExe, g.zRepositoryName, zRequestFName, zReplyFName,
176 inet_ntoa(p->addr.sin_addr), p->zOptions
177 );
178 fossil_system(zCmd);
179 in = fossil_fopen(zReplyFName, "rb");
180 if( in ){
181 while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
182 send(p->s, zHdr, got, 0);
183 }
184 }
185
186 end_request:
187 if( out ) fclose(out);
188 if( in ) fclose(in);
189 closesocket(p->s);
190 file_delete(zRequestFName);
191 file_delete(zReplyFName);
192 free(p);
193 }
194
195
196 /*
197 ** Start a listening socket and process incoming HTTP requests on
198 ** that socket.
199 */
@@ -206,11 +268,12 @@
268 if( !GetTempPathW(MAX_PATH, zTmpPath) ){
269 fossil_fatal("unable to get path to the temporary directory.");
270 }
271 zTempPrefix = mprintf("%sfossil_server_P%d_",
272 fossil_unicode_to_utf8(zTmpPath), iPort);
273 fossil_print("Listening for %s requests on TCP port %d\n",
274 (flags&HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
275 if( zBrowser ){
276 zBrowser = mprintf(zBrowser, iPort);
277 fossil_print("Launch webbrowser: %s\n", zBrowser);
278 fossil_system(zBrowser);
279 }
@@ -244,11 +307,15 @@
307 p = fossil_malloc( sizeof(*p) );
308 p->id = ++idCnt;
309 p->s = client;
310 p->addr = client_addr;
311 p->zOptions = blob_str(&options);
312 if( flags & HTTP_SERVER_SCGI ){
313 _beginthread(win32_scgi_request, 0, (void*)p);
314 }else{
315 _beginthread(win32_http_request, 0, (void*)p);
316 }
317 }
318 closesocket(s);
319 WSACleanup();
320 }
321
@@ -539,10 +606,14 @@
606 **
607 ** Enables automatic login if the --localauth option is present
608 ** and the "localauth" setting is off and the connection is from
609 ** localhost.
610 **
611 ** --scgi
612 **
613 ** Create an SCGI server instead of an HTTP server
614 **
615 **
616 ** fossil winsrv delete ?SERVICE-NAME?
617 **
618 ** Deletes a service. If the service is currently running, it will be
619 ** stopped first and then deleted.
@@ -592,10 +663,11 @@
663 const char *zPort = find_option("port", "P", 1);
664 const char *zNotFound = find_option("notfound", 0, 1);
665 const char *zFileGlob = find_option("files", 0, 1);
666 const char *zLocalAuth = find_option("localauth", 0, 0);
667 const char *zRepository = find_option("repository", "R", 1);
668 int useSCGI = find_option("scgi", 0, 0)!=0;
669 Blob binPath;
670
671 verify_all_options();
672 if( g.argc==4 ){
673 zSvcName = g.argv[3];
@@ -632,10 +704,11 @@
704 db_close(0);
705 /* Build the fully-qualified path to the service binary file. */
706 blob_zero(&binPath);
707 blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
708 if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
709 if( useSCGI ) blob_appendf(&binPath, " --scgi");
710 if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
711 if( zFileGlob ) blob_appendf(&binPath, " --files-urlenc %T", zFileGlob);
712 if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
713 blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
714 /* Create the service. */
715
--- www/adding_code.wiki
+++ www/adding_code.wiki
@@ -156,11 +156,11 @@
156156
157157
Once you have the command running, you can then start adding code to
158158
make it do useful things. There are lots of utility functions in
159159
Fossil for parsing command-line options and for
160160
opening and accessing and manipulating the repository and
161
-the working check-out. Study at the implementations of existing commands
161
+the working check-out. Study implementations of existing commands
162162
to get an idea of how things are done. You can easily find the implementations
163163
of existing commands by searching for "COMMAND: <i>name</i>" in the
164164
files of the "src/" directory.
165165
166166
<h2>5.0 Creating A New Web Page</h2>
167167
--- www/adding_code.wiki
+++ www/adding_code.wiki
@@ -156,11 +156,11 @@
156
157 Once you have the command running, you can then start adding code to
158 make it do useful things. There are lots of utility functions in
159 Fossil for parsing command-line options and for
160 opening and accessing and manipulating the repository and
161 the working check-out. Study at the implementations of existing commands
162 to get an idea of how things are done. You can easily find the implementations
163 of existing commands by searching for "COMMAND: <i>name</i>" in the
164 files of the "src/" directory.
165
166 <h2>5.0 Creating A New Web Page</h2>
167
--- www/adding_code.wiki
+++ www/adding_code.wiki
@@ -156,11 +156,11 @@
156
157 Once you have the command running, you can then start adding code to
158 make it do useful things. There are lots of utility functions in
159 Fossil for parsing command-line options and for
160 opening and accessing and manipulating the repository and
161 the working check-out. Study implementations of existing commands
162 to get an idea of how things are done. You can easily find the implementations
163 of existing commands by searching for "COMMAND: <i>name</i>" in the
164 files of the "src/" directory.
165
166 <h2>5.0 Creating A New Web Page</h2>
167
--- www/embeddeddoc.wiki
+++ www/embeddeddoc.wiki
@@ -103,12 +103,12 @@
103103
<blockquote><pre>
104104
#!/usr/bin/fossil
105105
repository: /fossil/fossil.fossil
106106
</pre></blockquote>
107107
108
-This is one of three ways to set up a
109
-<a href="quickstart.wiki#serversetup">fossil web server</a>.
108
+This is one of four ways to set up a
109
+<a href="./server.wiki">fossil web server</a>.
110110
111111
The "<b>/trunk/</b>" part of the URL tells fossil to use
112112
the documentation files from the most recent trunk check-in.
113113
If you wanted to see an historical version of this document,
114114
you could substitute the name of a check-in for "<b>/trunk/</b>".
115115
--- www/embeddeddoc.wiki
+++ www/embeddeddoc.wiki
@@ -103,12 +103,12 @@
103 <blockquote><pre>
104 #!/usr/bin/fossil
105 repository: /fossil/fossil.fossil
106 </pre></blockquote>
107
108 This is one of three ways to set up a
109 <a href="quickstart.wiki#serversetup">fossil web server</a>.
110
111 The "<b>/trunk/</b>" part of the URL tells fossil to use
112 the documentation files from the most recent trunk check-in.
113 If you wanted to see an historical version of this document,
114 you could substitute the name of a check-in for "<b>/trunk/</b>".
115
--- www/embeddeddoc.wiki
+++ www/embeddeddoc.wiki
@@ -103,12 +103,12 @@
103 <blockquote><pre>
104 #!/usr/bin/fossil
105 repository: /fossil/fossil.fossil
106 </pre></blockquote>
107
108 This is one of four ways to set up a
109 <a href="./server.wiki">fossil web server</a>.
110
111 The "<b>/trunk/</b>" part of the URL tells fossil to use
112 the documentation files from the most recent trunk check-in.
113 If you wanted to see an historical version of this document,
114 you could substitute the name of a check-in for "<b>/trunk/</b>".
115
+127 -84
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -46,11 +46,11 @@
4646
<li> [#tktchng | Ticket Changes] </li>
4747
<li> [#attachment | Attachments] </li>
4848
<li> [#event | Events] </li>
4949
</ul>
5050
51
-These seven artifact types are described in the sequel.
51
+These seven artifact types are described in the following sections.
5252
5353
In the current implementation (as of 2009-01-25) the artifacts that
5454
make up a fossil repository are stored in in as delta- and zlib-compressed
5555
blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
5656
is an implementation detail and might change in a future release. For
@@ -98,16 +98,16 @@
9898
9999
<blockquote>
100100
<b>B</b> <i>baseline-manifest</i><br>
101101
<b>C</b> <i>checkin-comment</i><br>
102102
<b>D</b> <i>time-and-date-stamp</i><br>
103
-<b>F</b> <i>filename</i> <i>SHA1-hash</i> <i>permissions</i> <i>old-name</i><br>
103
+<b>F</b> <i>filename</i> ?<i>SHA1-hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br>
104104
<b>N</b> <i>mimetype</i><br>
105105
<b>P</b> <i>SHA1-hash</i>+<br>
106
-<b>Q</b> (<b>+</b>|<b>-</b>)<i>SHA1-hash ?SHA1-hash?</i><br>
106
+<b>Q</b> (<b>+</b>|<b>-</b>)<i>SHA1-hash</i> ?<i>SHA1-hash</i>?<br>
107107
<b>R</b> <i>repository-checksum</i><br>
108
-<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name <b>*</b> ?value?</i><br>
108
+<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br>
109109
<b>U</b> <i>user-login</i><br>
110110
<b>Z</b> <i>manifest-checksum</i>
111111
</blockquote>
112112
113113
A manifest may optionally have a single B-card. The B-card specifies
@@ -291,11 +291,11 @@
291291
292292
Allowed cards in a control artifact are as follows:
293293
294294
<blockquote>
295295
<b>D</b> <i>time-and-date-stamp</i><br />
296
-<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name artifact-id ?value?</i><br />
296
+<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <i>artifact-id</i> ?<i>value</i>?<br />
297297
<b>U</b> <i>user-name</i><br />
298298
<b>Z</b> <i>checksum</i><br />
299299
</blockquote>
300300
301301
A control artifact must have one D card, one U card, one Z card and
@@ -475,11 +475,11 @@
475475
<b>C</b> <i>comment</i><br>
476476
<b>D</b> <i>time-and-date-stamp</i><br />
477477
<b>E</b> <i>event-time</i> <i>event-id</i><br />
478478
<b>N</b> <i>mimetype</i><br />
479479
<b>P</b> <i>parent-artifact-id</i>+<br />
480
-<b>T</b> <b>+</b><i>tag-name</i> <b>*</b> <i>value</i><br />
480
+<b>T</b> <b>+</b><i>tag-name</i> <b>*</b> ?<i>value</i>?<br />
481481
<b>U</b> <i>user-name</i><br />
482482
<b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br />
483483
<b>Z</b> <i>checksum</i>
484484
</blockquote>
485485
@@ -499,11 +499,11 @@
499499
The optional N card specifies the mimetype of the text of the event
500500
that is contained in the W card. If the N card is omitted, then the
501501
W card text mimetype is assumed to be text/x-fossil, which is the
502502
Fossil wiki format.
503503
504
-The option P card specifies a prior event with the same event-id from
504
+The optional P card specifies a prior event with the same event-id from
505505
which the current event is an edit. The P card is a hint to the system
506506
that it might be space efficient to store one event as a delta of the
507507
other.
508508
509509
An event might contain one or more T-cards used to set
@@ -531,12 +531,16 @@
531531
532532
533533
<a name="summary"></a>
534534
<h2>8.0 Card Summary</h2>
535535
536
-The following table summaries the various kinds of cards that
537
-appear on Fossil artifacts:
536
+The following table summarizes the various kinds of cards that appear
537
+on Fossil artifacts. A blank entry means that combination of card and
538
+artifact is not legal. A number or range of numbers indicates the number
539
+of times a card may (or must) appear in the corresponding artifact type.
540
+e.g. a value of 1 indicates a required unique card and 1+ indicates that one
541
+or more such cards are required.
538542
539543
<table border=1 width="100%">
540544
<tr>
541545
<th rowspan=2 valign=bottom>Card Format</th>
542546
<th colspan=7>Used By</th>
@@ -549,184 +553,223 @@
549553
<th>Ticket</th>
550554
<th>Attachment</th>
551555
<th>Event</th>
552556
</tr>
553557
<tr>
554
-<td><b>A</b> <i>filename target source</i></td>
555
-<td>&nbsp;</td>
556
-<td>&nbsp;</td>
557
-<td>&nbsp;</td>
558
-<td>&nbsp;</td>
559
-<td>&nbsp;</td>
560
-<td align=center><b>X</b></td>
561
-<td>&nbsp;</td>
562
-</tr>
563
-<tr>
564
-<td><b>B</b> <i>baseline</i></td>
565
-<td align=center><b>X</b></td>
566
-<td>&nbsp;</td>
567
-<td>&nbsp;</td>
568
-<td>&nbsp;</td>
569
-<td>&nbsp;</td>
570
-<td>&nbsp;</td>
571
-<td>&nbsp;</td>
572
-</tr>
573
-<tr>
574
-<td><b>C</b> <i>comment-text</i></td>
575
-<td align=center><b>X</b></td>
576
-<td>&nbsp;</td>
577
-<td>&nbsp;</td>
578
-<td>&nbsp;</td>
579
-<td>&nbsp;</td>
580
-<td align=center><b>X</b></td>
581
-<td align=center><b>X</b></td>
582
-</tr>
583
-<tr>
584
-<td><b>D</b> <i>date-time-stamp</i></td>
585
-<td align=center><b>X</b></td>
586
-<td align=center>&nbsp;</td>
587
-<td align=center><b>X</b></td>
588
-<td align=center><b>X</b></td>
589
-<td align=center><b>X</b></td>
590
-<td align=center><b>X</b></td>
591
-<td align=center><b>X</b></td>
558
+<td><b>A</b> <i>filename</i> <i>target</i> ?<i>source</i>?</td>
559
+<td>&nbsp;</td>
560
+<td>&nbsp;</td>
561
+<td>&nbsp;</td>
562
+<td>&nbsp;</td>
563
+<td>&nbsp;</td>
564
+<td align=center><b>1</b></td>
565
+<td>&nbsp;</td>
566
+</tr>
567
+<tr>
568
+<td><b>B</b> <i>baseline</i></td>
569
+<td align=center><b>0-1*</b></td>
570
+<td>&nbsp;</td>
571
+<td>&nbsp;</td>
572
+<td>&nbsp;</td>
573
+<td>&nbsp;</td>
574
+<td>&nbsp;</td>
575
+<td>&nbsp;</td>
576
+</tr>
577
+<tr><td>&nbsp;</td><td colspan='7'>* = Required for delta manifests</td></tr>
578
+<tr>
579
+<td><b>C</b> <i>comment-text</i></td>
580
+<td align=center><b>1</b></td>
581
+<td>&nbsp;</td>
582
+<td>&nbsp;</td>
583
+<td>&nbsp;</td>
584
+<td>&nbsp;</td>
585
+<td align=center><b>0-1</b></td>
586
+<td align=center><b>1</b></td>
587
+</tr>
588
+<tr>
589
+<td><b>D</b> <i>date-time-stamp</i></td>
590
+<td align=center><b>1</b></td>
591
+<td align=center>&nbsp;</td>
592
+<td align=center><b>1</b></td>
593
+<td align=center><b>1</b></td>
594
+<td align=center><b>1</b></td>
595
+<td align=center><b>1</b></td>
596
+<td align=center><b>1</b></td>
592597
</tr>
593598
<tr>
594599
<td><b>E</b> <i>event-time event-id</i></td>
595600
<td align=center>&nbsp;</td>
596601
<td align=center>&nbsp;</td>
597602
<td align=center>&nbsp;</td>
598603
<td align=center>&nbsp;</td>
599604
<td align=center>&nbsp;</td>
600605
<td align=center>&nbsp;</td>
601
-<td align=center><b>X</b></td>
606
+<td align=center><b>1</b></td>
602607
</tr>
603608
<tr>
604
-<td><b>F</b> <i>filename uuid permissions oldname</i></td>
605
-<td align=center><b>X</b></td>
609
+<td><b>F</b> <i>filename</i> ?<i>uuid</i>? ?<i>permissions</i>? ?<i>oldname</i>?</td>
610
+<td align=center><b>0+</b></td>
606611
<td align=center>&nbsp;</td>
607612
<td align=center>&nbsp;</td>
608613
<td align=center>&nbsp;</td>
609614
<td align=center>&nbsp;</td>
610615
<td align=center>&nbsp;</td>
611616
<td align=center>&nbsp;</td>
612617
</tr>
613618
<tr>
614
-<td><b>J</b> <i>name value</i></td>
619
+<td><b>J</b> <i>name</i> ?<i>value</i>?</td>
615620
<td align=center>&nbsp;</td>
616621
<td align=center>&nbsp;</td>
617622
<td align=center>&nbsp;</td>
618623
<td align=center>&nbsp;</td>
619
-<td align=center><b>X</b></td>
624
+<td align=center><b>1+</b></td>
620625
<td align=center>&nbsp;</td>
621626
<td align=center>&nbsp;</td>
622627
</tr>
623628
<tr>
624629
<td><b>K</b> <i>ticket-uuid</i></td>
625630
<td align=center>&nbsp;</td>
626631
<td align=center>&nbsp;</td>
627632
<td align=center>&nbsp;</td>
628633
<td align=center>&nbsp;</td>
629
-<td align=center><b>X</b></td>
634
+<td align=center><b>1</b></td>
630635
<td align=center>&nbsp;</td>
631636
<td align=center>&nbsp;</td>
632637
</tr>
633638
<tr>
634639
<td><b>L</b> <i>wiki-title</i></td>
635640
<td align=center>&nbsp;</td>
636641
<td align=center>&nbsp;</td>
637642
<td align=center>&nbsp;</td>
638
-<td align=center><b>X</b></td>
643
+<td align=center><b>1</b></td>
639644
<td align=center>&nbsp;</td>
640645
<td align=center>&nbsp;</td>
641646
<td align=center>&nbsp;</td>
642647
</tr>
643648
<tr>
644649
<td><b>M</b> <i>uuid</i></td>
645650
<td align=center>&nbsp;</td>
646
-<td align=center><b>X</b></td>
651
+<td align=center><b>1+</b></td>
647652
<td align=center>&nbsp;</td>
648653
<td align=center>&nbsp;</td>
649654
<td align=center>&nbsp;</td>
650655
<td align=center>&nbsp;</td>
651656
<td align=center>&nbsp;</td>
652657
</tr>
653658
<tr>
654659
<td><b>N</b> <i>mimetype</i></td>
655
-<td align=center><b>X</b></td>
660
+<td align=center><b>0-1</b></td>
656661
<td align=center>&nbsp;</td>
657662
<td align=center>&nbsp;</td>
658
-<td align=center><b>X</b></td>
663
+<td align=center><b>0-1</b></td>
659664
<td align=center>&nbsp;</td>
660
-<td align=center><b>X</b></td>
661
-<td align=center><b>X</b></td>
665
+<td align=center><b>0-1</b></td>
666
+<td align=center><b>0-1</b></td>
662667
</tr>
663668
<tr>
664669
<td><b>P</b> <i>uuid ...</i></td>
665
-<td align=center><b>X</b></td>
670
+<td align=center><b>0-1</b></td>
666671
<td align=center>&nbsp;</td>
667672
<td align=center>&nbsp;</td>
668
-<td align=center><b>X</b></td>
673
+<td align=center><b>0-1</b></td>
669674
<td align=center>&nbsp;</td>
670675
<td align=center>&nbsp;</td>
671
-<td align=center>&nbsp;</td>
676
+<td align=center><b>0-1</b></td>
672677
</tr>
673678
<tr>
674
-<td><b>Q</b> (<b>+</b>|<b>-</b>)<i>uuid uuid</i></td>
675
-<td align=center><b>X</b></td>
679
+<td><b>Q</b> (<b>+</b>|<b>-</b>)<i>uuid</i> ?<i>uuid</i>?</td>
680
+<td align=center><b>0+</b></td>
676681
<td align=center>&nbsp;</td>
677682
<td align=center>&nbsp;</td>
678683
<td align=center>&nbsp;</td>
679684
<td align=center>&nbsp;</td>
680685
<td align=center>&nbsp;</td>
681686
<td align=center>&nbsp;</td>
682687
</tr>
683688
<tr>
684689
<td><b>R</b> <i>md5sum</i></td>
685
-<td align=center><b>X</b></td>
690
+<td align=center><b>0-1*</b></td>
686691
<td align=center>&nbsp;</td>
687692
<td align=center>&nbsp;</td>
688693
<td align=center>&nbsp;</td>
689694
<td align=center>&nbsp;</td>
690695
<td align=center>&nbsp;</td>
691696
<td align=center>&nbsp;</td>
697
+<tr><td>&nbsp;</td><td colspan='7'>* = Required when using F cards</td></tr>
692698
<tr>
693
-<td><b>T</b> (<b>+</b>|<b>*</b>|<b>-</b>)<i>tagname uuid value</i></td>
694
-<td align=center><b>X</b></td>
699
+<td><b>T</b> (<b>+</b>|<b>*</b>|<b>-</b>)<i>tagname</i> <i>uuid</i> ?<i>value</i>?</td>
700
+<td align=center><b>0+</b></td>
695701
<td align=center>&nbsp;</td>
696
-<td align=center><b>X</b></td>
702
+<td align=center><b>1+</b></td>
697703
<td align=center>&nbsp;</td>
698704
<td align=center>&nbsp;</td>
699705
<td align=center>&nbsp;</td>
700
-<td align=center><b>X</b></td>
706
+<td align=center><b>0+</b></td>
701707
</tr>
702708
<tr>
703709
<td><b>U</b> <i>username</i></td>
704
-<td align=center><b>X</b></td>
710
+<td align=center><b>1</b></td>
705711
<td align=center>&nbsp;</td>
706
-<td align=center><b>X</b></td>
707
-<td align=center><b>X</b></td>
708
-<td align=center><b>X</b></td>
709
-<td align=center><b>X</b></td>
710
-<td align=center><b>X</b></td>
712
+<td align=center><b>1</b></td>
713
+<td align=center><b>1</b></td>
714
+<td align=center><b>1</b></td>
715
+<td align=center><b>0-1</b></td>
716
+<td align=center><b>0-1</b></td>
711717
</tr>
712718
<tr>
713719
<td><b>W</b> <i>size</i></td>
714720
<td align=center>&nbsp;</td>
715721
<td align=center>&nbsp;</td>
716722
<td align=center>&nbsp;</td>
717
-<td align=center><b>X</b></td>
723
+<td align=center><b>1</b></td>
718724
<td align=center>&nbsp;</td>
719725
<td align=center>&nbsp;</td>
720
-<td align=center><b>X</b></td>
726
+<td align=center><b>1</b></td>
721727
</tr>
722728
<tr>
723729
<td><b>Z</b> <i>md5sum</i></td>
724
-<td align=center><b>X</b></td>
725
-<td align=center><b>X</b></td>
726
-<td align=center><b>X</b></td>
727
-<td align=center><b>X</b></td>
728
-<td align=center><b>X</b></td>
729
-<td align=center><b>X</b></td>
730
-<td align=center><b>X</b></td>
730
+<td align=center><b>1</b></td>
731
+<td align=center><b>1</b></td>
732
+<td align=center><b>1</b></td>
733
+<td align=center><b>1</b></td>
734
+<td align=center><b>1</b></td>
735
+<td align=center><b>1</b></td>
736
+<td align=center><b>1</b></td>
731737
</tr>
732738
</table>
739
+
740
+
741
+<a name="addenda"></a>
742
+<h2>9.0 Addenda</h2>
743
+
744
+This section contains additional information which may be useful when
745
+implementing algorithms described above.
746
+
747
+<h3>R Card Hash Calculation</h3>
748
+
749
+Given a manifest file named <tt>MF</tt>, the following Bash shell code
750
+demonstrates how to compute the value of the R card in that manifest.
751
+This example uses manifest [28987096ac]. Lines starting with <tt>#</tt> are
752
+shell input and other lines are output. This demonstration assumes that the
753
+file versions represented by the input manifest are checked out
754
+under the current directory.
755
+
756
+<nowiki><pre>
757
+# head MF
758
+-----BEGIN PGP SIGNED MESSAGE-----
759
+Hash: SHA1
760
+
761
+C Make\sthe\s"clearsign"\sPGP\ssigning\sdefault\sto\soff.
762
+D 2010-02-23T15:33:14
763
+F BUILD.txt 4f7988767e4e48b29f7eddd0e2cdea4555b9161c
764
+F COPYRIGHT-GPL2.txt 06877624ea5c77efe3b7e39b0f909eda6e25a4ec
765
+...
766
+
767
+# grep '^R ' MF
768
+R c0788982781981c96a0d81465fec7192
769
+
770
+# for i in $(awk '/^F /{print $2}' MF); do \
771
+ echo $i $(stat -c '%s' $i); \
772
+ cat $i; \
773
+done | md5sum
774
+c0788982781981c96a0d81465fec7192 -
775
+</pre></nowiki>
733776
734777
ADDED www/hacker-howto.wiki
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -46,11 +46,11 @@
46 <li> [#tktchng | Ticket Changes] </li>
47 <li> [#attachment | Attachments] </li>
48 <li> [#event | Events] </li>
49 </ul>
50
51 These seven artifact types are described in the sequel.
52
53 In the current implementation (as of 2009-01-25) the artifacts that
54 make up a fossil repository are stored in in as delta- and zlib-compressed
55 blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
56 is an implementation detail and might change in a future release. For
@@ -98,16 +98,16 @@
98
99 <blockquote>
100 <b>B</b> <i>baseline-manifest</i><br>
101 <b>C</b> <i>checkin-comment</i><br>
102 <b>D</b> <i>time-and-date-stamp</i><br>
103 <b>F</b> <i>filename</i> <i>SHA1-hash</i> <i>permissions</i> <i>old-name</i><br>
104 <b>N</b> <i>mimetype</i><br>
105 <b>P</b> <i>SHA1-hash</i>+<br>
106 <b>Q</b> (<b>+</b>|<b>-</b>)<i>SHA1-hash ?SHA1-hash?</i><br>
107 <b>R</b> <i>repository-checksum</i><br>
108 <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name <b>*</b> ?value?</i><br>
109 <b>U</b> <i>user-login</i><br>
110 <b>Z</b> <i>manifest-checksum</i>
111 </blockquote>
112
113 A manifest may optionally have a single B-card. The B-card specifies
@@ -291,11 +291,11 @@
291
292 Allowed cards in a control artifact are as follows:
293
294 <blockquote>
295 <b>D</b> <i>time-and-date-stamp</i><br />
296 <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name artifact-id ?value?</i><br />
297 <b>U</b> <i>user-name</i><br />
298 <b>Z</b> <i>checksum</i><br />
299 </blockquote>
300
301 A control artifact must have one D card, one U card, one Z card and
@@ -475,11 +475,11 @@
475 <b>C</b> <i>comment</i><br>
476 <b>D</b> <i>time-and-date-stamp</i><br />
477 <b>E</b> <i>event-time</i> <i>event-id</i><br />
478 <b>N</b> <i>mimetype</i><br />
479 <b>P</b> <i>parent-artifact-id</i>+<br />
480 <b>T</b> <b>+</b><i>tag-name</i> <b>*</b> <i>value</i><br />
481 <b>U</b> <i>user-name</i><br />
482 <b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br />
483 <b>Z</b> <i>checksum</i>
484 </blockquote>
485
@@ -499,11 +499,11 @@
499 The optional N card specifies the mimetype of the text of the event
500 that is contained in the W card. If the N card is omitted, then the
501 W card text mimetype is assumed to be text/x-fossil, which is the
502 Fossil wiki format.
503
504 The option P card specifies a prior event with the same event-id from
505 which the current event is an edit. The P card is a hint to the system
506 that it might be space efficient to store one event as a delta of the
507 other.
508
509 An event might contain one or more T-cards used to set
@@ -531,12 +531,16 @@
531
532
533 <a name="summary"></a>
534 <h2>8.0 Card Summary</h2>
535
536 The following table summaries the various kinds of cards that
537 appear on Fossil artifacts:
 
 
 
 
538
539 <table border=1 width="100%">
540 <tr>
541 <th rowspan=2 valign=bottom>Card Format</th>
542 <th colspan=7>Used By</th>
@@ -549,184 +553,223 @@
549 <th>Ticket</th>
550 <th>Attachment</th>
551 <th>Event</th>
552 </tr>
553 <tr>
554 <td><b>A</b> <i>filename target source</i></td>
555 <td>&nbsp;</td>
556 <td>&nbsp;</td>
557 <td>&nbsp;</td>
558 <td>&nbsp;</td>
559 <td>&nbsp;</td>
560 <td align=center><b>X</b></td>
561 <td>&nbsp;</td>
562 </tr>
563 <tr>
564 <td><b>B</b> <i>baseline</i></td>
565 <td align=center><b>X</b></td>
566 <td>&nbsp;</td>
567 <td>&nbsp;</td>
568 <td>&nbsp;</td>
569 <td>&nbsp;</td>
570 <td>&nbsp;</td>
571 <td>&nbsp;</td>
572 </tr>
573 <tr>
574 <td><b>C</b> <i>comment-text</i></td>
575 <td align=center><b>X</b></td>
576 <td>&nbsp;</td>
577 <td>&nbsp;</td>
578 <td>&nbsp;</td>
579 <td>&nbsp;</td>
580 <td align=center><b>X</b></td>
581 <td align=center><b>X</b></td>
582 </tr>
583 <tr>
584 <td><b>D</b> <i>date-time-stamp</i></td>
585 <td align=center><b>X</b></td>
586 <td align=center>&nbsp;</td>
587 <td align=center><b>X</b></td>
588 <td align=center><b>X</b></td>
589 <td align=center><b>X</b></td>
590 <td align=center><b>X</b></td>
591 <td align=center><b>X</b></td>
 
592 </tr>
593 <tr>
594 <td><b>E</b> <i>event-time event-id</i></td>
595 <td align=center>&nbsp;</td>
596 <td align=center>&nbsp;</td>
597 <td align=center>&nbsp;</td>
598 <td align=center>&nbsp;</td>
599 <td align=center>&nbsp;</td>
600 <td align=center>&nbsp;</td>
601 <td align=center><b>X</b></td>
602 </tr>
603 <tr>
604 <td><b>F</b> <i>filename uuid permissions oldname</i></td>
605 <td align=center><b>X</b></td>
606 <td align=center>&nbsp;</td>
607 <td align=center>&nbsp;</td>
608 <td align=center>&nbsp;</td>
609 <td align=center>&nbsp;</td>
610 <td align=center>&nbsp;</td>
611 <td align=center>&nbsp;</td>
612 </tr>
613 <tr>
614 <td><b>J</b> <i>name value</i></td>
615 <td align=center>&nbsp;</td>
616 <td align=center>&nbsp;</td>
617 <td align=center>&nbsp;</td>
618 <td align=center>&nbsp;</td>
619 <td align=center><b>X</b></td>
620 <td align=center>&nbsp;</td>
621 <td align=center>&nbsp;</td>
622 </tr>
623 <tr>
624 <td><b>K</b> <i>ticket-uuid</i></td>
625 <td align=center>&nbsp;</td>
626 <td align=center>&nbsp;</td>
627 <td align=center>&nbsp;</td>
628 <td align=center>&nbsp;</td>
629 <td align=center><b>X</b></td>
630 <td align=center>&nbsp;</td>
631 <td align=center>&nbsp;</td>
632 </tr>
633 <tr>
634 <td><b>L</b> <i>wiki-title</i></td>
635 <td align=center>&nbsp;</td>
636 <td align=center>&nbsp;</td>
637 <td align=center>&nbsp;</td>
638 <td align=center><b>X</b></td>
639 <td align=center>&nbsp;</td>
640 <td align=center>&nbsp;</td>
641 <td align=center>&nbsp;</td>
642 </tr>
643 <tr>
644 <td><b>M</b> <i>uuid</i></td>
645 <td align=center>&nbsp;</td>
646 <td align=center><b>X</b></td>
647 <td align=center>&nbsp;</td>
648 <td align=center>&nbsp;</td>
649 <td align=center>&nbsp;</td>
650 <td align=center>&nbsp;</td>
651 <td align=center>&nbsp;</td>
652 </tr>
653 <tr>
654 <td><b>N</b> <i>mimetype</i></td>
655 <td align=center><b>X</b></td>
656 <td align=center>&nbsp;</td>
657 <td align=center>&nbsp;</td>
658 <td align=center><b>X</b></td>
659 <td align=center>&nbsp;</td>
660 <td align=center><b>X</b></td>
661 <td align=center><b>X</b></td>
662 </tr>
663 <tr>
664 <td><b>P</b> <i>uuid ...</i></td>
665 <td align=center><b>X</b></td>
666 <td align=center>&nbsp;</td>
667 <td align=center>&nbsp;</td>
668 <td align=center><b>X</b></td>
669 <td align=center>&nbsp;</td>
670 <td align=center>&nbsp;</td>
671 <td align=center>&nbsp;</td>
672 </tr>
673 <tr>
674 <td><b>Q</b> (<b>+</b>|<b>-</b>)<i>uuid uuid</i></td>
675 <td align=center><b>X</b></td>
676 <td align=center>&nbsp;</td>
677 <td align=center>&nbsp;</td>
678 <td align=center>&nbsp;</td>
679 <td align=center>&nbsp;</td>
680 <td align=center>&nbsp;</td>
681 <td align=center>&nbsp;</td>
682 </tr>
683 <tr>
684 <td><b>R</b> <i>md5sum</i></td>
685 <td align=center><b>X</b></td>
686 <td align=center>&nbsp;</td>
687 <td align=center>&nbsp;</td>
688 <td align=center>&nbsp;</td>
689 <td align=center>&nbsp;</td>
690 <td align=center>&nbsp;</td>
691 <td align=center>&nbsp;</td>
 
692 <tr>
693 <td><b>T</b> (<b>+</b>|<b>*</b>|<b>-</b>)<i>tagname uuid value</i></td>
694 <td align=center><b>X</b></td>
695 <td align=center>&nbsp;</td>
696 <td align=center><b>X</b></td>
697 <td align=center>&nbsp;</td>
698 <td align=center>&nbsp;</td>
699 <td align=center>&nbsp;</td>
700 <td align=center><b>X</b></td>
701 </tr>
702 <tr>
703 <td><b>U</b> <i>username</i></td>
704 <td align=center><b>X</b></td>
705 <td align=center>&nbsp;</td>
706 <td align=center><b>X</b></td>
707 <td align=center><b>X</b></td>
708 <td align=center><b>X</b></td>
709 <td align=center><b>X</b></td>
710 <td align=center><b>X</b></td>
711 </tr>
712 <tr>
713 <td><b>W</b> <i>size</i></td>
714 <td align=center>&nbsp;</td>
715 <td align=center>&nbsp;</td>
716 <td align=center>&nbsp;</td>
717 <td align=center><b>X</b></td>
718 <td align=center>&nbsp;</td>
719 <td align=center>&nbsp;</td>
720 <td align=center><b>X</b></td>
721 </tr>
722 <tr>
723 <td><b>Z</b> <i>md5sum</i></td>
724 <td align=center><b>X</b></td>
725 <td align=center><b>X</b></td>
726 <td align=center><b>X</b></td>
727 <td align=center><b>X</b></td>
728 <td align=center><b>X</b></td>
729 <td align=center><b>X</b></td>
730 <td align=center><b>X</b></td>
731 </tr>
732 </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
733
734 DDED www/hacker-howto.wiki
--- www/fileformat.wiki
+++ www/fileformat.wiki
@@ -46,11 +46,11 @@
46 <li> [#tktchng | Ticket Changes] </li>
47 <li> [#attachment | Attachments] </li>
48 <li> [#event | Events] </li>
49 </ul>
50
51 These seven artifact types are described in the following sections.
52
53 In the current implementation (as of 2009-01-25) the artifacts that
54 make up a fossil repository are stored in in as delta- and zlib-compressed
55 blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
56 is an implementation detail and might change in a future release. For
@@ -98,16 +98,16 @@
98
99 <blockquote>
100 <b>B</b> <i>baseline-manifest</i><br>
101 <b>C</b> <i>checkin-comment</i><br>
102 <b>D</b> <i>time-and-date-stamp</i><br>
103 <b>F</b> <i>filename</i> ?<i>SHA1-hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br>
104 <b>N</b> <i>mimetype</i><br>
105 <b>P</b> <i>SHA1-hash</i>+<br>
106 <b>Q</b> (<b>+</b>|<b>-</b>)<i>SHA1-hash</i> ?<i>SHA1-hash</i>?<br>
107 <b>R</b> <i>repository-checksum</i><br>
108 <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br>
109 <b>U</b> <i>user-login</i><br>
110 <b>Z</b> <i>manifest-checksum</i>
111 </blockquote>
112
113 A manifest may optionally have a single B-card. The B-card specifies
@@ -291,11 +291,11 @@
291
292 Allowed cards in a control artifact are as follows:
293
294 <blockquote>
295 <b>D</b> <i>time-and-date-stamp</i><br />
296 <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <i>artifact-id</i> ?<i>value</i>?<br />
297 <b>U</b> <i>user-name</i><br />
298 <b>Z</b> <i>checksum</i><br />
299 </blockquote>
300
301 A control artifact must have one D card, one U card, one Z card and
@@ -475,11 +475,11 @@
475 <b>C</b> <i>comment</i><br>
476 <b>D</b> <i>time-and-date-stamp</i><br />
477 <b>E</b> <i>event-time</i> <i>event-id</i><br />
478 <b>N</b> <i>mimetype</i><br />
479 <b>P</b> <i>parent-artifact-id</i>+<br />
480 <b>T</b> <b>+</b><i>tag-name</i> <b>*</b> ?<i>value</i>?<br />
481 <b>U</b> <i>user-name</i><br />
482 <b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br />
483 <b>Z</b> <i>checksum</i>
484 </blockquote>
485
@@ -499,11 +499,11 @@
499 The optional N card specifies the mimetype of the text of the event
500 that is contained in the W card. If the N card is omitted, then the
501 W card text mimetype is assumed to be text/x-fossil, which is the
502 Fossil wiki format.
503
504 The optional P card specifies a prior event with the same event-id from
505 which the current event is an edit. The P card is a hint to the system
506 that it might be space efficient to store one event as a delta of the
507 other.
508
509 An event might contain one or more T-cards used to set
@@ -531,12 +531,16 @@
531
532
533 <a name="summary"></a>
534 <h2>8.0 Card Summary</h2>
535
536 The following table summarizes the various kinds of cards that appear
537 on Fossil artifacts. A blank entry means that combination of card and
538 artifact is not legal. A number or range of numbers indicates the number
539 of times a card may (or must) appear in the corresponding artifact type.
540 e.g. a value of 1 indicates a required unique card and 1+ indicates that one
541 or more such cards are required.
542
543 <table border=1 width="100%">
544 <tr>
545 <th rowspan=2 valign=bottom>Card Format</th>
546 <th colspan=7>Used By</th>
@@ -549,184 +553,223 @@
553 <th>Ticket</th>
554 <th>Attachment</th>
555 <th>Event</th>
556 </tr>
557 <tr>
558 <td><b>A</b> <i>filename</i> <i>target</i> ?<i>source</i>?</td>
559 <td>&nbsp;</td>
560 <td>&nbsp;</td>
561 <td>&nbsp;</td>
562 <td>&nbsp;</td>
563 <td>&nbsp;</td>
564 <td align=center><b>1</b></td>
565 <td>&nbsp;</td>
566 </tr>
567 <tr>
568 <td><b>B</b> <i>baseline</i></td>
569 <td align=center><b>0-1*</b></td>
570 <td>&nbsp;</td>
571 <td>&nbsp;</td>
572 <td>&nbsp;</td>
573 <td>&nbsp;</td>
574 <td>&nbsp;</td>
575 <td>&nbsp;</td>
576 </tr>
577 <tr><td>&nbsp;</td><td colspan='7'>* = Required for delta manifests</td></tr>
578 <tr>
579 <td><b>C</b> <i>comment-text</i></td>
580 <td align=center><b>1</b></td>
581 <td>&nbsp;</td>
582 <td>&nbsp;</td>
583 <td>&nbsp;</td>
584 <td>&nbsp;</td>
585 <td align=center><b>0-1</b></td>
586 <td align=center><b>1</b></td>
587 </tr>
588 <tr>
589 <td><b>D</b> <i>date-time-stamp</i></td>
590 <td align=center><b>1</b></td>
591 <td align=center>&nbsp;</td>
592 <td align=center><b>1</b></td>
593 <td align=center><b>1</b></td>
594 <td align=center><b>1</b></td>
595 <td align=center><b>1</b></td>
596 <td align=center><b>1</b></td>
597 </tr>
598 <tr>
599 <td><b>E</b> <i>event-time event-id</i></td>
600 <td align=center>&nbsp;</td>
601 <td align=center>&nbsp;</td>
602 <td align=center>&nbsp;</td>
603 <td align=center>&nbsp;</td>
604 <td align=center>&nbsp;</td>
605 <td align=center>&nbsp;</td>
606 <td align=center><b>1</b></td>
607 </tr>
608 <tr>
609 <td><b>F</b> <i>filename</i> ?<i>uuid</i>? ?<i>permissions</i>? ?<i>oldname</i>?</td>
610 <td align=center><b>0+</b></td>
611 <td align=center>&nbsp;</td>
612 <td align=center>&nbsp;</td>
613 <td align=center>&nbsp;</td>
614 <td align=center>&nbsp;</td>
615 <td align=center>&nbsp;</td>
616 <td align=center>&nbsp;</td>
617 </tr>
618 <tr>
619 <td><b>J</b> <i>name</i> ?<i>value</i>?</td>
620 <td align=center>&nbsp;</td>
621 <td align=center>&nbsp;</td>
622 <td align=center>&nbsp;</td>
623 <td align=center>&nbsp;</td>
624 <td align=center><b>1+</b></td>
625 <td align=center>&nbsp;</td>
626 <td align=center>&nbsp;</td>
627 </tr>
628 <tr>
629 <td><b>K</b> <i>ticket-uuid</i></td>
630 <td align=center>&nbsp;</td>
631 <td align=center>&nbsp;</td>
632 <td align=center>&nbsp;</td>
633 <td align=center>&nbsp;</td>
634 <td align=center><b>1</b></td>
635 <td align=center>&nbsp;</td>
636 <td align=center>&nbsp;</td>
637 </tr>
638 <tr>
639 <td><b>L</b> <i>wiki-title</i></td>
640 <td align=center>&nbsp;</td>
641 <td align=center>&nbsp;</td>
642 <td align=center>&nbsp;</td>
643 <td align=center><b>1</b></td>
644 <td align=center>&nbsp;</td>
645 <td align=center>&nbsp;</td>
646 <td align=center>&nbsp;</td>
647 </tr>
648 <tr>
649 <td><b>M</b> <i>uuid</i></td>
650 <td align=center>&nbsp;</td>
651 <td align=center><b>1+</b></td>
652 <td align=center>&nbsp;</td>
653 <td align=center>&nbsp;</td>
654 <td align=center>&nbsp;</td>
655 <td align=center>&nbsp;</td>
656 <td align=center>&nbsp;</td>
657 </tr>
658 <tr>
659 <td><b>N</b> <i>mimetype</i></td>
660 <td align=center><b>0-1</b></td>
661 <td align=center>&nbsp;</td>
662 <td align=center>&nbsp;</td>
663 <td align=center><b>0-1</b></td>
664 <td align=center>&nbsp;</td>
665 <td align=center><b>0-1</b></td>
666 <td align=center><b>0-1</b></td>
667 </tr>
668 <tr>
669 <td><b>P</b> <i>uuid ...</i></td>
670 <td align=center><b>0-1</b></td>
671 <td align=center>&nbsp;</td>
672 <td align=center>&nbsp;</td>
673 <td align=center><b>0-1</b></td>
674 <td align=center>&nbsp;</td>
675 <td align=center>&nbsp;</td>
676 <td align=center><b>0-1</b></td>
677 </tr>
678 <tr>
679 <td><b>Q</b> (<b>+</b>|<b>-</b>)<i>uuid</i> ?<i>uuid</i>?</td>
680 <td align=center><b>0+</b></td>
681 <td align=center>&nbsp;</td>
682 <td align=center>&nbsp;</td>
683 <td align=center>&nbsp;</td>
684 <td align=center>&nbsp;</td>
685 <td align=center>&nbsp;</td>
686 <td align=center>&nbsp;</td>
687 </tr>
688 <tr>
689 <td><b>R</b> <i>md5sum</i></td>
690 <td align=center><b>0-1*</b></td>
691 <td align=center>&nbsp;</td>
692 <td align=center>&nbsp;</td>
693 <td align=center>&nbsp;</td>
694 <td align=center>&nbsp;</td>
695 <td align=center>&nbsp;</td>
696 <td align=center>&nbsp;</td>
697 <tr><td>&nbsp;</td><td colspan='7'>* = Required when using F cards</td></tr>
698 <tr>
699 <td><b>T</b> (<b>+</b>|<b>*</b>|<b>-</b>)<i>tagname</i> <i>uuid</i> ?<i>value</i>?</td>
700 <td align=center><b>0+</b></td>
701 <td align=center>&nbsp;</td>
702 <td align=center><b>1+</b></td>
703 <td align=center>&nbsp;</td>
704 <td align=center>&nbsp;</td>
705 <td align=center>&nbsp;</td>
706 <td align=center><b>0+</b></td>
707 </tr>
708 <tr>
709 <td><b>U</b> <i>username</i></td>
710 <td align=center><b>1</b></td>
711 <td align=center>&nbsp;</td>
712 <td align=center><b>1</b></td>
713 <td align=center><b>1</b></td>
714 <td align=center><b>1</b></td>
715 <td align=center><b>0-1</b></td>
716 <td align=center><b>0-1</b></td>
717 </tr>
718 <tr>
719 <td><b>W</b> <i>size</i></td>
720 <td align=center>&nbsp;</td>
721 <td align=center>&nbsp;</td>
722 <td align=center>&nbsp;</td>
723 <td align=center><b>1</b></td>
724 <td align=center>&nbsp;</td>
725 <td align=center>&nbsp;</td>
726 <td align=center><b>1</b></td>
727 </tr>
728 <tr>
729 <td><b>Z</b> <i>md5sum</i></td>
730 <td align=center><b>1</b></td>
731 <td align=center><b>1</b></td>
732 <td align=center><b>1</b></td>
733 <td align=center><b>1</b></td>
734 <td align=center><b>1</b></td>
735 <td align=center><b>1</b></td>
736 <td align=center><b>1</b></td>
737 </tr>
738 </table>
739
740
741 <a name="addenda"></a>
742 <h2>9.0 Addenda</h2>
743
744 This section contains additional information which may be useful when
745 implementing algorithms described above.
746
747 <h3>R Card Hash Calculation</h3>
748
749 Given a manifest file named <tt>MF</tt>, the following Bash shell code
750 demonstrates how to compute the value of the R card in that manifest.
751 This example uses manifest [28987096ac]. Lines starting with <tt>#</tt> are
752 shell input and other lines are output. This demonstration assumes that the
753 file versions represented by the input manifest are checked out
754 under the current directory.
755
756 <nowiki><pre>
757 # head MF
758 -----BEGIN PGP SIGNED MESSAGE-----
759 Hash: SHA1
760
761 C Make\sthe\s"clearsign"\sPGP\ssigning\sdefault\sto\soff.
762 D 2010-02-23T15:33:14
763 F BUILD.txt 4f7988767e4e48b29f7eddd0e2cdea4555b9161c
764 F COPYRIGHT-GPL2.txt 06877624ea5c77efe3b7e39b0f909eda6e25a4ec
765 ...
766
767 # grep '^R ' MF
768 R c0788982781981c96a0d81465fec7192
769
770 # for i in $(awk '/^F /{print $2}' MF); do \
771 echo $i $(stat -c '%s' $i); \
772 cat $i; \
773 done | md5sum
774 c0788982781981c96a0d81465fec7192 -
775 </pre></nowiki>
776
777 DDED www/hacker-howto.wiki
--- a/www/hacker-howto.wiki
+++ b/www/hacker-howto.wiki
@@ -0,0 +1,13 @@
1
+<title>Fossil Hackers How-To</title>
2
+
3
+The following links are of interest to programmers who want . Ordinary users can safely ignore this information.
4
+
5
+ * [./build.wiki | How To Compile And Install Fossil]
6
+ * [./d_in_ide.md | Using]
7
+ * [./tech_overview.wiki | ts To The Fossil Project]
8
+ * [./fileformat.wiki|Fossil Artifact File Format]
9
+ * [./sync.wiki|The Sync Protocol]
10
+ * [./style.wiki | Coding Style Guidelines]
11
+ * [./checkin.wiki | Pre-checkinlease Checklist]
12
+ * [./backoffice.md | Tadding_cod Fossil]
13
+ * [./contribute.wiki|Contributing Code Or Enhancements To The Fossil Project]
--- a/www/hacker-howto.wiki
+++ b/www/hacker-howto.wiki
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/www/hacker-howto.wiki
+++ b/www/hacker-howto.wiki
@@ -0,0 +1,13 @@
1 <title>Fossil Hackers How-To</title>
2
3 The following links are of interest to programmers who want . Ordinary users can safely ignore this information.
4
5 * [./build.wiki | How To Compile And Install Fossil]
6 * [./d_in_ide.md | Using]
7 * [./tech_overview.wiki | ts To The Fossil Project]
8 * [./fileformat.wiki|Fossil Artifact File Format]
9 * [./sync.wiki|The Sync Protocol]
10 * [./style.wiki | Coding Style Guidelines]
11 * [./checkin.wiki | Pre-checkinlease Checklist]
12 * [./backoffice.md | Tadding_cod Fossil]
13 * [./contribute.wiki|Contributing Code Or Enhancements To The Fossil Project]
+6 -6
--- www/index.wiki
+++ www/index.wiki
@@ -20,11 +20,11 @@
2020
<li> [./quickstart.wiki | Quick Start]
2121
<li> [./build.wiki | Install]
2222
<li> [../COPYRIGHT-BSD2.txt | License]
2323
<li> [/timeline | Recent changes]
2424
<li> [./faq.wiki | FAQ]
25
-<li> [./contribute.wiki | Contributing]
25
+<li> [./hacker-howto.wiki | Hacker How-To]
2626
<li> [./changes.wiki | Change Log]
2727
<li> [./hints.wiki | Tip &amp; Hints]
2828
<li> [./permutedindex.wiki#pindex | Documentation Index]
2929
<li> [http://www.fossil-scm.org/schimpf-book/home | Jim Schimpf's book]
3030
<li> Mailing list
@@ -81,33 +81,33 @@
8181
Installation is trivial: simply download a
8282
<a href="http://www.fossil-scm.org/download.html">precompiled binary</a>
8383
for Linux, Mac, or Windows and put it on your $PATH.
8484
[./build.wiki | Easy-to-compile source code] is available for
8585
users on other platforms. Fossil sources are also mostly self-contained,
86
- requiring only the "zlib" library and the standard C library to build.
86
+ requiring only the standard C library to build.
8787
8888
5. <b>Simple Networking</b> -
8989
Fossil uses plain old HTTP (with
9090
[./quickstart.wiki#proxy | proxy support])
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/SCGI Enabled</b> -
9797
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].
98
+ server does make collaboration easier. Fossil supports four different
99
+ yet simple [./server.wiki | 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
Fossil stores content using an [./fileformat.wiki | enduring file format]
105105
in an SQLite database so that transactions are
106106
atomic even if interrupted by a power loss or system crash. Furthermore,
107107
automatic [./selfcheck.wiki | self-checks] verify that all aspects of
108
- the repository are consistent prior to each commit. In over three years
108
+ the repository are consistent prior to each commit. In over six years
109109
of operation, no work has ever been lost after having been committed to
110110
a Fossil repository.
111111
112112
<hr>
113113
<h3>Links For Fossil Users:</h3>
114114
--- www/index.wiki
+++ www/index.wiki
@@ -20,11 +20,11 @@
20 <li> [./quickstart.wiki | Quick Start]
21 <li> [./build.wiki | Install]
22 <li> [../COPYRIGHT-BSD2.txt | License]
23 <li> [/timeline | Recent changes]
24 <li> [./faq.wiki | FAQ]
25 <li> [./contribute.wiki | Contributing]
26 <li> [./changes.wiki | Change Log]
27 <li> [./hints.wiki | Tip &amp; Hints]
28 <li> [./permutedindex.wiki#pindex | Documentation Index]
29 <li> [http://www.fossil-scm.org/schimpf-book/home | Jim Schimpf's book]
30 <li> Mailing list
@@ -81,33 +81,33 @@
81 Installation is trivial: simply download a
82 <a href="http://www.fossil-scm.org/download.html">precompiled binary</a>
83 for Linux, Mac, or Windows and put it on your $PATH.
84 [./build.wiki | Easy-to-compile source code] is available for
85 users on other platforms. Fossil sources are also mostly self-contained,
86 requiring only the "zlib" library and the standard C library to build.
87
88 5. <b>Simple Networking</b> -
89 Fossil uses plain old HTTP (with
90 [./quickstart.wiki#proxy | proxy support])
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 Fossil stores content using an [./fileformat.wiki | enduring file format]
105 in an SQLite database so that transactions are
106 atomic even if interrupted by a power loss or system crash. Furthermore,
107 automatic [./selfcheck.wiki | self-checks] verify that all aspects of
108 the repository are consistent prior to each commit. In over three years
109 of operation, no work has ever been lost after having been committed to
110 a Fossil repository.
111
112 <hr>
113 <h3>Links For Fossil Users:</h3>
114
--- www/index.wiki
+++ www/index.wiki
@@ -20,11 +20,11 @@
20 <li> [./quickstart.wiki | Quick Start]
21 <li> [./build.wiki | Install]
22 <li> [../COPYRIGHT-BSD2.txt | License]
23 <li> [/timeline | Recent changes]
24 <li> [./faq.wiki | FAQ]
25 <li> [./hacker-howto.wiki | Hacker How-To]
26 <li> [./changes.wiki | Change Log]
27 <li> [./hints.wiki | Tip &amp; Hints]
28 <li> [./permutedindex.wiki#pindex | Documentation Index]
29 <li> [http://www.fossil-scm.org/schimpf-book/home | Jim Schimpf's book]
30 <li> Mailing list
@@ -81,33 +81,33 @@
81 Installation is trivial: simply download a
82 <a href="http://www.fossil-scm.org/download.html">precompiled binary</a>
83 for Linux, Mac, or Windows and put it on your $PATH.
84 [./build.wiki | Easy-to-compile source code] is available for
85 users on other platforms. Fossil sources are also mostly self-contained,
86 requiring only the standard C library to build.
87
88 5. <b>Simple Networking</b> -
89 Fossil uses plain old HTTP (with
90 [./quickstart.wiki#proxy | proxy support])
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/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 [./server.wiki | 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 Fossil stores content using an [./fileformat.wiki | enduring file format]
105 in an SQLite database so that transactions are
106 atomic even if interrupted by a power loss or system crash. Furthermore,
107 automatic [./selfcheck.wiki | self-checks] verify that all aspects of
108 the repository are consistent prior to each commit. In over six years
109 of operation, no work has ever been lost after having been committed to
110 a Fossil repository.
111
112 <hr>
113 <h3>Links For Fossil Users:</h3>
114
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -28,10 +28,11 @@
2828
fileformat.wiki {Fossil File Format}
2929
fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
3030
foss-cklist.wiki {Checklist For Successful Open-Source Projects}
3131
fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
3232
fossil-v-git.wiki {Fossil Versus Git}
33
+ hacker-howto.wiki {Hacker How-To}
3334
hints.wiki {Fossil Tips And Usage Hints}
3435
index.wiki {Home Page}
3536
inout.wiki {Import And Export To And From Git}
3637
makefile.wiki {The Fossil Build Process}
3738
newrepo.wiki {How To Create A New Fossil Repository}
3839
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -28,10 +28,11 @@
28 fileformat.wiki {Fossil File Format}
29 fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
30 foss-cklist.wiki {Checklist For Successful Open-Source Projects}
31 fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
32 fossil-v-git.wiki {Fossil Versus Git}
 
33 hints.wiki {Fossil Tips And Usage Hints}
34 index.wiki {Home Page}
35 inout.wiki {Import And Export To And From Git}
36 makefile.wiki {The Fossil Build Process}
37 newrepo.wiki {How To Create A New Fossil Repository}
38
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -28,10 +28,11 @@
28 fileformat.wiki {Fossil File Format}
29 fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
30 foss-cklist.wiki {Checklist For Successful Open-Source Projects}
31 fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
32 fossil-v-git.wiki {Fossil Versus Git}
33 hacker-howto.wiki {Hacker How-To}
34 hints.wiki {Fossil Tips And Usage Hints}
35 index.wiki {Home Page}
36 inout.wiki {Import And Export To And From Git}
37 makefile.wiki {The Fossil Build Process}
38 newrepo.wiki {How To Create A New Fossil Repository}
39
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -88,16 +88,18 @@
8888
<li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
8989
<li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
9090
<li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
9191
<li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
9292
<li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
93
+<li><a href="hacker-howto.wiki">Hacker How-To</a></li>
9394
<li><a href="adding_code.wiki">Hacking Fossil</a></li>
9495
<li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
9596
<li><a href="index.wiki">Home Page</a></li>
9697
<li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
9798
<li><a href="server.wiki">How To Configure A Fossil Server</a></li>
9899
<li><a href="newrepo.wiki">How To Create A New Fossil Repository</a></li>
100
+<li><a href="hacker-howto.wiki">How-To &mdash; Hacker</a></li>
99101
<li><a href="fossil-from-msvc.wiki">IDE &mdash; Integrating Fossil in the Microsoft Express 2010</a></li>
100102
<li><a href="tech_overview.wiki">Implementation Of Fossil &mdash; A Technical Overview Of The Design And</a></li>
101103
<li><a href="inout.wiki">Import And Export To And From Git</a></li>
102104
<li><a href="build.wiki">Installing Fossil &mdash; Compiling and</a></li>
103105
<li><a href="fossil-from-msvc.wiki">Integrating Fossil in the Microsoft Express 2010 IDE</a></li>
104106
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -88,16 +88,18 @@
88 <li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
89 <li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
90 <li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
91 <li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
92 <li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
 
93 <li><a href="adding_code.wiki">Hacking Fossil</a></li>
94 <li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
95 <li><a href="index.wiki">Home Page</a></li>
96 <li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
97 <li><a href="server.wiki">How To Configure A Fossil Server</a></li>
98 <li><a href="newrepo.wiki">How To Create A New Fossil Repository</a></li>
 
99 <li><a href="fossil-from-msvc.wiki">IDE &mdash; Integrating Fossil in the Microsoft Express 2010</a></li>
100 <li><a href="tech_overview.wiki">Implementation Of Fossil &mdash; A Technical Overview Of The Design And</a></li>
101 <li><a href="inout.wiki">Import And Export To And From Git</a></li>
102 <li><a href="build.wiki">Installing Fossil &mdash; Compiling and</a></li>
103 <li><a href="fossil-from-msvc.wiki">Integrating Fossil in the Microsoft Express 2010 IDE</a></li>
104
--- www/permutedindex.wiki
+++ www/permutedindex.wiki
@@ -88,16 +88,18 @@
88 <li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
89 <li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
90 <li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
91 <li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
92 <li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
93 <li><a href="hacker-howto.wiki">Hacker How-To</a></li>
94 <li><a href="adding_code.wiki">Hacking Fossil</a></li>
95 <li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
96 <li><a href="index.wiki">Home Page</a></li>
97 <li><a href="selfhost.wiki">Hosting Repositories &mdash; Fossil Self</a></li>
98 <li><a href="server.wiki">How To Configure A Fossil Server</a></li>
99 <li><a href="newrepo.wiki">How To Create A New Fossil Repository</a></li>
100 <li><a href="hacker-howto.wiki">How-To &mdash; Hacker</a></li>
101 <li><a href="fossil-from-msvc.wiki">IDE &mdash; Integrating Fossil in the Microsoft Express 2010</a></li>
102 <li><a href="tech_overview.wiki">Implementation Of Fossil &mdash; A Technical Overview Of The Design And</a></li>
103 <li><a href="inout.wiki">Import And Export To And From Git</a></li>
104 <li><a href="build.wiki">Installing Fossil &mdash; Compiling and</a></li>
105 <li><a href="fossil-from-msvc.wiki">Integrating Fossil in the Microsoft Express 2010 IDE</a></li>
106
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -285,69 +285,40 @@
285285
mistake. Undo and redo only work for changes that have
286286
not yet been checked in using commit and there is only a single
287287
level of undo/redo.</p>
288288
289289
290
-<a name="serversetup"></a>
291290
<h2>Setting Up A Server</h2>
292291
293
- <p>The easiest way to set up a server is:</p>
292
+ <p>Fossil can act as a stand-alone web server using one of these
293
+ commands:</p>
294294
295295
<blockquote>
296
- <b>[/help/server | fossil server]</b> <i>repository-filename</i>
296
+ <b>[/help/server | fossil server]</b> <i>repository-filename</i><br>
297
+ <b>[/help/ui | fossil ui]</b> <i>repository-filename</i>
297298
</blockquote>
298299
299
- <p>Or</b>
300
-
301
- <blockquote>
302
- <b>[/help/ui | fossil ui]</b> <i>repository-filename</i>
303
- </blockquote>
300
+ <p>The <i>repository-filename</i> can be omitted when these commands
301
+ are run from within an open check-out, which a particularly useful
302
+ shortcut for the <b>fossil ui</b> command.
304303
305304
<p>The <b>ui</b> command is intended for accessing the web interface
306305
from a local desktop. The <b>ui</b> command binds to the loopback IP
307306
address only (and thus makes the web interface visible only on the
308307
local machine) and it automatically start your web browser pointing at the
309308
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
- <a name="cgiserver"></a>
320
- To use the CGI server, create a CGI script that
321
- looks something like this:</p>
322
-
323
- <blockquote><b>
324
- #!/usr/local/bin/fossil<br>
325
- repository: /home/proj1/repos1.fossil
326
- </b></blockquote>
327
-
328
- <p>Adjust the paths in this CGI script to match your installation
329
- and make sure both repository file and the directory that contains it
330
- are readable and writable by the user that CGI scripts run as.
331
- Then point clients at the CGI script. That's all there is to it!</p>
332
-
333
- <a name="inetdserver"></a>
334
- <p>You can also run fossil from inetd or xinetd. For an inetd
335
- installation, make an entry in /etc/inetd.conf that looks something
336
- like this:</p>
337
-
338
- <blockquote><b>
339
- 80 stream tcp nowait.1000 root /usr/bin/fossil \<br>
340
- /usr/bin/fossil http /home/proj1/repos1.fossil
341
- </b></blockquote>
342
-
343
- <p>Adjust the paths to suit your installation, of course. Notice that
344
- fossil runs as root. This is not required - you can run it as an
345
- unprivileged user. But it is more secure to run fossil as root.
346
- When you do run fossil as root, it automatically puts itself in a
347
- chroot jail in the same directory as the repository, then drops
348
- root privileges prior to reading any information from the socket.</p>
309
+ which binds on all IP addresses and does not try to start a web browser.</p>
310
+
311
+ <p>Servers are also easily configured as:
312
+ <ul>
313
+ <li>[./server.wiki#inetd|inetd/xinetd]
314
+ <li>[./server.wiki#cgi|CGI]
315
+ <li>[./server.wiki#scgi|SCGI]
316
+ </ul>
317
+
318
+ <p>The the [./selfhost.wiki | self-hosting fossil repositories] use
319
+ CGI.
349320
350321
<a name="proxy"></a>
351322
<h2>HTTP Proxies</h2>
352323
353324
<p>If you are behind a restrictive firewall that requires you to use
354325
355326
ADDED www/scgi.wiki
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -285,69 +285,40 @@
285 mistake. Undo and redo only work for changes that have
286 not yet been checked in using commit and there is only a single
287 level of undo/redo.</p>
288
289
290 <a name="serversetup"></a>
291 <h2>Setting Up A Server</h2>
292
293 <p>The easiest way to set up a server is:</p>
 
294
295 <blockquote>
296 <b>[/help/server | fossil server]</b> <i>repository-filename</i>
 
297 </blockquote>
298
299 <p>Or</b>
300
301 <blockquote>
302 <b>[/help/ui | fossil ui]</b> <i>repository-filename</i>
303 </blockquote>
304
305 <p>The <b>ui</b> command is intended for accessing the web interface
306 from a local desktop. The <b>ui</b> command binds to the loopback IP
307 address only (and thus makes the web interface visible only on the
308 local machine) and it automatically start your web browser pointing at the
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 <a name="cgiserver"></a>
320 To use the CGI server, create a CGI script that
321 looks something like this:</p>
322
323 <blockquote><b>
324 #!/usr/local/bin/fossil<br>
325 repository: /home/proj1/repos1.fossil
326 </b></blockquote>
327
328 <p>Adjust the paths in this CGI script to match your installation
329 and make sure both repository file and the directory that contains it
330 are readable and writable by the user that CGI scripts run as.
331 Then point clients at the CGI script. That's all there is to it!</p>
332
333 <a name="inetdserver"></a>
334 <p>You can also run fossil from inetd or xinetd. For an inetd
335 installation, make an entry in /etc/inetd.conf that looks something
336 like this:</p>
337
338 <blockquote><b>
339 80 stream tcp nowait.1000 root /usr/bin/fossil \<br>
340 /usr/bin/fossil http /home/proj1/repos1.fossil
341 </b></blockquote>
342
343 <p>Adjust the paths to suit your installation, of course. Notice that
344 fossil runs as root. This is not required - you can run it as an
345 unprivileged user. But it is more secure to run fossil as root.
346 When you do run fossil as root, it automatically puts itself in a
347 chroot jail in the same directory as the repository, then drops
348 root privileges prior to reading any information from the socket.</p>
349
350 <a name="proxy"></a>
351 <h2>HTTP Proxies</h2>
352
353 <p>If you are behind a restrictive firewall that requires you to use
354
355 DDED www/scgi.wiki
--- www/quickstart.wiki
+++ www/quickstart.wiki
@@ -285,69 +285,40 @@
285 mistake. Undo and redo only work for changes that have
286 not yet been checked in using commit and there is only a single
287 level of undo/redo.</p>
288
289
 
290 <h2>Setting Up A Server</h2>
291
292 <p>Fossil can act as a stand-alone web server using one of these
293 commands:</p>
294
295 <blockquote>
296 <b>[/help/server | fossil server]</b> <i>repository-filename</i><br>
297 <b>[/help/ui | fossil ui]</b> <i>repository-filename</i>
298 </blockquote>
299
300 <p>The <i>repository-filename</i> can be omitted when these commands
301 are run from within an open check-out, which a particularly useful
302 shortcut for the <b>fossil ui</b> command.
 
 
303
304 <p>The <b>ui</b> command is intended for accessing the web interface
305 from a local desktop. The <b>ui</b> command binds to the loopback IP
306 address only (and thus makes the web interface visible only on the
307 local machine) and it automatically start your web browser pointing at the
308 server. For cross-machine collaboration, use the <b>server</b> command,
309 which binds on all IP addresses and does not try to start a web browser.</p>
310
311 <p>Servers are also easily configured as:
312 <ul>
313 <li>[./server.wiki#inetd|inetd/xinetd]
314 <li>[./server.wiki#cgi|CGI]
315 <li>[./server.wiki#scgi|SCGI]
316 </ul>
317
318 <p>The the [./selfhost.wiki | self-hosting fossil repositories] use
319 CGI.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
321 <a name="proxy"></a>
322 <h2>HTTP Proxies</h2>
323
324 <p>If you are behind a restrictive firewall that requires you to use
325
326 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.
--- www/selfhost.wiki
+++ www/selfhost.wiki
@@ -21,12 +21,12 @@
2121
2222
Server (1) runs as a CGI script on a
2323
<a href="http://www.linode.com/">Linode 1024</a> located in Dallas, TX
2424
- on the same virtual machine that
2525
hosts <a href="http://www.sqlite.org/">SQLite</a> and over a
26
-dozen other smaller projects. This demonstrates that Fossil does not
27
-require much server power.
26
+dozen other smaller projects. This demonstrates that Fossil can run on
27
+a low-power host processor.
2828
Multiple fossil-based projects can easily be hosted on the same machine,
2929
even if that machine is itself one of several dozen virtual machines on
3030
single physical box. The CGI script that runs the canonical Fossil
3131
self-hosting repository is as follows:
3232
@@ -38,11 +38,12 @@
3838
Server (3) runs as a CGI script on a shared hosting account at
3939
<a href="http://www.he.net/">Hurricane Electric</a> in Fremont, CA.
4040
This server demonstrates the ability of
4141
Fossil to run on an economical shared-host web account with no
4242
privileges beyond port 80 HTTP access and CGI. It is not necessary
43
-to have a dedicated server to run Fossil. As far as we are aware,
43
+to have a dedicated computer with administrator to run Fossil.
44
+As far as we are aware,
4445
Fossil is the only full-featured configuration management system
4546
that can run in
4647
such a restricted environment. The CGI script that runs on the
4748
Hurricane Electric server is the same as the CGI script shown above,
4849
except that the pathnames are modified to suit the environment:
4950
--- www/selfhost.wiki
+++ www/selfhost.wiki
@@ -21,12 +21,12 @@
21
22 Server (1) runs as a CGI script on a
23 <a href="http://www.linode.com/">Linode 1024</a> located in Dallas, TX
24 - on the same virtual machine that
25 hosts <a href="http://www.sqlite.org/">SQLite</a> and over a
26 dozen other smaller projects. This demonstrates that Fossil does not
27 require much server power.
28 Multiple fossil-based projects can easily be hosted on the same machine,
29 even if that machine is itself one of several dozen virtual machines on
30 single physical box. The CGI script that runs the canonical Fossil
31 self-hosting repository is as follows:
32
@@ -38,11 +38,12 @@
38 Server (3) runs as a CGI script on a shared hosting account at
39 <a href="http://www.he.net/">Hurricane Electric</a> in Fremont, CA.
40 This server demonstrates the ability of
41 Fossil to run on an economical shared-host web account with no
42 privileges beyond port 80 HTTP access and CGI. It is not necessary
43 to have a dedicated server to run Fossil. As far as we are aware,
 
44 Fossil is the only full-featured configuration management system
45 that can run in
46 such a restricted environment. The CGI script that runs on the
47 Hurricane Electric server is the same as the CGI script shown above,
48 except that the pathnames are modified to suit the environment:
49
--- www/selfhost.wiki
+++ www/selfhost.wiki
@@ -21,12 +21,12 @@
21
22 Server (1) runs as a CGI script on a
23 <a href="http://www.linode.com/">Linode 1024</a> located in Dallas, TX
24 - on the same virtual machine that
25 hosts <a href="http://www.sqlite.org/">SQLite</a> and over a
26 dozen other smaller projects. This demonstrates that Fossil can run on
27 a low-power host processor.
28 Multiple fossil-based projects can easily be hosted on the same machine,
29 even if that machine is itself one of several dozen virtual machines on
30 single physical box. The CGI script that runs the canonical Fossil
31 self-hosting repository is as follows:
32
@@ -38,11 +38,12 @@
38 Server (3) runs as a CGI script on a shared hosting account at
39 <a href="http://www.he.net/">Hurricane Electric</a> in Fremont, CA.
40 This server demonstrates the ability of
41 Fossil to run on an economical shared-host web account with no
42 privileges beyond port 80 HTTP access and CGI. It is not necessary
43 to have a dedicated computer with administrator to run Fossil.
44 As far as we are aware,
45 Fossil is the only full-featured configuration management system
46 that can run in
47 such a restricted environment. The CGI script that runs on the
48 Hurricane Electric server is the same as the CGI script shown above,
49 except that the pathnames are modified to suit the environment:
50
+214 -89
--- www/server.wiki
+++ www/server.wiki
@@ -1,124 +1,249 @@
11
<title>How To Configure A Fossil Server</title>
2
-<nowiki>
3
-<p>This guide is intended to help guide you in setting up a Fossil server.</p>
4
-
2
+<h2>Introduction</h2><blockquote>
3
+<p>A server is not necessary to use Fossil, but a server does help in collaborating with
4
+peers. A Fossil server also works well as a complete website for a project.
5
+For example, the complete <b>http://www.fossil-scm.org/</b> website, including the
6
+page you are now reading (but excepting the download page),
7
+is just a Fossil server displaying the content of the
8
+self-hosting repository for Fossil.</p>
9
+<p>This article is a guide for setting up your own Fossil server.</p></blockquote>
10
+<h2>Overview</h2><blockquote>
11
+There are basically four ways to set up a Fossil server:
12
+<ol>
13
+<li>A stand-alone server
14
+<li>Using inetd or xinetd or stunnel
15
+<li>CGI
16
+<li>SCGI (a.k.a. SimpleCGI)
17
+</ol>
18
+Each of these can serve either a single repository, or a directory hierarchy
19
+containing many repositories with names ending in ".fossil".
20
+</blockquote>
21
+<a name="standalone"></a>
522
<h2>Standalone server</h2><blockquote>
6
-The easiest way to set up a Fossil server is to use the <tt>server</tt> or
7
-<tt>ui</tt> command. Assuming the repository you are interested in serving is
8
-in the file "<tt>repo.fossil</tt>", you can use either of these commands to
9
-start Fossil as a server:
23
+The easiest way to set up a Fossil server is to use either the
24
+[/help/server|server] or the [/help/ui|ui] commands:
1025
<ul>
11
-<li><tt>fossil server repo.fossil</tt>
12
-<li><tt>fossil ui repo.fossil</tt>
26
+<li><b>fossil server</b> <i>REPOSITORY</i>
27
+<li><b>fossil ui</b> <i>REPOSITORY</i>
1328
</ul>
14
-
1529
<p>
16
-Both of these commands start a Fossil server on port 8080 on the local machine,
17
-which can be accessed with the URL: <tt>http://localhost:8080/</tt> using any
18
-handy web browser. The difference between the two commands is that "ui", in
19
-addition to starting the Fossil server, also starts a web browser and points it
20
-to the URL mentioned above. On the other hand, the "ui" command binds to
21
-the loopback IP address only (127.0.0.1) so that the "ui" command cannot be
30
+The <i>REPOSITORY</i> argument is either the name of the repository file, or
31
+a directory containing many repositories.
32
+Both of these commands start a Fossil server, usually on TCP port 8080, though
33
+a higher numbered port might also be used if 8080 is already occupied. You can
34
+access these using URLs of the form <b>http://localhost:8080/</b>, or if
35
+<i>REPOSITORY</i> is a directory, URLs of the form
36
+<b>http://localhost:8080/</b><i>repo</i><b>/</b> where <i>repo</i> is the base
37
+name of the repository file without the ".fossil" suffix.
38
+The difference between "ui" and "server" is that "ui" will
39
+also start a web browser and points it
40
+to the URL mentioned above, and "ui" command binds to
41
+the loopback IP address (127.0.0.1) only so that the "ui" command cannot be
2242
used to serve content to a different machine.
2343
</p>
2444
<p>
25
-NOTES:
26
-<ol>
27
-<li>The option "--port NNN" will start the server on port "NNN" instead of 8080.
28
-<li>If port 8080 is already being used (perhaps by another Fossil server), then
29
-Fossil will use the next available port number.
30
-<li>Starting either command from within an "open" Fossil checkout will start a
31
-server using the repository corresponding to the checkout.
32
-<li>This is an excellent option for quickly sharing with coworkers on a small network.
33
-<li>A huge advantage to this deployment scenario is that no special "root" or "administrator" access is required in order to share the repository.
34
-</ol>
35
-</p>
36
-</blockquote>
37
-
38
-<h2>Fossil as an ''inetd'' service</h2><blockquote>
39
-<p>
40
-Modify your <tt>/etc/inetd.conf</tt> (on Linux, modify as appropriate for your platform) so it contains a line like this:
41
-<blockquote>
42
-<tt>
43
-12345 stream tcp nowait.1000 root /path-to/fossil /path-to/fossil http /other-path-to/repository
44
-</tt>
45
-</blockquote>
46
-In this example, you are telling "inetd" that when an incoming connection on port "12345" happens, it should launch the binary "/path-to/fossil". Obviously you will need to modify the "path-to" parts as appropriate for your particular setup.
47
-</p>
48
-<p>
49
-This is a more complex setup than the "standalone" server, but it has the advantage of only using system resources when an actual connection is attempted. If no-one ever connects to that port, a Fossil server will not (automatically) run. It has the disadvantage of requiring "root" access and therefore may not normally be available to lower-priced "shared" servers on the internet.
50
-</p>
51
-</blockquote>
52
-
53
-<h2>Fossil as a ''CGI script''</h2><blockquote>
54
-<p>
55
-This is the most flexible and most likely to be widely usable of these deployment scenarios. In order for it to work, you must have the ability to install "CGI scripts" on the server you are interested in using.
56
-</p>
57
-</blockquote>
58
-
59
-<h3>One script per repository</h3><blockquote>
60
-<p>
61
-Create a script (let's call it 'repo') in your CGI directory which has content like this:
62
-<blockquote><tt>
63
-#!/path-to/fossil<br>
64
-repository: /path-to-repo/repository
65
-</tt></blockquote>
66
-</p>
67
-<p>
68
-It may be necessary to set permissions properly, or to modify an ".htaccess" file or other server-specific things like that. Consult with your server provider if you need that sort of assistance.
69
-</p>
70
-<p>
71
-Once the script is set up correctly, and assuming your server is also set correctly, you should be able to access your repository with a URL like: <tt>http://mydomain.org/cgi-bin/repo</tt> (assuming the "repo" script is accessible under "cgi-bin", which would be a typical deployment on Apache for instance).
72
-</p>
73
-</blockquote>
74
-
75
-<h3>Serving multiple repositories with one script</h3><blockquote>
76
-<p>
77
-This scenario is almost identical to the previous one. However, here we will assume you have multiple repositories, in one directory.
78
-(Call the directory 'fossils'). All repositories served, in this case, must
79
-use the ".fossil" filename suffix.
80
-As before, create a script (again, 'repo'):
81
-<blockquote><tt>
82
-#!/path-to/fossil<br>
83
-directory: /path-to-repo/fossils<br>
84
-notfound: http://url-to-go-to-if-repo-not-found/
85
-</tt></blockquote>
86
-</p>
87
-<p>
88
-Once deployed, a URL like: <tt>http://mydomain.org/cgi-bin/repo/XYZ</tt> will serve up the repository "fossils/XYX.fossil" (if it exists). This makes serving multiple projects on one server pretty painless.
45
+If one of the commands above is run from within an option checkout,
46
+then the <i>REPOSITORY</i> argument can be omitted and the checkout is used as
47
+the repository.
48
+</p>
49
+<p>
50
+Both commands have additional command-line options that can be used to refine
51
+their behavior. See the [/help/server|online documentation] for an overview.
52
+</p>
53
+</blockquote>
54
+<a name="inetd"></a>
55
+<h2>Fossil as an inetd/xinetd or stunnel service</h2><blockquote>
56
+<p>
57
+A Fossil server can be launched on-demand by inetd or xinetd using
58
+the [/help/http|fossil http] command. To launch Fossil from inetd, modify
59
+your inetd configuration file (typically "/etc/inetd.conf") to contain a
60
+line something like this:
61
+<blockquote>
62
+<pre>
63
+12345 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil
64
+</pre>
65
+</blockquote>
66
+In this example, you are telling "inetd" that when an incoming connection
67
+appears on port "12345", that it should launch the binary "/usr/bin/fossil"
68
+program with the arguments shown.
69
+Obviously you will
70
+need to modify the pathnames parts as appropriate for your particular setup.
71
+The final argument is either the name of the fossil repository to be served,
72
+or a directory containing multiple repositories.
73
+</p>
74
+<p>
75
+If you system is running xinetd, then the configuration is likely to be
76
+in the file "/etc/xinetd.conf" or in a subfile of "/etc/xinetd.d".
77
+An xinetd configuration file will appear like this:</p>
78
+<blockquote>
79
+<pre>
80
+service http-alt
81
+{
82
+ port = 591
83
+ socket_type = stream
84
+ wait = no
85
+ user = root
86
+ server = /usr/bin/fossil
87
+ server_args = http /home/fossil/repos/
88
+}
89
+</pre>
90
+</blockquote>
91
+<p>
92
+The xinetd example above has Fossil configured to serve multiple
93
+repositories, contained under the "/home/fossil/repos/" directory.
94
+</p>
95
+<p>
96
+In both cases notice that Fossil was launched as root. This is not required,
97
+but if it is done, then Fossil will automatically put itself into a chroot
98
+jail for the user who owns the fossil repository before reading any information
99
+off of the wire.
100
+</p>
101
+<p>
102
+[http://www.stunnel.org/ | Stunnel version 4] is an inetd-like process that
103
+accepts and decodes SSL-encrypted connections. Fossil can be run directly from
104
+stunnel in a mannar similar to inetd and xinetd. This can be used to provide
105
+a secure link to a Fossil project. The configuration needed to get stunnel4
106
+to invoke Fossil is very similar to the inetd and xinetd examples shown above.
107
+See the stunnel4 documentation for details.
108
+<p>
109
+Using inetd or xinetd or stunnel is a more complex setup
110
+than the "standalone" server, but it has the
111
+advantage of only using system resources when an actual connection is
112
+attempted. If no-one ever connects to that port, a Fossil server will
113
+not (automatically) run. It has the disadvantage of requiring "root" access
114
+and therefore may not normally be available to lower-priced "shared" servers
115
+on the internet.
116
+</p>
117
+</blockquote>
118
+<a name="cgi"></a>
119
+<h2>Fossil as CGI</h2><blockquote>
120
+<p>
121
+A Fossil server can also be run from an ordinary web server as a CGI program.
122
+This feature allows Fossil to be seamlessly integrated into a larger website.
123
+CGI is how the [./selfhost.wiki | self-hosting fossil repositories] are
124
+implemented.
125
+</p>
126
+<p>
127
+To run Fossil as CGI, create a CGI script (here called "repo") in the CGI directory
128
+of your web server and having content like this:
129
+<blockquote><pre>
130
+#!/usr/bin/fossil
131
+repository: /home/fossil/repo.fossil
132
+</pre></blockquote>
133
+</p>
134
+<p>
135
+As always, adjust your paths appropriately.
136
+It may be necessary to set permissions properly, or to modify an ".htaccess"
137
+file or other server-specific things like that. Consult the documentation
138
+for your particular server.
139
+</p>
140
+<p>
141
+Once the script is set up correctly, and assuming your server is also set
142
+correctly, you should be able to access your repository with a URL like:
143
+<b>http://mydomain.org/cgi-bin/repo</b> (assuming the "repo" script is
144
+accessible under "cgi-bin", which would be a typical deployment on Apache
145
+for instance).
146
+</p>
147
+<p>
148
+To server multiple repositories from a directory using CGI, use the "directory:"
149
+tag in the CGI script rather than "repository:". You might also want to add
150
+a "notfound:" tag to tell where to redirect if the particular repository requested
151
+by the URL is not found:
152
+<blockquote><pre>
153
+#!/usr/bin/fossil
154
+directory: /home/fossil/repos
155
+notfound: http://url-to-go-to-if-repo-not-found/
156
+</pre></blockquote>
157
+</p>
158
+<p>
159
+Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b>
160
+will serve up the repository "/home/fossil/repos/XYX.fossil" (if it exists).
161
+</p>
162
+</blockquote>
163
+
164
+<a name="scgi"></a>
165
+<h2>Fossil as SCGI</h2><blockquote>
166
+
167
+<p>
168
+The [/help/server|fossil server] command, described above as a way of
169
+starting a stand-alone web server, can also be used for SCGI. Simply add
170
+the --scgi command-line option and the stand-alone server will interpret
171
+and respond to the SimpleCGI or SCGI protocol rather than raw HTTP. This can
172
+be used in combination with a webserver (such as [http://nginx.org|Nginx])
173
+that does not support CGI. A typical Nginx configuration to support SCGI
174
+with Fossil would look something like this:
175
+<blockquote><pre>
176
+location ~ ^/demo_project/ {
177
+ include scgi_params;
178
+ scgi_pass localhost:9000;
179
+ scgi_param SCRIPT_NAME "/demo_project";
180
+}
181
+</pre></blockquote>
182
+<p>
183
+Note that Fossil requires the SCRIPT_NAME variable
184
+in order to function properly, but Nginx does not provide this
185
+variable by default.
186
+So it is necessary to provide the SCRIPT_NAME parameter in the configuration.
187
+Failure to do this will cause Fossil to return an error.
188
+</p>
189
+<p>
190
+All of the features of the stand-alone server mode described above,
191
+such as the ability to server a directory full of Fossil repositories
192
+rather than just a single repository, work the same way in SCGI mode.
89193
</p>
90194
</blockquote>
91195
92196
<h2>Securing a repository with SSL</h2><blockquote>
93197
<p>
94
-Using either of the CGI script approaches, it is trivial to use SSL to secure the server. Simply set up the Fossil CGI scripts etc. as above, but modify the Apache (or IIS, etc.) server to require SSL (that is, a URL with "https://") in order to access the CGI script directory. This may also be accomplished (on Apache, at least) using appropriate ".htaccess" rules.
198
+Using either CGI or SCGI, it is trivial to use SSL to
199
+secure the server. Simply set up the Fossil CGI scripts etc. as above,
200
+but modify the Apache (or IIS, etc.) server to require SSL (that is, a
201
+URL with "https://") in order to access the CGI script directory. This
202
+may also be accomplished (on Apache, at least) using appropriate
203
+".htaccess" rules.
95204
</p>
96205
<p>
97
-If you are using "inetd" to serve your repository, then you simply need to add "/usr/bin/stunnel" (perhaps on a different path, depending on your setup) before the command line to launch Fossil.
206
+If you are using "inetd" to serve your repository, then you simply need
207
+to add "/usr/bin/stunnel" (perhaps on a different path, depending on your
208
+setup) before the command line to launch Fossil.
98209
</p>
99210
<p>
100
-At this stage, the standalone server (e.g. "fossil server") does not support SSL.
211
+At this stage, the standalone server (e.g. "fossil server") does not
212
+support SSL.
101213
</p>
102214
<p>
103215
For more information, see <a href="./ssl.wiki">Using SSL with Fossil</a>.
104216
</p>
105217
</blockquote>
106218
107219
<h2>Various security concerns with hosted repositories</h2><blockquote>
108220
<p>
109
-There are two main concerns relating to usage of Fossil for sharing sensitive information (source or any other data):
221
+There are two main concerns relating to usage of Fossil for sharing
222
+sensitive information (source or any other data):
110223
<ul>
111
-<li>Interception of the Fossil synchronization stream, thereby capturing data, and
224
+<li>Interception of the Fossil synchronization stream, thereby capturing
225
+data, and
112226
<li>Direct access to the Fossil repository on the server
113227
</ul>
114228
</p>
115229
<p>
116
-Regarding the first, it is adequate to secure the server using SSL, and disallowing any non-SSL access. The data stream will be encrypted by the HTTPS protocol, rendering the data reasonably secure. The truly paranoid may wish to deploy <i>ssh</i> encrypted tunnels, but that is quite a bit more difficult and cumbersome to set up (particularly for a larger number of users).
230
+Regarding the first, it is adequate to secure the server using SSL, and
231
+disallowing any non-SSL access. The data stream will be encrypted by
232
+the HTTPS protocol, rendering the data reasonably secure. The truly
233
+paranoid may wish to deploy <i>ssh</i> encrypted tunnels, but that is
234
+quite a bit more difficult and cumbersome to set up (particularly for
235
+a larger number of users).
117236
</p>
118237
<p>
119
-As far as direct access to the repository, the same steps must be taken as for any other internet-facing data-store. Access passwords to any disk-accessing accounts should be strong (and preferably changed from time to time). However, the data in the repository itself are <i>not</i> encrypted (unless you save encrypted data yourself), and so the system administrators of your server will be able to access your data (as with any hosting service setup). The only workaround in this case is to host the server yourself, in which case you will need to allocate resources to deal with administration issues.
238
+As far as direct access to the repository, the same steps must be taken
239
+as for any other internet-facing data-store. Access passwords to any
240
+disk-accessing accounts should be strong (and preferably changed from
241
+time to time). However, the data in the repository itself are <i>not</i>
242
+encrypted (unless you save encrypted data yourself), and so the system
243
+administrators of your server will be able to access your data (as with
244
+any hosting service setup). The only workaround in this case is to
245
+host the server yourself, in which case you will need to allocate
246
+resources to deal with administration issues.
120247
</p>
121248
122249
</blockquote>
123
-
124
-</nowiki>
125250
--- www/server.wiki
+++ www/server.wiki
@@ -1,124 +1,249 @@
1 <title>How To Configure A Fossil Server</title>
2 <nowiki>
3 <p>This guide is intended to help guide you in setting up a Fossil server.</p>
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5 <h2>Standalone server</h2><blockquote>
6 The easiest way to set up a Fossil server is to use the <tt>server</tt> or
7 <tt>ui</tt> command. Assuming the repository you are interested in serving is
8 in the file "<tt>repo.fossil</tt>", you can use either of these commands to
9 start Fossil as a server:
10 <ul>
11 <li><tt>fossil server repo.fossil</tt>
12 <li><tt>fossil ui repo.fossil</tt>
13 </ul>
14
15 <p>
16 Both of these commands start a Fossil server on port 8080 on the local machine,
17 which can be accessed with the URL: <tt>http://localhost:8080/</tt> using any
18 handy web browser. The difference between the two commands is that "ui", in
19 addition to starting the Fossil server, also starts a web browser and points it
20 to the URL mentioned above. On the other hand, the "ui" command binds to
21 the loopback IP address only (127.0.0.1) so that the "ui" command cannot be
 
 
 
 
 
 
22 used to serve content to a different machine.
23 </p>
24 <p>
25 NOTES:
26 <ol>
27 <li>The option "--port NNN" will start the server on port "NNN" instead of 8080.
28 <li>If port 8080 is already being used (perhaps by another Fossil server), then
29 Fossil will use the next available port number.
30 <li>Starting either command from within an "open" Fossil checkout will start a
31 server using the repository corresponding to the checkout.
32 <li>This is an excellent option for quickly sharing with coworkers on a small network.
33 <li>A huge advantage to this deployment scenario is that no special "root" or "administrator" access is required in order to share the repository.
34 </ol>
35 </p>
36 </blockquote>
37
38 <h2>Fossil as an ''inetd'' service</h2><blockquote>
39 <p>
40 Modify your <tt>/etc/inetd.conf</tt> (on Linux, modify as appropriate for your platform) so it contains a line like this:
41 <blockquote>
42 <tt>
43 12345 stream tcp nowait.1000 root /path-to/fossil /path-to/fossil http /other-path-to/repository
44 </tt>
45 </blockquote>
46 In this example, you are telling "inetd" that when an incoming connection on port "12345" happens, it should launch the binary "/path-to/fossil". Obviously you will need to modify the "path-to" parts as appropriate for your particular setup.
47 </p>
48 <p>
49 This is a more complex setup than the "standalone" server, but it has the advantage of only using system resources when an actual connection is attempted. If no-one ever connects to that port, a Fossil server will not (automatically) run. It has the disadvantage of requiring "root" access and therefore may not normally be available to lower-priced "shared" servers on the internet.
50 </p>
51 </blockquote>
52
53 <h2>Fossil as a ''CGI script''</h2><blockquote>
54 <p>
55 This is the most flexible and most likely to be widely usable of these deployment scenarios. In order for it to work, you must have the ability to install "CGI scripts" on the server you are interested in using.
56 </p>
57 </blockquote>
58
59 <h3>One script per repository</h3><blockquote>
60 <p>
61 Create a script (let's call it 'repo') in your CGI directory which has content like this:
62 <blockquote><tt>
63 #!/path-to/fossil<br>
64 repository: /path-to-repo/repository
65 </tt></blockquote>
66 </p>
67 <p>
68 It may be necessary to set permissions properly, or to modify an ".htaccess" file or other server-specific things like that. Consult with your server provider if you need that sort of assistance.
69 </p>
70 <p>
71 Once the script is set up correctly, and assuming your server is also set correctly, you should be able to access your repository with a URL like: <tt>http://mydomain.org/cgi-bin/repo</tt> (assuming the "repo" script is accessible under "cgi-bin", which would be a typical deployment on Apache for instance).
72 </p>
73 </blockquote>
74
75 <h3>Serving multiple repositories with one script</h3><blockquote>
76 <p>
77 This scenario is almost identical to the previous one. However, here we will assume you have multiple repositories, in one directory.
78 (Call the directory 'fossils'). All repositories served, in this case, must
79 use the ".fossil" filename suffix.
80 As before, create a script (again, 'repo'):
81 <blockquote><tt>
82 #!/path-to/fossil<br>
83 directory: /path-to-repo/fossils<br>
84 notfound: http://url-to-go-to-if-repo-not-found/
85 </tt></blockquote>
86 </p>
87 <p>
88 Once deployed, a URL like: <tt>http://mydomain.org/cgi-bin/repo/XYZ</tt> will serve up the repository "fossils/XYX.fossil" (if it exists). This makes serving multiple projects on one server pretty painless.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89 </p>
90 </blockquote>
91
92 <h2>Securing a repository with SSL</h2><blockquote>
93 <p>
94 Using either of the CGI script approaches, it is trivial to use SSL to secure the server. Simply set up the Fossil CGI scripts etc. as above, but modify the Apache (or IIS, etc.) server to require SSL (that is, a URL with "https://") in order to access the CGI script directory. This may also be accomplished (on Apache, at least) using appropriate ".htaccess" rules.
 
 
 
 
 
95 </p>
96 <p>
97 If you are using "inetd" to serve your repository, then you simply need to add "/usr/bin/stunnel" (perhaps on a different path, depending on your setup) before the command line to launch Fossil.
 
 
98 </p>
99 <p>
100 At this stage, the standalone server (e.g. "fossil server") does not support SSL.
 
101 </p>
102 <p>
103 For more information, see <a href="./ssl.wiki">Using SSL with Fossil</a>.
104 </p>
105 </blockquote>
106
107 <h2>Various security concerns with hosted repositories</h2><blockquote>
108 <p>
109 There are two main concerns relating to usage of Fossil for sharing sensitive information (source or any other data):
 
110 <ul>
111 <li>Interception of the Fossil synchronization stream, thereby capturing data, and
 
112 <li>Direct access to the Fossil repository on the server
113 </ul>
114 </p>
115 <p>
116 Regarding the first, it is adequate to secure the server using SSL, and disallowing any non-SSL access. The data stream will be encrypted by the HTTPS protocol, rendering the data reasonably secure. The truly paranoid may wish to deploy <i>ssh</i> encrypted tunnels, but that is quite a bit more difficult and cumbersome to set up (particularly for a larger number of users).
 
 
 
 
 
117 </p>
118 <p>
119 As far as direct access to the repository, the same steps must be taken as for any other internet-facing data-store. Access passwords to any disk-accessing accounts should be strong (and preferably changed from time to time). However, the data in the repository itself are <i>not</i> encrypted (unless you save encrypted data yourself), and so the system administrators of your server will be able to access your data (as with any hosting service setup). The only workaround in this case is to host the server yourself, in which case you will need to allocate resources to deal with administration issues.
 
 
 
 
 
 
 
 
120 </p>
121
122 </blockquote>
123
124 </nowiki>
125
--- www/server.wiki
+++ www/server.wiki
@@ -1,124 +1,249 @@
1 <title>How To Configure A Fossil Server</title>
2 <h2>Introduction</h2><blockquote>
3 <p>A server is not necessary to use Fossil, but a server does help in collaborating with
4 peers. A Fossil server also works well as a complete website for a project.
5 For example, the complete <b>http://www.fossil-scm.org/</b> website, including the
6 page you are now reading (but excepting the download page),
7 is just a Fossil server displaying the content of the
8 self-hosting repository for Fossil.</p>
9 <p>This article is a guide for setting up your own Fossil server.</p></blockquote>
10 <h2>Overview</h2><blockquote>
11 There are basically four ways to set up a Fossil server:
12 <ol>
13 <li>A stand-alone server
14 <li>Using inetd or xinetd or stunnel
15 <li>CGI
16 <li>SCGI (a.k.a. SimpleCGI)
17 </ol>
18 Each of these can serve either a single repository, or a directory hierarchy
19 containing many repositories with names ending in ".fossil".
20 </blockquote>
21 <a name="standalone"></a>
22 <h2>Standalone server</h2><blockquote>
23 The easiest way to set up a Fossil server is to use either the
24 [/help/server|server] or the [/help/ui|ui] commands:
 
 
25 <ul>
26 <li><b>fossil server</b> <i>REPOSITORY</i>
27 <li><b>fossil ui</b> <i>REPOSITORY</i>
28 </ul>
 
29 <p>
30 The <i>REPOSITORY</i> argument is either the name of the repository file, or
31 a directory containing many repositories.
32 Both of these commands start a Fossil server, usually on TCP port 8080, though
33 a higher numbered port might also be used if 8080 is already occupied. You can
34 access these using URLs of the form <b>http://localhost:8080/</b>, or if
35 <i>REPOSITORY</i> is a directory, URLs of the form
36 <b>http://localhost:8080/</b><i>repo</i><b>/</b> where <i>repo</i> is the base
37 name of the repository file without the ".fossil" suffix.
38 The difference between "ui" and "server" is that "ui" will
39 also start a web browser and points it
40 to the URL mentioned above, and "ui" command binds to
41 the loopback IP address (127.0.0.1) only so that the "ui" command cannot be
42 used to serve content to a different machine.
43 </p>
44 <p>
45 If one of the commands above is run from within an option checkout,
46 then the <i>REPOSITORY</i> argument can be omitted and the checkout is used as
47 the repository.
48 </p>
49 <p>
50 Both commands have additional command-line options that can be used to refine
51 their behavior. See the [/help/server|online documentation] for an overview.
52 </p>
53 </blockquote>
54 <a name="inetd"></a>
55 <h2>Fossil as an inetd/xinetd or stunnel service</h2><blockquote>
56 <p>
57 A Fossil server can be launched on-demand by inetd or xinetd using
58 the [/help/http|fossil http] command. To launch Fossil from inetd, modify
59 your inetd configuration file (typically "/etc/inetd.conf") to contain a
60 line something like this:
61 <blockquote>
62 <pre>
63 12345 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil
64 </pre>
65 </blockquote>
66 In this example, you are telling "inetd" that when an incoming connection
67 appears on port "12345", that it should launch the binary "/usr/bin/fossil"
68 program with the arguments shown.
69 Obviously you will
70 need to modify the pathnames parts as appropriate for your particular setup.
71 The final argument is either the name of the fossil repository to be served,
72 or a directory containing multiple repositories.
73 </p>
74 <p>
75 If you system is running xinetd, then the configuration is likely to be
76 in the file "/etc/xinetd.conf" or in a subfile of "/etc/xinetd.d".
77 An xinetd configuration file will appear like this:</p>
78 <blockquote>
79 <pre>
80 service http-alt
81 {
82 port = 591
83 socket_type = stream
84 wait = no
85 user = root
86 server = /usr/bin/fossil
87 server_args = http /home/fossil/repos/
88 }
89 </pre>
90 </blockquote>
91 <p>
92 The xinetd example above has Fossil configured to serve multiple
93 repositories, contained under the "/home/fossil/repos/" directory.
94 </p>
95 <p>
96 In both cases notice that Fossil was launched as root. This is not required,
97 but if it is done, then Fossil will automatically put itself into a chroot
98 jail for the user who owns the fossil repository before reading any information
99 off of the wire.
100 </p>
101 <p>
102 [http://www.stunnel.org/ | Stunnel version 4] is an inetd-like process that
103 accepts and decodes SSL-encrypted connections. Fossil can be run directly from
104 stunnel in a mannar similar to inetd and xinetd. This can be used to provide
105 a secure link to a Fossil project. The configuration needed to get stunnel4
106 to invoke Fossil is very similar to the inetd and xinetd examples shown above.
107 See the stunnel4 documentation for details.
108 <p>
109 Using inetd or xinetd or stunnel is a more complex setup
110 than the "standalone" server, but it has the
111 advantage of only using system resources when an actual connection is
112 attempted. If no-one ever connects to that port, a Fossil server will
113 not (automatically) run. It has the disadvantage of requiring "root" access
114 and therefore may not normally be available to lower-priced "shared" servers
115 on the internet.
116 </p>
117 </blockquote>
118 <a name="cgi"></a>
119 <h2>Fossil as CGI</h2><blockquote>
120 <p>
121 A Fossil server can also be run from an ordinary web server as a CGI program.
122 This feature allows Fossil to be seamlessly integrated into a larger website.
123 CGI is how the [./selfhost.wiki | self-hosting fossil repositories] are
124 implemented.
125 </p>
126 <p>
127 To run Fossil as CGI, create a CGI script (here called "repo") in the CGI directory
128 of your web server and having content like this:
129 <blockquote><pre>
130 #!/usr/bin/fossil
131 repository: /home/fossil/repo.fossil
132 </pre></blockquote>
133 </p>
134 <p>
135 As always, adjust your paths appropriately.
136 It may be necessary to set permissions properly, or to modify an ".htaccess"
137 file or other server-specific things like that. Consult the documentation
138 for your particular server.
139 </p>
140 <p>
141 Once the script is set up correctly, and assuming your server is also set
142 correctly, you should be able to access your repository with a URL like:
143 <b>http://mydomain.org/cgi-bin/repo</b> (assuming the "repo" script is
144 accessible under "cgi-bin", which would be a typical deployment on Apache
145 for instance).
146 </p>
147 <p>
148 To server multiple repositories from a directory using CGI, use the "directory:"
149 tag in the CGI script rather than "repository:". You might also want to add
150 a "notfound:" tag to tell where to redirect if the particular repository requested
151 by the URL is not found:
152 <blockquote><pre>
153 #!/usr/bin/fossil
154 directory: /home/fossil/repos
155 notfound: http://url-to-go-to-if-repo-not-found/
156 </pre></blockquote>
157 </p>
158 <p>
159 Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b>
160 will serve up the repository "/home/fossil/repos/XYX.fossil" (if it exists).
161 </p>
162 </blockquote>
163
164 <a name="scgi"></a>
165 <h2>Fossil as SCGI</h2><blockquote>
166
167 <p>
168 The [/help/server|fossil server] command, described above as a way of
169 starting a stand-alone web server, can also be used for SCGI. Simply add
170 the --scgi command-line option and the stand-alone server will interpret
171 and respond to the SimpleCGI or SCGI protocol rather than raw HTTP. This can
172 be used in combination with a webserver (such as [http://nginx.org|Nginx])
173 that does not support CGI. A typical Nginx configuration to support SCGI
174 with Fossil would look something like this:
175 <blockquote><pre>
176 location ~ ^/demo_project/ {
177 include scgi_params;
178 scgi_pass localhost:9000;
179 scgi_param SCRIPT_NAME "/demo_project";
180 }
181 </pre></blockquote>
182 <p>
183 Note that Fossil requires the SCRIPT_NAME variable
184 in order to function properly, but Nginx does not provide this
185 variable by default.
186 So it is necessary to provide the SCRIPT_NAME parameter in the configuration.
187 Failure to do this will cause Fossil to return an error.
188 </p>
189 <p>
190 All of the features of the stand-alone server mode described above,
191 such as the ability to server a directory full of Fossil repositories
192 rather than just a single repository, work the same way in SCGI mode.
193 </p>
194 </blockquote>
195
196 <h2>Securing a repository with SSL</h2><blockquote>
197 <p>
198 Using either CGI or SCGI, it is trivial to use SSL to
199 secure the server. Simply set up the Fossil CGI scripts etc. as above,
200 but modify the Apache (or IIS, etc.) server to require SSL (that is, a
201 URL with "https://") in order to access the CGI script directory. This
202 may also be accomplished (on Apache, at least) using appropriate
203 ".htaccess" rules.
204 </p>
205 <p>
206 If you are using "inetd" to serve your repository, then you simply need
207 to add "/usr/bin/stunnel" (perhaps on a different path, depending on your
208 setup) before the command line to launch Fossil.
209 </p>
210 <p>
211 At this stage, the standalone server (e.g. "fossil server") does not
212 support SSL.
213 </p>
214 <p>
215 For more information, see <a href="./ssl.wiki">Using SSL with Fossil</a>.
216 </p>
217 </blockquote>
218
219 <h2>Various security concerns with hosted repositories</h2><blockquote>
220 <p>
221 There are two main concerns relating to usage of Fossil for sharing
222 sensitive information (source or any other data):
223 <ul>
224 <li>Interception of the Fossil synchronization stream, thereby capturing
225 data, and
226 <li>Direct access to the Fossil repository on the server
227 </ul>
228 </p>
229 <p>
230 Regarding the first, it is adequate to secure the server using SSL, and
231 disallowing any non-SSL access. The data stream will be encrypted by
232 the HTTPS protocol, rendering the data reasonably secure. The truly
233 paranoid may wish to deploy <i>ssh</i> encrypted tunnels, but that is
234 quite a bit more difficult and cumbersome to set up (particularly for
235 a larger number of users).
236 </p>
237 <p>
238 As far as direct access to the repository, the same steps must be taken
239 as for any other internet-facing data-store. Access passwords to any
240 disk-accessing accounts should be strong (and preferably changed from
241 time to time). However, the data in the repository itself are <i>not</i>
242 encrypted (unless you save encrypted data yourself), and so the system
243 administrators of your server will be able to access your data (as with
244 any hosting service setup). The only workaround in this case is to
245 host the server yourself, in which case you will need to allocate
246 resources to deal with administration issues.
247 </p>
248
249 </blockquote>
 
 
250
+9 -3
--- www/webui.wiki
+++ www/webui.wiki
@@ -67,11 +67,12 @@
6767
URL. So there is never any fumbling around trying to find an open
6868
port or to type arcane strings into your browser URL entry box.
6969
The interface just pops right up, ready to run.
7070
7171
The Fossil web interface is also very easy to setup and run on a
72
-network server, as either a CGI program or from inetd. Details on how
72
+network server, as either a CGI program or from inetd, or as an
73
+SCGI server. Details on how
7374
to do that are described further below.
7475
7576
<h2>Things To Do Using The Web Interface</h2>
7677
7778
You can view <b>timelines</b> of changes to the project. The default
@@ -135,11 +136,12 @@
135136
<h2>Installing On A Network Server</h2>
136137
137138
When you create a new Fossil project and after you have configured it
138139
like you want it using the web interface, you can make the project
139140
available to a distributed team by simply copying the single
140
-repository file up to a web server that supports CGI. Just put the
141
+repository file up to a web server that supports CGI or SCGI. To
142
+run Fossil as CGI, just put the
141143
<b>sample-project.fossil</b> file in a directory where CGI scripts
142144
have both read and write permission on the file and the directory that
143145
contains the file, then add a CGI script that looks something like this:
144146
145147
<verbatim>
@@ -151,11 +153,15 @@
151153
of course, and also make sure the Fossil binary is installed on the server.
152154
But that is <u>all</u> you have to do. You now have everything you need to host
153155
a distributed software development project in less than five minutes using a
154156
two-line CGI script.
155157
156
-You don't have a CGI-capable web server running on your server machine?
158
+Instructions for setting up an SCGI server are
159
+[./scgi.wiki | available separately].
160
+
161
+You don't have a CGI- or SCGI-capable web server running on your
162
+server machine?
157163
Not a problem. The Fossil interface can also be launched via inetd or
158164
xinetd. An inetd configuration line sufficient to launch the Fossil
159165
web interface looks like this:
160166
161167
<verbatim>
162168
--- www/webui.wiki
+++ www/webui.wiki
@@ -67,11 +67,12 @@
67 URL. So there is never any fumbling around trying to find an open
68 port or to type arcane strings into your browser URL entry box.
69 The interface just pops right up, ready to run.
70
71 The Fossil web interface is also very easy to setup and run on a
72 network server, as either a CGI program or from inetd. Details on how
 
73 to do that are described further below.
74
75 <h2>Things To Do Using The Web Interface</h2>
76
77 You can view <b>timelines</b> of changes to the project. The default
@@ -135,11 +136,12 @@
135 <h2>Installing On A Network Server</h2>
136
137 When you create a new Fossil project and after you have configured it
138 like you want it using the web interface, you can make the project
139 available to a distributed team by simply copying the single
140 repository file up to a web server that supports CGI. Just put the
 
141 <b>sample-project.fossil</b> file in a directory where CGI scripts
142 have both read and write permission on the file and the directory that
143 contains the file, then add a CGI script that looks something like this:
144
145 <verbatim>
@@ -151,11 +153,15 @@
151 of course, and also make sure the Fossil binary is installed on the server.
152 But that is <u>all</u> you have to do. You now have everything you need to host
153 a distributed software development project in less than five minutes using a
154 two-line CGI script.
155
156 You don't have a CGI-capable web server running on your server machine?
 
 
 
 
157 Not a problem. The Fossil interface can also be launched via inetd or
158 xinetd. An inetd configuration line sufficient to launch the Fossil
159 web interface looks like this:
160
161 <verbatim>
162
--- www/webui.wiki
+++ www/webui.wiki
@@ -67,11 +67,12 @@
67 URL. So there is never any fumbling around trying to find an open
68 port or to type arcane strings into your browser URL entry box.
69 The interface just pops right up, ready to run.
70
71 The Fossil web interface is also very easy to setup and run on a
72 network server, as either a CGI program or from inetd, or as an
73 SCGI server. Details on how
74 to do that are described further below.
75
76 <h2>Things To Do Using The Web Interface</h2>
77
78 You can view <b>timelines</b> of changes to the project. The default
@@ -135,11 +136,12 @@
136 <h2>Installing On A Network Server</h2>
137
138 When you create a new Fossil project and after you have configured it
139 like you want it using the web interface, you can make the project
140 available to a distributed team by simply copying the single
141 repository file up to a web server that supports CGI or SCGI. To
142 run Fossil as CGI, just put the
143 <b>sample-project.fossil</b> file in a directory where CGI scripts
144 have both read and write permission on the file and the directory that
145 contains the file, then add a CGI script that looks something like this:
146
147 <verbatim>
@@ -151,11 +153,15 @@
153 of course, and also make sure the Fossil binary is installed on the server.
154 But that is <u>all</u> you have to do. You now have everything you need to host
155 a distributed software development project in less than five minutes using a
156 two-line CGI script.
157
158 Instructions for setting up an SCGI server are
159 [./scgi.wiki | available separately].
160
161 You don't have a CGI- or SCGI-capable web server running on your
162 server machine?
163 Not a problem. The Fossil interface can also be launched via inetd or
164 xinetd. An inetd configuration line sufficient to launch the Fossil
165 web interface looks like this:
166
167 <verbatim>
168

Keyboard Shortcuts

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