From 9596c4a2587a9e512ea46fbd7b6fc1ecb878590f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 19 Oct 2025 10:59:38 +0200 Subject: [PATCH] http: return error for a second Location: header Unless it is identical to the previous one. Follow-up to dbcaa0065719acc0383 Adjusted test 580, added test 772 and 773 Fixes #19130 Reported-by: Jakub Stasiak Closes #19134 --- lib/http.c | 48 ++++++++++++++++++++++---------------- tests/data/Makefile.am | 2 +- tests/data/test580 | 11 +++++++++ tests/data/test772 | 52 ++++++++++++++++++++++++++++++++++++++++++ tests/data/test773 | 49 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 tests/data/test772 create mode 100644 tests/data/test773 diff --git a/lib/http.c b/lib/http.c index db37995a12..2d5da2e0e1 100644 --- a/lib/http.c +++ b/lib/http.c @@ -3265,9 +3265,7 @@ static CURLcode http_header_l(struct Curl_easy *data, data->info.filetime = k->timeofdoc; return CURLE_OK; } - if((k->httpcode >= 300 && k->httpcode < 400) && - HD_IS(hd, hdlen, "Location:") && - !data->req.location) { + if(HD_IS(hd, hdlen, "Location:")) { /* this is the URL that the server advises us to use instead */ char *location = Curl_copy_header_value(hd); if(!location) @@ -3276,23 +3274,33 @@ static CURLcode http_header_l(struct Curl_easy *data, /* ignore empty data */ free(location); else { - data->req.location = location; - - if(data->set.http_follow_mode) { - CURLcode result; - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->req.location); /* clone */ - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - - /* some cases of POST and PUT etc needs to rewind the data - stream at this point */ - result = http_perhapsrewind(data, conn); - if(result) - return result; - - /* mark the next request as a followed location: */ - data->state.this_is_a_follow = TRUE; + if(data->req.location && + strcmp(data->req.location, location)) { + failf(data, "Multiple Location headers"); + free(location); + return CURLE_WEIRD_SERVER_REPLY; + } + else { + free(data->req.location); + data->req.location = location; + + if((k->httpcode >= 300 && k->httpcode < 400) && + data->set.http_follow_mode) { + CURLcode result; + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->req.location); /* clone */ + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + + /* some cases of POST and PUT etc needs to rewind the data + stream at this point */ + result = http_perhapsrewind(data, conn); + if(result) + return result; + + /* mark the next request as a followed location: */ + data->state.this_is_a_follow = TRUE; + } } } } diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 99c287507f..9984e92839 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -110,7 +110,7 @@ test736 test737 test738 test739 test740 test741 test742 test743 test744 \ test745 test746 test747 test748 test749 test750 test751 test752 test753 \ test754 test755 test756 test757 test758 test759 test760 test761 test762 \ test763 test764 test765 test766 test767 test768 test769 test770 test771 \ -\ +test772 test773 \ test780 test781 test782 test783 test784 test785 test786 test787 test788 \ test789 test790 test791 test792 test793 test794 test796 test797 \ \ diff --git a/tests/data/test580 b/tests/data/test580 index 63cd0ca0de..c7f4bcfcd7 100644 --- a/tests/data/test580 +++ b/tests/data/test580 @@ -20,6 +20,14 @@ Connection: close Location: and there's a second one too! / moo.html + +HTTP/1.1 302 eat this! +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Location: this-is-the-first.html +Content-Length: 0 +Connection: close + # Client-side @@ -51,5 +59,8 @@ Host: %HOSTIP:%HTTPPORT Accept: */* + +8 + diff --git a/tests/data/test772 b/tests/data/test772 new file mode 100644 index 0000000000..f3b1d954e8 --- /dev/null +++ b/tests/data/test772 @@ -0,0 +1,52 @@ + + + +HTTP +HTTP GET +Location + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Content-Length: 0 +Connection: close +Location: this +Location: that + + + + +# +# Client-side + + +http + + +HTTP with two Location: headers triggers error + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +8 + + + diff --git a/tests/data/test773 b/tests/data/test773 new file mode 100644 index 0000000000..42d28dadd3 --- /dev/null +++ b/tests/data/test773 @@ -0,0 +1,49 @@ + + + +HTTP +HTTP GET +Location + + + +# +# Server-side + + +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Content-Length: 0 +Connection: close +Location: this +Location: this + + + + +# +# Client-side + + +http + + +HTTP with two identical Location: headers triggers no error + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + + -- 2.47.3