Fossil SCM
Enhancements to CGI query parameter processing in an attempt to deal with the issue described at [forum:/forumpost/049e8650ed|forum post 049e8650ed].
Commit
140cb312ca6e5c83fe0478ee2772d9d0f2695f2d55b5df4ee0c59e638b90db00
Parent
8af3d425d2862b7…
1 file changed
+32
-20
+32
-20
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -196,11 +196,11 @@ | ||
| 196 | 196 | |
| 197 | 197 | /* |
| 198 | 198 | ** Set the reply content type |
| 199 | 199 | */ |
| 200 | 200 | void cgi_set_content_type(const char *zType){ |
| 201 | - zContentType = mprintf("%s", zType); | |
| 201 | + zContentType = fossil_strdup(zType); | |
| 202 | 202 | } |
| 203 | 203 | |
| 204 | 204 | /* |
| 205 | 205 | ** Set the reply content to the specified BLOB. |
| 206 | 206 | */ |
| @@ -213,11 +213,11 @@ | ||
| 213 | 213 | |
| 214 | 214 | /* |
| 215 | 215 | ** Set the reply status code |
| 216 | 216 | */ |
| 217 | 217 | void cgi_set_status(int iStat, const char *zStat){ |
| 218 | - zReplyStatus = mprintf("%s", zStat); | |
| 218 | + zReplyStatus = fossil_strdup(zStat); | |
| 219 | 219 | iReplyStatus = iStat; |
| 220 | 220 | } |
| 221 | 221 | |
| 222 | 222 | /* |
| 223 | 223 | ** Append text to the header of an HTTP reply |
| @@ -580,14 +580,14 @@ | ||
| 580 | 580 | ** is its fully decoded value. |
| 581 | 581 | ** |
| 582 | 582 | ** Copies are made of both the zName and zValue parameters. |
| 583 | 583 | */ |
| 584 | 584 | void cgi_set_parameter(const char *zName, const char *zValue){ |
| 585 | - cgi_set_parameter_nocopy(mprintf("%s",zName), mprintf("%s",zValue), 0); | |
| 585 | + cgi_set_parameter_nocopy(fossil_strdup(zName),fossil_strdup(zValue), 0); | |
| 586 | 586 | } |
| 587 | 587 | void cgi_set_query_parameter(const char *zName, const char *zValue){ |
| 588 | - cgi_set_parameter_nocopy(mprintf("%s",zName), mprintf("%s",zValue), 1); | |
| 588 | + cgi_set_parameter_nocopy(fossil_strdup(zName),fossil_strdup(zValue), 1); | |
| 589 | 589 | } |
| 590 | 590 | |
| 591 | 591 | /* |
| 592 | 592 | ** Replace a parameter with a new value. |
| 593 | 593 | */ |
| @@ -650,11 +650,11 @@ | ||
| 650 | 650 | /* |
| 651 | 651 | ** Add a query parameter. The zName portion is fixed but a copy |
| 652 | 652 | ** must be made of zValue. |
| 653 | 653 | */ |
| 654 | 654 | void cgi_setenv(const char *zName, const char *zValue){ |
| 655 | - cgi_set_parameter_nocopy(zName, mprintf("%s",zValue), 0); | |
| 655 | + cgi_set_parameter_nocopy(zName, fossil_strdup(zValue), 0); | |
| 656 | 656 | } |
| 657 | 657 | |
| 658 | 658 | /* |
| 659 | 659 | ** Add a list of query parameters or cookies to the parameter set. |
| 660 | 660 | ** |
| @@ -1050,10 +1050,15 @@ | ||
| 1050 | 1050 | ** computed from REQUEST_URI and SCRIPT_NAME. If PATH_INFO is provided |
| 1051 | 1051 | ** but REQUEST_URI is not, then compute REQUEST_URI from PATH_INFO and |
| 1052 | 1052 | ** SCRIPT_NAME. If neither REQUEST_URI nor PATH_INFO are provided, then |
| 1053 | 1053 | ** assume that PATH_INFO is an empty string and set REQUEST_URI equal |
| 1054 | 1054 | ** to PATH_INFO. |
| 1055 | +** | |
| 1056 | +** Sometimes PATH_INFO is missing and SCRIPT_NAME is not a prefix of | |
| 1057 | +** REQUEST_URI. (See https://fossil-scm.org/forum/forumpost/049e8650ed) | |
| 1058 | +** In that case, truncate SCRIPT_NAME so that it is a proper prefix | |
| 1059 | +** of REQUEST_URI. | |
| 1055 | 1060 | ** |
| 1056 | 1061 | ** SCGI typically omits PATH_INFO. CGI sometimes omits REQUEST_URI and |
| 1057 | 1062 | ** PATH_INFO when it is empty. |
| 1058 | 1063 | ** |
| 1059 | 1064 | ** CGI Parameter quick reference: |
| @@ -1095,11 +1100,11 @@ | ||
| 1095 | 1100 | nRU = strlen(zRequestUri); |
| 1096 | 1101 | nPI = strlen(zPathInfo); |
| 1097 | 1102 | if( nRU<nPI ){ |
| 1098 | 1103 | malformed_request("PATH_INFO is longer than REQUEST_URI"); |
| 1099 | 1104 | } |
| 1100 | - zScriptName = mprintf("%.*s", (int)(nRU-nPI), zRequestUri); | |
| 1105 | + zScriptName = fossil_strndup(zRequestUri,(int)(nRU-nPI)); | |
| 1101 | 1106 | cgi_set_parameter("SCRIPT_NAME", zScriptName); |
| 1102 | 1107 | } |
| 1103 | 1108 | |
| 1104 | 1109 | #ifdef _WIN32 |
| 1105 | 1110 | /* The Microsoft IIS web server does not define REQUEST_URI, instead it uses |
| @@ -1109,11 +1114,11 @@ | ||
| 1109 | 1114 | if( zServerSoftware && strstr(zServerSoftware, "Microsoft-IIS") ){ |
| 1110 | 1115 | int i, j; |
| 1111 | 1116 | cgi_set_parameter("REQUEST_URI", zPathInfo); |
| 1112 | 1117 | for(i=0; zPathInfo[i]==zScriptName[i] && zPathInfo[i]; i++){} |
| 1113 | 1118 | for(j=i; zPathInfo[j] && zPathInfo[j]!='?'; j++){} |
| 1114 | - zPathInfo = mprintf("%.*s", j-i, zPathInfo+i); | |
| 1119 | + zPathInfo = fossil_strndup(zPathInfo+i, j-i); | |
| 1115 | 1120 | cgi_replace_parameter("PATH_INFO", zPathInfo); |
| 1116 | 1121 | } |
| 1117 | 1122 | #endif |
| 1118 | 1123 | if( zRequestUri==0 ){ |
| 1119 | 1124 | const char *z = zPathInfo; |
| @@ -1126,12 +1131,19 @@ | ||
| 1126 | 1131 | } |
| 1127 | 1132 | if( zPathInfo==0 ){ |
| 1128 | 1133 | int i, j; |
| 1129 | 1134 | for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){} |
| 1130 | 1135 | for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){} |
| 1131 | - zPathInfo = mprintf("%.*s", j-i, zRequestUri+i); | |
| 1132 | - cgi_set_parameter("PATH_INFO", zPathInfo); | |
| 1136 | + zPathInfo = fossil_strndup(zRequestUri+i, j-i); | |
| 1137 | + cgi_set_parameter_nocopy("PATH_INFO", zPathInfo, 0); | |
| 1138 | + if( j>i && zScriptName[i]!=0 ){ | |
| 1139 | + /* If SCRIPT_NAME is not a prefix of REQUEST_URI, truncate it so | |
| 1140 | + ** that it is. See https://fossil-scm.org/forum/forumpost/049e8650ed | |
| 1141 | + */ | |
| 1142 | + char *zNew = fossil_strndup(zScriptName, i); | |
| 1143 | + cgi_replace_parameter("SCRIPT_NAME", zNew); | |
| 1144 | + } | |
| 1133 | 1145 | } |
| 1134 | 1146 | #ifdef FOSSIL_ENABLE_JSON |
| 1135 | 1147 | if(noJson==0 && json_request_is_json_api(zPathInfo)){ |
| 1136 | 1148 | /* We need to change some following behaviour depending on whether |
| 1137 | 1149 | ** we are operating in JSON mode or not. We cannot, however, be |
| @@ -1145,30 +1157,30 @@ | ||
| 1145 | 1157 | "Internal misconfiguration of g.json.isJsonMode"); |
| 1146 | 1158 | } |
| 1147 | 1159 | #endif |
| 1148 | 1160 | z = (char*)P("HTTP_COOKIE"); |
| 1149 | 1161 | if( z ){ |
| 1150 | - z = mprintf("%s",z); | |
| 1162 | + z = fossil_strdup(z); | |
| 1151 | 1163 | add_param_list(z, ';'); |
| 1152 | 1164 | } |
| 1153 | 1165 | |
| 1154 | 1166 | z = (char*)P("QUERY_STRING"); |
| 1155 | 1167 | if( z ){ |
| 1156 | - z = mprintf("%s",z); | |
| 1168 | + z = fossil_strdup(z); | |
| 1157 | 1169 | add_param_list(z, '&'); |
| 1158 | 1170 | } |
| 1159 | 1171 | |
| 1160 | 1172 | z = (char*)P("REMOTE_ADDR"); |
| 1161 | 1173 | if( z ){ |
| 1162 | - g.zIpAddr = mprintf("%s", z); | |
| 1174 | + g.zIpAddr = fossil_strdup(z); | |
| 1163 | 1175 | } |
| 1164 | 1176 | |
| 1165 | 1177 | len = atoi(PD("CONTENT_LENGTH", "0")); |
| 1166 | 1178 | zType = P("CONTENT_TYPE"); |
| 1167 | 1179 | zSemi = zType ? strchr(zType, ';') : 0; |
| 1168 | 1180 | if( zSemi ){ |
| 1169 | - g.zContentType = mprintf("%.*s", (int)(zSemi-zType), zType); | |
| 1181 | + g.zContentType = fossil_strndup(zType, (int)(zSemi-zType)); | |
| 1170 | 1182 | zType = g.zContentType; |
| 1171 | 1183 | }else{ |
| 1172 | 1184 | g.zContentType = zType; |
| 1173 | 1185 | } |
| 1174 | 1186 | blob_zero(&g.cgiIn); |
| @@ -1695,11 +1707,11 @@ | ||
| 1695 | 1707 | if( zIpAddr==0 ){ |
| 1696 | 1708 | zIpAddr = cgi_remote_ip(fileno(g.httpIn)); |
| 1697 | 1709 | } |
| 1698 | 1710 | if( zIpAddr ){ |
| 1699 | 1711 | cgi_setenv("REMOTE_ADDR", zIpAddr); |
| 1700 | - g.zIpAddr = mprintf("%s", zIpAddr); | |
| 1712 | + g.zIpAddr = fossil_strdup(zIpAddr); | |
| 1701 | 1713 | } |
| 1702 | 1714 | |
| 1703 | 1715 | |
| 1704 | 1716 | /* Get all the optional fields that follow the first line. |
| 1705 | 1717 | */ |
| @@ -1746,11 +1758,11 @@ | ||
| 1746 | 1758 | }else if( fossil_strcmp(zFieldName,"authorization:")==0 ){ |
| 1747 | 1759 | cgi_setenv("HTTP_AUTHORIZATION", zVal); |
| 1748 | 1760 | }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){ |
| 1749 | 1761 | const char *zIpAddr = cgi_accept_forwarded_for(zVal); |
| 1750 | 1762 | if( zIpAddr!=0 ){ |
| 1751 | - g.zIpAddr = mprintf("%s", zIpAddr); | |
| 1763 | + g.zIpAddr = fossil_strdup(zIpAddr); | |
| 1752 | 1764 | cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr); |
| 1753 | 1765 | } |
| 1754 | 1766 | }else if( fossil_strcmp(zFieldName,"range:")==0 ){ |
| 1755 | 1767 | int x1 = 0; |
| 1756 | 1768 | int x2 = 0; |
| @@ -1786,11 +1798,11 @@ | ||
| 1786 | 1798 | if( nCycles==0 ){ json_bootstrap_early(); } |
| 1787 | 1799 | #endif |
| 1788 | 1800 | if( zIpAddr ){ |
| 1789 | 1801 | if( nCycles==0 ){ |
| 1790 | 1802 | cgi_setenv("REMOTE_ADDR", zIpAddr); |
| 1791 | - g.zIpAddr = mprintf("%s", zIpAddr); | |
| 1803 | + g.zIpAddr = fossil_strdup(zIpAddr); | |
| 1792 | 1804 | } |
| 1793 | 1805 | }else{ |
| 1794 | 1806 | fossil_panic("missing SSH IP address"); |
| 1795 | 1807 | } |
| 1796 | 1808 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| @@ -1848,11 +1860,11 @@ | ||
| 1848 | 1860 | for(i=0; zToken[i] && zToken[i]!='?'; i++){} |
| 1849 | 1861 | if( zToken[i] ) zToken[i++] = 0; |
| 1850 | 1862 | if( nCycles==0 ){ |
| 1851 | 1863 | cgi_setenv("PATH_INFO", zToken); |
| 1852 | 1864 | }else{ |
| 1853 | - cgi_replace_parameter("PATH_INFO", mprintf("%s",zToken)); | |
| 1865 | + cgi_replace_parameter("PATH_INFO", fossil_strdup(zToken)); | |
| 1854 | 1866 | } |
| 1855 | 1867 | |
| 1856 | 1868 | /* Get all the optional fields that follow the first line. |
| 1857 | 1869 | */ |
| 1858 | 1870 | while( fgets(zLine,sizeof(zLine),g.httpIn) ){ |
| @@ -1870,11 +1882,11 @@ | ||
| 1870 | 1882 | zFieldName[i] = fossil_tolower(zFieldName[i]); |
| 1871 | 1883 | } |
| 1872 | 1884 | if( fossil_strcmp(zFieldName,"content-length:")==0 ){ |
| 1873 | 1885 | content_length = atoi(zVal); |
| 1874 | 1886 | }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){ |
| 1875 | - g.zContentType = zType = mprintf("%s", zVal); | |
| 1887 | + g.zContentType = zType = fossil_strdup(zVal); | |
| 1876 | 1888 | }else if( fossil_strcmp(zFieldName,"host:")==0 ){ |
| 1877 | 1889 | if( nCycles==0 ){ |
| 1878 | 1890 | cgi_setenv("HTTP_HOST", zVal); |
| 1879 | 1891 | } |
| 1880 | 1892 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| @@ -1947,11 +1959,11 @@ | ||
| 1947 | 1959 | |
| 1948 | 1960 | /* Got all probes now first transport_open is completed |
| 1949 | 1961 | ** so return the command that was requested |
| 1950 | 1962 | */ |
| 1951 | 1963 | g.fSshClient |= CGI_SSH_COMPAT; |
| 1952 | - return mprintf("%s", zToken); | |
| 1964 | + return fossil_strdup(zToken); | |
| 1953 | 1965 | } |
| 1954 | 1966 | |
| 1955 | 1967 | /* |
| 1956 | 1968 | ** This routine handles the old fossil SSH transport_flip |
| 1957 | 1969 | ** and transport_open communications if detected. |
| @@ -2323,11 +2335,11 @@ | ||
| 2323 | 2335 | const char *cgi_ssh_remote_addr(const char *zDefault){ |
| 2324 | 2336 | char *zIndex; |
| 2325 | 2337 | const char *zSshConn = fossil_getenv("SSH_CONNECTION"); |
| 2326 | 2338 | |
| 2327 | 2339 | if( zSshConn && zSshConn[0] ){ |
| 2328 | - char *zSshClient = mprintf("%s",zSshConn); | |
| 2340 | + char *zSshClient = fossil_strdup(zSshConn); | |
| 2329 | 2341 | if( (zIndex = strchr(zSshClient,' '))!=0 ){ |
| 2330 | 2342 | zSshClient[zIndex-zSshClient] = '\0'; |
| 2331 | 2343 | return zSshClient; |
| 2332 | 2344 | } |
| 2333 | 2345 | } |
| 2334 | 2346 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -196,11 +196,11 @@ | |
| 196 | |
| 197 | /* |
| 198 | ** Set the reply content type |
| 199 | */ |
| 200 | void cgi_set_content_type(const char *zType){ |
| 201 | zContentType = mprintf("%s", zType); |
| 202 | } |
| 203 | |
| 204 | /* |
| 205 | ** Set the reply content to the specified BLOB. |
| 206 | */ |
| @@ -213,11 +213,11 @@ | |
| 213 | |
| 214 | /* |
| 215 | ** Set the reply status code |
| 216 | */ |
| 217 | void cgi_set_status(int iStat, const char *zStat){ |
| 218 | zReplyStatus = mprintf("%s", zStat); |
| 219 | iReplyStatus = iStat; |
| 220 | } |
| 221 | |
| 222 | /* |
| 223 | ** Append text to the header of an HTTP reply |
| @@ -580,14 +580,14 @@ | |
| 580 | ** is its fully decoded value. |
| 581 | ** |
| 582 | ** Copies are made of both the zName and zValue parameters. |
| 583 | */ |
| 584 | void cgi_set_parameter(const char *zName, const char *zValue){ |
| 585 | cgi_set_parameter_nocopy(mprintf("%s",zName), mprintf("%s",zValue), 0); |
| 586 | } |
| 587 | void cgi_set_query_parameter(const char *zName, const char *zValue){ |
| 588 | cgi_set_parameter_nocopy(mprintf("%s",zName), mprintf("%s",zValue), 1); |
| 589 | } |
| 590 | |
| 591 | /* |
| 592 | ** Replace a parameter with a new value. |
| 593 | */ |
| @@ -650,11 +650,11 @@ | |
| 650 | /* |
| 651 | ** Add a query parameter. The zName portion is fixed but a copy |
| 652 | ** must be made of zValue. |
| 653 | */ |
| 654 | void cgi_setenv(const char *zName, const char *zValue){ |
| 655 | cgi_set_parameter_nocopy(zName, mprintf("%s",zValue), 0); |
| 656 | } |
| 657 | |
| 658 | /* |
| 659 | ** Add a list of query parameters or cookies to the parameter set. |
| 660 | ** |
| @@ -1050,10 +1050,15 @@ | |
| 1050 | ** computed from REQUEST_URI and SCRIPT_NAME. If PATH_INFO is provided |
| 1051 | ** but REQUEST_URI is not, then compute REQUEST_URI from PATH_INFO and |
| 1052 | ** SCRIPT_NAME. If neither REQUEST_URI nor PATH_INFO are provided, then |
| 1053 | ** assume that PATH_INFO is an empty string and set REQUEST_URI equal |
| 1054 | ** to PATH_INFO. |
| 1055 | ** |
| 1056 | ** SCGI typically omits PATH_INFO. CGI sometimes omits REQUEST_URI and |
| 1057 | ** PATH_INFO when it is empty. |
| 1058 | ** |
| 1059 | ** CGI Parameter quick reference: |
| @@ -1095,11 +1100,11 @@ | |
| 1095 | nRU = strlen(zRequestUri); |
| 1096 | nPI = strlen(zPathInfo); |
| 1097 | if( nRU<nPI ){ |
| 1098 | malformed_request("PATH_INFO is longer than REQUEST_URI"); |
| 1099 | } |
| 1100 | zScriptName = mprintf("%.*s", (int)(nRU-nPI), zRequestUri); |
| 1101 | cgi_set_parameter("SCRIPT_NAME", zScriptName); |
| 1102 | } |
| 1103 | |
| 1104 | #ifdef _WIN32 |
| 1105 | /* The Microsoft IIS web server does not define REQUEST_URI, instead it uses |
| @@ -1109,11 +1114,11 @@ | |
| 1109 | if( zServerSoftware && strstr(zServerSoftware, "Microsoft-IIS") ){ |
| 1110 | int i, j; |
| 1111 | cgi_set_parameter("REQUEST_URI", zPathInfo); |
| 1112 | for(i=0; zPathInfo[i]==zScriptName[i] && zPathInfo[i]; i++){} |
| 1113 | for(j=i; zPathInfo[j] && zPathInfo[j]!='?'; j++){} |
| 1114 | zPathInfo = mprintf("%.*s", j-i, zPathInfo+i); |
| 1115 | cgi_replace_parameter("PATH_INFO", zPathInfo); |
| 1116 | } |
| 1117 | #endif |
| 1118 | if( zRequestUri==0 ){ |
| 1119 | const char *z = zPathInfo; |
| @@ -1126,12 +1131,19 @@ | |
| 1126 | } |
| 1127 | if( zPathInfo==0 ){ |
| 1128 | int i, j; |
| 1129 | for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){} |
| 1130 | for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){} |
| 1131 | zPathInfo = mprintf("%.*s", j-i, zRequestUri+i); |
| 1132 | cgi_set_parameter("PATH_INFO", zPathInfo); |
| 1133 | } |
| 1134 | #ifdef FOSSIL_ENABLE_JSON |
| 1135 | if(noJson==0 && json_request_is_json_api(zPathInfo)){ |
| 1136 | /* We need to change some following behaviour depending on whether |
| 1137 | ** we are operating in JSON mode or not. We cannot, however, be |
| @@ -1145,30 +1157,30 @@ | |
| 1145 | "Internal misconfiguration of g.json.isJsonMode"); |
| 1146 | } |
| 1147 | #endif |
| 1148 | z = (char*)P("HTTP_COOKIE"); |
| 1149 | if( z ){ |
| 1150 | z = mprintf("%s",z); |
| 1151 | add_param_list(z, ';'); |
| 1152 | } |
| 1153 | |
| 1154 | z = (char*)P("QUERY_STRING"); |
| 1155 | if( z ){ |
| 1156 | z = mprintf("%s",z); |
| 1157 | add_param_list(z, '&'); |
| 1158 | } |
| 1159 | |
| 1160 | z = (char*)P("REMOTE_ADDR"); |
| 1161 | if( z ){ |
| 1162 | g.zIpAddr = mprintf("%s", z); |
| 1163 | } |
| 1164 | |
| 1165 | len = atoi(PD("CONTENT_LENGTH", "0")); |
| 1166 | zType = P("CONTENT_TYPE"); |
| 1167 | zSemi = zType ? strchr(zType, ';') : 0; |
| 1168 | if( zSemi ){ |
| 1169 | g.zContentType = mprintf("%.*s", (int)(zSemi-zType), zType); |
| 1170 | zType = g.zContentType; |
| 1171 | }else{ |
| 1172 | g.zContentType = zType; |
| 1173 | } |
| 1174 | blob_zero(&g.cgiIn); |
| @@ -1695,11 +1707,11 @@ | |
| 1695 | if( zIpAddr==0 ){ |
| 1696 | zIpAddr = cgi_remote_ip(fileno(g.httpIn)); |
| 1697 | } |
| 1698 | if( zIpAddr ){ |
| 1699 | cgi_setenv("REMOTE_ADDR", zIpAddr); |
| 1700 | g.zIpAddr = mprintf("%s", zIpAddr); |
| 1701 | } |
| 1702 | |
| 1703 | |
| 1704 | /* Get all the optional fields that follow the first line. |
| 1705 | */ |
| @@ -1746,11 +1758,11 @@ | |
| 1746 | }else if( fossil_strcmp(zFieldName,"authorization:")==0 ){ |
| 1747 | cgi_setenv("HTTP_AUTHORIZATION", zVal); |
| 1748 | }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){ |
| 1749 | const char *zIpAddr = cgi_accept_forwarded_for(zVal); |
| 1750 | if( zIpAddr!=0 ){ |
| 1751 | g.zIpAddr = mprintf("%s", zIpAddr); |
| 1752 | cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr); |
| 1753 | } |
| 1754 | }else if( fossil_strcmp(zFieldName,"range:")==0 ){ |
| 1755 | int x1 = 0; |
| 1756 | int x2 = 0; |
| @@ -1786,11 +1798,11 @@ | |
| 1786 | if( nCycles==0 ){ json_bootstrap_early(); } |
| 1787 | #endif |
| 1788 | if( zIpAddr ){ |
| 1789 | if( nCycles==0 ){ |
| 1790 | cgi_setenv("REMOTE_ADDR", zIpAddr); |
| 1791 | g.zIpAddr = mprintf("%s", zIpAddr); |
| 1792 | } |
| 1793 | }else{ |
| 1794 | fossil_panic("missing SSH IP address"); |
| 1795 | } |
| 1796 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| @@ -1848,11 +1860,11 @@ | |
| 1848 | for(i=0; zToken[i] && zToken[i]!='?'; i++){} |
| 1849 | if( zToken[i] ) zToken[i++] = 0; |
| 1850 | if( nCycles==0 ){ |
| 1851 | cgi_setenv("PATH_INFO", zToken); |
| 1852 | }else{ |
| 1853 | cgi_replace_parameter("PATH_INFO", mprintf("%s",zToken)); |
| 1854 | } |
| 1855 | |
| 1856 | /* Get all the optional fields that follow the first line. |
| 1857 | */ |
| 1858 | while( fgets(zLine,sizeof(zLine),g.httpIn) ){ |
| @@ -1870,11 +1882,11 @@ | |
| 1870 | zFieldName[i] = fossil_tolower(zFieldName[i]); |
| 1871 | } |
| 1872 | if( fossil_strcmp(zFieldName,"content-length:")==0 ){ |
| 1873 | content_length = atoi(zVal); |
| 1874 | }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){ |
| 1875 | g.zContentType = zType = mprintf("%s", zVal); |
| 1876 | }else if( fossil_strcmp(zFieldName,"host:")==0 ){ |
| 1877 | if( nCycles==0 ){ |
| 1878 | cgi_setenv("HTTP_HOST", zVal); |
| 1879 | } |
| 1880 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| @@ -1947,11 +1959,11 @@ | |
| 1947 | |
| 1948 | /* Got all probes now first transport_open is completed |
| 1949 | ** so return the command that was requested |
| 1950 | */ |
| 1951 | g.fSshClient |= CGI_SSH_COMPAT; |
| 1952 | return mprintf("%s", zToken); |
| 1953 | } |
| 1954 | |
| 1955 | /* |
| 1956 | ** This routine handles the old fossil SSH transport_flip |
| 1957 | ** and transport_open communications if detected. |
| @@ -2323,11 +2335,11 @@ | |
| 2323 | const char *cgi_ssh_remote_addr(const char *zDefault){ |
| 2324 | char *zIndex; |
| 2325 | const char *zSshConn = fossil_getenv("SSH_CONNECTION"); |
| 2326 | |
| 2327 | if( zSshConn && zSshConn[0] ){ |
| 2328 | char *zSshClient = mprintf("%s",zSshConn); |
| 2329 | if( (zIndex = strchr(zSshClient,' '))!=0 ){ |
| 2330 | zSshClient[zIndex-zSshClient] = '\0'; |
| 2331 | return zSshClient; |
| 2332 | } |
| 2333 | } |
| 2334 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -196,11 +196,11 @@ | |
| 196 | |
| 197 | /* |
| 198 | ** Set the reply content type |
| 199 | */ |
| 200 | void cgi_set_content_type(const char *zType){ |
| 201 | zContentType = fossil_strdup(zType); |
| 202 | } |
| 203 | |
| 204 | /* |
| 205 | ** Set the reply content to the specified BLOB. |
| 206 | */ |
| @@ -213,11 +213,11 @@ | |
| 213 | |
| 214 | /* |
| 215 | ** Set the reply status code |
| 216 | */ |
| 217 | void cgi_set_status(int iStat, const char *zStat){ |
| 218 | zReplyStatus = fossil_strdup(zStat); |
| 219 | iReplyStatus = iStat; |
| 220 | } |
| 221 | |
| 222 | /* |
| 223 | ** Append text to the header of an HTTP reply |
| @@ -580,14 +580,14 @@ | |
| 580 | ** is its fully decoded value. |
| 581 | ** |
| 582 | ** Copies are made of both the zName and zValue parameters. |
| 583 | */ |
| 584 | void cgi_set_parameter(const char *zName, const char *zValue){ |
| 585 | cgi_set_parameter_nocopy(fossil_strdup(zName),fossil_strdup(zValue), 0); |
| 586 | } |
| 587 | void cgi_set_query_parameter(const char *zName, const char *zValue){ |
| 588 | cgi_set_parameter_nocopy(fossil_strdup(zName),fossil_strdup(zValue), 1); |
| 589 | } |
| 590 | |
| 591 | /* |
| 592 | ** Replace a parameter with a new value. |
| 593 | */ |
| @@ -650,11 +650,11 @@ | |
| 650 | /* |
| 651 | ** Add a query parameter. The zName portion is fixed but a copy |
| 652 | ** must be made of zValue. |
| 653 | */ |
| 654 | void cgi_setenv(const char *zName, const char *zValue){ |
| 655 | cgi_set_parameter_nocopy(zName, fossil_strdup(zValue), 0); |
| 656 | } |
| 657 | |
| 658 | /* |
| 659 | ** Add a list of query parameters or cookies to the parameter set. |
| 660 | ** |
| @@ -1050,10 +1050,15 @@ | |
| 1050 | ** computed from REQUEST_URI and SCRIPT_NAME. If PATH_INFO is provided |
| 1051 | ** but REQUEST_URI is not, then compute REQUEST_URI from PATH_INFO and |
| 1052 | ** SCRIPT_NAME. If neither REQUEST_URI nor PATH_INFO are provided, then |
| 1053 | ** assume that PATH_INFO is an empty string and set REQUEST_URI equal |
| 1054 | ** to PATH_INFO. |
| 1055 | ** |
| 1056 | ** Sometimes PATH_INFO is missing and SCRIPT_NAME is not a prefix of |
| 1057 | ** REQUEST_URI. (See https://fossil-scm.org/forum/forumpost/049e8650ed) |
| 1058 | ** In that case, truncate SCRIPT_NAME so that it is a proper prefix |
| 1059 | ** of REQUEST_URI. |
| 1060 | ** |
| 1061 | ** SCGI typically omits PATH_INFO. CGI sometimes omits REQUEST_URI and |
| 1062 | ** PATH_INFO when it is empty. |
| 1063 | ** |
| 1064 | ** CGI Parameter quick reference: |
| @@ -1095,11 +1100,11 @@ | |
| 1100 | nRU = strlen(zRequestUri); |
| 1101 | nPI = strlen(zPathInfo); |
| 1102 | if( nRU<nPI ){ |
| 1103 | malformed_request("PATH_INFO is longer than REQUEST_URI"); |
| 1104 | } |
| 1105 | zScriptName = fossil_strndup(zRequestUri,(int)(nRU-nPI)); |
| 1106 | cgi_set_parameter("SCRIPT_NAME", zScriptName); |
| 1107 | } |
| 1108 | |
| 1109 | #ifdef _WIN32 |
| 1110 | /* The Microsoft IIS web server does not define REQUEST_URI, instead it uses |
| @@ -1109,11 +1114,11 @@ | |
| 1114 | if( zServerSoftware && strstr(zServerSoftware, "Microsoft-IIS") ){ |
| 1115 | int i, j; |
| 1116 | cgi_set_parameter("REQUEST_URI", zPathInfo); |
| 1117 | for(i=0; zPathInfo[i]==zScriptName[i] && zPathInfo[i]; i++){} |
| 1118 | for(j=i; zPathInfo[j] && zPathInfo[j]!='?'; j++){} |
| 1119 | zPathInfo = fossil_strndup(zPathInfo+i, j-i); |
| 1120 | cgi_replace_parameter("PATH_INFO", zPathInfo); |
| 1121 | } |
| 1122 | #endif |
| 1123 | if( zRequestUri==0 ){ |
| 1124 | const char *z = zPathInfo; |
| @@ -1126,12 +1131,19 @@ | |
| 1131 | } |
| 1132 | if( zPathInfo==0 ){ |
| 1133 | int i, j; |
| 1134 | for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){} |
| 1135 | for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){} |
| 1136 | zPathInfo = fossil_strndup(zRequestUri+i, j-i); |
| 1137 | cgi_set_parameter_nocopy("PATH_INFO", zPathInfo, 0); |
| 1138 | if( j>i && zScriptName[i]!=0 ){ |
| 1139 | /* If SCRIPT_NAME is not a prefix of REQUEST_URI, truncate it so |
| 1140 | ** that it is. See https://fossil-scm.org/forum/forumpost/049e8650ed |
| 1141 | */ |
| 1142 | char *zNew = fossil_strndup(zScriptName, i); |
| 1143 | cgi_replace_parameter("SCRIPT_NAME", zNew); |
| 1144 | } |
| 1145 | } |
| 1146 | #ifdef FOSSIL_ENABLE_JSON |
| 1147 | if(noJson==0 && json_request_is_json_api(zPathInfo)){ |
| 1148 | /* We need to change some following behaviour depending on whether |
| 1149 | ** we are operating in JSON mode or not. We cannot, however, be |
| @@ -1145,30 +1157,30 @@ | |
| 1157 | "Internal misconfiguration of g.json.isJsonMode"); |
| 1158 | } |
| 1159 | #endif |
| 1160 | z = (char*)P("HTTP_COOKIE"); |
| 1161 | if( z ){ |
| 1162 | z = fossil_strdup(z); |
| 1163 | add_param_list(z, ';'); |
| 1164 | } |
| 1165 | |
| 1166 | z = (char*)P("QUERY_STRING"); |
| 1167 | if( z ){ |
| 1168 | z = fossil_strdup(z); |
| 1169 | add_param_list(z, '&'); |
| 1170 | } |
| 1171 | |
| 1172 | z = (char*)P("REMOTE_ADDR"); |
| 1173 | if( z ){ |
| 1174 | g.zIpAddr = fossil_strdup(z); |
| 1175 | } |
| 1176 | |
| 1177 | len = atoi(PD("CONTENT_LENGTH", "0")); |
| 1178 | zType = P("CONTENT_TYPE"); |
| 1179 | zSemi = zType ? strchr(zType, ';') : 0; |
| 1180 | if( zSemi ){ |
| 1181 | g.zContentType = fossil_strndup(zType, (int)(zSemi-zType)); |
| 1182 | zType = g.zContentType; |
| 1183 | }else{ |
| 1184 | g.zContentType = zType; |
| 1185 | } |
| 1186 | blob_zero(&g.cgiIn); |
| @@ -1695,11 +1707,11 @@ | |
| 1707 | if( zIpAddr==0 ){ |
| 1708 | zIpAddr = cgi_remote_ip(fileno(g.httpIn)); |
| 1709 | } |
| 1710 | if( zIpAddr ){ |
| 1711 | cgi_setenv("REMOTE_ADDR", zIpAddr); |
| 1712 | g.zIpAddr = fossil_strdup(zIpAddr); |
| 1713 | } |
| 1714 | |
| 1715 | |
| 1716 | /* Get all the optional fields that follow the first line. |
| 1717 | */ |
| @@ -1746,11 +1758,11 @@ | |
| 1758 | }else if( fossil_strcmp(zFieldName,"authorization:")==0 ){ |
| 1759 | cgi_setenv("HTTP_AUTHORIZATION", zVal); |
| 1760 | }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){ |
| 1761 | const char *zIpAddr = cgi_accept_forwarded_for(zVal); |
| 1762 | if( zIpAddr!=0 ){ |
| 1763 | g.zIpAddr = fossil_strdup(zIpAddr); |
| 1764 | cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr); |
| 1765 | } |
| 1766 | }else if( fossil_strcmp(zFieldName,"range:")==0 ){ |
| 1767 | int x1 = 0; |
| 1768 | int x2 = 0; |
| @@ -1786,11 +1798,11 @@ | |
| 1798 | if( nCycles==0 ){ json_bootstrap_early(); } |
| 1799 | #endif |
| 1800 | if( zIpAddr ){ |
| 1801 | if( nCycles==0 ){ |
| 1802 | cgi_setenv("REMOTE_ADDR", zIpAddr); |
| 1803 | g.zIpAddr = fossil_strdup(zIpAddr); |
| 1804 | } |
| 1805 | }else{ |
| 1806 | fossil_panic("missing SSH IP address"); |
| 1807 | } |
| 1808 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| @@ -1848,11 +1860,11 @@ | |
| 1860 | for(i=0; zToken[i] && zToken[i]!='?'; i++){} |
| 1861 | if( zToken[i] ) zToken[i++] = 0; |
| 1862 | if( nCycles==0 ){ |
| 1863 | cgi_setenv("PATH_INFO", zToken); |
| 1864 | }else{ |
| 1865 | cgi_replace_parameter("PATH_INFO", fossil_strdup(zToken)); |
| 1866 | } |
| 1867 | |
| 1868 | /* Get all the optional fields that follow the first line. |
| 1869 | */ |
| 1870 | while( fgets(zLine,sizeof(zLine),g.httpIn) ){ |
| @@ -1870,11 +1882,11 @@ | |
| 1882 | zFieldName[i] = fossil_tolower(zFieldName[i]); |
| 1883 | } |
| 1884 | if( fossil_strcmp(zFieldName,"content-length:")==0 ){ |
| 1885 | content_length = atoi(zVal); |
| 1886 | }else if( fossil_strcmp(zFieldName,"content-type:")==0 ){ |
| 1887 | g.zContentType = zType = fossil_strdup(zVal); |
| 1888 | }else if( fossil_strcmp(zFieldName,"host:")==0 ){ |
| 1889 | if( nCycles==0 ){ |
| 1890 | cgi_setenv("HTTP_HOST", zVal); |
| 1891 | } |
| 1892 | }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ |
| @@ -1947,11 +1959,11 @@ | |
| 1959 | |
| 1960 | /* Got all probes now first transport_open is completed |
| 1961 | ** so return the command that was requested |
| 1962 | */ |
| 1963 | g.fSshClient |= CGI_SSH_COMPAT; |
| 1964 | return fossil_strdup(zToken); |
| 1965 | } |
| 1966 | |
| 1967 | /* |
| 1968 | ** This routine handles the old fossil SSH transport_flip |
| 1969 | ** and transport_open communications if detected. |
| @@ -2323,11 +2335,11 @@ | |
| 2335 | const char *cgi_ssh_remote_addr(const char *zDefault){ |
| 2336 | char *zIndex; |
| 2337 | const char *zSshConn = fossil_getenv("SSH_CONNECTION"); |
| 2338 | |
| 2339 | if( zSshConn && zSshConn[0] ){ |
| 2340 | char *zSshClient = fossil_strdup(zSshConn); |
| 2341 | if( (zIndex = strchr(zSshClient,' '))!=0 ){ |
| 2342 | zSshClient[zIndex-zSshClient] = '\0'; |
| 2343 | return zSshClient; |
| 2344 | } |
| 2345 | } |
| 2346 |