Curl_http(), decomplexify

Split out adding of individual request headers into a switch. Check
the connection http version only on fresh connections, use separate
methods.

Add TE: header directly without allocation. Add bit for indicating
Connection: header has been added and custom headers should not do
that again.

Closes #18444
This commit is contained in:
Stefan Eissing
2025-09-01 15:52:30 +02:00
committed by Daniel Stenberg
parent e00cb001c6
commit 4d040c71d7
25 changed files with 345 additions and 319 deletions

View File

@@ -105,24 +105,16 @@ static void http_exp100_got100(struct Curl_easy *data);
static CURLcode http_firstwrite(struct Curl_easy *data);
static CURLcode http_header(struct Curl_easy *data,
const char *hd, size_t hdlen);
static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn);
static CURLcode http_range(struct Curl_easy *data,
Curl_HttpReq httpreq);
static CURLcode http_req_complete(struct Curl_easy *data,
struct dynbuf *r, int httpversion,
Curl_HttpReq httpreq);
static CURLcode http_req_set_reader(struct Curl_easy *data,
Curl_HttpReq httpreq, int httpversion,
const char **tep);
static CURLcode http_req_set_TE(struct Curl_easy *data,
struct dynbuf *req,
int httpversion);
static CURLcode http_size(struct Curl_easy *data);
static CURLcode http_statusline(struct Curl_easy *data,
struct connectdata *conn);
static CURLcode http_target(struct Curl_easy *data, struct connectdata *conn,
struct dynbuf *req);
static CURLcode http_target(struct Curl_easy *data, struct dynbuf *req);
static CURLcode http_useragent(struct Curl_easy *data);
#ifdef HAVE_LIBZ
static CURLcode http_transferencode(struct Curl_easy *data);
#endif
/*
@@ -1709,10 +1701,8 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
we will force length zero then */
curlx_str_casecompare(&name, "Content-Length"))
;
else if(data->state.aptr.te &&
/* when asking for Transfer-Encoding, do not pass on a custom
Connection: */
curlx_str_casecompare(&name, "Connection"))
else if(curlx_str_casecompare(&name, "Connection"))
/* Normal Connection: header generation takes care of this */
;
else if((httpversion >= 20) &&
curlx_str_casecompare(&name, "Transfer-Encoding"))
@@ -1817,14 +1807,14 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
}
#endif
void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
void Curl_http_method(struct Curl_easy *data,
const char **method, Curl_HttpReq *reqp)
{
Curl_HttpReq httpreq = (Curl_HttpReq)data->state.httpreq;
const char *request;
if(conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
if(data->conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
httpreq = HTTPREQ_GET;
else if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) &&
else if((data->conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) &&
data->state.upload)
httpreq = HTTPREQ_PUT;
@@ -1875,10 +1865,12 @@ static CURLcode http_useragent(struct Curl_easy *data)
}
static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn)
static CURLcode http_set_aptr_host(struct Curl_easy *data)
{
const char *ptr;
struct connectdata *conn = data->conn;
struct dynamically_allocated_data *aptr = &data->state.aptr;
const char *ptr;
if(!data->state.this_is_a_follow) {
/* Free to avoid leaking memory on multiple requests */
free(data->state.first_host);
@@ -1966,7 +1958,6 @@ static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn)
* Append the request-target to the HTTP request
*/
static CURLcode http_target(struct Curl_easy *data,
struct connectdata *conn,
struct dynbuf *r)
{
CURLcode result = CURLE_OK;
@@ -1979,7 +1970,7 @@ static CURLcode http_target(struct Curl_easy *data,
}
#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
if(data->conn->bits.httpproxy && !data->conn->bits.tunnel_proxy) {
/* Using a proxy but does not tunnel through it */
/* The path sent to the proxy is in fact the entire URL. But if the remote
@@ -1993,8 +1984,8 @@ static CURLcode http_target(struct Curl_easy *data,
if(!h)
return CURLE_OUT_OF_MEMORY;
if(conn->host.dispname != conn->host.name) {
uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
if(data->conn->host.dispname != data->conn->host.name) {
uc = curl_url_set(h, CURLUPART_HOST, data->conn->host.name, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
@@ -2060,8 +2051,6 @@ static CURLcode http_target(struct Curl_easy *data,
}
else
#else
(void)conn; /* not used in disabled-proxy builds */
#endif
{
result = curlx_dyn_add(r, path);
@@ -2247,21 +2236,13 @@ static CURLcode http_resume(struct Curl_easy *data, Curl_HttpReq httpreq)
return CURLE_OK;
}
static CURLcode http_req_set_reader(struct Curl_easy *data,
Curl_HttpReq httpreq, int httpversion,
const char **tep)
static CURLcode http_req_set_TE(struct Curl_easy *data,
struct dynbuf *req,
int httpversion)
{
CURLcode result = CURLE_OK;
const char *ptr;
result = set_reader(data, httpreq);
if(result)
return result;
result = http_resume(data, httpreq);
if(result)
return result;
ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
if(ptr) {
/* Some kind of TE is requested, check if 'chunked' is chosen */
@@ -2295,7 +2276,7 @@ static CURLcode http_req_set_reader(struct Curl_easy *data,
}
if(data->req.upload_chunky)
*tep = "Transfer-Encoding: chunked\r\n";
result = curlx_dyn_add(req, "Transfer-Encoding: chunked\r\n");
}
return result;
}
@@ -2335,9 +2316,10 @@ static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r,
return CURLE_OK;
}
static CURLcode http_req_complete(struct Curl_easy *data,
struct dynbuf *r, int httpversion,
Curl_HttpReq httpreq)
static CURLcode http_add_content_hds(struct Curl_easy *data,
struct dynbuf *r,
int httpversion,
Curl_HttpReq httpreq)
{
CURLcode result = CURLE_OK;
curl_off_t req_clen;
@@ -2405,26 +2387,17 @@ static CURLcode http_req_complete(struct Curl_easy *data,
break;
}
/* end of headers */
result = curlx_dyn_addn(r, STRCONST("\r\n"));
if(!result) {
Curl_pgrsSetUploadSize(data, req_clen);
if(announced_exp100)
result = http_exp100_add_reader(data);
}
Curl_pgrsSetUploadSize(data, req_clen);
if(announced_exp100)
result = http_exp100_add_reader(data);
out:
if(!result) {
/* setup variables for the upcoming transfer */
Curl_xfer_setup_sendrecv(data, FIRSTSOCKET, -1);
}
return result;
}
#ifndef CURL_DISABLE_COOKIES
static CURLcode http_cookies(struct Curl_easy *data,
struct connectdata *conn,
struct dynbuf *r)
{
CURLcode result = CURLE_OK;
@@ -2441,9 +2414,9 @@ static CURLcode http_cookies(struct Curl_easy *data,
if(data->cookies && data->state.cookie_engine) {
const char *host = data->state.aptr.cookiehost ?
data->state.aptr.cookiehost : conn->host.name;
data->state.aptr.cookiehost : data->conn->host.name;
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
rc = Curl_cookie_getlist(data, conn, host, &list);
rc = Curl_cookie_getlist(data, data->conn, host, &list);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
if(!rc) {
@@ -2494,7 +2467,7 @@ static CURLcode http_cookies(struct Curl_easy *data,
return result;
}
#else
#define http_cookies(a,b,c) CURLE_OK
#define http_cookies(a,b) CURLE_OK
#endif
static CURLcode http_range(struct Curl_easy *data,
@@ -2616,63 +2589,13 @@ static CURLcode http_firstwrite(struct Curl_easy *data)
return CURLE_OK;
}
#ifdef HAVE_LIBZ
static CURLcode http_transferencode(struct Curl_easy *data)
{
if(!Curl_checkheaders(data, STRCONST("TE")) &&
data->set.http_transfer_encoding) {
/* When we are to insert a TE: header in the request, we must also insert
TE in a Connection: header, so we need to merge the custom provided
Connection: header and prevent the original to get sent. Note that if
the user has inserted his/her own TE: header we do not do this magic
but then assume that the user will handle it all! */
char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
#define TE_HEADER "TE: gzip\r\n"
Curl_safefree(data->state.aptr.te);
if(cptr) {
cptr = Curl_copy_header_value(cptr);
if(!cptr)
return CURLE_OUT_OF_MEMORY;
}
/* Create the (updated) Connection: header */
data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
free(cptr);
if(!data->state.aptr.te)
return CURLE_OUT_OF_MEMORY;
}
return CURLE_OK;
}
#endif
/*
* Curl_http() gets called from the generic multi_do() function when an HTTP
* request is to be performed. This creates and sends a properly constructed
* HTTP request.
*/
CURLcode Curl_http(struct Curl_easy *data, bool *done)
static CURLcode http_check_new_conn(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
Curl_HttpReq httpreq;
const char *te = ""; /* transfer-encoding */
const char *request;
const char *httpstring;
struct dynbuf req;
char *altused = NULL;
const char *p_accept; /* Accept: string */
unsigned char httpversion;
const char *alpn;
const char *info_version = NULL;
const char *alpn;
CURLcode result;
/* Always consider the DO phase done after this function call, even if there
may be parts of the request that are not yet sent, since we can deal with
the rest of the request in the PERFORM phase. */
*done = TRUE;
alpn = Curl_conn_get_alpn_negotiated(data, conn);
if(alpn && !strcmp("h3", alpn)) {
DEBUGASSERT(Curl_conn_http_version(data, conn) == 30);
@@ -2684,7 +2607,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
conn->bits.proxy && !conn->bits.tunnel_proxy) {
result = Curl_http2_switch(data);
if(result)
goto fail;
return result;
}
else
#endif
@@ -2697,7 +2620,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
DEBUGF(infof(data, "HTTP/2 over clean TCP"));
result = Curl_http2_switch(data);
if(result)
goto fail;
return result;
info_version = "HTTP/2";
/* There is no ALPN here, but the connection is now definitely h2 */
conn->httpversion_seen = 20;
@@ -2706,159 +2629,313 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
info_version = "HTTP/1.x";
}
if(info_version && !data->conn->bits.reuse)
if(info_version)
infof(data, "using %s", info_version);
return CURLE_OK;
}
static CURLcode http_add_connection_hd(struct Curl_easy *data,
struct dynbuf *req)
{
char *custom = Curl_checkheaders(data, STRCONST("Connection"));
char *custom_val = custom ? Curl_copy_header_value(custom) : NULL;
const char *sep = (custom_val && *custom_val) ? ", " : "Connection: ";
CURLcode result = CURLE_OK;
size_t rlen = curlx_dyn_len(req);
if(custom && !custom_val)
return CURLE_OUT_OF_MEMORY;
if(custom_val && *custom_val)
result = curlx_dyn_addf(req, "Connection: %s", custom_val);
if(!result && data->state.http_hd_te) {
result = curlx_dyn_addf(req, "%s%s", sep, "TE");
sep = ", ";
}
if(!result && data->state.http_hd_upgrade) {
result = curlx_dyn_addf(req, "%s%s", sep, "Upgrade");
sep = ", ";
}
if(!result && data->state.http_hd_h2_settings) {
result = curlx_dyn_addf(req, "%s%s", sep, "HTTP2-Settings");
}
if(rlen < curlx_dyn_len(req))
result = curlx_dyn_addn(req, STRCONST("\r\n"));
free(custom_val);
return result;
}
/* Header identifier in order we send them by default */
typedef enum {
H1_HD_REQUEST,
H1_HD_HOST,
#ifndef CURL_DISABLE_PROXY
H1_HD_PROXY_AUTH,
#endif
H1_HD_USER_AUTH,
H1_HD_RANGE,
H1_HD_USER_AGENT,
H1_HD_ACCEPT,
H1_HD_TE,
H1_HD_ACCEPT_ENCODING,
H1_HD_REFERER,
#ifndef CURL_DISABLE_PROXY
H1_HD_PROXY_CONNECTION,
#endif
H1_HD_TRANSFER_ENCODING,
#ifndef CURL_DISABLE_ALTSVC
H1_HD_ALT_USED,
#endif
H1_HD_UPGRADE,
H1_HD_COOKIES,
H1_HD_CONDITIONALS,
H1_HD_CUSTOM,
H1_HD_CONTENT,
H1_HD_CONNECTION,
H1_HD_LAST /* the last, empty header line */
} http_hd_t;
static CURLcode http_add_hd(struct Curl_easy *data,
struct dynbuf *req,
http_hd_t id,
unsigned char httpversion,
const char *method,
Curl_HttpReq httpreq)
{
CURLcode result = CURLE_OK;
switch(id) {
case H1_HD_REQUEST:
/* add the main request stuff */
/* GET/HEAD/POST/PUT */
result = curlx_dyn_addf(req, "%s ", method);
if(!result)
result = http_target(data, req);
if(!result)
result = curlx_dyn_addf(req, " HTTP/%s\r\n",
get_http_string(httpversion));
break;
case H1_HD_HOST:
if(data->state.aptr.host)
result = curlx_dyn_add(req, data->state.aptr.host);
break;
#ifndef CURL_DISABLE_PROXY
case H1_HD_PROXY_AUTH:
if(data->state.aptr.proxyuserpwd)
result = curlx_dyn_add(req, data->state.aptr.proxyuserpwd);
break;
#endif
case H1_HD_USER_AUTH:
if(data->state.aptr.userpwd)
result = curlx_dyn_add(req, data->state.aptr.userpwd);
break;
case H1_HD_RANGE:
if(data->state.use_range && data->state.aptr.rangeline)
result = curlx_dyn_add(req, data->state.aptr.rangeline);
break;
case H1_HD_USER_AGENT:
if(data->set.str[STRING_USERAGENT] && /* User-Agent: */
*data->set.str[STRING_USERAGENT] &&
data->state.aptr.uagent)
result = curlx_dyn_add(req, data->state.aptr.uagent);
break;
case H1_HD_ACCEPT:
if(!Curl_checkheaders(data, STRCONST("Accept")))
result = curlx_dyn_add(req, "Accept: */*\r\n");
break;
case H1_HD_TE:
#ifdef HAVE_LIBZ
if(!Curl_checkheaders(data, STRCONST("TE")) &&
data->set.http_transfer_encoding) {
data->state.http_hd_te = TRUE;
result = curlx_dyn_add(req, "TE: gzip\r\n");
}
#endif
break;
case H1_HD_ACCEPT_ENCODING:
Curl_safefree(data->state.aptr.accept_encoding);
if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
data->set.str[STRING_ENCODING])
result = curlx_dyn_addf(req, "Accept-Encoding: %s\r\n",
data->set.str[STRING_ENCODING]);
break;
case H1_HD_REFERER:
Curl_safefree(data->state.aptr.ref);
if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer")))
result = curlx_dyn_addf(req, "Referer: %s\r\n", data->state.referer);
break;
#ifndef CURL_DISABLE_PROXY
case H1_HD_PROXY_CONNECTION:
if(data->conn->bits.httpproxy &&
!data->conn->bits.tunnel_proxy &&
!Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
!Curl_checkProxyheaders(data, data->conn, STRCONST("Proxy-Connection")))
result = curlx_dyn_add(req, "Proxy-Connection: Keep-Alive\r\n");
break;
#endif
case H1_HD_TRANSFER_ENCODING:
result = http_req_set_TE(data, req, httpversion);
break;
#ifndef CURL_DISABLE_ALTSVC
case H1_HD_ALT_USED:
if(data->conn->bits.altused &&
!Curl_checkheaders(data, STRCONST("Alt-Used")))
result = curlx_dyn_addf(req, "Alt-Used: %s:%d\r\n",
data->conn->conn_to_host.name,
data->conn->conn_to_port);
break;
#endif
case H1_HD_UPGRADE:
if(!Curl_conn_is_ssl(data->conn, FIRSTSOCKET) && (httpversion < 20) &&
(data->state.http_neg.wanted & CURL_HTTP_V2x) &&
data->state.http_neg.h2_upgrade) {
/* append HTTP2 upgrade magic stuff to the HTTP request if it is not done
over SSL */
result = Curl_http2_request_upgrade(req, data);
}
#ifndef CURL_DISABLE_WEBSOCKETS
if(!result && data->conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
result = Curl_ws_request(data, req);
#endif
break;
case H1_HD_COOKIES:
result = http_cookies(data, req);
break;
case H1_HD_CONDITIONALS:
result = Curl_add_timecondition(data, req);
break;
case H1_HD_CUSTOM:
result = Curl_add_custom_headers(data, FALSE, httpversion, req);
break;
case H1_HD_CONTENT:
result = http_add_content_hds(data, req, httpversion, httpreq);
break;
case H1_HD_CONNECTION: {
result = http_add_connection_hd(data, req);
break;
}
case H1_HD_LAST:
result = curlx_dyn_addn(req, STRCONST("\r\n"));
break;
}
return result;
}
/*
* Curl_http() gets called from the generic multi_do() function when an HTTP
* request is to be performed. This creates and sends a properly constructed
* HTTP request.
*/
CURLcode Curl_http(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
Curl_HttpReq httpreq;
const char *method;
struct dynbuf req;
unsigned char httpversion;
size_t hd_id;
/* Always consider the DO phase done after this function call, even if there
may be parts of the request that are not yet sent, since we can deal with
the rest of the request in the PERFORM phase. */
*done = TRUE;
/* initialize a dynamic send-buffer */
curlx_dyn_init(&req, DYN_HTTP_REQUEST);
/* make sure the header buffer is reset - if there are leftovers from a
previous transfer */
curlx_dyn_reset(&data->state.headerb);
if(!data->conn->bits.reuse) {
result = http_check_new_conn(data);
if(result)
goto out;
}
/* Add collecting of headers written to client. For a new connection,
* we might have done that already, but reuse
* or multiplex needs it here as well. */
result = Curl_headers_init(data);
if(result)
goto fail;
goto out;
result = http_host(data, conn);
if(result)
goto fail;
data->state.http_hd_te = FALSE;
data->state.http_hd_upgrade = FALSE;
data->state.http_hd_h2_settings = FALSE;
result = http_useragent(data);
if(result)
goto fail;
/* what kind of request do we need to send? */
Curl_http_method(data, &method, &httpreq);
Curl_http_method(data, conn, &request, &httpreq);
/* setup the authentication headers */
{
/* select host to send */
result = http_set_aptr_host(data);
if(!result) {
/* setup the authentication headers, how that method and host are known */
char *pq = NULL;
if(data->state.up.query) {
pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
if(!pq)
return CURLE_OUT_OF_MEMORY;
}
result = Curl_http_output_auth(data, conn, request, httpreq,
result = Curl_http_output_auth(data, data->conn, method, httpreq,
(pq ? pq : data->state.up.path), FALSE);
free(pq);
if(result)
goto fail;
}
Curl_safefree(data->state.aptr.ref);
if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) {
data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
if(!data->state.aptr.ref)
return CURLE_OUT_OF_MEMORY;
}
if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
data->set.str[STRING_ENCODING]) {
free(data->state.aptr.accept_encoding);
data->state.aptr.accept_encoding =
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
if(!data->state.aptr.accept_encoding)
return CURLE_OUT_OF_MEMORY;
}
else
Curl_safefree(data->state.aptr.accept_encoding);
#ifdef HAVE_LIBZ
/* we only consider transfer-encoding magic if libz support is built-in */
result = http_transferencode(data);
if(result)
goto fail;
#endif
goto out;
result = http_useragent(data);
if(result)
goto out;
/* Setup input reader, resume information and ranges */
result = set_reader(data, httpreq);
if(!result)
result = http_resume(data, httpreq);
if(!result)
result = http_range(data, httpreq);
if(result)
goto out;
httpversion = http_request_version(data);
httpstring = get_http_string(httpversion);
result = http_req_set_reader(data, httpreq, httpversion, &te);
if(result)
goto fail;
p_accept = Curl_checkheaders(data,
STRCONST("Accept")) ? NULL : "Accept: */*\r\n";
result = http_range(data, httpreq);
if(result)
goto fail;
/* initialize a dynamic send-buffer */
curlx_dyn_init(&req, DYN_HTTP_REQUEST);
/* make sure the header buffer is reset - if there are leftovers from a
previous transfer */
curlx_dyn_reset(&data->state.headerb);
/* add the main request stuff */
/* GET/HEAD/POST/PUT */
result = curlx_dyn_addf(&req, "%s ", request);
if(!result)
result = http_target(data, conn, &req);
if(result) {
curlx_dyn_free(&req);
goto fail;
/* Add request line and all headers to `req` */
for(hd_id = 0; hd_id <= H1_HD_LAST; ++hd_id) {
result = http_add_hd(data, &req, (http_hd_t)hd_id,
httpversion, method, httpreq);
if(result)
goto out;
}
#ifndef CURL_DISABLE_ALTSVC
if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) {
altused = aprintf("Alt-Used: %s:%d\r\n",
conn->conn_to_host.name, conn->conn_to_port);
if(!altused) {
curlx_dyn_free(&req);
return CURLE_OUT_OF_MEMORY;
}
}
#endif
result =
curlx_dyn_addf(&req,
" HTTP/%s\r\n" /* HTTP version */
"%s" /* host */
"%s" /* proxyuserpwd */
"%s" /* userpwd */
"%s" /* range */
"%s" /* user agent */
"%s" /* accept */
"%s" /* TE: */
"%s" /* accept-encoding */
"%s" /* referer */
"%s" /* Proxy-Connection */
"%s" /* transfer-encoding */
"%s",/* Alt-Used */
/* setup variables for the upcoming transfer and send */
Curl_xfer_setup_sendrecv(data, FIRSTSOCKET, -1);
result = Curl_req_send(data, &req, httpversion);
httpstring,
(data->state.aptr.host ? data->state.aptr.host : ""),
#ifndef CURL_DISABLE_PROXY
data->state.aptr.proxyuserpwd ?
data->state.aptr.proxyuserpwd : "",
#else
"",
#endif
data->state.aptr.userpwd ? data->state.aptr.userpwd : "",
(data->state.use_range && data->state.aptr.rangeline) ?
data->state.aptr.rangeline : "",
(data->set.str[STRING_USERAGENT] &&
*data->set.str[STRING_USERAGENT] &&
data->state.aptr.uagent) ?
data->state.aptr.uagent : "",
p_accept ? p_accept : "",
data->state.aptr.te ? data->state.aptr.te : "",
(data->set.str[STRING_ENCODING] &&
*data->set.str[STRING_ENCODING] &&
data->state.aptr.accept_encoding) ?
data->state.aptr.accept_encoding : "",
(data->state.referer && data->state.aptr.ref) ?
data->state.aptr.ref : "" /* Referer: <data> */,
#ifndef CURL_DISABLE_PROXY
(conn->bits.httpproxy &&
!conn->bits.tunnel_proxy &&
!Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
!Curl_checkProxyheaders(data, conn,
STRCONST("Proxy-Connection"))) ?
"Proxy-Connection: Keep-Alive\r\n":"",
#else
"",
#endif
te,
altused ? altused : ""
);
if((httpversion >= 20) && data->req.upload_chunky)
/* upload_chunky was set above to set up the request in a chunky fashion,
but is disabled here again to avoid that the chunked encoded version is
actually used when sending the request body over h2 */
data->req.upload_chunky = FALSE;
out:
if(CURLE_TOO_LARGE == result)
failf(data, "HTTP request too large");
/* clear userpwd and proxyuserpwd to avoid reusing old credentials
* from reused connections */
@@ -2866,53 +2943,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
#endif
free(altused);
if(result) {
curlx_dyn_free(&req);
goto fail;
}
if(!Curl_conn_is_ssl(conn, FIRSTSOCKET) && (httpversion < 20) &&
(data->state.http_neg.wanted & CURL_HTTP_V2x) &&
data->state.http_neg.h2_upgrade) {
/* append HTTP2 upgrade magic stuff to the HTTP request if it is not done
over SSL */
result = Curl_http2_request_upgrade(&req, data);
if(result) {
curlx_dyn_free(&req);
return result;
}
}
result = http_cookies(data, conn, &req);
#ifndef CURL_DISABLE_WEBSOCKETS
if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
result = Curl_ws_request(data, &req);
#endif
if(!result)
result = Curl_add_timecondition(data, &req);
if(!result)
result = Curl_add_custom_headers(data, FALSE, httpversion, &req);
if(!result) {
/* req_send takes ownership of the 'req' memory on success */
result = http_req_complete(data, &req, httpversion, httpreq);
if(!result)
result = Curl_req_send(data, &req, httpversion);
}
curlx_dyn_free(&req);
if(result)
goto fail;
if((httpversion >= 20) && data->req.upload_chunky)
/* upload_chunky was set above to set up the request in a chunky fashion,
but is disabled here again to avoid that the chunked encoded version is
actually used when sending the request body over h2 */
data->req.upload_chunky = FALSE;
fail:
if(CURLE_TOO_LARGE == result)
failf(data, "HTTP request too large");
return result;
}

View File

@@ -106,7 +106,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, bool is_connect,
CURLcode Curl_dynhds_add_custom(struct Curl_easy *data, bool is_connect,
struct dynhds *hds);
void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
void Curl_http_method(struct Curl_easy *data,
const char **method, Curl_HttpReq *);
/* protocol-specific functions set up to be called by the main engine */

View File

@@ -1820,8 +1820,9 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
return result;
}
data->state.http_hd_upgrade = TRUE;
data->state.http_hd_h2_settings = TRUE;
result = curlx_dyn_addf(req,
"Connection: Upgrade, HTTP2-Settings\r\n"
"Upgrade: %s\r\n"
"HTTP2-Settings: %s\r\n",
NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);

View File

@@ -775,7 +775,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
}
}
Curl_http_method(data, conn, &method, &httpreq);
Curl_http_method(data, &method, &httpreq);
payload_hash =
parse_content_sha_hdr(data, curlx_str(&provider1),

View File

@@ -162,11 +162,6 @@ static CURLcode dynhds_add_custom(struct Curl_easy *data,
we will force length zero then */
hd_name_eq(name, namelen, STRCONST("Content-Length:")))
;
else if(data->state.aptr.te &&
/* when asking for Transfer-Encoding, do not pass on a custom
Connection: */
hd_name_eq(name, namelen, STRCONST("Connection:")))
;
else if((httpversion >= 20) &&
hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:")))
/* HTTP/2 and HTTP/3 do not support chunked requests */

View File

@@ -320,7 +320,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->state.aptr.uagent);
Curl_safefree(data->state.aptr.userpwd);
Curl_safefree(data->state.aptr.accept_encoding);
Curl_safefree(data->state.aptr.te);
Curl_safefree(data->state.aptr.rangeline);
Curl_safefree(data->state.aptr.ref);
Curl_safefree(data->state.aptr.host);

View File

@@ -1122,7 +1122,6 @@ struct UrlState {
#ifndef CURL_DISABLE_RTSP
char *rtsp_transport;
#endif
char *te; /* TE: request header */
/* transfer credentials */
char *user;
@@ -1178,6 +1177,11 @@ struct UrlState {
internal use and the user does not have ownership of the
handle. */
BIT(http_ignorecustom); /* ignore custom method from now */
#ifndef CURL_DISABLE_HTTP
BIT(http_hd_te); /* Added HTTP header TE: */
BIT(http_hd_upgrade); /* Added HTTP header Upgrade: */
BIT(http_hd_h2_settings); /* Added HTTP header H2Settings: */
#endif
};
/*

View File

@@ -1023,11 +1023,6 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req)
MUST include the "websocket" keyword. */
"Upgrade", "websocket"
},
{
/* The request MUST contain a |Connection| header field whose value
MUST include the "Upgrade" token. */
"Connection", "Upgrade",
},
{
/* The request MUST include a header field with the name
|Sec-WebSocket-Version|. The value of this header field MUST be
@@ -1043,7 +1038,7 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req)
"Sec-WebSocket-Key", NULL,
}
};
heads[3].val = &keyval[0];
heads[2].val = &keyval[0];
/* 16 bytes random */
result = Curl_rand(data, (unsigned char *)rand, sizeof(rand));
@@ -1065,6 +1060,7 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req)
heads[i].val);
}
}
data->state.http_hd_upgrade = TRUE;
k->upgr101 = UPGR101_WS;
return result;
}

