]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
http: return error for a second Location: header
authorDaniel Stenberg <daniel@haxx.se>
Sun, 19 Oct 2025 08:59:38 +0000 (10:59 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 20 Oct 2025 07:35:23 +0000 (09:35 +0200)
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
tests/data/Makefile.am
tests/data/test580
tests/data/test772 [new file with mode: 0644]
tests/data/test773 [new file with mode: 0644]

index db37995a12c7db10a706b1fbdf0ff37652d8a007..2d5da2e0e142c6bd0513f553b457208e702e3f46 100644 (file)
@@ -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;
+        }
       }
     }
   }
index 99c287507f764bd8e6ce2ede7f67391c8fef26fd..9984e92839f833e93ea21f2ffdcd18d8156c7d49 100644 (file)
@@ -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 \
 \
index 63cd0ca0deb9ff0fbe9d4f37fba365bfc77ec7c1..c7f4bcfcd778ac4e42178e953ae6dc09a77d6ca5 100644 (file)
@@ -20,6 +20,14 @@ Connection: close
 Location: and there's a second one too! / moo.html\r
 \r
 </data>
+<datacheck>
+HTTP/1.1 302 eat this!\r
+Date: Tue, 09 Nov 2010 14:49:00 GMT\r
+Server: test-server/fake\r
+Location: this-is-the-first.html\r
+Content-Length: 0\r
+Connection: close\r
+</datacheck>
 </reply>
 
 # Client-side
@@ -51,5 +59,8 @@ Host: %HOSTIP:%HTTPPORT
 Accept: */*\r
 \r
 </protocol>
+<errorcode>
+8
+</errorcode>
 </verify>
 </testcase>
diff --git a/tests/data/test772 b/tests/data/test772
new file mode 100644 (file)
index 0000000..f3b1d95
--- /dev/null
@@ -0,0 +1,52 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+Location
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data crlf="yes" nocheck="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Content-Length: 0
+Connection: close
+Location: this
+Location: that
+
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+<name>
+HTTP with two Location: headers triggers error
+</name>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="yes">
+GET /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+User-Agent: curl/%VERSION
+Accept: */*
+
+</protocol>
+<errorcode>
+8
+</errorcode>
+</verify>
+</testcase>
diff --git a/tests/data/test773 b/tests/data/test773
new file mode 100644 (file)
index 0000000..42d28da
--- /dev/null
@@ -0,0 +1,49 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+Location
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data crlf="yes" nocheck="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Content-Length: 0
+Connection: close
+Location: this
+Location: this
+
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+<name>
+HTTP with two identical Location: headers triggers no error
+</name>
+<command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="yes">
+GET /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+User-Agent: curl/%VERSION
+Accept: */*
+
+</protocol>
+</verify>
+</testcase>