Fossil SCM

Add the test-httpmsg command.

drh 2019-07-23 16:10 trunk
Commit 1ad56ceeaf6be17121253ead85ac7e0eff97dc2b8e6c4fb8ba0bbbd7299c4580
3 files changed +126 -28 +5 -5 +8 -2
+126 -28
--- src/http.c
+++ src/http.c
@@ -29,10 +29,21 @@
2929
#ifndef fileno
3030
#define fileno(s) _fileno(s)
3131
#endif
3232
#endif
3333
34
+
35
+#if INTERFACE
36
+/*
37
+** Bits of the mHttpFlags parameter to http_exchange()
38
+*/
39
+#define HTTP_USE_LOGIN 0x00001 /* Add a login card to the sync message */
40
+#define HTTP_GENERIC 0x00002 /* Generic HTTP request */
41
+#define HTTP_VERBOSE 0x00004 /* HTTP status messages */
42
+#define HTTP_QUIET 0x00008 /* No surplus output */
43
+#endif
44
+
3445
/* Maximum number of HTTP Authorization attempts */
3546
#define MAX_HTTP_AUTH 2
3647
3748
/* Keep track of HTTP Basic Authorization failures */
3849
static int fSeenHttpAuth = 0;
@@ -97,22 +108,22 @@
97108
/*
98109
** Construct an appropriate HTTP request header. Write the header
99110
** into pHdr. This routine initializes the pHdr blob. pPayload is
100111
** the complete payload (including the login card) already compressed.
101112
*/
102
-static void http_build_header(Blob *pPayload, Blob *pHdr){
113
+static void http_build_header(
114
+ Blob *pPayload, /* the payload that will be sent */
115
+ Blob *pHdr, /* construct the header here */
116
+ const char *zAltMimetype /* Alternative mimetype */
117
+){
103118
int i;
104
- const char *zSep;
119
+ int nPayload = pPayload ? blob_size(pPayload) : 0;
105120
106121
blob_zero(pHdr);
107122
i = strlen(g.url.path);
108
- if( i>0 && g.url.path[i-1]=='/' ){
109
- zSep = "";
110
- }else{
111
- zSep = "/";
112
- }
113
- blob_appendf(pHdr, "POST %s%s HTTP/1.1\r\n", g.url.path, zSep);
123
+ blob_appendf(pHdr, "%s %s HTTP/1.0\r\n",
124
+ nPayload>0 ? "POST" : "GET", g.url.path);
114125
if( g.url.proxyAuth ){
115126
blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
116127
}
117128
if( g.zHttpAuth && g.zHttpAuth[0] ){
118129
const char *zCredentials = g.zHttpAuth;
@@ -121,16 +132,21 @@
121132
fossil_free(zEncoded);
122133
}
123134
blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
124135
blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
125136
if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
126
- if( g.fHttpTrace ){
127
- blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
128
- }else{
129
- blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
137
+ if( nPayload ){
138
+ if( zAltMimetype ){
139
+ blob_appendf(pHdr, "Content-Type: %s\r\n", zAltMimetype);
140
+ }else if( g.fHttpTrace ){
141
+ blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
142
+ }else{
143
+ blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
144
+ }
145
+ blob_appendf(pHdr, "Content-Length: %d\r\n", blob_size(pPayload));
130146
}
131
- blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
147
+ blob_append(pHdr, "\r\n", 2);
132148
}
133149
134150
/*
135151
** Use Fossil credentials for HTTP Basic Authorization prompt
136152
*/
@@ -200,11 +216,17 @@
200216
**
201217
** The server address is contain in the "g" global structure. The
202218
** url_parse() routine should have been called prior to this routine
203219
** in order to fill this structure appropriately.
204220
*/
205
-int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
221
+int http_exchange(
222
+ Blob *pSend, /* Message to be sent */
223
+ Blob *pReply, /* Write the reply here */
224
+ int mHttpFlags, /* Flags. See above */
225
+ int maxRedirect, /* Max number of redirects */
226
+ const char *zAltMimetype /* Alternative mimetype if not NULL */
227
+){
206228
Blob login; /* The login card */
207229
Blob payload; /* The complete payload including login card */
208230
Blob hdr; /* The HTTP request header */
209231
int closeConnection; /* True to close the connection when done */
210232
int iLength; /* Expected length of the reply payload */
@@ -220,22 +242,26 @@
220242
fossil_warning("%s", transport_errmsg(&g.url));
221243
return 1;
222244
}
223245
224246
/* Construct the login card and prepare the complete payload */
225
- blob_zero(&login);
226
- if( useLogin ) http_build_login_card(pSend, &login);
227
- if( g.fHttpTrace ){
228
- payload = login;
229
- blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
247
+ if( blob_size(pSend)==0 ){
248
+ blob_zero(&payload);
230249
}else{
231
- blob_compress2(&login, pSend, &payload);
232
- blob_reset(&login);
250
+ blob_zero(&login);
251
+ if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
252
+ if( g.fHttpTrace ){
253
+ payload = login;
254
+ blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
255
+ }else{
256
+ blob_compress2(&login, pSend, &payload);
257
+ blob_reset(&login);
258
+ }
233259
}
234260
235261
/* Construct the HTTP request header */
236
- http_build_header(&payload, &hdr);
262
+ http_build_header(&payload, &hdr, zAltMimetype);
237263
238264
/* When tracing, write the transmitted HTTP message both to standard
239265
** output and into a file. The file can then be used to drive the
240266
** server-side like this:
241267
**
@@ -261,10 +287,15 @@
261287
}
262288
263289
/*
264290
** Send the request to the server.
265291
*/
292
+ if( mHttpFlags & HTTP_VERBOSE ){
293
+ fossil_print("URL: %s\n", g.url.canonical);
294
+ fossil_print("Sending %d byte header and %d byte payload\n",
295
+ blob_size(&hdr), blob_size(&payload));
296
+ }
266297
transport_send(&g.url, &hdr);
267298
transport_send(&g.url, &payload);
268299
blob_reset(&hdr);
269300
blob_reset(&payload);
270301
transport_flip(&g.url);
@@ -273,21 +304,24 @@
273304
** Read and interpret the server reply
274305
*/
275306
closeConnection = 1;
276307
iLength = -1;
277308
while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
278
- /* printf("[%s]\n", zLine); fflush(stdout); */
309
+ if( mHttpFlags & HTTP_VERBOSE ){
310
+ fossil_print("Read: [%s]\n", zLine);
311
+ }
279312
if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
280313
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
281314
if( rc==401 ){
282315
if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
283316
if( g.zHttpAuth ){
284317
if( g.zHttpAuth ) free(g.zHttpAuth);
285318
}
286319
g.zHttpAuth = prompt_for_httpauth_creds();
287320
transport_close(&g.url);
288
- return http_exchange(pSend, pReply, useLogin, maxRedirect);
321
+ return http_exchange(pSend, pReply, mHttpFlags,
322
+ maxRedirect, zAltMimetype);
289323
}
290324
}
291325
if( rc!=200 && rc!=301 && rc!=302 && rc!=307 && rc!=308 ){
292326
int ii;
293327
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
@@ -338,27 +372,34 @@
338372
j = strlen(zLine) - 1;
339373
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
340374
j -= 4;
341375
zLine[j] = 0;
342376
}
343
- fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
377
+ if( (mHttpFlags & HTTP_QUIET)==0 ){
378
+ fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
379
+ }
344380
url_parse(&zLine[i], 0);
345381
transport_close(&g.url);
346382
transport_global_shutdown(&g.url);
347383
fSeenHttpAuth = 0;
348384
if( g.zHttpAuth ) free(g.zHttpAuth);
349385
g.zHttpAuth = get_httpauth();
350386
if( rc==301 || rc==308 ) url_remember();
351
- return http_exchange(pSend, pReply, useLogin, maxRedirect);
387
+ return http_exchange(pSend, pReply, mHttpFlags,
388
+ maxRedirect, zAltMimetype);
352389
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
353390
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
354391
isCompressed = 0;
355392
}else if( fossil_strnicmp(&zLine[14],
356393
"application/x-fossil-uncompressed", -1)==0 ){
357394
isCompressed = 0;
358
- }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
359
- isError = 1;
395
+ }else{
396
+ if( (mHttpFlags & HTTP_GENERIC)==0
397
+ && fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0
398
+ ){
399
+ isError = 1;
400
+ }
360401
}
361402
}
362403
}
363404
if( iLength<0 ){
364405
fossil_warning("server did not reply");
@@ -419,5 +460,62 @@
419460
*/
420461
write_err:
421462
transport_close(&g.url);
422463
return 1;
423464
}
465
+
466
+/*
467
+** COMMAND: test-httpmsg
468
+**
469
+** Usage: %fossil test-httpmsg URL ?PAYLOAD? ?OPTIONS?
470
+**
471
+** Send an HTTP message to URL and get the reply. PAYLOAD is a file containing
472
+** the payload, or "-" to read payload from standard input. a POST message
473
+** is sent if PAYLOAD is specified and is non-empty. If PAYLOAD is omitted
474
+** or is an empty file, then a GET message is sent.
475
+**
476
+** Options:
477
+**
478
+** --mimetype TYPE Mimetype of the payload
479
+** --out FILE Store the reply in FILE
480
+** -v Verbose output
481
+*/
482
+void test_wget_command(void){
483
+ const char *zMimetype;
484
+ const char *zInFile;
485
+ const char *zOutFile;
486
+ Blob in, out;
487
+ unsigned int mHttpFlags = HTTP_GENERIC;
488
+
489
+ zMimetype = find_option("mimetype",0,1);
490
+ zOutFile = find_option("out","o",1);
491
+ if( find_option("verbose","v",0)!=0 ) mHttpFlags |= HTTP_VERBOSE;
492
+ if( g.argc!=3 && g.argc!=4 ){
493
+ usage("URL ?PAYLOAD?");
494
+ }
495
+ zInFile = g.argc==4 ? g.argv[3] : 0;
496
+ url_parse(g.argv[2], 0);
497
+ if( g.url.protocol[0]!='h' ){
498
+ fossil_fatal("the %s command supports only http: and https:", g.argv[1]);
499
+ }
500
+ if( zInFile ){
501
+ blob_read_from_file(&in, zInFile, ExtFILE);
502
+ if( zMimetype==0 ){
503
+ if( fossil_strcmp(zInFile,"-")==0 ){
504
+ zMimetype = "application/x-unknown";
505
+ }else{
506
+ zMimetype = mimetype_from_name(zInFile);
507
+ }
508
+ }
509
+ }else{
510
+ blob_init(&in, 0, 0);
511
+ }
512
+ blob_init(&out, 0, 0);
513
+ if( (mHttpFlags & HTTP_VERBOSE)==0 && zOutFile==0 ){
514
+ zOutFile = "-";
515
+ mHttpFlags |= HTTP_QUIET;
516
+ }
517
+ http_exchange(&in, &out, mHttpFlags, 4, zMimetype);
518
+ if( zOutFile ) blob_write_to_file(&out, zOutFile);
519
+ blob_zero(&in);
520
+ blob_zero(&out);
521
+}
424522
--- src/http.c
+++ src/http.c
@@ -29,10 +29,21 @@
29 #ifndef fileno
30 #define fileno(s) _fileno(s)
31 #endif
32 #endif
33
 
 
 
 
 
 
 
 
 
 
 