View File

@@ -66,8 +66,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip
Connection: TE
</protocol>
</verify>

View File

@@ -176,8 +176,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip
Connection: TE
</protocol>
</verify>

View File

@@ -67,8 +67,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip
Connection: TE
</protocol>
</verify>

View File

@@ -66,8 +66,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: close, TE
TE: gzip
Connection: close, TE
</protocol>
</verify>

View File

@@ -66,8 +66,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip
Connection: TE
</protocol>
</verify>

View File

@@ -66,8 +66,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip
Connection: TE
</protocol>
</verify>

View File

@@ -183,9 +183,9 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip
Accept-Encoding: xxx
Connection: TE
</protocol>
</verify>

View File

@@ -52,8 +52,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip
Connection: TE
</protocol>
<errorcode>

View File

@@ -52,9 +52,9 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: AAMAAABkAAQAAQAAAAIAAAAA
Connection: Upgrade, HTTP2-Settings
</protocol>

View File

@@ -47,9 +47,9 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: Upgrade, HTTP2-Settings
Upgrade: %H2CVER
HTTP2-Settings: AAMAAABkAAQAAQAAAAIAAAAA
Connection: Upgrade, HTTP2-Settings
</protocol>
</verify>

View File

@@ -53,9 +53,9 @@ Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: NDMyMTUzMjE2MzIxNzMyMQ==
Connection: Upgrade
</protocol>
<errorcode>

