http: return error for a second Location: header

Unless it is identical to the previous one.

Follow-up to dbcaa00657

Adjusted test 580, added test 772 and 773

Fixes #19130
Reported-by: Jakub Stasiak
Closes #19134
This commit is contained in:
Daniel Stenberg 2025-10-19 10:59:38 +02:00
parent cbd7823fd1
commit 9596c4a258
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
5 changed files with 138 additions and 18 deletions

View 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->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(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;
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;
/* 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;
/* mark the next request as a followed location: */
data->state.this_is_a_follow = TRUE;
}
}
}
}