Fossil SCM

When an initial HTTP request fails with error code "400 Bad Request" when using NL-only line endings, retry using CRLF to see if the problem is a web server that does not follow RFC-2616 section 19.3 paragraph 3.

drh 2024-10-13 22:38 omit-cr
Commit 537cc60b5ff070e4a23edeb7de9ed15f7346815a1c7486b1c57c0d6d9da6ee63
1 file changed +36 -12
+36 -12
--- src/http.c
+++ src/http.c
@@ -46,10 +46,19 @@
4646
/* The N value for most recent http-request-N.txt and http-reply-N.txt
4747
** trace files.
4848
*/
4949
static int traceCnt = 0;
5050
51
+/* True to send full CRLF, not just a NL, in the HTTP headers. This is
52
+** to work around issues in some web servers.
53
+*/
54
+#if CRLF_SZ==1
55
+static int sendCRLF = 0;
56
+#else
57
+static int sendCRLF = 1;
58
+#endif
59
+
5160
/*
5261
** Construct the "login" card with the client credentials.
5362
**
5463
** login LOGIN NONCE SIGNATURE
5564
**
@@ -135,38 +144,40 @@
135144
Blob *pPayload, /* the payload that will be sent */
136145
Blob *pHdr, /* construct the header here */
137146
const char *zAltMimetype /* Alternative mimetype */
138147
){
139148
int nPayload = pPayload ? blob_size(pPayload) : 0;
149
+ const char *zCRLF = sendCRLF ? "\r\n" : "\n";
140150
141151
blob_zero(pHdr);
142
- blob_appendf(pHdr, "%s %s%s HTTP/1.0" CRLF,
152
+ blob_appendf(pHdr, "%s %s%s HTTP/1.0%s",
143153
nPayload>0 ? "POST" : "GET", g.url.path,
144
- g.url.path[0]==0 ? "/" : "");
154
+ g.url.path[0]==0 ? "/" : "", zCRLF);
145155
if( g.url.proxyAuth ){
146
- blob_appendf(pHdr, "Proxy-Authorization: %s" CRLF, g.url.proxyAuth);
156
+ blob_appendf(pHdr, "Proxy-Authorization: %s%s", g.url.proxyAuth, zCRLF);
147157
}
148158
if( g.zHttpAuth && g.zHttpAuth[0] ){
149159
const char *zCredentials = g.zHttpAuth;
150160
char *zEncoded = encode64(zCredentials, -1);
151
- blob_appendf(pHdr, "Authorization: Basic %s" CRLF, zEncoded);
161
+ blob_appendf(pHdr, "Authorization: Basic %s%s", zEncoded, zCRLF);
152162
fossil_free(zEncoded);
153163
}
154
- blob_appendf(pHdr, "Host: %s" CRLF, g.url.hostname);
155
- blob_appendf(pHdr, "User-Agent: %s" CRLF, get_user_agent());
156
- if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH" CRLF);
164
+ blob_appendf(pHdr, "Host: %s%s", g.url.hostname, zCRLF);
165
+ blob_appendf(pHdr, "User-Agent: %s%s", get_user_agent(), zCRLF);
166
+ if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH%s", zCRLF);
157167
if( nPayload ){
158168
if( zAltMimetype ){
159
- blob_appendf(pHdr, "Content-Type: %s" CRLF, zAltMimetype);
169
+ blob_appendf(pHdr, "Content-Type: %s", zAltMimetype);
160170
}else if( g.fHttpTrace ){
161
- blob_appendf(pHdr, "Content-Type: application/x-fossil-debug" CRLF);
171
+ blob_appendf(pHdr, "Content-Type: application/x-fossil-debug");
162172
}else{
163
- blob_appendf(pHdr, "Content-Type: application/x-fossil" CRLF);
173
+ blob_appendf(pHdr, "Content-Type: application/x-fossil");
164174
}
165
- blob_appendf(pHdr, "Content-Length: %d" CRLF, blob_size(pPayload));
175
+ blob_appendf(pHdr, "%sContent-Length: %d%s",
176
+ zCRLF, blob_size(pPayload), zCRLF);
166177
}
167
- blob_append(pHdr, CRLF, CRLF_SZ);
178
+ blob_appendf(pHdr, "%s", zCRLF);
168179
}
169180
170181
/*
171182
** Use Fossil credentials for HTTP Basic Authorization prompt
172183
*/
@@ -541,10 +552,16 @@
541552
if( rc!=200 && rc!=301 && rc!=302 && rc!=307 && rc!=308 ){
542553
int ii;
543554
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
544555
while( zLine[ii]==' ' ) ii++;
545556
fossil_warning("server says: %s", &zLine[ii]);
557
+ if( rc==400 && sendCRLF==0 && strstr(zLine,"Bad Request")!=0 ){
558
+ sendCRLF = 1;
559
+ transport_close(&g.url);
560
+ return http_exchange(pSend, pReply, mHttpFlags,
561
+ maxRedirect, zAltMimetype);
562
+ }
546563
goto write_err;
547564
}
548565
if( iHttpVersion==0 ){
549566
closeConnection = 1;
550567
}else{
@@ -626,10 +643,17 @@
626643
if( mHttpFlags & HTTP_NOCOMPRESS ) isCompressed = 0;
627644
}else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
628645
isError = 1;
629646
}
630647
}
648
+ }else if( sendCRLF==1
649
+ && rc==200
650
+ && fossil_strnicmp(zLine, "server: ", 8)==0 ){
651
+ fossil_warning("Server bug work-around: %s requires CRLF line endings "
652
+ "contra RFC-2616 section 19.3 paragraph 3",
653
+ zLine+8);
654
+ sendCRLF = 2;
631655
}
632656
}
633657
if( iHttpVersion<0 ){
634658
/* We got nothing back from the server. If using the ssh: protocol,
635659
** this might mean we need to add or remove the PATH=... argument
636660
--- src/http.c
+++ src/http.c
@@ -46,10 +46,19 @@
46 /* The N value for most recent http-request-N.txt and http-reply-N.txt
47 ** trace files.
48 */
49 static int traceCnt = 0;
50
 
 
 
 
 
 
 
 
 
51 /*
52 ** Construct the "login" card with the client credentials.
53 **
54 ** login LOGIN NONCE SIGNATURE
55 **
@@ -135,38 +144,40 @@
135 Blob *pPayload, /* the payload that will be sent */
136 Blob *pHdr, /* construct the header here */
137 const char *zAltMimetype /* Alternative mimetype */
138 ){
139 int nPayload = pPayload ? blob_size(pPayload) : 0;
 
140
141 blob_zero(pHdr);
142 blob_appendf(pHdr, "%s %s%s HTTP/1.0" CRLF,
143 nPayload>0 ? "POST" : "GET", g.url.path,
144 g.url.path[0]==0 ? "/" : "");
145 if( g.url.proxyAuth ){
146 blob_appendf(pHdr, "Proxy-Authorization: %s" CRLF, g.url.proxyAuth);
147 }
148 if( g.zHttpAuth && g.zHttpAuth[0] ){
149 const char *zCredentials = g.zHttpAuth;
150 char *zEncoded = encode64(zCredentials, -1);
151 blob_appendf(pHdr, "Authorization: Basic %s" CRLF, zEncoded);
152 fossil_free(zEncoded);
153 }
154 blob_appendf(pHdr, "Host: %s" CRLF, g.url.hostname);
155 blob_appendf(pHdr, "User-Agent: %s" CRLF, get_user_agent());
156 if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH" CRLF);
157 if( nPayload ){
158 if( zAltMimetype ){
159 blob_appendf(pHdr, "Content-Type: %s" CRLF, zAltMimetype);
160 }else if( g.fHttpTrace ){
161 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug" CRLF);
162 }else{
163 blob_appendf(pHdr, "Content-Type: application/x-fossil" CRLF);
164 }
165 blob_appendf(pHdr, "Content-Length: %d" CRLF, blob_size(pPayload));
 
166 }
167 blob_append(pHdr, CRLF, CRLF_SZ);
168 }
169
170 /*
171 ** Use Fossil credentials for HTTP Basic Authorization prompt
172 */
@@ -541,10 +552,16 @@
541 if( rc!=200 && rc!=301 && rc!=302 && rc!=307 && rc!=308 ){
542 int ii;
543 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
544 while( zLine[ii]==' ' ) ii++;
545 fossil_warning("server says: %s", &zLine[ii]);
 
 
 
 
 
 
546 goto write_err;
547 }
548 if( iHttpVersion==0 ){
549 closeConnection = 1;
550 }else{
@@ -626,10 +643,17 @@
626 if( mHttpFlags & HTTP_NOCOMPRESS ) isCompressed = 0;
627 }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
628 isError = 1;
629 }
630 }
 
 
 
 
 
 
 
