From b8b56248bddc646bf8d262dc9c5b45ce68a1ef08 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 10 Sep 2004 20:58:51 +0000 Subject: [PATCH] - Bug report #1025986. When following a Location: with a custom Host: header replacement, curl only replaced the Host: header on the initial request and didn't replace it on the following ones. This resulted in requests with two Host: headers. Now, curl checks if the location is on the same host as the initial request and then continues to replace the Host: header. And when it moves to another host, it doesn't replace the Host: header but it also doesn't make the second Host: header get used in the request. This change is verified by the two new test cases 184 and 185. --- CHANGES | 13 ++++++++ lib/http.c | 36 +++++++++++++++-------- lib/url.c | 2 +- lib/urldata.h | 8 ++--- tests/data/Makefile.am | 3 +- tests/data/test184 | 67 ++++++++++++++++++++++++++++++++++++++++++ tests/data/test185 | 67 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 177 insertions(+), 19 deletions(-) create mode 100644 tests/data/test184 create mode 100644 tests/data/test185 diff --git a/CHANGES b/CHANGES index 88eb32cd0..123353265 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,19 @@ Changelog +Daniel (10 September 2004) +- Bug report #1025986. When following a Location: with a custom Host: header + replacement, curl only replaced the Host: header on the initial request + and didn't replace it on the following ones. This resulted in requests with + two Host: headers. + + Now, curl checks if the location is on the same host as the initial request + and then continues to replace the Host: header. And when it moves to another + host, it doesn't replace the Host: header but it also doesn't make the + second Host: header get used in the request. + + This change is verified by the two new test cases 184 and 185. + Daniel (31 August 2004) - David Tarendash fount out that curl_multi_add_handle() returned CURLM_CALL_MULTI_PERFORM instead of CURLM_OK. diff --git a/lib/http.c b/lib/http.c index 29ce503f8..52dc8486b 100644 --- a/lib/http.c +++ b/lib/http.c @@ -299,8 +299,8 @@ Curl_http_output_auth(struct connectdata *conn, /* To prevent the user+password to get sent to other than the original host due to a location-follow, we do some weirdo checks here */ if(!data->state.this_is_a_follow || - !data->state.auth_host || - curl_strequal(data->state.auth_host, conn->host.name) || + !data->state.first_host || + curl_strequal(data->state.first_host, conn->host.name) || data->set.http_disable_hostname_check_before_authentication) { /* Send proxy authentication header if needed */ @@ -1156,14 +1156,13 @@ CURLcode Curl_http_connect(struct connectdata *conn) return result; } - if(conn->bits.user_passwd && !data->state.this_is_a_follow) { - /* Authorization: is requested, this is not a followed location, get the - original host name */ - if (data->state.auth_host) + if(!data->state.this_is_a_follow) { + /* this is not a followed location, get the original host name */ + if (data->state.first_host) /* Free to avoid leaking memory on multiple requests*/ - free(data->state.auth_host); + free(data->state.first_host); - data->state.auth_host = strdup(conn->host.name); + data->state.first_host = strdup(conn->host.name); } return CURLE_OK; @@ -1363,11 +1362,13 @@ CURLcode Curl_http(struct connectdata *conn) Curl_safefree(conn->allocptr.host); ptr = checkheaders(data, "Host:"); - if(ptr && !data->state.this_is_a_follow) { + if(ptr && (!data->state.this_is_a_follow || + curl_strequal(data->state.first_host, conn->host.name))) { /* If we have a given custom Host: header, we extract the host name in order to possibly use it for cookie reasons later on. We only allow the custom Host: header if this is NOT a redirect, as setting Host: in the - redirected request is being out on thin ice. */ + redirected request is being out on thin ice. Except if the host name + is the same as the first one! */ char *start = ptr+strlen("Host:"); while(*start && isspace((int)*start )) start++; @@ -1379,6 +1380,7 @@ CURLcode Curl_http(struct connectdata *conn) if(ptr != start) { size_t len=ptr-start; + Curl_safefree(conn->allocptr.cookiehost); conn->allocptr.cookiehost = malloc(len+1); if(!conn->allocptr.cookiehost) return CURLE_OUT_OF_MEMORY; @@ -1727,9 +1729,17 @@ CURLcode Curl_http(struct connectdata *conn) if(*ptr) { /* only send this if the contents was non-blank */ - result = add_bufferf(req_buffer, "%s\r\n", headers->data); - if(result) - return result; + if(conn->allocptr.host && + /* a Host: header was sent already, don't pass on any custom Host: + header as that will produce *two* in the same request! */ + curl_strnequal("Host:", headers->data, 5)) + ; + else { + + result = add_bufferf(req_buffer, "%s\r\n", headers->data); + if(result) + return result; + } } } headers = headers->next; diff --git a/lib/url.c b/lib/url.c index 8099688df..8bf89cf01 100644 --- a/lib/url.c +++ b/lib/url.c @@ -211,7 +211,7 @@ CURLcode Curl_close(struct SessionHandle *data) if(data->change.cookielist) /* clean up list if any */ curl_slist_free_all(data->change.cookielist); - Curl_safefree(data->state.auth_host); + Curl_safefree(data->state.first_host); Curl_safefree(data->state.scratch); if(data->change.proxy_alloc) diff --git a/lib/urldata.h b/lib/urldata.h index 7be2a9324..e50a589ca 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -720,10 +720,10 @@ struct UrlState { bytes / second */ bool this_is_a_follow; /* this is a followed Location: request */ - char *auth_host; /* if set, this should be the host name that we will - sent authorization to, no else. Used to make Location: - following not keep sending user+password... This is - strdup() data. + char *first_host; /* if set, this should be the host name that we will + sent authorization to, no else. Used to make Location: + following not keep sending user+password... This is + strdup() data. */ struct curl_ssl_session *session; /* array of 'numsessions' size */ diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 02f618bb6..3135a419a 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -25,7 +25,8 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \ test158 test159 test511 test160 test161 test162 test163 test164 \ test512 test165 test166 test167 test168 test169 test170 test171 \ test172 test204 test205 test173 test174 test175 test176 test177 \ - test513 test514 test178 test179 test180 test181 test182 test183 + test513 test514 test178 test179 test180 test181 test182 test183 \ + test184 test185 # The following tests have been removed from the dist since they no longer # work. We need to fix the test suite's FTPS server first, then bring them diff --git a/tests/data/test184 b/tests/data/test184 new file mode 100644 index 000000000..547993f6a --- /dev/null +++ b/tests/data/test184 @@ -0,0 +1,67 @@ +# Server-side + + +HTTP/1.1 301 OK swsbounce +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 4 +Location: http://yet.another.host/184 + +moo + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 4 + +moo + + +HTTP/1.1 301 OK swsbounce +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 4 +Location: http://yet.another.host/184 + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 4 + +moo + + + +# Client-side + + +http + + +SSL + + +HTTP replace Host: when following Location: to new host + + +http://deathstar.another.galaxy/184 -L -H "Host: another.visitor.stay.a.while.stay.foreeeeeever" --proxy http://%HOSTIP:%HTTPPORT + + + +# Verify data after the test has been "shot" + + +^User-Agent: curl/.* + + +GET http://deathstar.another.galaxy/184 HTTP/1.1 +User-Agent: curl/7.12.2-CVS (i686-pc-linux-gnu) libcurl/7.12.2-CVS OpenSSL/0.9.6b zlib/1.1.4 libidn/0.4.6 +Pragma: no-cache +Accept: */* +Host: another.visitor.stay.a.while.stay.foreeeeeever + +GET http://yet.another.host/184 HTTP/1.1 +Host: yet.another.host +Pragma: no-cache +Accept: */* + + + + diff --git a/tests/data/test185 b/tests/data/test185 new file mode 100644 index 000000000..2af7b1425 --- /dev/null +++ b/tests/data/test185 @@ -0,0 +1,67 @@ +# Server-side + + +HTTP/1.1 301 OK swsbounce +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 4 +Location: go/west/185 + +moo + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 4 + +moo + + +HTTP/1.1 301 OK swsbounce +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 4 +Location: go/west/185 + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Content-Length: 4 + +moo + + + +# Client-side + + +http + + +SSL + + +HTTP replace Host: when following Location: on the same host + + +http://deathstar.another.galaxy/185 -L -H "Host: another.visitor.stay.a.while.stay.foreeeeeever" --proxy http://%HOSTIP:%HTTPPORT + + + +# Verify data after the test has been "shot" + + +^User-Agent: curl/.* + + +GET http://deathstar.another.galaxy/185 HTTP/1.1 +User-Agent: curl/7.12.2-CVS (i686-pc-linux-gnu) libcurl/7.12.2-CVS OpenSSL/0.9.6b zlib/1.1.4 libidn/0.4.6 +Pragma: no-cache +Accept: */* +Host: another.visitor.stay.a.while.stay.foreeeeeever + +GET http://deathstar.another.galaxy/go/west/185 HTTP/1.1 +Pragma: no-cache +Accept: */* +Host: another.visitor.stay.a.while.stay.foreeeeeever + + + +