http_proxy: fix adding custom proxy headers

Reported-by: Joshua Rogers
Fixes #19227
Closes #19239
This commit is contained in:
Daniel Stenberg 2025-10-25 18:48:36 +02:00
parent fb0c014e30
commit cdd945e486
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2

View file

@ -48,18 +48,11 @@
#include "curl_memory.h"
#include "memdebug.h"
static bool hd_name_eq(const char *n1, size_t n1len,
const char *n2, size_t n2len)
{
return (n1len == n2len) ? curl_strnequal(n1, n2, n1len) : FALSE;
}
static CURLcode dynhds_add_custom(struct Curl_easy *data,
bool is_connect, int httpversion,
struct dynhds *hds)
{
struct connectdata *conn = data->conn;
const char *ptr;
struct curl_slist *h[2];
struct curl_slist *headers;
int numlists = 1; /* by default */
@ -95,86 +88,76 @@ static CURLcode dynhds_add_custom(struct Curl_easy *data,
/* loop through one or two lists */
for(i = 0; i < numlists; i++) {
for(headers = h[i]; headers; headers = headers->next) {
const char *name, *value;
size_t namelen, valuelen;
struct Curl_str name;
const char *value = NULL;
size_t valuelen = 0;
const char *ptr = headers->data;
/* There are 2 quirks in place for custom headers:
* 1. setting only 'name:' to suppress a header from being sent
* 2. setting only 'name;' to send an empty (illegal) header
*/
ptr = strchr(headers->data, ':');
if(ptr) {
name = headers->data;
namelen = ptr - headers->data;
ptr++; /* pass the colon */
curlx_str_passblanks(&ptr);
if(*ptr) {
value = ptr;
valuelen = strlen(value);
if(!curlx_str_cspn(&ptr, &name, ";:")) {
if(!curlx_str_single(&ptr, ':')) {
curlx_str_passblanks(&ptr);
if(*ptr) {
value = ptr;
valuelen = strlen(value);
}
else {
/* quirk #1, suppress this header */
continue;
}
}
else {
/* quirk #1, suppress this header */
else if(!curlx_str_single(&ptr, ';')) {
curlx_str_passblanks(&ptr);
if(!*ptr) {
/* quirk #2, send an empty header */
value = "";
valuelen = 0;
}
else {
/* this may be used for something else in the future,
* ignore this for now */
continue;
}
}
else
/* neither : nor ; in provided header value. We ignore this
* silently */
continue;
}
}
else {
ptr = strchr(headers->data, ';');
else
/* no name, move on */
continue;
if(!ptr) {
/* neither : nor ; in provided header value. We seem
* to ignore this silently */
continue;
}
name = headers->data;
namelen = ptr - headers->data;
ptr++; /* pass the semicolon */
curlx_str_passblanks(&ptr);
if(!*ptr) {
/* quirk #2, send an empty header */
value = "";
valuelen = 0;
}
else {
/* this may be used for something else in the future,
* ignore this for now */
continue;
}
}
DEBUGASSERT(name && value);
DEBUGASSERT(curlx_strlen(&name) && value);
if(data->state.aptr.host &&
/* a Host: header was sent already, do not pass on any custom Host:
header as that will produce *two* in the same request! */
hd_name_eq(name, namelen, STRCONST("Host:")))
;
curlx_str_casecompare(&name, "Host"));
else if(data->state.httpreq == HTTPREQ_POST_FORM &&
/* this header (extended by formdata.c) is sent later */
hd_name_eq(name, namelen, STRCONST("Content-Type:")))
;
curlx_str_casecompare(&name, "Content-Type"));
else if(data->state.httpreq == HTTPREQ_POST_MIME &&
/* this header is sent later */
hd_name_eq(name, namelen, STRCONST("Content-Type:")))
;
curlx_str_casecompare(&name, "Content-Type"));
else if(data->req.authneg &&
/* while doing auth neg, do not allow the custom length since
we will force length zero then */
hd_name_eq(name, namelen, STRCONST("Content-Length:")))
;
curlx_str_casecompare(&name, "Content-Length"));
else if((httpversion >= 20) &&
hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:")))
/* HTTP/2 and HTTP/3 do not support chunked requests */
;
else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) ||
hd_name_eq(name, namelen, STRCONST("Cookie:"))) &&
curlx_str_casecompare(&name, "Transfer-Encoding"));
/* HTTP/2 and HTTP/3 do not support chunked requests */
else if((curlx_str_casecompare(&name, "Authorization") ||
curlx_str_casecompare(&name, "Cookie")) &&
/* be careful of sending this potentially sensitive header to
other hosts */
!Curl_auth_allowed_to_host(data))
;
!Curl_auth_allowed_to_host(data));
else {
CURLcode result;
result = Curl_dynhds_add(hds, name, namelen, value, valuelen);
CURLcode result =
Curl_dynhds_add(hds, curlx_str(&name), curlx_strlen(&name),
value, valuelen);
if(result)
return result;
}