Fossil SCM
Fix the HTTP-reply parser so that it is able to deal with replies that lack a Content-Length header field. This resolves the issue reported by [forum:/forumpost/12ac403fd29cfc89|forum post 12ac403fd29cfc89]. Also in this merge: (1) Add the --xverbose option to "fossil clone". (2) Improved error messages when web servers misbehave. See also my misguided and incorrect [https://bz.apache.org/bugzilla/show_bug.cgi?id=68905|Apache bug 68905]. Special thanks to Apache devs for setting me straight.
Commit
a8e33fb161f45b65167f0dfe39b6fcbad21f5844ee469131fd8fa8fc09cd5e99
Parent
9c40ddbcd182f26…
4 files changed
+33
-10
+13
-1
+57
-9
+10
-1
+33
-10
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -1238,11 +1238,11 @@ | ||
| 1238 | 1238 | } |
| 1239 | 1239 | fputs(z, pLog); |
| 1240 | 1240 | } |
| 1241 | 1241 | |
| 1242 | 1242 | /* Forward declaration */ |
| 1243 | -static NORETURN void malformed_request(const char *zMsg); | |
| 1243 | +static NORETURN void malformed_request(const char *zMsg, ...); | |
| 1244 | 1244 | |
| 1245 | 1245 | /* |
| 1246 | 1246 | ** Checks the QUERY_STRING environment variable, sets it up |
| 1247 | 1247 | ** via add_param_list() and, if found, applies its "skin" |
| 1248 | 1248 | ** setting. Returns 0 if no QUERY_STRING is set, 1 if it is, |
| @@ -1321,10 +1321,11 @@ | ||
| 1321 | 1321 | char *zSemi; |
| 1322 | 1322 | int len; |
| 1323 | 1323 | const char *zRequestUri = cgi_parameter("REQUEST_URI",0); |
| 1324 | 1324 | const char *zScriptName = cgi_parameter("SCRIPT_NAME",0); |
| 1325 | 1325 | const char *zPathInfo = cgi_parameter("PATH_INFO",0); |
| 1326 | + const char *zContentLength = 0; | |
| 1326 | 1327 | #ifdef _WIN32 |
| 1327 | 1328 | const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0); |
| 1328 | 1329 | #endif |
| 1329 | 1330 | |
| 1330 | 1331 | #ifdef FOSSIL_ENABLE_JSON |
| @@ -1418,11 +1419,19 @@ | ||
| 1418 | 1419 | z = (char*)P("REMOTE_ADDR"); |
| 1419 | 1420 | if( z ){ |
| 1420 | 1421 | g.zIpAddr = fossil_strdup(z); |
| 1421 | 1422 | } |
| 1422 | 1423 | |
| 1423 | - len = atoi(PD("CONTENT_LENGTH", "0")); | |
| 1424 | + zContentLength = P("CONTENT_LENGTH"); | |
| 1425 | + if( zContentLength==0 ){ | |
| 1426 | + len = 0; | |
| 1427 | + if( sqlite3_stricmp(PD("REQUEST_METHOD",""),"POST")==0 ){ | |
| 1428 | + malformed_request("missing CONTENT_LENGTH on a POST method"); | |
| 1429 | + } | |
| 1430 | + }else{ | |
| 1431 | + len = atoi(zContentLength); | |
| 1432 | + } | |
| 1424 | 1433 | zType = P("CONTENT_TYPE"); |
| 1425 | 1434 | zSemi = zType ? strchr(zType, ';') : 0; |
| 1426 | 1435 | if( zSemi ){ |
| 1427 | 1436 | g.zContentType = fossil_strndup(zType, (int)(zSemi-zType)); |
| 1428 | 1437 | zType = g.zContentType; |
| @@ -1912,15 +1921,26 @@ | ||
| 1912 | 1921 | |
| 1913 | 1922 | |
| 1914 | 1923 | /* |
| 1915 | 1924 | ** Send a reply indicating that the HTTP request was malformed |
| 1916 | 1925 | */ |
| 1917 | -static NORETURN void malformed_request(const char *zMsg){ | |
| 1918 | - cgi_set_status(501, "Not Implemented"); | |
| 1919 | - cgi_printf( | |
| 1920 | - "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg | |
| 1921 | - ); | |
| 1926 | +static NORETURN void malformed_request(const char *zMsg, ...){ | |
| 1927 | + va_list ap; | |
| 1928 | + char *z; | |
| 1929 | + va_start(ap, zMsg); | |
| 1930 | + z = vmprintf(zMsg, ap); | |
| 1931 | + va_end(ap); | |
| 1932 | + cgi_set_status(400, "Bad Request"); | |
| 1933 | + zContentType = "text/plain"; | |
| 1934 | + if( g.zReqType==0 ) g.zReqType = "WWW"; | |
| 1935 | + if( g.zReqType[0]=='C' && PD("SERVER_SOFTWARE",0)!=0 ){ | |
| 1936 | + const char *zServer = PD("SERVER_SOFTWARE",""); | |
| 1937 | + cgi_printf("Bad CGI Request from \"%s\": %s\n",zServer,z); | |
| 1938 | + }else{ | |
| 1939 | + cgi_printf("Bad %s Request: %s\n", g.zReqType, z); | |
| 1940 | + } | |
| 1941 | + fossil_free(z); | |
| 1922 | 1942 | cgi_reply(); |
| 1923 | 1943 | fossil_exit(0); |
| 1924 | 1944 | } |
| 1925 | 1945 | |
| 1926 | 1946 | /* |
| @@ -2033,12 +2053,13 @@ | ||
| 2033 | 2053 | char *z, *zToken; |
| 2034 | 2054 | int i; |
| 2035 | 2055 | const char *zScheme = "http"; |
| 2036 | 2056 | char zLine[2000]; /* A single line of input. */ |
| 2037 | 2057 | g.fullHttpReply = 1; |
| 2058 | + g.zReqType = "HTTP"; | |
| 2038 | 2059 | if( cgi_fgets(zLine, sizeof(zLine))==0 ){ |
| 2039 | - malformed_request("missing HTTP header"); | |
| 2060 | + malformed_request("missing header"); | |
| 2040 | 2061 | } |
| 2041 | 2062 | blob_append(&g.httpHeader, zLine, -1); |
| 2042 | 2063 | cgi_trace(zLine); |
| 2043 | 2064 | zToken = extract_token(zLine, &z); |
| 2044 | 2065 | if( zToken==0 ){ |
| @@ -2046,17 +2067,18 @@ | ||
| 2046 | 2067 | } |
| 2047 | 2068 | if( fossil_strcmp(zToken,"GET")!=0 |
| 2048 | 2069 | && fossil_strcmp(zToken,"POST")!=0 |
| 2049 | 2070 | && fossil_strcmp(zToken,"HEAD")!=0 |
| 2050 | 2071 | ){ |
| 2051 | - malformed_request("unsupported HTTP method"); | |
| 2072 | + malformed_request("unsupported HTTP method: \"%s\" - Fossil only supports" | |
| 2073 | + "GET, POST, and HEAD", zToken); | |
| 2052 | 2074 | } |
| 2053 | 2075 | cgi_setenv("GATEWAY_INTERFACE","CGI/1.0"); |
| 2054 | 2076 | cgi_setenv("REQUEST_METHOD",zToken); |
| 2055 | 2077 | zToken = extract_token(z, &z); |
| 2056 | 2078 | if( zToken==0 ){ |
| 2057 | - malformed_request("malformed URL in HTTP header"); | |
| 2079 | + malformed_request("malformed URI in the HTTP header"); | |
| 2058 | 2080 | } |
| 2059 | 2081 | cgi_setenv("REQUEST_URI", zToken); |
| 2060 | 2082 | cgi_setenv("SCRIPT_NAME", ""); |
| 2061 | 2083 | for(i=0; zToken[i] && zToken[i]!='?'; i++){} |
| 2062 | 2084 | if( zToken[i] ) zToken[i++] = 0; |
| @@ -2164,10 +2186,11 @@ | ||
| 2164 | 2186 | g.zIpAddr = fossil_strdup(zIpAddr); |
| 2165 | 2187 | } |
| 2166 | 2188 | }else{ |
| 2167 | 2189 | fossil_fatal("missing SSH IP address"); |
| 2168 | 2190 | } |
| 2191 | + g.zReqType = "HTTP"; | |
| 2169 | 2192 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 2170 | 2193 | malformed_request("missing HTTP header"); |
| 2171 | 2194 | } |
| 2172 | 2195 | cgi_trace(zLine); |
| 2173 | 2196 | zToken = extract_token(zLine, &z); |
| 2174 | 2197 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1238,11 +1238,11 @@ | |
| 1238 | } |
| 1239 | fputs(z, pLog); |
| 1240 | } |
| 1241 | |
| 1242 | /* Forward declaration */ |
| 1243 | static NORETURN void malformed_request(const char *zMsg); |
| 1244 | |
| 1245 | /* |
| 1246 | ** Checks the QUERY_STRING environment variable, sets it up |
| 1247 | ** via add_param_list() and, if found, applies its "skin" |
| 1248 | ** setting. Returns 0 if no QUERY_STRING is set, 1 if it is, |
| @@ -1321,10 +1321,11 @@ | |
| 1321 | char *zSemi; |
| 1322 | int len; |
| 1323 | const char *zRequestUri = cgi_parameter("REQUEST_URI",0); |
| 1324 | const char *zScriptName = cgi_parameter("SCRIPT_NAME",0); |
| 1325 | const char *zPathInfo = cgi_parameter("PATH_INFO",0); |
| 1326 | #ifdef _WIN32 |
| 1327 | const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0); |
| 1328 | #endif |
| 1329 | |
| 1330 | #ifdef FOSSIL_ENABLE_JSON |
| @@ -1418,11 +1419,19 @@ | |
| 1418 | z = (char*)P("REMOTE_ADDR"); |
| 1419 | if( z ){ |
| 1420 | g.zIpAddr = fossil_strdup(z); |
| 1421 | } |
| 1422 | |
| 1423 | len = atoi(PD("CONTENT_LENGTH", "0")); |
| 1424 | zType = P("CONTENT_TYPE"); |
| 1425 | zSemi = zType ? strchr(zType, ';') : 0; |
| 1426 | if( zSemi ){ |
| 1427 | g.zContentType = fossil_strndup(zType, (int)(zSemi-zType)); |
| 1428 | zType = g.zContentType; |
| @@ -1912,15 +1921,26 @@ | |
| 1912 | |
| 1913 | |
| 1914 | /* |
| 1915 | ** Send a reply indicating that the HTTP request was malformed |
| 1916 | */ |
| 1917 | static NORETURN void malformed_request(const char *zMsg){ |
| 1918 | cgi_set_status(501, "Not Implemented"); |
| 1919 | cgi_printf( |
| 1920 | "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg |
| 1921 | ); |
| 1922 | cgi_reply(); |
| 1923 | fossil_exit(0); |
| 1924 | } |
| 1925 | |
| 1926 | /* |
| @@ -2033,12 +2053,13 @@ | |
| 2033 | char *z, *zToken; |
| 2034 | int i; |
| 2035 | const char *zScheme = "http"; |
| 2036 | char zLine[2000]; /* A single line of input. */ |
| 2037 | g.fullHttpReply = 1; |
| 2038 | if( cgi_fgets(zLine, sizeof(zLine))==0 ){ |
| 2039 | malformed_request("missing HTTP header"); |
| 2040 | } |
| 2041 | blob_append(&g.httpHeader, zLine, -1); |
| 2042 | cgi_trace(zLine); |
| 2043 | zToken = extract_token(zLine, &z); |
| 2044 | if( zToken==0 ){ |
| @@ -2046,17 +2067,18 @@ | |
| 2046 | } |
| 2047 | if( fossil_strcmp(zToken,"GET")!=0 |
| 2048 | && fossil_strcmp(zToken,"POST")!=0 |
| 2049 | && fossil_strcmp(zToken,"HEAD")!=0 |
| 2050 | ){ |
| 2051 | malformed_request("unsupported HTTP method"); |
| 2052 | } |
| 2053 | cgi_setenv("GATEWAY_INTERFACE","CGI/1.0"); |
| 2054 | cgi_setenv("REQUEST_METHOD",zToken); |
| 2055 | zToken = extract_token(z, &z); |
| 2056 | if( zToken==0 ){ |
| 2057 | malformed_request("malformed URL in HTTP header"); |
| 2058 | } |
| 2059 | cgi_setenv("REQUEST_URI", zToken); |
| 2060 | cgi_setenv("SCRIPT_NAME", ""); |
| 2061 | for(i=0; zToken[i] && zToken[i]!='?'; i++){} |
| 2062 | if( zToken[i] ) zToken[i++] = 0; |
| @@ -2164,10 +2186,11 @@ | |
| 2164 | g.zIpAddr = fossil_strdup(zIpAddr); |
| 2165 | } |
| 2166 | }else{ |
| 2167 | fossil_fatal("missing SSH IP address"); |
| 2168 | } |
| 2169 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 2170 | malformed_request("missing HTTP header"); |
| 2171 | } |
| 2172 | cgi_trace(zLine); |
| 2173 | zToken = extract_token(zLine, &z); |
| 2174 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1238,11 +1238,11 @@ | |
| 1238 | } |
| 1239 | fputs(z, pLog); |
| 1240 | } |
| 1241 | |
| 1242 | /* Forward declaration */ |
| 1243 | static NORETURN void malformed_request(const char *zMsg, ...); |
| 1244 | |
| 1245 | /* |
| 1246 | ** Checks the QUERY_STRING environment variable, sets it up |
| 1247 | ** via add_param_list() and, if found, applies its "skin" |
| 1248 | ** setting. Returns 0 if no QUERY_STRING is set, 1 if it is, |
| @@ -1321,10 +1321,11 @@ | |
| 1321 | char *zSemi; |
| 1322 | int len; |
| 1323 | const char *zRequestUri = cgi_parameter("REQUEST_URI",0); |
| 1324 | const char *zScriptName = cgi_parameter("SCRIPT_NAME",0); |
| 1325 | const char *zPathInfo = cgi_parameter("PATH_INFO",0); |
| 1326 | const char *zContentLength = 0; |
| 1327 | #ifdef _WIN32 |
| 1328 | const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0); |
| 1329 | #endif |
| 1330 | |
| 1331 | #ifdef FOSSIL_ENABLE_JSON |
| @@ -1418,11 +1419,19 @@ | |
| 1419 | z = (char*)P("REMOTE_ADDR"); |
| 1420 | if( z ){ |
| 1421 | g.zIpAddr = fossil_strdup(z); |
| 1422 | } |
| 1423 | |
| 1424 | zContentLength = P("CONTENT_LENGTH"); |
| 1425 | if( zContentLength==0 ){ |
| 1426 | len = 0; |
| 1427 | if( sqlite3_stricmp(PD("REQUEST_METHOD",""),"POST")==0 ){ |
| 1428 | malformed_request("missing CONTENT_LENGTH on a POST method"); |
| 1429 | } |
| 1430 | }else{ |
| 1431 | len = atoi(zContentLength); |
| 1432 | } |
| 1433 | zType = P("CONTENT_TYPE"); |
| 1434 | zSemi = zType ? strchr(zType, ';') : 0; |
| 1435 | if( zSemi ){ |
| 1436 | g.zContentType = fossil_strndup(zType, (int)(zSemi-zType)); |
| 1437 | zType = g.zContentType; |
| @@ -1912,15 +1921,26 @@ | |
| 1921 | |
| 1922 | |
| 1923 | /* |
| 1924 | ** Send a reply indicating that the HTTP request was malformed |
| 1925 | */ |
| 1926 | static NORETURN void malformed_request(const char *zMsg, ...){ |
| 1927 | va_list ap; |
| 1928 | char *z; |
| 1929 | va_start(ap, zMsg); |
| 1930 | z = vmprintf(zMsg, ap); |
| 1931 | va_end(ap); |
| 1932 | cgi_set_status(400, "Bad Request"); |
| 1933 | zContentType = "text/plain"; |
| 1934 | if( g.zReqType==0 ) g.zReqType = "WWW"; |
| 1935 | if( g.zReqType[0]=='C' && PD("SERVER_SOFTWARE",0)!=0 ){ |
| 1936 | const char *zServer = PD("SERVER_SOFTWARE",""); |
| 1937 | cgi_printf("Bad CGI Request from \"%s\": %s\n",zServer,z); |
| 1938 | }else{ |
| 1939 | cgi_printf("Bad %s Request: %s\n", g.zReqType, z); |
| 1940 | } |
| 1941 | fossil_free(z); |
| 1942 | cgi_reply(); |
| 1943 | fossil_exit(0); |
| 1944 | } |
| 1945 | |
| 1946 | /* |
| @@ -2033,12 +2053,13 @@ | |
| 2053 | char *z, *zToken; |
| 2054 | int i; |
| 2055 | const char *zScheme = "http"; |
| 2056 | char zLine[2000]; /* A single line of input. */ |
| 2057 | g.fullHttpReply = 1; |
| 2058 | g.zReqType = "HTTP"; |
| 2059 | if( cgi_fgets(zLine, sizeof(zLine))==0 ){ |
| 2060 | malformed_request("missing header"); |
| 2061 | } |
| 2062 | blob_append(&g.httpHeader, zLine, -1); |
| 2063 | cgi_trace(zLine); |
| 2064 | zToken = extract_token(zLine, &z); |
| 2065 | if( zToken==0 ){ |
| @@ -2046,17 +2067,18 @@ | |
| 2067 | } |
| 2068 | if( fossil_strcmp(zToken,"GET")!=0 |
| 2069 | && fossil_strcmp(zToken,"POST")!=0 |
| 2070 | && fossil_strcmp(zToken,"HEAD")!=0 |
| 2071 | ){ |
| 2072 | malformed_request("unsupported HTTP method: \"%s\" - Fossil only supports" |
| 2073 | "GET, POST, and HEAD", zToken); |
| 2074 | } |
| 2075 | cgi_setenv("GATEWAY_INTERFACE","CGI/1.0"); |
| 2076 | cgi_setenv("REQUEST_METHOD",zToken); |
| 2077 | zToken = extract_token(z, &z); |
| 2078 | if( zToken==0 ){ |
| 2079 | malformed_request("malformed URI in the HTTP header"); |
| 2080 | } |
| 2081 | cgi_setenv("REQUEST_URI", zToken); |
| 2082 | cgi_setenv("SCRIPT_NAME", ""); |
| 2083 | for(i=0; zToken[i] && zToken[i]!='?'; i++){} |
| 2084 | if( zToken[i] ) zToken[i++] = 0; |
| @@ -2164,10 +2186,11 @@ | |
| 2186 | g.zIpAddr = fossil_strdup(zIpAddr); |
| 2187 | } |
| 2188 | }else{ |
| 2189 | fossil_fatal("missing SSH IP address"); |
| 2190 | } |
| 2191 | g.zReqType = "HTTP"; |
| 2192 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 2193 | malformed_request("missing HTTP header"); |
| 2194 | } |
| 2195 | cgi_trace(zLine); |
| 2196 | zToken = extract_token(zLine, &z); |
| 2197 |
+13
-1
| --- src/clone.c | ||
| +++ src/clone.c | ||
| @@ -136,10 +136,11 @@ | ||
| 136 | 136 | ** --ssl-identity FILENAME Use the SSL identity if requested by the server |
| 137 | 137 | ** --transport-command CMD Use CMD to move messages to the server and back |
| 138 | 138 | ** -u|--unversioned Also sync unversioned content |
| 139 | 139 | ** -v|--verbose Show more statistics in output |
| 140 | 140 | ** --workdir DIR Also open a check-out in DIR |
| 141 | +** --xverbose Extra debugging output | |
| 141 | 142 | ** |
| 142 | 143 | ** See also: [[init]], [[open]] |
| 143 | 144 | */ |
| 144 | 145 | void clone_cmd(void){ |
| 145 | 146 | char *zPassword; |
| @@ -161,10 +162,11 @@ | ||
| 161 | 162 | if( find_option("save-http-password",0,0)!=0 ){ |
| 162 | 163 | urlFlags &= ~URL_PROMPT_PW; |
| 163 | 164 | urlFlags |= URL_REMEMBER_PW; |
| 164 | 165 | } |
| 165 | 166 | if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE; |
| 167 | + if( find_option("xverbose",0,0)!=0) syncFlags |= SYNC_XVERBOSE; | |
| 166 | 168 | if( find_option("unversioned","u",0)!=0 ){ |
| 167 | 169 | syncFlags |= SYNC_UNVERSIONED; |
| 168 | 170 | if( syncFlags & SYNC_VERBOSE ){ |
| 169 | 171 | syncFlags |= SYNC_UV_TRACE; |
| 170 | 172 | } |
| @@ -267,11 +269,21 @@ | ||
| 267 | 269 | verify_cancel(); |
| 268 | 270 | db_end_transaction(0); |
| 269 | 271 | db_close(1); |
| 270 | 272 | if( nErr ){ |
| 271 | 273 | file_delete(zRepo); |
| 272 | - fossil_fatal("server returned an error - clone aborted"); | |
| 274 | + if( g.fHttpTrace ){ | |
| 275 | + fossil_fatal( | |
| 276 | + "server returned an error - clone aborted\n\n%s", | |
| 277 | + http_last_trace_reply() | |
| 278 | + ); | |
| 279 | + }else{ | |
| 280 | + fossil_fatal( | |
| 281 | + "server returned an error - clone aborted\n" | |
| 282 | + "Rerun using --httptrace for more detail" | |
| 283 | + ); | |
| 284 | + } | |
| 273 | 285 | } |
| 274 | 286 | db_open_repository(zRepo); |
| 275 | 287 | } |
| 276 | 288 | db_begin_transaction(); |
| 277 | 289 | if( db_exists("SELECT 1 FROM delta WHERE srcId IN phantom") ){ |
| 278 | 290 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -136,10 +136,11 @@ | |
| 136 | ** --ssl-identity FILENAME Use the SSL identity if requested by the server |
| 137 | ** --transport-command CMD Use CMD to move messages to the server and back |
| 138 | ** -u|--unversioned Also sync unversioned content |
| 139 | ** -v|--verbose Show more statistics in output |
| 140 | ** --workdir DIR Also open a check-out in DIR |
| 141 | ** |
| 142 | ** See also: [[init]], [[open]] |
| 143 | */ |
| 144 | void clone_cmd(void){ |
| 145 | char *zPassword; |
| @@ -161,10 +162,11 @@ | |
| 161 | if( find_option("save-http-password",0,0)!=0 ){ |
| 162 | urlFlags &= ~URL_PROMPT_PW; |
| 163 | urlFlags |= URL_REMEMBER_PW; |
| 164 | } |
| 165 | if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE; |
| 166 | if( find_option("unversioned","u",0)!=0 ){ |
| 167 | syncFlags |= SYNC_UNVERSIONED; |
| 168 | if( syncFlags & SYNC_VERBOSE ){ |
| 169 | syncFlags |= SYNC_UV_TRACE; |
| 170 | } |
| @@ -267,11 +269,21 @@ | |
| 267 | verify_cancel(); |
| 268 | db_end_transaction(0); |
| 269 | db_close(1); |
| 270 | if( nErr ){ |
| 271 | file_delete(zRepo); |
| 272 | fossil_fatal("server returned an error - clone aborted"); |
| 273 | } |
| 274 | db_open_repository(zRepo); |
| 275 | } |
| 276 | db_begin_transaction(); |
| 277 | if( db_exists("SELECT 1 FROM delta WHERE srcId IN phantom") ){ |
| 278 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -136,10 +136,11 @@ | |
| 136 | ** --ssl-identity FILENAME Use the SSL identity if requested by the server |
| 137 | ** --transport-command CMD Use CMD to move messages to the server and back |
| 138 | ** -u|--unversioned Also sync unversioned content |
| 139 | ** -v|--verbose Show more statistics in output |
| 140 | ** --workdir DIR Also open a check-out in DIR |
| 141 | ** --xverbose Extra debugging output |
| 142 | ** |
| 143 | ** See also: [[init]], [[open]] |
| 144 | */ |
| 145 | void clone_cmd(void){ |
| 146 | char *zPassword; |
| @@ -161,10 +162,11 @@ | |
| 162 | if( find_option("save-http-password",0,0)!=0 ){ |
| 163 | urlFlags &= ~URL_PROMPT_PW; |
| 164 | urlFlags |= URL_REMEMBER_PW; |
| 165 | } |
| 166 | if( find_option("verbose","v",0)!=0) syncFlags |= SYNC_VERBOSE; |
| 167 | if( find_option("xverbose",0,0)!=0) syncFlags |= SYNC_XVERBOSE; |
| 168 | if( find_option("unversioned","u",0)!=0 ){ |
| 169 | syncFlags |= SYNC_UNVERSIONED; |
| 170 | if( syncFlags & SYNC_VERBOSE ){ |
| 171 | syncFlags |= SYNC_UV_TRACE; |
| 172 | } |
| @@ -267,11 +269,21 @@ | |
| 269 | verify_cancel(); |
| 270 | db_end_transaction(0); |
| 271 | db_close(1); |
| 272 | if( nErr ){ |
| 273 | file_delete(zRepo); |
| 274 | if( g.fHttpTrace ){ |
| 275 | fossil_fatal( |
| 276 | "server returned an error - clone aborted\n\n%s", |
| 277 | http_last_trace_reply() |
| 278 | ); |
| 279 | }else{ |
| 280 | fossil_fatal( |
| 281 | "server returned an error - clone aborted\n" |
| 282 | "Rerun using --httptrace for more detail" |
| 283 | ); |
| 284 | } |
| 285 | } |
| 286 | db_open_repository(zRepo); |
| 287 | } |
| 288 | db_begin_transaction(); |
| 289 | if( db_exists("SELECT 1 FROM delta WHERE srcId IN phantom") ){ |
| 290 |
+57
-9
| --- src/http.c | ||
| +++ src/http.c | ||
| @@ -47,10 +47,15 @@ | ||
| 47 | 47 | #define MAX_HTTP_AUTH 2 |
| 48 | 48 | |
| 49 | 49 | /* Keep track of HTTP Basic Authorization failures */ |
| 50 | 50 | static int fSeenHttpAuth = 0; |
| 51 | 51 | |
| 52 | +/* The N value for most recent http-request-N.txt and http-reply-N.txt | |
| 53 | +** trace files. | |
| 54 | +*/ | |
| 55 | +static int traceCnt = 0; | |
| 56 | + | |
| 52 | 57 | /* |
| 53 | 58 | ** Construct the "login" card with the client credentials. |
| 54 | 59 | ** |
| 55 | 60 | ** login LOGIN NONCE SIGNATURE |
| 56 | 61 | ** |
| @@ -389,10 +394,29 @@ | ||
| 389 | 394 | */ |
| 390 | 395 | void ssh_add_path_argument(Blob *pCmd){ |
| 391 | 396 | blob_append_escaped_arg(pCmd, |
| 392 | 397 | "PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1); |
| 393 | 398 | } |
| 399 | + | |
| 400 | +/* | |
| 401 | +** Return the complete text of the last HTTP reply as saved in the | |
| 402 | +** http-reply-N.txt file. This only works if run using --httptrace. | |
| 403 | +** Without the --httptrace option, this routine returns a NULL pointer. | |
| 404 | +** It still might return a NULL pointer if for some reason it cannot | |
| 405 | +** find and open the last http-reply-N.txt file. | |
| 406 | +*/ | |
| 407 | +char *http_last_trace_reply(void){ | |
| 408 | + Blob x; | |
| 409 | + int n; | |
| 410 | + char *zFilename; | |
| 411 | + if( g.fHttpTrace==0 ) return 0; | |
| 412 | + zFilename = mprintf("http-reply-%d.txt", traceCnt); | |
| 413 | + n = blob_read_from_file(&x, zFilename, ExtFILE); | |
| 414 | + fossil_free(zFilename); | |
| 415 | + if( n<=0 ) return 0; | |
| 416 | + return blob_str(&x); | |
| 417 | +} | |
| 394 | 418 | |
| 395 | 419 | /* |
| 396 | 420 | ** Sign the content in pSend, compress it, and send it to the server |
| 397 | 421 | ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply |
| 398 | 422 | ** in pRecv. pRecv is assumed to be uninitialized when |
| @@ -412,11 +436,10 @@ | ||
| 412 | 436 | Blob login; /* The login card */ |
| 413 | 437 | Blob payload; /* The complete payload including login card */ |
| 414 | 438 | Blob hdr; /* The HTTP request header */ |
| 415 | 439 | int closeConnection; /* True to close the connection when done */ |
| 416 | 440 | int iLength; /* Expected length of the reply payload */ |
| 417 | - int iRecvLen; /* Received length of the reply payload */ | |
| 418 | 441 | int rc = 0; /* Result code */ |
| 419 | 442 | int iHttpVersion; /* Which version of HTTP protocol server uses */ |
| 420 | 443 | char *zLine; /* A single line of the reply header */ |
| 421 | 444 | int i; /* Loop counter */ |
| 422 | 445 | int isError = 0; /* True if the reply is an error message */ |
| @@ -465,11 +488,10 @@ | ||
| 465 | 488 | ** server-side like this: |
| 466 | 489 | ** |
| 467 | 490 | ** ./fossil test-http <http-request-1.txt |
| 468 | 491 | */ |
| 469 | 492 | if( g.fHttpTrace ){ |
| 470 | - static int traceCnt = 0; | |
| 471 | 493 | char *zOutFile; |
| 472 | 494 | FILE *out; |
| 473 | 495 | traceCnt++; |
| 474 | 496 | zOutFile = mprintf("http-request-%d.txt", traceCnt); |
| 475 | 497 | out = fopen(zOutFile, "wb"); |
| @@ -502,10 +524,11 @@ | ||
| 502 | 524 | /* |
| 503 | 525 | ** Read and interpret the server reply |
| 504 | 526 | */ |
| 505 | 527 | closeConnection = 1; |
| 506 | 528 | iLength = -1; |
| 529 | + iHttpVersion = -1; | |
| 507 | 530 | while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){ |
| 508 | 531 | if( mHttpFlags & HTTP_VERBOSE ){ |
| 509 | 532 | fossil_print("Read: [%s]\n", zLine); |
| 510 | 533 | } |
| 511 | 534 | if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){ |
| @@ -540,10 +563,11 @@ | ||
| 540 | 563 | for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){} |
| 541 | 564 | while( zLine[ii]==' ' ) ii++; |
| 542 | 565 | fossil_warning("server says: %s", &zLine[ii]); |
| 543 | 566 | goto write_err; |
| 544 | 567 | } |
| 568 | + if( iHttpVersion<0 ) iHttpVersion = 1; | |
| 545 | 569 | closeConnection = 0; |
| 546 | 570 | }else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){ |
| 547 | 571 | for(i=15; fossil_isspace(zLine[i]); i++){} |
| 548 | 572 | iLength = atoi(&zLine[i]); |
| 549 | 573 | }else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){ |
| @@ -613,11 +637,11 @@ | ||
| 613 | 637 | isError = 1; |
| 614 | 638 | } |
| 615 | 639 | } |
| 616 | 640 | } |
| 617 | 641 | } |
| 618 | - if( iLength<0 ){ | |
| 642 | + if( iHttpVersion<0 ){ | |
| 619 | 643 | /* We got nothing back from the server. If using the ssh: protocol, |
| 620 | 644 | ** this might mean we need to add or remove the PATH=... argument |
| 621 | 645 | ** to the SSH command being sent. If that is the case, retry the |
| 622 | 646 | ** request after adding or removing the PATH= argument. |
| 623 | 647 | */ |
| @@ -659,17 +683,41 @@ | ||
| 659 | 683 | |
| 660 | 684 | /* |
| 661 | 685 | ** Extract the reply payload that follows the header |
| 662 | 686 | */ |
| 663 | 687 | blob_zero(pReply); |
| 664 | - blob_resize(pReply, iLength); | |
| 665 | - iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength); | |
| 666 | - if( iRecvLen != iLength ){ | |
| 667 | - fossil_warning("response truncated: got %d bytes of %d", iRecvLen, iLength); | |
| 668 | - goto write_err; | |
| 688 | + if( iLength==0 ){ | |
| 689 | + /* No content to read */ | |
| 690 | + }else if( iLength>0 ){ | |
| 691 | + /* Read content of a known length */ | |
| 692 | + int iRecvLen; /* Received length of the reply payload */ | |
| 693 | + blob_resize(pReply, iLength); | |
| 694 | + iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength); | |
| 695 | + if( mHttpFlags & HTTP_VERBOSE ){ | |
| 696 | + fossil_print("Reply received: %d of %d bytes\n", iRecvLen, iLength); | |
| 697 | + } | |
| 698 | + if( iRecvLen != iLength ){ | |
| 699 | + fossil_warning("response truncated: got %d bytes of %d", | |
| 700 | + iRecvLen, iLength); | |
| 701 | + goto write_err; | |
| 702 | + } | |
| 703 | + }else{ | |
| 704 | + /* Read content until end-of-file */ | |
| 705 | + int iRecvLen; /* Received length of the reply payload */ | |
| 706 | + unsigned int nReq = 1000; | |
| 707 | + unsigned int nPrior = 0; | |
| 708 | + do{ | |
| 709 | + nReq *= 2; | |
| 710 | + blob_resize(pReply, nPrior+nReq); | |
| 711 | + iRecvLen = transport_receive(&g.url, &pReply->aData[nPrior], (int)nReq); | |
| 712 | + nPrior += iRecvLen; | |
| 713 | + pReply->nUsed = nPrior; | |
| 714 | + }while( iRecvLen==nReq && nReq<0x20000000 ); | |
| 715 | + if( mHttpFlags & HTTP_VERBOSE ){ | |
| 716 | + fossil_print("Reply received: %u bytes (w/o content-length)\n", nPrior); | |
| 717 | + } | |
| 669 | 718 | } |
| 670 | - blob_resize(pReply, iLength); | |
| 671 | 719 | if( isError ){ |
| 672 | 720 | char *z; |
| 673 | 721 | int i, j; |
| 674 | 722 | z = blob_str(pReply); |
| 675 | 723 | for(i=j=0; z[i]; i++, j++){ |
| 676 | 724 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -47,10 +47,15 @@ | |
| 47 | #define MAX_HTTP_AUTH 2 |
| 48 | |
| 49 | /* Keep track of HTTP Basic Authorization failures */ |
| 50 | static int fSeenHttpAuth = 0; |
| 51 | |
| 52 | /* |
| 53 | ** Construct the "login" card with the client credentials. |
| 54 | ** |
| 55 | ** login LOGIN NONCE SIGNATURE |
| 56 | ** |
| @@ -389,10 +394,29 @@ | |
| 389 | */ |
| 390 | void ssh_add_path_argument(Blob *pCmd){ |
| 391 | blob_append_escaped_arg(pCmd, |
| 392 | "PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1); |
| 393 | } |
| 394 | |
| 395 | /* |
| 396 | ** Sign the content in pSend, compress it, and send it to the server |
| 397 | ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply |
| 398 | ** in pRecv. pRecv is assumed to be uninitialized when |
| @@ -412,11 +436,10 @@ | |
| 412 | Blob login; /* The login card */ |
| 413 | Blob payload; /* The complete payload including login card */ |
| 414 | Blob hdr; /* The HTTP request header */ |
| 415 | int closeConnection; /* True to close the connection when done */ |
| 416 | int iLength; /* Expected length of the reply payload */ |
| 417 | int iRecvLen; /* Received length of the reply payload */ |
| 418 | int rc = 0; /* Result code */ |
| 419 | int iHttpVersion; /* Which version of HTTP protocol server uses */ |
| 420 | char *zLine; /* A single line of the reply header */ |
| 421 | int i; /* Loop counter */ |
| 422 | int isError = 0; /* True if the reply is an error message */ |
| @@ -465,11 +488,10 @@ | |
| 465 | ** server-side like this: |
| 466 | ** |
| 467 | ** ./fossil test-http <http-request-1.txt |
| 468 | */ |
| 469 | if( g.fHttpTrace ){ |
| 470 | static int traceCnt = 0; |
| 471 | char *zOutFile; |
| 472 | FILE *out; |
| 473 | traceCnt++; |
| 474 | zOutFile = mprintf("http-request-%d.txt", traceCnt); |
| 475 | out = fopen(zOutFile, "wb"); |
| @@ -502,10 +524,11 @@ | |
| 502 | /* |
| 503 | ** Read and interpret the server reply |
| 504 | */ |
| 505 | closeConnection = 1; |
| 506 | iLength = -1; |
| 507 | while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){ |
| 508 | if( mHttpFlags & HTTP_VERBOSE ){ |
| 509 | fossil_print("Read: [%s]\n", zLine); |
| 510 | } |
| 511 | if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){ |
| @@ -540,10 +563,11 @@ | |
| 540 | for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){} |
| 541 | while( zLine[ii]==' ' ) ii++; |
| 542 | fossil_warning("server says: %s", &zLine[ii]); |
| 543 | goto write_err; |
| 544 | } |
| 545 | closeConnection = 0; |
| 546 | }else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){ |
| 547 | for(i=15; fossil_isspace(zLine[i]); i++){} |
| 548 | iLength = atoi(&zLine[i]); |
| 549 | }else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){ |
| @@ -613,11 +637,11 @@ | |
| 613 | isError = 1; |
| 614 | } |
| 615 | } |
| 616 | } |
| 617 | } |
| 618 | if( iLength<0 ){ |
| 619 | /* We got nothing back from the server. If using the ssh: protocol, |
| 620 | ** this might mean we need to add or remove the PATH=... argument |
| 621 | ** to the SSH command being sent. If that is the case, retry the |
| 622 | ** request after adding or removing the PATH= argument. |
| 623 | */ |
| @@ -659,17 +683,41 @@ | |
| 659 | |
| 660 | /* |
| 661 | ** Extract the reply payload that follows the header |
| 662 | */ |
| 663 | blob_zero(pReply); |
| 664 | blob_resize(pReply, iLength); |
| 665 | iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength); |
| 666 | if( iRecvLen != iLength ){ |
| 667 | fossil_warning("response truncated: got %d bytes of %d", iRecvLen, iLength); |
| 668 | goto write_err; |
| 669 | } |
| 670 | blob_resize(pReply, iLength); |
| 671 | if( isError ){ |
| 672 | char *z; |
| 673 | int i, j; |
| 674 | z = blob_str(pReply); |
| 675 | for(i=j=0; z[i]; i++, j++){ |
| 676 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -47,10 +47,15 @@ | |
| 47 | #define MAX_HTTP_AUTH 2 |
| 48 | |
| 49 | /* Keep track of HTTP Basic Authorization failures */ |
| 50 | static int fSeenHttpAuth = 0; |
| 51 | |
| 52 | /* The N value for most recent http-request-N.txt and http-reply-N.txt |
| 53 | ** trace files. |
| 54 | */ |
| 55 | static int traceCnt = 0; |
| 56 | |
| 57 | /* |
| 58 | ** Construct the "login" card with the client credentials. |
| 59 | ** |
| 60 | ** login LOGIN NONCE SIGNATURE |
| 61 | ** |
| @@ -389,10 +394,29 @@ | |
| 394 | */ |
| 395 | void ssh_add_path_argument(Blob *pCmd){ |
| 396 | blob_append_escaped_arg(pCmd, |
| 397 | "PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1); |
| 398 | } |
| 399 | |
| 400 | /* |
| 401 | ** Return the complete text of the last HTTP reply as saved in the |
| 402 | ** http-reply-N.txt file. This only works if run using --httptrace. |
| 403 | ** Without the --httptrace option, this routine returns a NULL pointer. |
| 404 | ** It still might return a NULL pointer if for some reason it cannot |
| 405 | ** find and open the last http-reply-N.txt file. |
| 406 | */ |
| 407 | char *http_last_trace_reply(void){ |
| 408 | Blob x; |
| 409 | int n; |
| 410 | char *zFilename; |
| 411 | if( g.fHttpTrace==0 ) return 0; |
| 412 | zFilename = mprintf("http-reply-%d.txt", traceCnt); |
| 413 | n = blob_read_from_file(&x, zFilename, ExtFILE); |
| 414 | fossil_free(zFilename); |
| 415 | if( n<=0 ) return 0; |
| 416 | return blob_str(&x); |
| 417 | } |
| 418 | |
| 419 | /* |
| 420 | ** Sign the content in pSend, compress it, and send it to the server |
| 421 | ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply |
| 422 | ** in pRecv. pRecv is assumed to be uninitialized when |
| @@ -412,11 +436,10 @@ | |
| 436 | Blob login; /* The login card */ |
| 437 | Blob payload; /* The complete payload including login card */ |
| 438 | Blob hdr; /* The HTTP request header */ |
| 439 | int closeConnection; /* True to close the connection when done */ |
| 440 | int iLength; /* Expected length of the reply payload */ |
| 441 | int rc = 0; /* Result code */ |
| 442 | int iHttpVersion; /* Which version of HTTP protocol server uses */ |
| 443 | char *zLine; /* A single line of the reply header */ |
| 444 | int i; /* Loop counter */ |
| 445 | int isError = 0; /* True if the reply is an error message */ |
| @@ -465,11 +488,10 @@ | |
| 488 | ** server-side like this: |
| 489 | ** |
| 490 | ** ./fossil test-http <http-request-1.txt |
| 491 | */ |
| 492 | if( g.fHttpTrace ){ |
| 493 | char *zOutFile; |
| 494 | FILE *out; |
| 495 | traceCnt++; |
| 496 | zOutFile = mprintf("http-request-%d.txt", traceCnt); |
| 497 | out = fopen(zOutFile, "wb"); |
| @@ -502,10 +524,11 @@ | |
| 524 | /* |
| 525 | ** Read and interpret the server reply |
| 526 | */ |
| 527 | closeConnection = 1; |
| 528 | iLength = -1; |
| 529 | iHttpVersion = -1; |
| 530 | while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){ |
| 531 | if( mHttpFlags & HTTP_VERBOSE ){ |
| 532 | fossil_print("Read: [%s]\n", zLine); |
| 533 | } |
| 534 | if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){ |
| @@ -540,10 +563,11 @@ | |
| 563 | for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){} |
| 564 | while( zLine[ii]==' ' ) ii++; |
| 565 | fossil_warning("server says: %s", &zLine[ii]); |
| 566 | goto write_err; |
| 567 | } |
| 568 | if( iHttpVersion<0 ) iHttpVersion = 1; |
| 569 | closeConnection = 0; |
| 570 | }else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){ |
| 571 | for(i=15; fossil_isspace(zLine[i]); i++){} |
| 572 | iLength = atoi(&zLine[i]); |
| 573 | }else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){ |
| @@ -613,11 +637,11 @@ | |
| 637 | isError = 1; |
| 638 | } |
| 639 | } |
| 640 | } |
| 641 | } |
| 642 | if( iHttpVersion<0 ){ |
| 643 | /* We got nothing back from the server. If using the ssh: protocol, |
| 644 | ** this might mean we need to add or remove the PATH=... argument |
| 645 | ** to the SSH command being sent. If that is the case, retry the |
| 646 | ** request after adding or removing the PATH= argument. |
| 647 | */ |
| @@ -659,17 +683,41 @@ | |
| 683 | |
| 684 | /* |
| 685 | ** Extract the reply payload that follows the header |
| 686 | */ |
| 687 | blob_zero(pReply); |
| 688 | if( iLength==0 ){ |
| 689 | /* No content to read */ |
| 690 | }else if( iLength>0 ){ |
| 691 | /* Read content of a known length */ |
| 692 | int iRecvLen; /* Received length of the reply payload */ |
| 693 | blob_resize(pReply, iLength); |
| 694 | iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength); |
| 695 | if( mHttpFlags & HTTP_VERBOSE ){ |
| 696 | fossil_print("Reply received: %d of %d bytes\n", iRecvLen, iLength); |
| 697 | } |
| 698 | if( iRecvLen != iLength ){ |
| 699 | fossil_warning("response truncated: got %d bytes of %d", |
| 700 | iRecvLen, iLength); |
| 701 | goto write_err; |
| 702 | } |
| 703 | }else{ |
| 704 | /* Read content until end-of-file */ |
| 705 | int iRecvLen; /* Received length of the reply payload */ |
| 706 | unsigned int nReq = 1000; |
| 707 | unsigned int nPrior = 0; |
| 708 | do{ |
| 709 | nReq *= 2; |
| 710 | blob_resize(pReply, nPrior+nReq); |
| 711 | iRecvLen = transport_receive(&g.url, &pReply->aData[nPrior], (int)nReq); |
| 712 | nPrior += iRecvLen; |
| 713 | pReply->nUsed = nPrior; |
| 714 | }while( iRecvLen==nReq && nReq<0x20000000 ); |
| 715 | if( mHttpFlags & HTTP_VERBOSE ){ |
| 716 | fossil_print("Reply received: %u bytes (w/o content-length)\n", nPrior); |
| 717 | } |
| 718 | } |
| 719 | if( isError ){ |
| 720 | char *z; |
| 721 | int i, j; |
| 722 | z = blob_str(pReply); |
| 723 | for(i=j=0; z[i]; i++, j++){ |
| 724 |
+10
-1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -227,10 +227,11 @@ | ||
| 227 | 227 | const char *zCkoutAlias; /* doc/ uses this branch as an alias for "ckout" */ |
| 228 | 228 | const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */ |
| 229 | 229 | const char *zSSLIdentity; /* Value of --ssl-identity option, filename of |
| 230 | 230 | ** SSL client identity */ |
| 231 | 231 | const char *zCgiFile; /* Name of the CGI file */ |
| 232 | + const char *zReqType; /* Type of request: "HTTP", "CGI", "SCGI" */ | |
| 232 | 233 | #if USE_SEE |
| 233 | 234 | const char *zPidKey; /* Saved value of the --usepidkey option. Only |
| 234 | 235 | * applicable when using SEE on Windows or Linux. */ |
| 235 | 236 | #endif |
| 236 | 237 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| @@ -2363,10 +2364,11 @@ | ||
| 2363 | 2364 | g.httpOut = stdout; |
| 2364 | 2365 | g.httpIn = stdin; |
| 2365 | 2366 | fossil_binary_mode(g.httpOut); |
| 2366 | 2367 | fossil_binary_mode(g.httpIn); |
| 2367 | 2368 | g.cgiOutput = 1; |
| 2369 | + g.zReqType = "CGI"; | |
| 2368 | 2370 | fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT); |
| 2369 | 2371 | /* Find the name of the CGI control file */ |
| 2370 | 2372 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 2371 | 2373 | g.zCgiFile = g.argv[2]; |
| 2372 | 2374 | }else if( g.argc>=2 ){ |
| @@ -2846,10 +2848,11 @@ | ||
| 2846 | 2848 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 2847 | 2849 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0; |
| 2848 | 2850 | g.fNoHttpCompress = find_option("nocompress",0,0)!=0; |
| 2849 | 2851 | g.zExtRoot = find_option("extroot",0,1); |
| 2850 | 2852 | g.zCkoutAlias = find_option("ckout-alias",0,1); |
| 2853 | + g.zReqType = "HTTP"; | |
| 2851 | 2854 | zInFile = find_option("in",0,1); |
| 2852 | 2855 | if( zInFile ){ |
| 2853 | 2856 | backoffice_disable(); |
| 2854 | 2857 | g.httpIn = fossil_fopen(zInFile, "rb"); |
| 2855 | 2858 | if( g.httpIn==0 ) fossil_fatal("cannot open \"%s\" for reading", zInFile); |
| @@ -2869,10 +2872,11 @@ | ||
| 2869 | 2872 | _setmode(_fileno(stdout), _O_BINARY); |
| 2870 | 2873 | #endif |
| 2871 | 2874 | } |
| 2872 | 2875 | zIpAddr = find_option("ipaddr",0,1); |
| 2873 | 2876 | useSCGI = find_option("scgi", 0, 0)!=0; |
| 2877 | + if( useSCGI ) g.zReqType = "SCGI"; | |
| 2874 | 2878 | zAltBase = find_option("baseurl", 0, 1); |
| 2875 | 2879 | if( find_option("nodelay",0,0)!=0 ) backoffice_no_delay(); |
| 2876 | 2880 | if( zAltBase ) set_base_url(zAltBase); |
| 2877 | 2881 | if( find_option("https",0,0)!=0 ){ |
| 2878 | 2882 | zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */ |
| @@ -2995,10 +2999,11 @@ | ||
| 2995 | 2999 | g.httpOut = stdout; |
| 2996 | 3000 | fossil_binary_mode(g.httpOut); |
| 2997 | 3001 | fossil_binary_mode(g.httpIn); |
| 2998 | 3002 | g.zExtRoot = find_option("extroot",0,1); |
| 2999 | 3003 | find_server_repository(2, 0); |
| 3004 | + g.zReqType = "HTTP"; | |
| 3000 | 3005 | g.cgiOutput = 1; |
| 3001 | 3006 | g.fNoHttpCompress = 1; |
| 3002 | 3007 | g.fullHttpReply = 1; |
| 3003 | 3008 | g.sslNotAvailable = 1; /* Avoid attempts to redirect */ |
| 3004 | 3009 | zIpAddr = bTest ? 0 : cgi_ssh_remote_addr(0); |
| @@ -3231,11 +3236,15 @@ | ||
| 3231 | 3236 | zNotFound = find_option("notfound", 0, 1); |
| 3232 | 3237 | allowRepoList = find_option("repolist",0,0)!=0; |
| 3233 | 3238 | if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1; |
| 3234 | 3239 | zAltBase = find_option("baseurl", 0, 1); |
| 3235 | 3240 | fCreate = find_option("create",0,0)!=0; |
| 3236 | - if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; | |
| 3241 | + g.zReqType = "HTTP"; | |
| 3242 | + if( find_option("scgi", 0, 0)!=0 ){ | |
| 3243 | + g.zReqType = "SCGI"; | |
| 3244 | + flags |= HTTP_SERVER_SCGI; | |
| 3245 | + } | |
| 3237 | 3246 | if( zAltBase ){ |
| 3238 | 3247 | set_base_url(zAltBase); |
| 3239 | 3248 | } |
| 3240 | 3249 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0 || isUiCmd; |
| 3241 | 3250 | fNoBrowser = find_option("nobrowser", "B", 0)!=0; |
| 3242 | 3251 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -227,10 +227,11 @@ | |
| 227 | const char *zCkoutAlias; /* doc/ uses this branch as an alias for "ckout" */ |
| 228 | const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */ |
| 229 | const char *zSSLIdentity; /* Value of --ssl-identity option, filename of |
| 230 | ** SSL client identity */ |
| 231 | const char *zCgiFile; /* Name of the CGI file */ |
| 232 | #if USE_SEE |
| 233 | const char *zPidKey; /* Saved value of the --usepidkey option. Only |
| 234 | * applicable when using SEE on Windows or Linux. */ |
| 235 | #endif |
| 236 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| @@ -2363,10 +2364,11 @@ | |
| 2363 | g.httpOut = stdout; |
| 2364 | g.httpIn = stdin; |
| 2365 | fossil_binary_mode(g.httpOut); |
| 2366 | fossil_binary_mode(g.httpIn); |
| 2367 | g.cgiOutput = 1; |
| 2368 | fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT); |
| 2369 | /* Find the name of the CGI control file */ |
| 2370 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 2371 | g.zCgiFile = g.argv[2]; |
| 2372 | }else if( g.argc>=2 ){ |
| @@ -2846,10 +2848,11 @@ | |
| 2846 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 2847 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0; |
| 2848 | g.fNoHttpCompress = find_option("nocompress",0,0)!=0; |
| 2849 | g.zExtRoot = find_option("extroot",0,1); |
| 2850 | g.zCkoutAlias = find_option("ckout-alias",0,1); |
| 2851 | zInFile = find_option("in",0,1); |
| 2852 | if( zInFile ){ |
| 2853 | backoffice_disable(); |
| 2854 | g.httpIn = fossil_fopen(zInFile, "rb"); |
| 2855 | if( g.httpIn==0 ) fossil_fatal("cannot open \"%s\" for reading", zInFile); |
| @@ -2869,10 +2872,11 @@ | |
| 2869 | _setmode(_fileno(stdout), _O_BINARY); |
| 2870 | #endif |
| 2871 | } |
| 2872 | zIpAddr = find_option("ipaddr",0,1); |
| 2873 | useSCGI = find_option("scgi", 0, 0)!=0; |
| 2874 | zAltBase = find_option("baseurl", 0, 1); |
| 2875 | if( find_option("nodelay",0,0)!=0 ) backoffice_no_delay(); |
| 2876 | if( zAltBase ) set_base_url(zAltBase); |
| 2877 | if( find_option("https",0,0)!=0 ){ |
| 2878 | zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */ |
| @@ -2995,10 +2999,11 @@ | |
| 2995 | g.httpOut = stdout; |
| 2996 | fossil_binary_mode(g.httpOut); |
| 2997 | fossil_binary_mode(g.httpIn); |
| 2998 | g.zExtRoot = find_option("extroot",0,1); |
| 2999 | find_server_repository(2, 0); |
| 3000 | g.cgiOutput = 1; |
| 3001 | g.fNoHttpCompress = 1; |
| 3002 | g.fullHttpReply = 1; |
| 3003 | g.sslNotAvailable = 1; /* Avoid attempts to redirect */ |
| 3004 | zIpAddr = bTest ? 0 : cgi_ssh_remote_addr(0); |
| @@ -3231,11 +3236,15 @@ | |
| 3231 | zNotFound = find_option("notfound", 0, 1); |
| 3232 | allowRepoList = find_option("repolist",0,0)!=0; |
| 3233 | if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1; |
| 3234 | zAltBase = find_option("baseurl", 0, 1); |
| 3235 | fCreate = find_option("create",0,0)!=0; |
| 3236 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 3237 | if( zAltBase ){ |
| 3238 | set_base_url(zAltBase); |
| 3239 | } |
| 3240 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0 || isUiCmd; |
| 3241 | fNoBrowser = find_option("nobrowser", "B", 0)!=0; |
| 3242 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -227,10 +227,11 @@ | |
| 227 | const char *zCkoutAlias; /* doc/ uses this branch as an alias for "ckout" */ |
| 228 | const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */ |
| 229 | const char *zSSLIdentity; /* Value of --ssl-identity option, filename of |
| 230 | ** SSL client identity */ |
| 231 | const char *zCgiFile; /* Name of the CGI file */ |
| 232 | const char *zReqType; /* Type of request: "HTTP", "CGI", "SCGI" */ |
| 233 | #if USE_SEE |
| 234 | const char *zPidKey; /* Saved value of the --usepidkey option. Only |
| 235 | * applicable when using SEE on Windows or Linux. */ |
| 236 | #endif |
| 237 | int useLocalauth; /* No login required if from 127.0.0.1 */ |
| @@ -2363,10 +2364,11 @@ | |
| 2364 | g.httpOut = stdout; |
| 2365 | g.httpIn = stdin; |
| 2366 | fossil_binary_mode(g.httpOut); |
| 2367 | fossil_binary_mode(g.httpIn); |
| 2368 | g.cgiOutput = 1; |
| 2369 | g.zReqType = "CGI"; |
| 2370 | fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT); |
| 2371 | /* Find the name of the CGI control file */ |
| 2372 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 2373 | g.zCgiFile = g.argv[2]; |
| 2374 | }else if( g.argc>=2 ){ |
| @@ -2846,10 +2848,11 @@ | |
| 2848 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 2849 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0; |
| 2850 | g.fNoHttpCompress = find_option("nocompress",0,0)!=0; |
| 2851 | g.zExtRoot = find_option("extroot",0,1); |
| 2852 | g.zCkoutAlias = find_option("ckout-alias",0,1); |
| 2853 | g.zReqType = "HTTP"; |
| 2854 | zInFile = find_option("in",0,1); |
| 2855 | if( zInFile ){ |
| 2856 | backoffice_disable(); |
| 2857 | g.httpIn = fossil_fopen(zInFile, "rb"); |
| 2858 | if( g.httpIn==0 ) fossil_fatal("cannot open \"%s\" for reading", zInFile); |
| @@ -2869,10 +2872,11 @@ | |
| 2872 | _setmode(_fileno(stdout), _O_BINARY); |
| 2873 | #endif |
| 2874 | } |
| 2875 | zIpAddr = find_option("ipaddr",0,1); |
| 2876 | useSCGI = find_option("scgi", 0, 0)!=0; |
| 2877 | if( useSCGI ) g.zReqType = "SCGI"; |
| 2878 | zAltBase = find_option("baseurl", 0, 1); |
| 2879 | if( find_option("nodelay",0,0)!=0 ) backoffice_no_delay(); |
| 2880 | if( zAltBase ) set_base_url(zAltBase); |
| 2881 | if( find_option("https",0,0)!=0 ){ |
| 2882 | zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */ |
| @@ -2995,10 +2999,11 @@ | |
| 2999 | g.httpOut = stdout; |
| 3000 | fossil_binary_mode(g.httpOut); |
| 3001 | fossil_binary_mode(g.httpIn); |
| 3002 | g.zExtRoot = find_option("extroot",0,1); |
| 3003 | find_server_repository(2, 0); |
| 3004 | g.zReqType = "HTTP"; |
| 3005 | g.cgiOutput = 1; |
| 3006 | g.fNoHttpCompress = 1; |
| 3007 | g.fullHttpReply = 1; |
| 3008 | g.sslNotAvailable = 1; /* Avoid attempts to redirect */ |
| 3009 | zIpAddr = bTest ? 0 : cgi_ssh_remote_addr(0); |
| @@ -3231,11 +3236,15 @@ | |
| 3236 | zNotFound = find_option("notfound", 0, 1); |
| 3237 | allowRepoList = find_option("repolist",0,0)!=0; |
| 3238 | if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1; |
| 3239 | zAltBase = find_option("baseurl", 0, 1); |
| 3240 | fCreate = find_option("create",0,0)!=0; |
| 3241 | g.zReqType = "HTTP"; |
| 3242 | if( find_option("scgi", 0, 0)!=0 ){ |
| 3243 | g.zReqType = "SCGI"; |
| 3244 | flags |= HTTP_SERVER_SCGI; |
| 3245 | } |
| 3246 | if( zAltBase ){ |
| 3247 | set_base_url(zAltBase); |
| 3248 | } |
| 3249 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0 || isUiCmd; |
| 3250 | fNoBrowser = find_option("nobrowser", "B", 0)!=0; |
| 3251 |