| | @@ -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 | |