631 }
632 }
633 if( iHttpVersion<0 ){
634 /* We got nothing back from the server. If using the ssh: protocol,
635 ** this might mean we need to add or remove the PATH=... argument
636
--- src/http.c
+++ src/http.c
@@ -46,10 +46,19 @@
46 /* The N value for most recent http-request-N.txt and http-reply-N.txt
47 ** trace files.
48 */
49 static int traceCnt = 0;
50
51 /* True to send full CRLF, not just a NL, in the HTTP headers. This is
52 ** to work around issues in some web servers.
53 */
54 #if CRLF_SZ==1
55 static int sendCRLF = 0;
56 #else
57 static int sendCRLF = 1;
58 #endif
59
60 /*
61 ** Construct the "login" card with the client credentials.
62 **
63 ** login LOGIN NONCE SIGNATURE
64 **
@@ -135,38 +144,40 @@
144 Blob *pPayload, /* the payload that will be sent */
145 Blob *pHdr, /* construct the header here */
146 const char *zAltMimetype /* Alternative mimetype */
147 ){
148 int nPayload = pPayload ? blob_size(pPayload) : 0;
149 const char *zCRLF = sendCRLF ? "\r\n" : "\n";
150
151 blob_zero(pHdr);
152 blob_appendf(pHdr, "%s %s%s HTTP/1.0%s",
153 nPayload>0 ? "POST" : "GET", g.url.path,
154 g.url.path[0]==0 ? "/" : "", zCRLF);
155 if( g.url.proxyAuth ){
156 blob_appendf(pHdr, "Proxy-Authorization: %s%s", g.url.proxyAuth, zCRLF);
157 }
158 if( g.zHttpAuth && g.zHttpAuth[0] ){
159 const char *zCredentials = g.zHttpAuth;
160 char *zEncoded = encode64(zCredentials, -1);
161 blob_appendf(pHdr, "Authorization: Basic %s%s", zEncoded, zCRLF);
162 fossil_free(zEncoded);
163 }
164 blob_appendf(pHdr, "Host: %s%s", g.url.hostname, zCRLF);
165 blob_appendf(pHdr, "User-Agent: %s%s", get_user_agent(), zCRLF);
166 if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH%s", zCRLF);
167 if( nPayload ){
168 if( zAltMimetype ){
169 blob_appendf(pHdr, "Content-Type: %s", zAltMimetype);
170 }else if( g.fHttpTrace ){
171 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug");
172 }else{
173 blob_appendf(pHdr, "Content-Type: application/x-fossil");
174 }
175 blob_appendf(pHdr, "%sContent-Length: %d%s",
176 zCRLF, blob_size(pPayload), zCRLF);
177 }
178 blob_appendf(pHdr, "%s", zCRLF);
179 }
180
181 /*
182 ** Use Fossil credentials for HTTP Basic Authorization prompt
183 */
@@ -541,10 +552,16 @@
552 if( rc!=200 && rc!=301 && rc!=302 && rc!=307 && rc!=308 ){
553 int ii;
554 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
555 while( zLine[ii]==' ' ) ii++;
556 fossil_warning("server says: %s", &zLine[ii]);
557 if( rc==400 && sendCRLF==0 && strstr(zLine,"Bad Request")!=0 ){
558 sendCRLF = 1;
559 transport_close(&g.url);
560 return http_exchange(pSend, pReply, mHttpFlags,
561 maxRedirect, zAltMimetype);
562 }
563 goto write_err;
564 }
565 if( iHttpVersion==0 ){
566 closeConnection = 1;
567 }else{
@@ -626,10 +643,17 @@
643 if( mHttpFlags & HTTP_NOCOMPRESS ) isCompressed = 0;
644 }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
645 isError = 1;
646 }
647 }
648 }else if( sendCRLF==1
649 && rc==200
650 && fossil_strnicmp(zLine, "server: ", 8)==0 ){
651 fossil_warning("Server bug work-around: %s requires CRLF line endings "
652 "contra RFC-2616 section 19.3 paragraph 3",
653 zLine+8);
654 sendCRLF = 2;
655 }
656 }
657 if( iHttpVersion<0 ){
658 /* We got nothing back from the server. If using the ssh: protocol,
659 ** this might mean we need to add or remove the PATH=... argument
660

Keyboard Shortcuts

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