From: Daniel Stenberg Date: Sat, 25 Oct 2025 16:48:36 +0000 (+0200) Subject: http_proxy: fix adding custom proxy headers X-Git-Tag: curl-8_17_0~90 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cdd945e486392dd9f337e8e0edd6d6f7d8ddc524;p=thirdparty%2Fcurl.git http_proxy: fix adding custom proxy headers Reported-by: Joshua Rogers Fixes #19227 Closes #19239 --- diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 845ba2e8f8..f6e546b9fd 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -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 */ - continue; + 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 { - ptr = strchr(headers->data, ';'); - - if(!ptr) { - /* neither : nor ; in provided header value. We seem - * to ignore this silently */ + else + /* neither : nor ; in provided header value. We 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; - } } + else + /* no name, move on */ + 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; }