34 /* Maximum number of HTTP Authorization attempts */
35 #define MAX_HTTP_AUTH 2
36
37 /* Keep track of HTTP Basic Authorization failures */
38 static int fSeenHttpAuth = 0;
@@ -97,22 +108,22 @@
97 /*
98 ** Construct an appropriate HTTP request header. Write the header
99 ** into pHdr. This routine initializes the pHdr blob. pPayload is
100 ** the complete payload (including the login card) already compressed.
101 */
102 static void http_build_header(Blob *pPayload, Blob *pHdr){
 
 
 
 
103 int i;
104 const char *zSep;
105
106 blob_zero(pHdr);
107 i = strlen(g.url.path);
108 if( i>0 && g.url.path[i-1]=='/' ){
109 zSep = "";
110 }else{
111 zSep = "/";
112 }
113 blob_appendf(pHdr, "POST %s%s HTTP/1.1\r\n", g.url.path, zSep);
114 if( g.url.proxyAuth ){
115 blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
116 }
117 if( g.zHttpAuth && g.zHttpAuth[0] ){
118 const char *zCredentials = g.zHttpAuth;
@@ -121,16 +132,21 @@
121 fossil_free(zEncoded);
122 }
123 blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
124 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
125 if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
126 if( g.fHttpTrace ){
127 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
128 }else{
129 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
 
 
 
 
 
130 }
131 blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
132 }
133
134 /*
135 ** Use Fossil credentials for HTTP Basic Authorization prompt
136 */
@@ -200,11 +216,17 @@
200 **
201 ** The server address is contain in the "g" global structure. The
202 ** url_parse() routine should have been called prior to this routine
203 ** in order to fill this structure appropriately.
204 */
205 int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
 
 
 
 
 
 
206 Blob login; /* The login card */
207 Blob payload; /* The complete payload including login card */
208 Blob hdr; /* The HTTP request header */
209 int closeConnection; /* True to close the connection when done */
210 int iLength; /* Expected length of the reply payload */
@@ -220,22 +242,26 @@
220 fossil_warning("%s", transport_errmsg(&g.url));
221 return 1;
222 }
223
224 /* Construct the login card and prepare the complete payload */
225 blob_zero(&login);
226 if( useLogin ) http_build_login_card(pSend, &login);
227 if( g.fHttpTrace ){
228 payload = login;
229 blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
230 }else{
231 blob_compress2(&login, pSend, &payload);
232 blob_reset(&login);
 
 
 
 
 
 
 
233 }
234
235 /* Construct the HTTP request header */
236 http_build_header(&payload, &hdr);
237
238 /* When tracing, write the transmitted HTTP message both to standard
239 ** output and into a file. The file can then be used to drive the
240 ** server-side like this:
241 **
@@ -261,10 +287,15 @@
261 }
262
263 /*
264 ** Send the request to the server.
265 */
 
 
 
 
 
