← Commit list

4d040c71d7

Stefan Eissing
Stefan Eissing
2025-09-02
FAILED Duration: 151s

Subject

Curl_http(), decomplexify

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/http.c+308 -277
@@ -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,213 +2629,321 @@ 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;
+}
- /* 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;
+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);
- result = http_host(data, conn);
- if(result)
- goto fail;
+ if(custom && !custom_val)
+ return CURLE_OUT_OF_MEMORY;
- result = http_useragent(data);
- if(result)
- goto fail;
+ 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"));
- Curl_http_method(data, conn, &request, &httpreq);
+ free(custom_val);
+ return result;
+}
- /* setup the authentication headers */
- {
- 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,
- (pq ? pq : data->state.up.path), FALSE);
- free(pq);
- if(result)
- goto fail;
- }
+/* 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;
- 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;
- }
+ case H1_HD_HOST:
+ if(data->state.aptr.host)
+ result = curlx_dyn_add(req, data->state.aptr.host);
+ break;
- 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);
+#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
- /* we only consider transfer-encoding magic if libz support is built-in */
- result = http_transferencode(data);
- if(result)
- goto fail;
+ 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;
- httpversion = http_request_version(data);
- httpstring = get_http_string(httpversion);
+ 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;
- result = http_req_set_reader(data, httpreq, httpversion, &te);
- if(result)
- goto fail;
+ 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
- p_accept = Curl_checkheaders(data,
- STRCONST("Accept")) ? NULL : "Accept: */*\r\n";
+ case H1_HD_TRANSFER_ENCODING:
+ result = http_req_set_TE(data, req, httpversion);
+ break;
- result = http_range(data, httpreq);
- if(result)
- goto fail;
+#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);
- /* 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;
+ if(!data->conn->bits.reuse) {
+ result = http_check_new_conn(data);
+ 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 */
-
- 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 : ""
- );
+ /* 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 out;
- /* clear userpwd and proxyuserpwd to avoid reusing old credentials
- * from reused connections */
- Curl_safefree(data->state.aptr.userpwd);
-#ifndef CURL_DISABLE_PROXY
- Curl_safefree(data->state.aptr.proxyuserpwd);
-#endif
- free(altused);
+ data->state.http_hd_te = FALSE;
+ data->state.http_hd_upgrade = FALSE;
+ data->state.http_hd_h2_settings = FALSE;
- if(result) {
- curlx_dyn_free(&req);
- goto fail;
- }
+ /* what kind of request do we need to send? */
+ Curl_http_method(data, &method, &httpreq);
- 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;
+ /* 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, data->conn, method, httpreq,
+ (pq ? pq : data->state.up.path), FALSE);
+ free(pq);
}
+ if(result)
+ goto out;
- 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
+ result = http_useragent(data);
+ if(result)
+ goto out;
+
+ /* Setup input reader, resume information and ranges */
+ result = set_reader(data, httpreq);
if(!result)
- result = Curl_add_timecondition(data, &req);
+ result = http_resume(data, httpreq);
if(!result)
- result = Curl_add_custom_headers(data, FALSE, httpversion, &req);
+ result = http_range(data, httpreq);
+ if(result)
+ goto out;
- 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);
+ httpversion = http_request_version(data);
+ /* 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;
}
- curlx_dyn_free(&req);
- if(result)
- goto fail;
+
+ /* setup variables for the upcoming transfer and send */
+ Curl_xfer_setup_sendrecv(data, FIRSTSOCKET, -1);
+ result = Curl_req_send(data, &req, httpversion);
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:
+
+out:
if(CURLE_TOO_LARGE == result)
failf(data, "HTTP request too large");
+
+ /* clear userpwd and proxyuserpwd to avoid reusing old credentials
+ * from reused connections */
+ Curl_safefree(data->state.aptr.userpwd);
+#ifndef CURL_DISABLE_PROXY
+ Curl_safefree(data->state.aptr.proxyuserpwd);
+#endif
+ curlx_dyn_free(&req);
return result;
}
lib/http.h+1 -1
@@ -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 */
lib/http2.c+2 -1
@@ -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);
lib/http_aws_sigv4.c+1 -1
@@ -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),
lib/http_proxy.c+0 -5
@@ -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 */
lib/url.c+0 -1
@@ -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);
lib/urldata.h+5 -1
@@ -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
};
/*
lib/ws.c+2 -6
@@ -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;
}
tests/data/test1122+1 -1
@@ -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>
tests/data/test1123+1 -1
@@ -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>
tests/data/test1124+1 -1
@@ -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>
tests/data/test1125+1 -1
@@ -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>
tests/data/test1170+1 -1
@@ -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>
tests/data/test1171+1 -1
@@ -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>
tests/data/test1277+1 -1
@@ -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>
tests/data/test1546+1 -1
@@ -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>
tests/data/test1704+1 -1
@@ -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>
tests/data/test1800+1 -1
@@ -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>
tests/data/test2300+1 -1
@@ -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>
tests/data/test2301+1 -1
@@ -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>
tests/data/test2302+1 -1
@@ -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>
tests/data/test2303+1 -1
@@ -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
tests/data/test2304+1 -1
@@ -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>
tests/data/test387+1 -1
@@ -43,8 +43,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
-Connection: TE
TE: gzip
+Connection: TE
</protocol>
tests/data/test418+1 -1
@@ -51,8 +51,8 @@ GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
-Connection: TE
TE: gzip
+Connection: TE
</protocol>