Fossil SCM

Limit the number of HTTP redirects that any http_exchange() call will follow to 20 (the limit used by most browsers). Previously, a misconfigured server or incorrect URL could cause Fossil to follow an endless trail of redirects without user intervention.

joel 2013-02-01 07:01 trunk
Commit 13ffb9b4d1eb3f97b9704d341a3f65eaadce1cc3
1 file changed +19 -1
+19 -1
--- src/http.c
+++ src/http.c
@@ -120,10 +120,16 @@
120120
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
121121
}
122122
blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
123123
}
124124
125
+/*
126
+** Maximum number of HTTP redirects that any http_exchange() call will
127
+** follow before throwing a fatal error. Most browsers use a limit of 20.
128
+*/
129
+#define MAX_REDIRECTS 20
130
+
125131
/*
126132
** Sign the content in pSend, compress it, and send it to the server
127133
** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
128134
** in pRecv. pRecv is assumed to be uninitialized when
129135
** this routine is called - this routine will initialize it.
@@ -131,10 +137,19 @@
131137
** The server address is contain in the "g" global structure. The
132138
** url_parse() routine should have been called prior to this routine
133139
** in order to fill this structure appropriately.
134140
*/
135141
int http_exchange(Blob *pSend, Blob *pReply, int useLogin){
142
+ return _http_exchange(pSend, pReply, useLogin, 0);
143
+}
144
+
145
+/*
146
+** Actual implementation details of http_exchange(). This is done so we can
147
+** track the number of redirects without changing the signature of that
148
+** function and requiring callers to initialize numRedirects.
149
+*/
150
+int _http_exchange(Blob *pSend, Blob *pReply, int useLogin, int numRedirects){
136151
Blob login; /* The login card */
137152
Blob payload; /* The complete payload including login card */
138153
Blob hdr; /* The HTTP request header */
139154
int closeConnection; /* True to close the connection when done */
140155
int iLength; /* Length of the reply payload */
@@ -230,10 +245,13 @@
230245
closeConnection = 1;
231246
}else if( c=='k' || c=='K' ){
232247
closeConnection = 0;
233248
}
234249
}else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
250
+ if ( numRedirects>=MAX_REDIRECTS ){
251
+ fossil_fatal("redirect limit exceeded");
252
+ }
235253
int i, j;
236254
for(i=9; zLine[i] && zLine[i]==' '; i++){}
237255
if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
238256
j = strlen(zLine) - 1;
239257
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
@@ -241,11 +259,11 @@
241259
zLine[j] = 0;
242260
}
243261
fossil_print("redirect to %s\n", &zLine[i]);
244262
url_parse(&zLine[i]);
245263
transport_close();
246
- return http_exchange(pSend, pReply, useLogin);
264
+ return _http_exchange(pSend, pReply, useLogin, numRedirects + 1);
247265
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
248266
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
249267
isCompressed = 0;
250268
}else if( fossil_strnicmp(&zLine[14],
251269
"application/x-fossil-uncompressed", -1)==0 ){
252270
--- src/http.c
+++ src/http.c
@@ -120,10 +120,16 @@
120 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
121 }
122 blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
123 }
124
 
 
 
 
 
 
125 /*
126 ** Sign the content in pSend, compress it, and send it to the server
127 ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
128 ** in pRecv. pRecv is assumed to be uninitialized when
129 ** this routine is called - this routine will initialize it.
@@ -131,10 +137,19 @@
131 ** The server address is contain in the "g" global structure. The
132 ** url_parse() routine should have been called prior to this routine
133 ** in order to fill this structure appropriately.
134 */
135 int http_exchange(Blob *pSend, Blob *pReply, int useLogin){
 
 
 
 
 
 
 
 
 
136 Blob login; /* The login card */
137 Blob payload; /* The complete payload including login card */
138 Blob hdr; /* The HTTP request header */
139 int closeConnection; /* True to close the connection when done */
140 int iLength; /* Length of the reply payload */
@@ -230,10 +245,13 @@
230 closeConnection = 1;
231 }else if( c=='k' || c=='K' ){
232 closeConnection = 0;
233 }
234 }else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
 
 
 
235 int i, j;
236 for(i=9; zLine[i] && zLine[i]==' '; i++){}
237 if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
238 j = strlen(zLine) - 1;
239 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
@@ -241,11 +259,11 @@
241 zLine[j] = 0;
242 }
243 fossil_print("redirect to %s\n", &zLine[i]);
244 url_parse(&zLine[i]);
245 transport_close();
246 return http_exchange(pSend, pReply, useLogin);
247 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
248 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
249 isCompressed = 0;
250 }else if( fossil_strnicmp(&zLine[14],
251 "application/x-fossil-uncompressed", -1)==0 ){
252
--- src/http.c
+++ src/http.c
@@ -120,10 +120,16 @@
120 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
121 }
122 blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
123 }
124
125 /*
126 ** Maximum number of HTTP redirects that any http_exchange() call will
127 ** follow before throwing a fatal error. Most browsers use a limit of 20.
128 */
129 #define MAX_REDIRECTS 20
130
131 /*
132 ** Sign the content in pSend, compress it, and send it to the server
133 ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
134 ** in pRecv. pRecv is assumed to be uninitialized when
135 ** this routine is called - this routine will initialize it.
@@ -131,10 +137,19 @@
137 ** The server address is contain in the "g" global structure. The
138 ** url_parse() routine should have been called prior to this routine
139 ** in order to fill this structure appropriately.
140 */
141 int http_exchange(Blob *pSend, Blob *pReply, int useLogin){
142 return _http_exchange(pSend, pReply, useLogin, 0);
143 }
144
145 /*
146 ** Actual implementation details of http_exchange(). This is done so we can
147 ** track the number of redirects without changing the signature of that
148 ** function and requiring callers to initialize numRedirects.
149 */
150 int _http_exchange(Blob *pSend, Blob *pReply, int useLogin, int numRedirects){
151 Blob login; /* The login card */
152 Blob payload; /* The complete payload including login card */
153 Blob hdr; /* The HTTP request header */
154 int closeConnection; /* True to close the connection when done */
155 int iLength; /* Length of the reply payload */
@@ -230,10 +245,13 @@
245 closeConnection = 1;
246 }else if( c=='k' || c=='K' ){
247 closeConnection = 0;
248 }
249 }else if( rc==302 && fossil_strnicmp(zLine, "location:", 9)==0 ){
250 if ( numRedirects>=MAX_REDIRECTS ){
251 fossil_fatal("redirect limit exceeded");
252 }
253 int i, j;
254 for(i=9; zLine[i] && zLine[i]==' '; i++){}
255 if( zLine[i]==0 ) fossil_fatal("malformed redirect: %s", zLine);
256 j = strlen(zLine) - 1;
257 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
@@ -241,11 +259,11 @@
259 zLine[j] = 0;
260 }
261 fossil_print("redirect to %s\n", &zLine[i]);
262 url_parse(&zLine[i]);
263 transport_close();
264 return _http_exchange(pSend, pReply, useLogin, numRedirects + 1);
265 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
266 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
267 isCompressed = 0;
268 }else if( fossil_strnicmp(&zLine[14],
269 "application/x-fossil-uncompressed", -1)==0 ){
270

Keyboard Shortcuts

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