View File

@@ -58,9 +58,9 @@ Host: %HOSTIP:%HTTPPORT
User-Agent: webbie-sox/3
Accept: */*
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: NDMyMTUzMjE2MzIxNzMyMQ==
Connection: Upgrade
%hex[%8a%00]hex%
</protocol>

View File

@@ -59,9 +59,9 @@ Host: %HOSTIP:%HTTPPORT
User-Agent: webbie-sox/3
Accept: */*
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: NDMyMTUzMjE2MzIxNzMyMQ==
Connection: Upgrade
%hex[%8a%808321]hex%
</protocol>

View File

@@ -49,9 +49,9 @@ Host: %HOSTIP:%HTTPPORT
User-Agent: webbie-sox/3
Accept: */*
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: NDMyMTUzMjE2MzIxNzMyMQ==
Connection: Upgrade
</protocol>
# 22 == CURLE_HTTP_RETURNED_ERROR

View File

@@ -58,9 +58,9 @@ Host: %HOSTIP:%HTTPPORT
User-Agent: websocket/%TESTNUMBER
Accept: */*
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: NDMyMTUzMjE2MzIxNzMyMQ==
Connection: Upgrade
</protocol>

View File

@@ -43,8 +43,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip
Connection: TE
</protocol>

View File

@@ -51,8 +51,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip
Connection: TE
</protocol>