266 transport_send(&g.url, &hdr);
267 transport_send(&g.url, &payload);
268 blob_reset(&hdr);
269 blob_reset(&payload);
270 transport_flip(&g.url);
@@ -273,21 +304,24 @@
273 ** Read and interpret the server reply
274 */
275 closeConnection = 1;
276 iLength = -1;
277 while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
278 /* printf("[%s]\n", zLine); fflush(stdout); */
 
 
279 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
280 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
281 if( rc==401 ){
282 if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
283 if( g.zHttpAuth ){
284 if( g.zHttpAuth ) free(g.zHttpAuth);
285 }
286 g.zHttpAuth = prompt_for_httpauth_creds();
287 transport_close(&g.url);
288 return http_exchange(pSend, pReply, useLogin, maxRedirect);
 
289 }
290 }
291 if( rc!=200 && rc!=301 && rc!=302 && rc!=307 && rc!=308 ){
292 int ii;
293 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
@@ -338,27 +372,34 @@
338 j = strlen(zLine) - 1;
339 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
340 j -= 4;
341 zLine[j] = 0;
342 }
343 fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
 
 
344 url_parse(&zLine[i], 0);
345 transport_close(&g.url);
346 transport_global_shutdown(&g.url);
347 fSeenHttpAuth = 0;
348 if( g.zHttpAuth ) free(g.zHttpAuth);
349 g.zHttpAuth = get_httpauth();
350 if( rc==301 || rc==308 ) url_remember();
351 return http_exchange(pSend, pReply, useLogin, maxRedirect);
 
