Fossil SCM

Account for CGI-hosted fossil instances by sending the xfer login card as a URL argument. This is somewhat inelegant but works around their inability to read HTTP headers. This version is still more verbose than it needs to be, and requires more testing for compatibility with trunk fossil versions.

stephan 2025-07-23 20:56 xfer-login-card
Commit 439af9348b5c1d05b8f338a991ce0699a67104385d9830d395e0c6bd5485efb3
+26 -8
--- src/cgi.c
+++ src/cgi.c
@@ -964,11 +964,11 @@
964964
** * it is impossible for a cookie or query parameter to
965965
** override the value of an environment variable since
966966
** environment variables always have uppercase names.
967967
**
968968
** 2018-03-29: Also ignore the entry if NAME that contains any characters
969
-** other than [a-zA-Z0-9_]. There are no known exploits involving unusual
969
+** other than [-a-zA-Z0-9_]. There are no known exploits involving unusual
970970
** names that contain characters outside that set, but it never hurts to
971971
** be extra cautious when sanitizing inputs.
972972
**
973973
** Parameters are separated by the "terminator" character. Whitespace
974974
** before the NAME is ignored.
@@ -1280,35 +1280,52 @@
12801280
12811281
/* Forward declaration */
12821282
static NORETURN void malformed_request(const char *zMsg, ...);
12831283
12841284
/*
1285
-** Checks the QUERY_STRING environment variable, sets it up
1286
-** via add_param_list() and, if found, applies its "skin"
1287
-** setting. Returns 0 if no QUERY_STRING is set, 1 if it is,
1288
-** and 2 if it sets the skin (in which case the cookie may
1289
-** still need flushing by the page, via cookie_render()).
1285
+** Checks the QUERY_STRING environment variable, sets it up via
1286
+** add_param_list() and, if found, applies its "skin" setting. Returns
1287
+** 0 if no QUERY_STRING is set, else it returns a bitmask of:
1288
+**
1289
+** 0x01 = QUERY_STRING was set.
1290
+** 0x02 = "skin" argument was set and processed
1291
+** 0x04 = "x-f-x-l" arg was processed.
1292
+**
1293
+* In the case of the skin, the cookie may still need flushing
1294
+** by the page, via cookie_render().
12901295
*/
12911296
int cgi_setup_query_string(void){
12921297
int rc = 0;
12931298
char * z = (char*)P("QUERY_STRING");
12941299
if( z ){
1295
- ++rc;
1300
+ rc = 0x01;
12961301
z = fossil_strdup(z);
12971302
add_param_list(z, '&');
12981303
z = (char*)P("skin");
12991304
if( z ){
13001305
char *zErr = skin_use_alternative(z, 2, SKIN_FROM_QPARAM);
1301
- ++rc;
1306
+ rc |= 0x02;
13021307
if( !zErr && P("once")==0 ){
13031308
cookie_write_parameter("skin","skin",z);
13041309
/* Per /chat discussion, passing ?skin=... without "once"
13051310
** implies the "udc" argument, so we force that into the
13061311
** environment here. */
13071312
cgi_set_parameter_nocopy("udc", "1", 1);
13081313
}
13091314
fossil_free(zErr);
1315
+ }
1316
+ if( !g.syncInfo.zLoginCard && 0!=(z=(char*)P("x-f-x-l")) ){
1317
+ /* CGI fossil instances do not read the HTTP headers, so
1318
+ ** they cannot see the X-Fossil-Xfer-Login card. As a consolation
1319
+ ** to them, we'll accept that via this query argument. */
1320
+ rc |= 0x04;
1321
+ fossil_free( g.syncInfo.zLoginCard );
1322
+ g.syncInfo.zLoginCard = fossil_strdup(z);
1323
+ g.syncInfo.bLoginCardHeader = 3;
1324
+ /*cgi_delete_parameter("x-f-x-l");*/
1325
+ /*fprintf(stderr, "query string setup: x-f-x-l=%s\n",
1326
+ g.syncInfo.zLoginCard);*/
13101327
}
13111328
}
13121329
return rc;
13131330
}
13141331
@@ -2224,10 +2241,11 @@
22242241
rangeStart = x1;
22252242
rangeEnd = x2+1;
22262243
}
22272244
}else if( fossil_strcmp(zFieldName, "x-fossil-xfer-login:")==0 ){
22282245
/*cgi_setenv("FOSSIL_LCH_cgi_handle_http_request", zVal);*/
2246
+ fossil_free( g.syncInfo.zLoginCard );
22292247
g.syncInfo.zLoginCard = fossil_strdup(zVal);
22302248
g.syncInfo.bLoginCardHeader = 1;
22312249
}
22322250
}
22332251
cgi_setenv("REQUEST_SCHEME",zScheme);
22342252
--- src/cgi.c
+++ src/cgi.c
@@ -964,11 +964,11 @@
964 ** * it is impossible for a cookie or query parameter to
965 ** override the value of an environment variable since
966 ** environment variables always have uppercase names.
967 **
968 ** 2018-03-29: Also ignore the entry if NAME that contains any characters
969 ** other than [a-zA-Z0-9_]. There are no known exploits involving unusual
970 ** names that contain characters outside that set, but it never hurts to
971 ** be extra cautious when sanitizing inputs.
972 **
973 ** Parameters are separated by the "terminator" character. Whitespace
974 ** before the NAME is ignored.
@@ -1280,35 +1280,52 @@
1280
1281 /* Forward declaration */
1282 static NORETURN void malformed_request(const char *zMsg, ...);
1283
1284 /*
1285 ** Checks the QUERY_STRING environment variable, sets it up
1286 ** via add_param_list() and, if found, applies its "skin"
1287 ** setting. Returns 0 if no QUERY_STRING is set, 1 if it is,
1288 ** and 2 if it sets the skin (in which case the cookie may
1289 ** still need flushing by the page, via cookie_render()).
 
 
 
 
 
1290 */
1291 int cgi_setup_query_string(void){
1292 int rc = 0;
1293 char * z = (char*)P("QUERY_STRING");
1294 if( z ){
1295 ++rc;
1296 z = fossil_strdup(z);
1297 add_param_list(z, '&');
1298 z = (char*)P("skin");
1299 if( z ){
1300 char *zErr = skin_use_alternative(z, 2, SKIN_FROM_QPARAM);
1301 ++rc;
1302 if( !zErr && P("once")==0 ){
1303 cookie_write_parameter("skin","skin",z);
1304 /* Per /chat discussion, passing ?skin=... without "once"
1305 ** implies the "udc" argument, so we force that into the
1306 ** environment here. */
1307 cgi_set_parameter_nocopy("udc", "1", 1);
1308 }
1309 fossil_free(zErr);
 
 
 
 
 
 
 
 
 
 
 
 
1310 }
1311 }
1312 return rc;
1313 }
1314
@@ -2224,10 +2241,11 @@
2224 rangeStart = x1;
2225 rangeEnd = x2+1;
2226 }
2227 }else if( fossil_strcmp(zFieldName, "x-fossil-xfer-login:")==0 ){
2228 /*cgi_setenv("FOSSIL_LCH_cgi_handle_http_request", zVal);*/
 
2229 g.syncInfo.zLoginCard = fossil_strdup(zVal);
2230 g.syncInfo.bLoginCardHeader = 1;
2231 }
2232 }
2233 cgi_setenv("REQUEST_SCHEME",zScheme);
2234
--- src/cgi.c
+++ src/cgi.c
@@ -964,11 +964,11 @@
964 ** * it is impossible for a cookie or query parameter to
965 ** override the value of an environment variable since
966 ** environment variables always have uppercase names.
967 **
968 ** 2018-03-29: Also ignore the entry if NAME that contains any characters
969 ** other than [-a-zA-Z0-9_]. There are no known exploits involving unusual
970 ** names that contain characters outside that set, but it never hurts to
971 ** be extra cautious when sanitizing inputs.
972 **
973 ** Parameters are separated by the "terminator" character. Whitespace
974 ** before the NAME is ignored.
@@ -1280,35 +1280,52 @@
1280
1281 /* Forward declaration */
1282 static NORETURN void malformed_request(const char *zMsg, ...);
1283
1284 /*
1285 ** Checks the QUERY_STRING environment variable, sets it up via
1286 ** add_param_list() and, if found, applies its "skin" setting. Returns
1287 ** 0 if no QUERY_STRING is set, else it returns a bitmask of:
1288 **
1289 ** 0x01 = QUERY_STRING was set.
1290 ** 0x02 = "skin" argument was set and processed
1291 ** 0x04 = "x-f-x-l" arg was processed.
1292 **
1293 * In the case of the skin, the cookie may still need flushing
1294 ** by the page, via cookie_render().
1295 */
1296 int cgi_setup_query_string(void){
1297 int rc = 0;
1298 char * z = (char*)P("QUERY_STRING");
1299 if( z ){
1300 rc = 0x01;
1301 z = fossil_strdup(z);
1302 add_param_list(z, '&');
1303 z = (char*)P("skin");
1304 if( z ){
1305 char *zErr = skin_use_alternative(z, 2, SKIN_FROM_QPARAM);
1306 rc |= 0x02;
1307 if( !zErr && P("once")==0 ){
1308 cookie_write_parameter("skin","skin",z);
1309 /* Per /chat discussion, passing ?skin=... without "once"
1310 ** implies the "udc" argument, so we force that into the
1311 ** environment here. */
1312 cgi_set_parameter_nocopy("udc", "1", 1);
1313 }
1314 fossil_free(zErr);
1315 }
1316 if( !g.syncInfo.zLoginCard && 0!=(z=(char*)P("x-f-x-l")) ){
1317 /* CGI fossil instances do not read the HTTP headers, so
1318 ** they cannot see the X-Fossil-Xfer-Login card. As a consolation
1319 ** to them, we'll accept that via this query argument. */
1320 rc |= 0x04;
1321 fossil_free( g.syncInfo.zLoginCard );
1322 g.syncInfo.zLoginCard = fossil_strdup(z);
1323 g.syncInfo.bLoginCardHeader = 3;
1324 /*cgi_delete_parameter("x-f-x-l");*/
1325 /*fprintf(stderr, "query string setup: x-f-x-l=%s\n",
1326 g.syncInfo.zLoginCard);*/
1327 }
1328 }
1329 return rc;
1330 }
1331
@@ -2224,10 +2241,11 @@
2241 rangeStart = x1;
2242 rangeEnd = x2+1;
2243 }
2244 }else if( fossil_strcmp(zFieldName, "x-fossil-xfer-login:")==0 ){
2245 /*cgi_setenv("FOSSIL_LCH_cgi_handle_http_request", zVal);*/
2246 fossil_free( g.syncInfo.zLoginCard );
2247 g.syncInfo.zLoginCard = fossil_strdup(zVal);
2248 g.syncInfo.bLoginCardHeader = 1;
2249 }
2250 }
2251 cgi_setenv("REQUEST_SCHEME",zScheme);
2252
+41 -9
--- src/http.c
+++ src/http.c
@@ -127,10 +127,35 @@
127127
blob_appendf(pLogin, "login %F %b %b", zLogin, &nonce, &sig);
128128
blob_reset(&pw);
129129
blob_reset(&sig);
130130
blob_reset(&nonce);
131131
}
132
+
133
+/*
134
+** If we're in "login card header" mode, append ?x-f-x-l=ABC to
135
+** g.url.path, replacing any "?..." part of g.url.path. ABC = the
136
+** %T-encoded contents of pLogin. This is workaround for feeding the
137
+** login card to CGI-hosted fossil instances, as those do not read the
138
+** HTTP headers so cannot see the X-Fossil-Xfer-Login (x-f-x-l)
139
+** header.
140
+*/
141
+static void url_append_login_card(Blob * const pLogin){
142
+ if( g.syncInfo.bLoginCardHeader ||
143
+ g.syncInfo.remoteVersion >= RELEASE_VERSION_NUMBER ){
144
+ char * x;
145
+ char * z = g.url.path;
146
+ while( z && *z && '?'!=*z ) ++z;
147
+ if( z && *z ) *z = 0;
148
+ x = mprintf("%s?x-f-x-l=%T", g.url.path ? g.url.path : "/",
149
+ blob_str(pLogin));
150
+ fossil_free(g.url.path);
151
+ g.url.path = x;
152
+ if( !g.syncInfo.bLoginCardHeader ){
153
+ g.syncInfo.bLoginCardHeader = 4;
154
+ }
155
+ }
156
+}
132157
133158
/*
134159
** Construct an appropriate HTTP request header. Write the header
135160
** into pHdr. This routine initializes the pHdr blob. pPayload is
136161
** the complete payload (including the login card if pLogin is NULL or
@@ -143,13 +168,17 @@
143168
const char *zAltMimetype /* Alternative mimetype */
144169
){
145170
int nPayload = pPayload ? blob_size(pPayload) : 0;
146171
147172
blob_zero(pHdr);
148
- blob_appendf(pHdr, "%s %s%s HTTP/1.0\r\n",
149
- nPayload>0 ? "POST" : "GET", g.url.path,
150
- g.url.path[0]==0 ? "/" : "");
173
+ if( nPayload>0 && pLogin && blob_size(pLogin)>0 ){
174
+ /* Add login card URL arg for POST requests */
175
+ url_append_login_card(pLogin);
176
+ }
177
+ blob_appendf(pHdr, "%s %s HTTP/1.0\r\n",
178
+ nPayload>0 ? "POST" : "GET",
179
+ (g.url.path && g.url.path[0]) ? g.url.path : "/");
151180
if( g.url.proxyAuth ){
152181
blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
153182
}
154183
if( g.zHttpAuth && g.zHttpAuth[0] ){
155184
const char *zCredentials = g.zHttpAuth;
@@ -159,11 +188,12 @@
159188
}
160189
blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
161190
blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
162191
if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
163192
if( pLogin && blob_size(pLogin) ){
164
- blob_appendf(pHdr, "X-Fossil-Xfer-Login: %b\r\n", pLogin);
193
+ blob_appendf(pHdr, "X-Fossil-Xfer-Login: %b\r\n", pLogin)
194
+ /* Noting that CGIs can't read headers */;
165195
}
166196
if( nPayload ){
167197
if( zAltMimetype ){
168198
blob_appendf(pHdr, "Content-Type: %s\r\n", zAltMimetype);
169199
}else if( g.fHttpTrace ){
@@ -394,11 +424,11 @@
394424
** * The test-ssh-needs-path command that shows the settings
395425
** that cache whether or not a PATH= is needed for a particular
396426
** HOSTNAME.
397427
*/
398428
void ssh_add_path_argument(Blob *pCmd){
399
- blob_append_escaped_arg(pCmd,
429
+ blob_append_escaped_arg(pCmd,
400430
"PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1);
401431
}
402432
403433
/*
404434
** Return the complete text of the last HTTP reply as saved in the
@@ -471,17 +501,18 @@
471501
blob_zero(&login);
472502
if( blob_size(pSend)==0 ){
473503
blob_zero(&payload);
474504
}else{
475505
if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
476
- if( g.syncInfo.bLoginCardHeader ) {
477
- /* Send the login card as an HTTP header. */
506
+ if( g.syncInfo.bLoginCardHeader>0 ){
507
+ /* The login card will be sent via an HTTP header and/or URL flag. */
478508
if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
479509
/* Maintenance note: we cannot blob_swap(pSend,&payload) here
480510
** because the HTTP 401 and redirect response handling below
481511
** needs pSend unmodified. payload won't be modified after
482
- ** this point, so we can make it a proxy for pSend. */
512
+ ** this point, so we can make it a proxy for pSend for
513
+ ** zero heap memory. */
483514
blob_init(&payload, blob_buffer(pSend), blob_size(pSend));
484515
}else{
485516
blob_compress(pSend, &payload);
486517
}
487518
}else{
@@ -530,10 +561,11 @@
530561
/*
531562
** Send the request to the server.
532563
*/
533564
if( mHttpFlags & HTTP_VERBOSE ){
534565
fossil_print("URL: %s\n", g.url.canonical);
566
+ fossil_print("URL path: %s\n", g.url.path);
535567
fossil_print("Sending %d byte header and %d byte payload\n",
536568
blob_size(&hdr), blob_size(&payload));
537569
}
538570
transport_send(&g.url, &hdr);
539571
transport_send(&g.url, &payload);
@@ -661,11 +693,11 @@
661693
}else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
662694
isError = 1;
663695
}
664696
}
665697
}else if( fossil_strnicmp(zLine, "x-fossil-xfer-login: ", 21)==0 ){
666
- /*cgi_setenv("FOSSIL_LCH_http_exchange", &zLine[21]);*/
698
+ fossil_free( g.syncInfo.zLoginCard );
667699
g.syncInfo.zLoginCard = fossil_strdup(&zLine[21]);
668700
g.syncInfo.bLoginCardHeader = 1;
669701
}
670702
}
671703
if( iHttpVersion<0 ){
672704
--- src/http.c
+++ src/http.c
@@ -127,10 +127,35 @@
127 blob_appendf(pLogin, "login %F %b %b", zLogin, &nonce, &sig);
128 blob_reset(&pw);
129 blob_reset(&sig);
130 blob_reset(&nonce);
131 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
133 /*
134 ** Construct an appropriate HTTP request header. Write the header
135 ** into pHdr. This routine initializes the pHdr blob. pPayload is
136 ** the complete payload (including the login card if pLogin is NULL or
@@ -143,13 +168,17 @@
143 const char *zAltMimetype /* Alternative mimetype */
144 ){
145 int nPayload = pPayload ? blob_size(pPayload) : 0;
146
147 blob_zero(pHdr);
148 blob_appendf(pHdr, "%s %s%s HTTP/1.0\r\n",
149 nPayload>0 ? "POST" : "GET", g.url.path,
150 g.url.path[0]==0 ? "/" : "");
 
 
 
 
151 if( g.url.proxyAuth ){
152 blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
153 }
154 if( g.zHttpAuth && g.zHttpAuth[0] ){
155 const char *zCredentials = g.zHttpAuth;
@@ -159,11 +188,12 @@
159 }
160 blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
161 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
162 if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
163 if( pLogin && blob_size(pLogin) ){
164 blob_appendf(pHdr, "X-Fossil-Xfer-Login: %b\r\n", pLogin);
 
165 }
166 if( nPayload ){
167 if( zAltMimetype ){
168 blob_appendf(pHdr, "Content-Type: %s\r\n", zAltMimetype);
169 }else if( g.fHttpTrace ){
@@ -394,11 +424,11 @@
394 ** * The test-ssh-needs-path command that shows the settings
395 ** that cache whether or not a PATH= is needed for a particular
396 ** HOSTNAME.
397 */
398 void ssh_add_path_argument(Blob *pCmd){
399 blob_append_escaped_arg(pCmd,
400 "PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1);
401 }
402
403 /*
404 ** Return the complete text of the last HTTP reply as saved in the
@@ -471,17 +501,18 @@
471 blob_zero(&login);
472 if( blob_size(pSend)==0 ){
473 blob_zero(&payload);
474 }else{
475 if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
476 if( g.syncInfo.bLoginCardHeader ) {
477 /* Send the login card as an HTTP header. */
478 if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
479 /* Maintenance note: we cannot blob_swap(pSend,&payload) here
480 ** because the HTTP 401 and redirect response handling below
481 ** needs pSend unmodified. payload won't be modified after
482 ** this point, so we can make it a proxy for pSend. */
 
483 blob_init(&payload, blob_buffer(pSend), blob_size(pSend));
484 }else{
485 blob_compress(pSend, &payload);
486 }
487 }else{
@@ -530,10 +561,11 @@
530 /*
531 ** Send the request to the server.
532 */
533 if( mHttpFlags & HTTP_VERBOSE ){
534 fossil_print("URL: %s\n", g.url.canonical);
 
535 fossil_print("Sending %d byte header and %d byte payload\n",
536 blob_size(&hdr), blob_size(&payload));
537 }
538 transport_send(&g.url, &hdr);
539 transport_send(&g.url, &payload);
@@ -661,11 +693,11 @@
661 }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
662 isError = 1;
663 }
664 }
665 }else if( fossil_strnicmp(zLine, "x-fossil-xfer-login: ", 21)==0 ){
666 /*cgi_setenv("FOSSIL_LCH_http_exchange", &zLine[21]);*/
667 g.syncInfo.zLoginCard = fossil_strdup(&zLine[21]);
668 g.syncInfo.bLoginCardHeader = 1;
669 }
670 }
671 if( iHttpVersion<0 ){
672
--- src/http.c
+++ src/http.c
@@ -127,10 +127,35 @@
127 blob_appendf(pLogin, "login %F %b %b", zLogin, &nonce, &sig);
128 blob_reset(&pw);
129 blob_reset(&sig);
130 blob_reset(&nonce);
131 }
132
133 /*
134 ** If we're in "login card header" mode, append ?x-f-x-l=ABC to
135 ** g.url.path, replacing any "?..." part of g.url.path. ABC = the
136 ** %T-encoded contents of pLogin. This is workaround for feeding the
137 ** login card to CGI-hosted fossil instances, as those do not read the
138 ** HTTP headers so cannot see the X-Fossil-Xfer-Login (x-f-x-l)
139 ** header.
140 */
141 static void url_append_login_card(Blob * const pLogin){
142 if( g.syncInfo.bLoginCardHeader ||
143 g.syncInfo.remoteVersion >= RELEASE_VERSION_NUMBER ){
144 char * x;
145 char * z = g.url.path;
146 while( z && *z && '?'!=*z ) ++z;
147 if( z && *z ) *z = 0;
148 x = mprintf("%s?x-f-x-l=%T", g.url.path ? g.url.path : "/",
149 blob_str(pLogin));
150 fossil_free(g.url.path);
151 g.url.path = x;
152 if( !g.syncInfo.bLoginCardHeader ){
153 g.syncInfo.bLoginCardHeader = 4;
154 }
155 }
156 }
157
158 /*
159 ** Construct an appropriate HTTP request header. Write the header
160 ** into pHdr. This routine initializes the pHdr blob. pPayload is
161 ** the complete payload (including the login card if pLogin is NULL or
@@ -143,13 +168,17 @@
168 const char *zAltMimetype /* Alternative mimetype */
169 ){
170 int nPayload = pPayload ? blob_size(pPayload) : 0;
171
172 blob_zero(pHdr);
173 if( nPayload>0 && pLogin && blob_size(pLogin)>0 ){
174 /* Add login card URL arg for POST requests */
175 url_append_login_card(pLogin);
176 }
177 blob_appendf(pHdr, "%s %s HTTP/1.0\r\n",
178 nPayload>0 ? "POST" : "GET",
179 (g.url.path && g.url.path[0]) ? g.url.path : "/");
180 if( g.url.proxyAuth ){
181 blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
182 }
183 if( g.zHttpAuth && g.zHttpAuth[0] ){
184 const char *zCredentials = g.zHttpAuth;
@@ -159,11 +188,12 @@
188 }
189 blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
190 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
191 if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
192 if( pLogin && blob_size(pLogin) ){
193 blob_appendf(pHdr, "X-Fossil-Xfer-Login: %b\r\n", pLogin)
194 /* Noting that CGIs can't read headers */;
195 }
196 if( nPayload ){
197 if( zAltMimetype ){
198 blob_appendf(pHdr, "Content-Type: %s\r\n", zAltMimetype);
199 }else if( g.fHttpTrace ){
@@ -394,11 +424,11 @@
424 ** * The test-ssh-needs-path command that shows the settings
425 ** that cache whether or not a PATH= is needed for a particular
426 ** HOSTNAME.
427 */
428 void ssh_add_path_argument(Blob *pCmd){
429 blob_append_escaped_arg(pCmd,
430 "PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1);
431 }
432
433 /*
434 ** Return the complete text of the last HTTP reply as saved in the
@@ -471,17 +501,18 @@
501 blob_zero(&login);
502 if( blob_size(pSend)==0 ){
503 blob_zero(&payload);
504 }else{
505 if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
506 if( g.syncInfo.bLoginCardHeader>0 ){
507 /* The login card will be sent via an HTTP header and/or URL flag. */
508 if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
509 /* Maintenance note: we cannot blob_swap(pSend,&payload) here
510 ** because the HTTP 401 and redirect response handling below
511 ** needs pSend unmodified. payload won't be modified after
512 ** this point, so we can make it a proxy for pSend for
513 ** zero heap memory. */
514 blob_init(&payload, blob_buffer(pSend), blob_size(pSend));
515 }else{
516 blob_compress(pSend, &payload);
517 }
518 }else{
@@ -530,10 +561,11 @@
561 /*
562 ** Send the request to the server.
563 */
564 if( mHttpFlags & HTTP_VERBOSE ){
565 fossil_print("URL: %s\n", g.url.canonical);
566 fossil_print("URL path: %s\n", g.url.path);
567 fossil_print("Sending %d byte header and %d byte payload\n",
568 blob_size(&hdr), blob_size(&payload));
569 }
570 transport_send(&g.url, &hdr);
571 transport_send(&g.url, &payload);
@@ -661,11 +693,11 @@
693 }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
694 isError = 1;
695 }
696 }
697 }else if( fossil_strnicmp(zLine, "x-fossil-xfer-login: ", 21)==0 ){
698 fossil_free( g.syncInfo.zLoginCard );
699 g.syncInfo.zLoginCard = fossil_strdup(&zLine[21]);
700 g.syncInfo.bLoginCardHeader = 1;
701 }
702 }
703 if( iHttpVersion<0 ){
704
--- src/http_transport.c
+++ src/http_transport.c
@@ -141,11 +141,11 @@
141141
){
142142
fossil_fatal("the ssh:// URL is asking to run an unsafe command [%s] on "
143143
"the server.", pUrlData->fossil);
144144
}
145145
if( (pUrlData->flags & URL_SSH_EXE)==0
146
- && (pUrlData->flags & URL_SSH_PATH)!=0
146
+ && (pUrlData->flags & URL_SSH_PATH)!=0
147147
){
148148
ssh_add_path_argument(&zCmd);
149149
}
150150
blob_append_escaped_arg(&zCmd, pUrlData->fossil, 1);
151151
blob_append(&zCmd, " test-http", 10);
152152
--- src/http_transport.c
+++ src/http_transport.c
@@ -141,11 +141,11 @@
141 ){
142 fossil_fatal("the ssh:// URL is asking to run an unsafe command [%s] on "
143 "the server.", pUrlData->fossil);
144 }
145 if( (pUrlData->flags & URL_SSH_EXE)==0
146 && (pUrlData->flags & URL_SSH_PATH)!=0
147 ){
148 ssh_add_path_argument(&zCmd);
149 }
150 blob_append_escaped_arg(&zCmd, pUrlData->fossil, 1);
151 blob_append(&zCmd, " test-http", 10);
152
--- src/http_transport.c
+++ src/http_transport.c
@@ -141,11 +141,11 @@
141 ){
142 fossil_fatal("the ssh:// URL is asking to run an unsafe command [%s] on "
143 "the server.", pUrlData->fossil);
144 }
145 if( (pUrlData->flags & URL_SSH_EXE)==0
146 && (pUrlData->flags & URL_SSH_PATH)!=0
147 ){
148 ssh_add_path_argument(&zCmd);
149 }
150 blob_append_escaped_arg(&zCmd, pUrlData->fossil, 1);
151 blob_append(&zCmd, " test-http", 10);
152
+11 -4
--- src/main.c
+++ src/main.c
@@ -292,16 +292,23 @@
292292
int bAvoidDeltaManifests; /* Avoid using delta manifests if true */
293293
294294
/* State for communicating specific details between the inbound HTTP
295295
** header parser (cgi.c), xfer.c, and http.c. */
296296
struct {
297
- char *zLoginCard; /* Inbound X-Fossil-Xfer-Login request header */
298
- int bLoginCardHeader; /* If true, emit login cards in outbound
297
+ char *zLoginCard; /* Inbound X-Fossil-Xfer-Login request header
298
+ ** or x-f-x-l URL parameter. */
299
+ int bLoginCardHeader; /* If non-0, emit login cards in outbound
299300
** requests as HTTP headers instead of as
300301
** part of the payload. Gets activated
301302
** on-demand based on xfer traffic
302
- ** contents. */
303
+ ** contents. Values, for
304
+ ** diagnostic/debuggin purposes: 1=set via
305
+ ** CLI --flag. 2=set via inbound HTTP
306
+ ** header. 3=set via query string
307
+ ** arg. 4=set via http_build_header(). */
308
+ int remoteVersion; /* Remote fossil version. Used for negotiating
309
+ ** how to handle the login card. */
303310
} syncInfo;
304311
#ifdef FOSSIL_ENABLE_JSON
305312
struct FossilJsonBits {
306313
int isJsonMode; /* True if running in JSON mode, else
307314
false. This changes how errors are
@@ -1506,11 +1513,11 @@
15061513
/* In order for ?skin=... to work when visiting the site from
15071514
** a typical external link, we have to process it here, as
15081515
** that parameter gets lost during the redirect. We "could"
15091516
** pass the whole query string along instead, but that seems
15101517
** unnecessary. */
1511
- if(cgi_setup_query_string()>1){
1518
+ if(cgi_setup_query_string() & 0x02){
15121519
cookie_render();
15131520
}
15141521
cgi_redirectf("%R%s", db_get("index-page", "/index"));
15151522
}
15161523
15171524
--- src/main.c
+++ src/main.c
@@ -292,16 +292,23 @@
292 int bAvoidDeltaManifests; /* Avoid using delta manifests if true */
293
294 /* State for communicating specific details between the inbound HTTP
295 ** header parser (cgi.c), xfer.c, and http.c. */
296 struct {
297 char *zLoginCard; /* Inbound X-Fossil-Xfer-Login request header */
298 int bLoginCardHeader; /* If true, emit login cards in outbound
 
299 ** requests as HTTP headers instead of as
300 ** part of the payload. Gets activated
301 ** on-demand based on xfer traffic
302 ** contents. */
 
 
 
 
 
 
303 } syncInfo;
304 #ifdef FOSSIL_ENABLE_JSON
305 struct FossilJsonBits {
306 int isJsonMode; /* True if running in JSON mode, else
307 false. This changes how errors are
@@ -1506,11 +1513,11 @@
1506 /* In order for ?skin=... to work when visiting the site from
1507 ** a typical external link, we have to process it here, as
1508 ** that parameter gets lost during the redirect. We "could"
1509 ** pass the whole query string along instead, but that seems
1510 ** unnecessary. */
1511 if(cgi_setup_query_string()>1){
1512 cookie_render();
1513 }
1514 cgi_redirectf("%R%s", db_get("index-page", "/index"));
1515 }
1516
1517
--- src/main.c
+++ src/main.c
@@ -292,16 +292,23 @@
292 int bAvoidDeltaManifests; /* Avoid using delta manifests if true */
293
294 /* State for communicating specific details between the inbound HTTP
295 ** header parser (cgi.c), xfer.c, and http.c. */
296 struct {
297 char *zLoginCard; /* Inbound X-Fossil-Xfer-Login request header
298 ** or x-f-x-l URL parameter. */
299 int bLoginCardHeader; /* If non-0, emit login cards in outbound
300 ** requests as HTTP headers instead of as
301 ** part of the payload. Gets activated
302 ** on-demand based on xfer traffic
303 ** contents. Values, for
304 ** diagnostic/debuggin purposes: 1=set via
305 ** CLI --flag. 2=set via inbound HTTP
306 ** header. 3=set via query string
307 ** arg. 4=set via http_build_header(). */
308 int remoteVersion; /* Remote fossil version. Used for negotiating
309 ** how to handle the login card. */
310 } syncInfo;
311 #ifdef FOSSIL_ENABLE_JSON
312 struct FossilJsonBits {
313 int isJsonMode; /* True if running in JSON mode, else
314 false. This changes how errors are
@@ -1506,11 +1513,11 @@
1513 /* In order for ?skin=... to work when visiting the site from
1514 ** a typical external link, we have to process it here, as
1515 ** that parameter gets lost during the redirect. We "could"
1516 ** pass the whole query string along instead, but that seems
1517 ** unnecessary. */
1518 if(cgi_setup_query_string() & 0x02){
1519 cookie_render();
1520 }
1521 cgi_redirectf("%R%s", db_get("index-page", "/index"));
1522 }
1523
1524
+2 -2
--- src/url.c
+++ src/url.c
@@ -227,17 +227,17 @@
227227
}else{
228228
pUrlData->port = pUrlData->dfltPort;
229229
pUrlData->hostname = pUrlData->name;
230230
}
231231
dehttpize(pUrlData->name);
232
- pUrlData->path = mprintf("%s", &zUrl[i]);
232
+ pUrlData->path = fossil_strdup(&zUrl[i]);
233233
for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
234234
if( pUrlData->path[i] ){
235235
pUrlData->path[i] = 0;
236236
i++;
237237
}
238
- zExe = mprintf("");
238
+ zExe = fossil_strdup("");
239239
while( pUrlData->path[i]!=0 ){
240240
char *zName, *zValue;
241241
zName = &pUrlData->path[i];
242242
zValue = zName;
243243
while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
244244
--- src/url.c
+++ src/url.c
@@ -227,17 +227,17 @@
227 }else{
228 pUrlData->port = pUrlData->dfltPort;
229 pUrlData->hostname = pUrlData->name;
230 }
231 dehttpize(pUrlData->name);
232 pUrlData->path = mprintf("%s", &zUrl[i]);
233 for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
234 if( pUrlData->path[i] ){
235 pUrlData->path[i] = 0;
236 i++;
237 }
238 zExe = mprintf("");
239 while( pUrlData->path[i]!=0 ){
240 char *zName, *zValue;
241 zName = &pUrlData->path[i];
242 zValue = zName;
243 while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
244
--- src/url.c
+++ src/url.c
@@ -227,17 +227,17 @@
227 }else{
228 pUrlData->port = pUrlData->dfltPort;
229 pUrlData->hostname = pUrlData->name;
230 }
231 dehttpize(pUrlData->name);
232 pUrlData->path = fossil_strdup(&zUrl[i]);
233 for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
234 if( pUrlData->path[i] ){
235 pUrlData->path[i] = 0;
236 i++;
237 }
238 zExe = fossil_strdup("");
239 while( pUrlData->path[i]!=0 ){
240 char *zName, *zValue;
241 zName = &pUrlData->path[i];
242 zValue = zName;
243 while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
244
+4 -2
--- src/xfer.c
+++ src/xfer.c
@@ -1725,11 +1725,12 @@
17251725
** The client announces to the server what version of Fossil it
17261726
** is running. The DATE and TIME are a pure numeric ISO8601 time
17271727
** for the specific check-in of the client.
17281728
*/
17291729
if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
1730
- xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
1730
+ xfer.remoteVersion = g.syncInfo.remoteVersion =
1731
+ atoi(blob_str(&xfer.aToken[2]));
17311732
g.syncInfo.bLoginCardHeader =
17321733
xfer.remoteVersion>=RELEASE_VERSION_NUMBER;
17331734
if( xfer.nToken>=5 ){
17341735
xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
17351736
xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
@@ -2786,11 +2787,12 @@
27862787
** The server announces to the server what version of Fossil it
27872788
** is running. The DATE and TIME are a pure numeric ISO8601 time
27882789
** for the specific check-in of the client.
27892790
*/
27902791
if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){
2791
- xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
2792
+ xfer.remoteVersion = g.syncInfo.remoteVersion =
2793
+ atoi(blob_str(&xfer.aToken[2]));
27922794
g.syncInfo.bLoginCardHeader =
27932795
xfer.remoteVersion>=RELEASE_VERSION_NUMBER;
27942796
if( xfer.nToken>=5 ){
27952797
xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
27962798
xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
27972799
--- src/xfer.c
+++ src/xfer.c
@@ -1725,11 +1725,12 @@
1725 ** The client announces to the server what version of Fossil it
1726 ** is running. The DATE and TIME are a pure numeric ISO8601 time
1727 ** for the specific check-in of the client.
1728 */
1729 if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
1730 xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
 
1731 g.syncInfo.bLoginCardHeader =
1732 xfer.remoteVersion>=RELEASE_VERSION_NUMBER;
1733 if( xfer.nToken>=5 ){
1734 xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
1735 xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
@@ -2786,11 +2787,12 @@
2786 ** The server announces to the server what version of Fossil it
2787 ** is running. The DATE and TIME are a pure numeric ISO8601 time
2788 ** for the specific check-in of the client.
2789 */
2790 if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){
2791 xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
 
2792 g.syncInfo.bLoginCardHeader =
2793 xfer.remoteVersion>=RELEASE_VERSION_NUMBER;
2794 if( xfer.nToken>=5 ){
2795 xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
2796 xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
2797
--- src/xfer.c
+++ src/xfer.c
@@ -1725,11 +1725,12 @@
1725 ** The client announces to the server what version of Fossil it
1726 ** is running. The DATE and TIME are a pure numeric ISO8601 time
1727 ** for the specific check-in of the client.
1728 */
1729 if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
1730 xfer.remoteVersion = g.syncInfo.remoteVersion =
1731 atoi(blob_str(&xfer.aToken[2]));
1732 g.syncInfo.bLoginCardHeader =
1733 xfer.remoteVersion>=RELEASE_VERSION_NUMBER;
1734 if( xfer.nToken>=5 ){
1735 xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
1736 xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
@@ -2786,11 +2787,12 @@
2787 ** The server announces to the server what version of Fossil it
2788 ** is running. The DATE and TIME are a pure numeric ISO8601 time
2789 ** for the specific check-in of the client.
2790 */
2791 if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){
2792 xfer.remoteVersion = g.syncInfo.remoteVersion =
2793 atoi(blob_str(&xfer.aToken[2]));
2794 g.syncInfo.bLoginCardHeader =
2795 xfer.remoteVersion>=RELEASE_VERSION_NUMBER;
2796 if( xfer.nToken>=5 ){
2797 xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
2798 xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
2799

Keyboard Shortcuts

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