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