352 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
353 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
354 isCompressed = 0;
355 }else if( fossil_strnicmp(&zLine[14],
356 "application/x-fossil-uncompressed", -1)==0 ){
357 isCompressed = 0;
358 }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
359 isError = 1;
 
 
 
 
360 }
361 }
362 }
363 if( iLength<0 ){
364 fossil_warning("server did not reply");
@@ -419,5 +460,62 @@
419 */
420 write_err:
421 transport_close(&g.url);
422 return 1;
423 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
--- src/http.c
+++ src/http.c
@@ -29,10 +29,21 @@
29 #ifndef fileno
30 #define fileno(s) _fileno(s)
31 #endif
32 #endif
33
34
35 #if INTERFACE
36 /*
37 ** Bits of the mHttpFlags parameter to http_exchange()
38 */
39 #define HTTP_USE_LOGIN 0x00001 /* Add a login card to the sync message */
40 #define HTTP_GENERIC 0x00002 /* Generic HTTP request */
41 #define HTTP_VERBOSE 0x00004 /* HTTP status messages */
42 #define HTTP_QUIET 0x00008 /* No surplus output */
43 #endif
44
45 /* Maximum number of HTTP Authorization attempts */
46 #define MAX_HTTP_AUTH 2
47
48 /* Keep track of HTTP Basic Authorization failures */
49 static int fSeenHttpAuth = 0;
@@ -97,22 +108,22 @@
108 /*
109 ** Construct an appropriate HTTP request header. Write the header
110 ** into pHdr. This routine initializes the pHdr blob. pPayload is
111 ** the complete payload (including the login card) already compressed.
112 */
113 static void http_build_header(
114 Blob *pPayload, /* the payload that will be sent */
115 Blob *pHdr, /* construct the header here */
116 const char *zAltMimetype /* Alternative mimetype */
117 ){
118 int i;
119 int nPayload = pPayload ? blob_size(pPayload) : 0;
120
121 blob_zero(pHdr);
122 i = strlen(g.url.path);
123 blob_appendf(pHdr, "%s %s HTTP/1.0\r\n",
124 nPayload>0 ? "POST" : "GET", g.url.path);
 
 
 
 
125 if( g.url.proxyAuth ){
126 blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
127 }
128 if( g.zHttpAuth && g.zHttpAuth[0] ){
129 const char *zCredentials = g.zHttpAuth;
@@ -121,16 +132,21 @@
132 fossil_free(zEncoded);
133 }
134 blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
135 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
136 if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
137 if( nPayload ){
138 if( zAltMimetype ){
139 blob_appendf(pHdr, "Content-Type: %s\r\n", zAltMimetype);
140 }else if( g.fHttpTrace ){
141 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
142 }else{
143 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
144 }
145 blob_appendf(pHdr, "Content-Length: %d\r\n", blob_size(pPayload));
146 }
147 blob_append(pHdr, "\r\n", 2);
148 }
149
150 /*
151 ** Use Fossil credentials for HTTP Basic Authorization prompt
152 */
@@ -200,11 +216,17 @@
216 **
217 ** The server address is contain in the "g" global structure. The
218 ** url_parse() routine should have been called prior to this routine
219 ** in order to fill this structure appropriately.
220 */
221 int http_exchange(
222 Blob *pSend, /* Message to be sent */
223 Blob *pReply, /* Write the reply here */
224 int mHttpFlags, /* Flags. See above */
225 int maxRedirect, /* Max number of redirects */
226 const char *zAltMimetype /* Alternative mimetype if not NULL */
227 ){
228 Blob login; /* The login card */
229 Blob payload; /* The complete payload including login card */
230 Blob hdr; /* The HTTP request header */
231 int closeConnection; /* True to close the connection when done */
232 int iLength; /* Expected length of the reply payload */
@@ -220,22 +242,26 @@
242 fossil_warning("%s", transport_errmsg(&g.url));
243 return 1;
244 }
245
246 /* Construct the login card and prepare the complete payload */
247 if( blob_size(pSend)==0 ){
248 blob_zero(&payload);
 
 
 
249 }else{
250 blob_zero(&login);
251 if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
252 if( g.fHttpTrace ){
253 payload = login;
254 blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
255 }else{
256 blob_compress2(&login, pSend, &payload);
257 blob_reset(&login);
258 }
259 }
260
261 /* Construct the HTTP request header */
262 http_build_header(&payload, &hdr, zAltMimetype);
263
264 /* When tracing, write the transmitted HTTP message both to standard
265 ** output and into a file. The file can then be used to drive the
266 ** server-side like this:
267 **
@@ -261,10 +287,15 @@
287 }
288
289 /*
290 ** Send the request to the server.
291 */
292 if( mHttpFlags & HTTP_VERBOSE ){
293 fossil_print("URL: %s\n", g.url.canonical);
294 fossil_print("Sending %d byte header and %d byte payload\n",
295 blob_size(&hdr), blob_size(&payload));
296 }
297 transport_send(&g.url, &hdr);
298 transport_send(&g.url, &payload);
299 blob_reset(&hdr);
300 blob_reset(&payload);
301 transport_flip(&g.url);
@@ -273,21 +304,24 @@
304 ** Read and interpret the server reply
305 */
306 closeConnection = 1;
307 iLength = -1;
308 while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
309 if( mHttpFlags & HTTP_VERBOSE ){
310 fossil_print("Read: [%s]\n", zLine);
311 }
312 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
313 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
314 if( rc==401 ){
315 if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
316 if( g.zHttpAuth ){
317 if( g.zHttpAuth ) free(g.zHttpAuth);
318 }
319 g.zHttpAuth = prompt_for_httpauth_creds();
320 transport_close(&g.url);
321 return http_exchange(pSend, pReply, mHttpFlags,
322 maxRedirect, zAltMimetype);
323 }
324 }
325 if( rc!=200 && rc!=301 && rc!=302 && rc!=307 && rc!=308 ){
326 int ii;
327 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
@@ -338,27 +372,34 @@
372 j = strlen(zLine) - 1;
373 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
374 j -= 4;
375 zLine[j] = 0;
376 }
377 if( (mHttpFlags & HTTP_QUIET)==0 ){
378 fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
379 }
380 url_parse(&zLine[i], 0);
381 transport_close(&g.url);
382 transport_global_shutdown(&g.url);
383 fSeenHttpAuth = 0;
384 if( g.zHttpAuth ) free(g.zHttpAuth);
385 g.zHttpAuth = get_httpauth();
386 if( rc==301 || rc==308 ) url_remember();
387 return http_exchange(pSend, pReply, mHttpFlags,
388 maxRedirect, zAltMimetype);
389 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
390 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
391 isCompressed = 0;
392 }else if( fossil_strnicmp(&zLine[14],
393 "application/x-fossil-uncompressed", -1)==0 ){
394 isCompressed = 0;
395 }else{
396 if( (mHttpFlags & HTTP_GENERIC)==0
397 && fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0
398 ){
399 isError = 1;
400 }
401 }
402 }
403 }
404 if( iLength<0 ){
405 fossil_warning("server did not reply");
@@ -419,5 +460,62 @@
460 */
461 write_err:
462 transport_close(&g.url);
463 return 1;
464 }
465
466 /*
467 ** COMMAND: test-httpmsg
468 **
469 ** Usage: %fossil test-httpmsg URL ?PAYLOAD? ?OPTIONS?
470 **
471 ** Send an HTTP message to URL and get the reply. PAYLOAD is a file containing
472 ** the payload, or "-" to read payload from standard input. a POST message
473 ** is sent if PAYLOAD is specified and is non-empty. If PAYLOAD is omitted
474 ** or is an empty file, then a GET message is sent.
475 **
476 ** Options:
477 **
478 ** --mimetype TYPE Mimetype of the payload
479 ** --out FILE Store the reply in FILE
480 ** -v Verbose output
481 */
482 void test_wget_command(void){
483 const char *zMimetype;
484 const char *zInFile;
485 const char *zOutFile;
486 Blob in, out;
487 unsigned int mHttpFlags = HTTP_GENERIC;
488
489 zMimetype = find_option("mimetype",0,1);
490 zOutFile = find_option("out","o",1);
491 if( find_option("verbose","v",0)!=0 ) mHttpFlags |= HTTP_VERBOSE;
492 if( g.argc!=3 && g.argc!=4 ){
493 usage("URL ?PAYLOAD?");
494 }
495 zInFile = g.argc==4 ? g.argv[3] : 0;
496 url_parse(g.argv[2], 0);
497 if( g.url.protocol[0]!='h' ){
498 fossil_fatal("the %s command supports only http: and https:", g.argv[1]);
499 }
500 if( zInFile ){
501 blob_read_from_file(&in, zInFile, ExtFILE);
502 if( zMimetype==0 ){
503 if( fossil_strcmp(zInFile,"-")==0 ){
504 zMimetype = "application/x-unknown";
505 }else{
506 zMimetype = mimetype_from_name(zInFile);
507 }
508 }
509 }else{
510 blob_init(&in, 0, 0);
511 }
512 blob_init(&out, 0, 0);
513 if( (mHttpFlags & HTTP_VERBOSE)==0 && zOutFile==0 ){
514 zOutFile = "-";
515 mHttpFlags |= HTTP_QUIET;
516 }
517 http_exchange(&in, &out, mHttpFlags, 4, zMimetype);
518 if( zOutFile ) blob_write_to_file(&out, zOutFile);
519 blob_zero(&in);
520 blob_zero(&out);
521 }
522
--- src/http_transport.c
+++ src/http_transport.c
@@ -165,17 +165,17 @@
165165
if( transport.isOpen==0 ){
166166
if( pUrlData->isSsh ){
167167
rc = transport_ssh_open(pUrlData);
168168
if( rc==0 ) transport.isOpen = 1;
169169
}else if( pUrlData->isHttps ){
170
- #ifdef FOSSIL_ENABLE_SSL
170
+#ifdef FOSSIL_ENABLE_SSL
171171
rc = ssl_open(pUrlData);
172172
if( rc==0 ) transport.isOpen = 1;
173
- #else
173
+#else
174174
socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
175175
rc = 1;
176
- #endif
176
+#endif
177177
}else if( pUrlData->isFile ){
178178
sqlite3_uint64 iRandId;
179179
sqlite3_randomness(sizeof(iRandId), &iRandId);
180180
transport.zOutFile = mprintf("%s-%llu-out.http",
181181
g.zRepositoryName, iRandId);
@@ -239,19 +239,19 @@
239239
transport.nSent += n;
240240
if( pUrlData->isSsh ){
241241
fwrite(z, 1, n, sshOut);
242242
fflush(sshOut);
243243
}else if( pUrlData->isHttps ){
244
- #ifdef FOSSIL_ENABLE_SSL
244
+#ifdef FOSSIL_ENABLE_SSL
245245
int sent;
246246
while( n>0 ){
247247
sent = ssl_send(0, z, n);
248248
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
249249
if( sent<=0 ) break;
250250
n -= sent;
251251
}
252
- #endif
252
+#endif
253253
}else if( pUrlData->isFile ){
254254
fwrite(z, 1, n, transport.pFile);
255255
}else{
256256
int sent;
257257
while( n>0 ){
258258
--- src/http_transport.c
+++ src/http_transport.c
@@ -165,17 +165,17 @@
165 if( transport.isOpen==0 ){
166 if( pUrlData->isSsh ){
167 rc = transport_ssh_open(pUrlData);
168 if( rc==0 ) transport.isOpen = 1;
169 }else if( pUrlData->isHttps ){
170 #ifdef FOSSIL_ENABLE_SSL
171 rc = ssl_open(pUrlData);
172 if( rc==0 ) transport.isOpen = 1;
173 #else
174 socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
175 rc = 1;
176 #endif
177 }else if( pUrlData->isFile ){
178 sqlite3_uint64 iRandId;
179 sqlite3_randomness(sizeof(iRandId), &iRandId);
180 transport.zOutFile = mprintf("%s-%llu-out.http",
181 g.zRepositoryName, iRandId);
@@ -239,19 +239,19 @@
239 transport.nSent += n;
240 if( pUrlData->isSsh ){
241 fwrite(z, 1, n, sshOut);
242 fflush(sshOut);
243 }else if( pUrlData->isHttps ){
244 #ifdef FOSSIL_ENABLE_SSL
245 int sent;
246 while( n>0 ){
247 sent = ssl_send(0, z, n);
248 /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
249 if( sent<=0 ) break;
250 n -= sent;
251 }
252 #endif
253 }else if( pUrlData->isFile ){
254 fwrite(z, 1, n, transport.pFile);
255 }else{
256 int sent;
257 while( n>0 ){
258
--- src/http_transport.c
+++ src/http_transport.c
@@ -165,17 +165,17 @@
165 if( transport.isOpen==0 ){
166 if( pUrlData->isSsh ){
167 rc = transport_ssh_open(pUrlData);
168 if( rc==0 ) transport.isOpen = 1;
169 }else if( pUrlData->isHttps ){
170 #ifdef FOSSIL_ENABLE_SSL
171 rc = ssl_open(pUrlData);
172 if( rc==0 ) transport.isOpen = 1;
173 #else
174 socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
175 rc = 1;
176 #endif
177 }else if( pUrlData->isFile ){
178 sqlite3_uint64 iRandId;
179 sqlite3_randomness(sizeof(iRandId), &iRandId);
180 transport.zOutFile = mprintf("%s-%llu-out.http",
181 g.zRepositoryName, iRandId);
@@ -239,19 +239,19 @@
239 transport.nSent += n;
240 if( pUrlData->isSsh ){
241 fwrite(z, 1, n, sshOut);
242 fflush(sshOut);
243 }else if( pUrlData->isHttps ){
244 #ifdef FOSSIL_ENABLE_SSL
245 int sent;
246 while( n>0 ){
247 sent = ssl_send(0, z, n);
248 /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
249 if( sent<=0 ) break;
250 n -= sent;
251 }
252 #endif
253 }else if( pUrlData->isFile ){
254 fwrite(z, 1, n, transport.pFile);
255 }else{
256 int sent;
257 while( n>0 ){
258
+8 -2
--- src/xfer.c
+++ src/xfer.c
@@ -1783,10 +1783,11 @@
17831783
int nUvFileRcvd = 0; /* Number of uvfile cards received on this cycle */
17841784
sqlite3_int64 mtime; /* Modification time on a UV file */
17851785
int autopushFailed = 0; /* Autopush following commit failed if true */
17861786
const char *zCkinLock; /* Name of check-in to lock. NULL for none */
17871787
const char *zClientId; /* A unique identifier for this check-out */
1788
+ unsigned int mHttpFlags;/* Flags for the http_exchange() subsystem */
17881789
17891790
if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
17901791
if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0
17911792
&& configRcvMask==0 && configSendMask==0 ) return 0;
17921793
if( syncFlags & SYNC_FROMPARENT ){
@@ -2020,12 +2021,17 @@
20202021
if( syncFlags & SYNC_VERBOSE ){
20212022
fossil_print("waiting for server...");
20222023
}
20232024
fflush(stdout);
20242025
/* Exchange messages with the server */
2025
- if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
2026
- MAX_REDIRECTS) ){
2026
+ if( (syncFlags & SYNC_CLONE)!=0 && nCycle==0 ){
2027
+ /* Do not send a login card on the first round-trip of a clone */
2028
+ mHttpFlags = 0;
2029
+ }else{
2030
+ mHttpFlags = HTTP_USE_LOGIN;
2031
+ }
2032
+ if( http_exchange(&send, &recv, mHttpFlags, MAX_REDIRECTS, 0) ){
20272033
nErr++;
20282034
go = 2;
20292035
break;
20302036
}
20312037
20322038
--- src/xfer.c
+++ src/xfer.c
@@ -1783,10 +1783,11 @@
1783 int nUvFileRcvd = 0; /* Number of uvfile cards received on this cycle */
1784 sqlite3_int64 mtime; /* Modification time on a UV file */
1785 int autopushFailed = 0; /* Autopush following commit failed if true */
1786 const char *zCkinLock; /* Name of check-in to lock. NULL for none */
1787 const char *zClientId; /* A unique identifier for this check-out */
 
1788
1789 if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
1790 if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0
1791 && configRcvMask==0 && configSendMask==0 ) return 0;
1792 if( syncFlags & SYNC_FROMPARENT ){
@@ -2020,12 +2021,17 @@
2020 if( syncFlags & SYNC_VERBOSE ){
2021 fossil_print("waiting for server...");
2022 }
2023 fflush(stdout);
2024 /* Exchange messages with the server */
2025 if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
2026 MAX_REDIRECTS) ){
 
 
 
 
 
2027 nErr++;
2028 go = 2;
2029 break;
2030 }
2031
2032
--- src/xfer.c
+++ src/xfer.c
@@ -1783,10 +1783,11 @@
1783 int nUvFileRcvd = 0; /* Number of uvfile cards received on this cycle */
1784 sqlite3_int64 mtime; /* Modification time on a UV file */
1785 int autopushFailed = 0; /* Autopush following commit failed if true */
1786 const char *zCkinLock; /* Name of check-in to lock. NULL for none */
1787 const char *zClientId; /* A unique identifier for this check-out */
1788 unsigned int mHttpFlags;/* Flags for the http_exchange() subsystem */
1789
1790 if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
1791 if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE|SYNC_UNVERSIONED))==0
1792 && configRcvMask==0 && configSendMask==0 ) return 0;
1793 if( syncFlags & SYNC_FROMPARENT ){
@@ -2020,12 +2021,17 @@
2021 if( syncFlags & SYNC_VERBOSE ){
2022 fossil_print("waiting for server...");
2023 }
2024 fflush(stdout);
2025 /* Exchange messages with the server */
2026 if( (syncFlags & SYNC_CLONE)!=0 && nCycle==0 ){
2027 /* Do not send a login card on the first round-trip of a clone */
2028 mHttpFlags = 0;
2029 }else{
2030 mHttpFlags = HTTP_USE_LOGIN;
2031 }
2032 if( http_exchange(&send, &recv, mHttpFlags, MAX_REDIRECTS, 0) ){
2033 nErr++;
2034 go = 2;
2035 break;
2036 }
2037
2038

Keyboard Shortcuts

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