From ca2a80266834bba8f490fd9ac51f77d1b8606d93 Mon Sep 17 00:00:00 2001 From: Haibo Huang Date: Fri, 10 Jul 2020 20:17:42 -0700 Subject: Upgrade curl to curl-7_71_1 Change-Id: Ief1f908509a0dd7944004e102310c255e42e4803 --- lib/http.c | 811 ++++++++++++++++++++++++++----------------------------------- 1 file changed, 344 insertions(+), 467 deletions(-) (limited to 'lib/http.c') diff --git a/lib/http.c b/lib/http.c index c3f7c350..28d66c28 100644 --- a/lib/http.c +++ b/lib/http.c @@ -125,7 +125,8 @@ const struct Curl_handler Curl_handler_http = { ZERO_NULL, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ - PROTOPT_CREDSPERREQUEST /* flags */ + PROTOPT_CREDSPERREQUEST | /* flags */ + PROTOPT_USERPWDCTRL }; #ifdef USE_SSL @@ -150,7 +151,8 @@ const struct Curl_handler Curl_handler_https = { ZERO_NULL, /* connection_check */ PORT_HTTPS, /* defport */ CURLPROTO_HTTPS, /* protocol */ - PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN | /* flags */ + PROTOPT_USERPWDCTRL }; #endif @@ -268,7 +270,7 @@ char *Curl_copy_header_value(const char *header) return NULL; memcpy(value, start, len); - value[len] = 0; /* zero terminate */ + value[len] = 0; /* null-terminate */ return value; } @@ -292,17 +294,21 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) char *out; if(proxy) { - userp = &conn->allocptr.proxyuserpwd; +#ifndef CURL_DISABLE_PROXY + userp = &data->state.aptr.proxyuserpwd; user = conn->http_proxy.user; pwd = conn->http_proxy.passwd; +#else + return CURLE_NOT_BUILT_IN; +#endif } else { - userp = &conn->allocptr.userpwd; + userp = &data->state.aptr.userpwd; user = conn->user; pwd = conn->passwd; } - out = aprintf("%s:%s", user, pwd); + out = aprintf("%s:%s", user, pwd ? pwd : ""); if(!out) return CURLE_OUT_OF_MEMORY; @@ -340,8 +346,9 @@ static CURLcode http_output_bearer(struct connectdata *conn) { char **userp; CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; - userp = &conn->allocptr.userpwd; + userp = &data->state.aptr.userpwd; free(*userp); *userp = aprintf("Authorization: Bearer %s\r\n", conn->data->set.str[STRING_BEARER]); @@ -427,7 +434,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) skip this rewinding stuff */ return CURLE_OK; - switch(data->set.httpreq) { + switch(data->state.httpreq) { case HTTPREQ_GET: case HTTPREQ_HEAD: return CURLE_OK; @@ -448,7 +455,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) } else { /* figure out how much data we are expected to send */ - switch(data->set.httpreq) { + switch(data->state.httpreq) { case HTTPREQ_POST: case HTTPREQ_PUT: if(data->state.infilesize != -1) @@ -578,6 +585,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) conn->data->set.httpversion = CURL_HTTP_VERSION_1_1; } } +#ifndef CURL_DISABLE_PROXY if(conn->bits.proxy_user_passwd && ((data->req.httpcode == 407) || (conn->bits.authneg && data->req.httpcode < 300))) { @@ -586,10 +594,11 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) if(!pickproxy) data->state.authproblem = TRUE; } +#endif if(pickhost || pickproxy) { - if((data->set.httpreq != HTTPREQ_GET) && - (data->set.httpreq != HTTPREQ_HEAD) && + if((data->state.httpreq != HTTPREQ_GET) && + (data->state.httpreq != HTTPREQ_HEAD) && !conn->bits.rewindaftersend) { result = http_perhapsrewind(conn); if(result) @@ -610,8 +619,8 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) authentication is not "done" yet and no authentication seems to be required and we didn't try HEAD or GET */ - if((data->set.httpreq != HTTPREQ_GET) && - (data->set.httpreq != HTTPREQ_HEAD)) { + if((data->state.httpreq != HTTPREQ_GET) && + (data->state.httpreq != HTTPREQ_HEAD)) { data->req.newurl = strdup(data->change.url); /* clone URL */ if(!data->req.newurl) return CURLE_OUT_OF_MEMORY; @@ -689,10 +698,13 @@ output_auth_headers(struct connectdata *conn, #endif if(authstatus->picked == CURLAUTH_BASIC) { /* Basic */ - if((proxy && conn->bits.proxy_user_passwd && - !Curl_checkProxyheaders(conn, "Proxy-authorization")) || - (!proxy && conn->bits.user_passwd && - !Curl_checkheaders(conn, "Authorization"))) { + if( +#ifndef CURL_DISABLE_PROXY + (proxy && conn->bits.proxy_user_passwd && + !Curl_checkProxyheaders(conn, "Proxy-authorization")) || +#endif + (!proxy && conn->bits.user_passwd && + !Curl_checkheaders(conn, "Authorization"))) { auth = "Basic"; result = http_output_basic(conn, proxy); if(result) @@ -719,10 +731,15 @@ output_auth_headers(struct connectdata *conn, } if(auth) { +#ifndef CURL_DISABLE_PROXY infof(data, "%s auth using %s with user '%s'\n", proxy ? "Proxy" : "Server", auth, proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") : - (conn->user ? conn->user : "")); + (conn->user ? conn->user : "")); +#else + infof(data, "Server auth using %s with user '%s'\n", + auth, conn->user ? conn->user : ""); +#endif authstatus->multipass = (!authstatus->done) ? TRUE : FALSE; } else @@ -762,7 +779,10 @@ Curl_http_output_auth(struct connectdata *conn, authhost = &data->state.authhost; authproxy = &data->state.authproxy; - if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || + if( +#ifndef CURL_DISABLE_PROXY + (conn->bits.httpproxy && conn->bits.proxy_user_passwd) || +#endif conn->bits.user_passwd || data->set.str[STRING_BEARER]) /* continue please */; else { @@ -1067,8 +1087,10 @@ static int http_should_fail(struct connectdata *conn) */ if((httpcode == 401) && !conn->bits.user_passwd) return TRUE; +#ifndef CURL_DISABLE_PROXY if((httpcode == 407) && !conn->bits.proxy_user_passwd) return TRUE; +#endif return data->state.authproblem; } @@ -1125,49 +1147,20 @@ static size_t readmoredata(char *buffer, return fullsize; } -/* ------------------------------------------------------------------------- */ -/* add_buffer functions */ - -/* - * Curl_add_buffer_init() sets up and returns a fine buffer struct - */ -Curl_send_buffer *Curl_add_buffer_init(void) -{ - return calloc(1, sizeof(Curl_send_buffer)); -} - -/* - * Curl_add_buffer_free() frees all associated resources. - */ -void Curl_add_buffer_free(Curl_send_buffer **inp) -{ - Curl_send_buffer *in; - if(!inp) - return; - in = *inp; - if(in) { /* deal with NULL input */ - free(in->buffer); - free(in); - } - *inp = NULL; -} - /* - * Curl_add_buffer_send() sends a header buffer and frees all associated + * Curl_buffer_send() sends a header buffer and frees all associated * memory. Body data may be appended to the header data if desired. * * Returns CURLcode */ -CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, - struct connectdata *conn, - - /* add the number of sent bytes to this - counter */ - curl_off_t *bytes_written, - - /* how much of the buffer contains body data */ - size_t included_body_bytes, - int socketindex) +CURLcode Curl_buffer_send(struct dynbuf *in, + struct connectdata *conn, + /* add the number of sent bytes to this + counter */ + curl_off_t *bytes_written, + /* how much of the buffer contains body data */ + size_t included_body_bytes, + int socketindex) { ssize_t amount; CURLcode result; @@ -1178,7 +1171,6 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, size_t sendsize; curl_socket_t sockfd; size_t headersize; - Curl_send_buffer *in = *inp; DEBUGASSERT(socketindex <= SECONDARYSOCKET); @@ -1187,8 +1179,8 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, /* The looping below is required since we use non-blocking sockets, but due to the circumstances we will just loop and try again and again etc */ - ptr = in->buffer; - size = in->size_used; + ptr = Curl_dyn_ptr(in); + size = Curl_dyn_len(in); headersize = size - included_body_bytes; /* the initial part that isn't body is header */ @@ -1199,12 +1191,15 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, /* Curl_convert_to_network calls failf if unsuccessful */ if(result) { /* conversion failed, free memory and return to the caller */ - Curl_add_buffer_free(inp); + Curl_dyn_free(in); return result; } - if((conn->handler->flags & PROTOPT_SSL || - conn->http_proxy.proxytype == CURLPROXY_HTTPS) + if((conn->handler->flags & PROTOPT_SSL +#ifndef CURL_DISABLE_PROXY + || conn->http_proxy.proxytype == CURLPROXY_HTTPS +#endif + ) && conn->httpversion != 20) { /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk when we speak HTTPS, as if only a fraction of it is sent now, this data @@ -1223,7 +1218,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, result = Curl_get_upload_buffer(data); if(result) { /* malloc failed, free memory and return to the caller */ - Curl_add_buffer_free(&in); + Curl_dyn_free(in); return result; } memcpy(data->state.ulbuf, ptr, sendsize); @@ -1286,7 +1281,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, size -= amount; - ptr = in->buffer + amount; + ptr = Curl_dyn_ptr(in) + amount; /* backup the currently set pointers */ http->backup.fread_func = data->state.fread_func; @@ -1300,7 +1295,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, http->postdata = ptr; http->postsize = (curl_off_t)size; - http->send_buffer = in; + http->send_buffer = *in; /* copy the whole struct */ http->sending = HTTPSEND_REQUEST; return CURLE_OK; @@ -1320,87 +1315,11 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp, return CURLE_SEND_ERROR; } } - Curl_add_buffer_free(&in); + Curl_dyn_free(in); return result; } - -/* - * add_bufferf() add the formatted input to the buffer. - */ -CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...) -{ - char *s; - va_list ap; - va_start(ap, fmt); - s = vaprintf(fmt, ap); /* this allocs a new string to append */ - va_end(ap); - - if(s) { - CURLcode result = Curl_add_buffer(inp, s, strlen(s)); - free(s); - return result; - } - /* If we failed, we cleanup the whole buffer and return error */ - Curl_add_buffer_free(inp); - return CURLE_OUT_OF_MEMORY; -} - -/* - * Curl_add_buffer() appends a memory chunk to the existing buffer - */ -CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr, - size_t size) -{ - char *new_rb; - Curl_send_buffer *in = *inp; - - if(~size < in->size_used) { - /* If resulting used size of send buffer would wrap size_t, cleanup - the whole buffer and return error. Otherwise the required buffer - size will fit into a single allocatable memory chunk */ - Curl_add_buffer_free(inp); - return CURLE_OUT_OF_MEMORY; - } - - if(!in->buffer || - ((in->size_used + size) > (in->size_max - 1))) { - /* If current buffer size isn't enough to hold the result, use a - buffer size that doubles the required size. If this new size - would wrap size_t, then just use the largest possible one */ - size_t new_size; - - if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) || - (~(size * 2) < (in->size_used * 2))) - new_size = (size_t)-1; - else - new_size = (in->size_used + size) * 2; - - if(in->buffer) - /* we have a buffer, enlarge the existing one */ - new_rb = Curl_saferealloc(in->buffer, new_size); - else - /* create a new buffer */ - new_rb = malloc(new_size); - - if(!new_rb) { - /* If we failed, we cleanup the whole buffer and return error */ - free(in); - *inp = NULL; - return CURLE_OUT_OF_MEMORY; - } - - in->buffer = new_rb; - in->size_max = new_size; - } - memcpy(&in->buffer[in->size_used], inptr, size); - - in->size_used += size; - - return CURLE_OK; -} - /* end of the add_buffer functions */ /* ------------------------------------------------------------------------- */ @@ -1473,6 +1392,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) function to make the re-use checks properly be able to check this bit. */ connkeep(conn, "HTTP default"); +#ifndef CURL_DISABLE_PROXY /* the CONNECT procedure might not have been completed */ result = Curl_proxy_connect(conn, FIRSTSOCKET); if(result) @@ -1489,7 +1409,6 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; -#ifndef CURL_DISABLE_PROXY if(conn->data->set.haproxyprotocol) { /* add HAProxy PROXY protocol header */ result = add_haproxy_protocol_header(conn); @@ -1525,7 +1444,7 @@ static int http_getsock_do(struct connectdata *conn, static CURLcode add_haproxy_protocol_header(struct connectdata *conn) { char proxy_header[128]; - Curl_send_buffer *req_buffer; + struct dynbuf req; CURLcode result; char tcp_version[5]; @@ -1546,19 +1465,14 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn) conn->data->info.conn_local_port, conn->data->info.conn_primary_port); - req_buffer = Curl_add_buffer_init(); - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&req, DYN_HAXPROXY); - result = Curl_add_bufferf(&req_buffer, proxy_header); + result = Curl_dyn_add(&req, proxy_header); if(result) return result; - result = Curl_add_buffer_send(&req_buffer, - conn, - &conn->data->info.request_size, - 0, - FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &conn->data->info.request_size, + 0, FIRSTSOCKET); return result; } @@ -1619,14 +1533,11 @@ CURLcode Curl_http_done(struct connectdata *conn, if(!http) return CURLE_OK; - if(http->send_buffer) { - Curl_add_buffer_free(&http->send_buffer); - } - + Curl_dyn_free(&http->send_buffer); Curl_http2_done(data, premature); Curl_quic_done(data, premature); - Curl_mime_cleanpart(&http->form); + Curl_dyn_reset(&data->state.headerb); if(status) return status; @@ -1692,7 +1603,7 @@ static const char *get_http_string(const struct Curl_easy *data, /* check and possibly add an Expect: header */ static CURLcode expect100(struct Curl_easy *data, struct connectdata *conn, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { CURLcode result = CURLE_OK; data->state.expect100header = FALSE; /* default to false unless it is set @@ -1708,8 +1619,7 @@ static CURLcode expect100(struct Curl_easy *data, Curl_compareheader(ptr, "Expect:", "100-continue"); } else { - result = Curl_add_bufferf(&req_buffer, - "Expect: 100-continue\r\n"); + result = Curl_dyn_add(req, "Expect: 100-continue\r\n"); if(!result) data->state.expect100header = TRUE; } @@ -1728,7 +1638,7 @@ enum proxy_use { will return an error code if one of the headers is not formatted correctly */ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, - Curl_send_buffer **buffer, + struct dynbuf *b, struct Curl_easy *handle) { char *ptr = NULL; @@ -1754,8 +1664,10 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, /* only add correctly formatted trailers */ ptr = strchr(trailers->data, ':'); if(ptr && *(ptr + 1) == ' ') { - result = Curl_add_bufferf(buffer, "%s%s", trailers->data, - endofline_native); + result = Curl_dyn_add(b, trailers->data); + if(result) + return result; + result = Curl_dyn_add(b, endofline_native); if(result) return result; } @@ -1763,14 +1675,13 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers, infof(handle, "Malformatted trailing header ! Skipping trailer."); trailers = trailers->next; } - result = Curl_add_buffer(buffer, endofline_network, - strlen(endofline_network)); + result = Curl_dyn_add(b, endofline_network); return result; } CURLcode Curl_add_custom_headers(struct connectdata *conn, bool is_connect, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { char *ptr; struct curl_slist *h[2]; @@ -1779,6 +1690,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, struct Curl_easy *data = conn->data; int i; +#ifndef CURL_DISABLE_PROXY enum proxy_use proxy; if(is_connect) @@ -1805,6 +1717,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, h[0] = data->set.headers; break; } +#else + (void)is_connect; + h[0] = data->set.headers; +#endif /* loop through one or two lists */ for(i = 0; i < numlists; i++) { @@ -1832,7 +1748,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, /* copy the source */ semicolonp = strdup(headers->data); if(!semicolonp) { - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(req); return CURLE_OUT_OF_MEMORY; } /* put a colon where the semicolon is */ @@ -1856,16 +1772,16 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, CURLcode result = CURLE_OK; char *compare = semicolonp ? semicolonp : headers->data; - if(conn->allocptr.host && + if(data->state.aptr.host && /* a Host: header was sent already, don't pass on any custom Host: header as that will produce *two* in the same request! */ checkprefix("Host:", compare)) ; - else if(data->set.httpreq == HTTPREQ_POST_FORM && + else if(data->state.httpreq == HTTPREQ_POST_FORM && /* this header (extended by formdata.c) is sent later */ checkprefix("Content-Type:", compare)) ; - else if(data->set.httpreq == HTTPREQ_POST_MIME && + else if(data->state.httpreq == HTTPREQ_POST_MIME && /* this header is sent later */ checkprefix("Content-Type:", compare)) ; @@ -1874,7 +1790,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, we will force length zero then */ checkprefix("Content-Length:", compare)) ; - else if(conn->allocptr.te && + else if(data->state.aptr.te && /* when asking for Transfer-Encoding, don't pass on a custom Connection: */ checkprefix("Connection:", compare)) @@ -1893,7 +1809,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, !strcasecompare(data->state.first_host, conn->host.name))) ; else { - result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare); + result = Curl_dyn_addf(req, "%s\r\n", compare); } if(semicolonp) free(semicolonp); @@ -1910,7 +1826,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, #ifndef CURL_DISABLE_PARSEDATE CURLcode Curl_add_timecondition(const struct connectdata *conn, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { struct Curl_easy *data = conn->data; const struct tm *tm; @@ -1969,17 +1885,17 @@ CURLcode Curl_add_timecondition(const struct connectdata *conn, tm->tm_min, tm->tm_sec); - result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr)); + result = Curl_dyn_add(req, datestr); return result; } #else /* disabled */ CURLcode Curl_add_timecondition(const struct connectdata *conn, - Curl_send_buffer *req_buffer) + struct dynbuf *req) { (void)conn; - (void)req_buffer; + (void)req; return CURLE_OK; } #endif @@ -2002,13 +1918,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) const char *te = ""; /* transfer-encoding */ const char *ptr; const char *request; - Curl_HttpReq httpreq = data->set.httpreq; + Curl_HttpReq httpreq = data->state.httpreq; #if !defined(CURL_DISABLE_COOKIES) char *addcookies = NULL; #endif curl_off_t included_body = 0; const char *httpstring; - Curl_send_buffer *req_buffer; + struct dynbuf req; curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ char *altused = NULL; @@ -2036,13 +1952,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) #ifdef USE_NGHTTP2 if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { +#ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { /* We don't support HTTP/2 proxies yet. Also it's debatable whether or not this setting should apply to HTTP/2 proxies. */ infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n"); break; } - +#endif DEBUGF(infof(data, "HTTP/2 over clean TCP\n")); conn->httpversion = 20; @@ -2116,8 +2033,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) with the user-agent string specified, we erase the previously made string here. */ if(Curl_checkheaders(conn, "User-Agent")) { - free(conn->allocptr.uagent); - conn->allocptr.uagent = NULL; + free(data->state.aptr.uagent); + data->state.aptr.uagent = NULL; } /* setup the authentication headers */ @@ -2145,14 +2062,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else conn->bits.authneg = FALSE; - Curl_safefree(conn->allocptr.ref); + Curl_safefree(data->state.aptr.ref); if(data->change.referer && !Curl_checkheaders(conn, "Referer")) { - conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); - if(!conn->allocptr.ref) + data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer); + if(!data->state.aptr.ref) return CURLE_OUT_OF_MEMORY; } else - conn->allocptr.ref = NULL; + data->state.aptr.ref = NULL; #if !defined(CURL_DISABLE_COOKIES) if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie")) @@ -2161,15 +2078,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!Curl_checkheaders(conn, "Accept-Encoding") && data->set.str[STRING_ENCODING]) { - Curl_safefree(conn->allocptr.accept_encoding); - conn->allocptr.accept_encoding = + Curl_safefree(data->state.aptr.accept_encoding); + data->state.aptr.accept_encoding = aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); - if(!conn->allocptr.accept_encoding) + if(!data->state.aptr.accept_encoding) return CURLE_OUT_OF_MEMORY; } else { - Curl_safefree(conn->allocptr.accept_encoding); - conn->allocptr.accept_encoding = NULL; + Curl_safefree(data->state.aptr.accept_encoding); + data->state.aptr.accept_encoding = NULL; } #ifdef HAVE_LIBZ @@ -2185,7 +2102,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) char *cptr = Curl_checkheaders(conn, "Connection"); #define TE_HEADER "TE: gzip\r\n" - Curl_safefree(conn->allocptr.te); + Curl_safefree(data->state.aptr.te); if(cptr) { cptr = Curl_copy_header_value(cptr); @@ -2194,11 +2111,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } /* Create the (updated) Connection: header */ - conn->allocptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, + data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, cptr ? cptr : "", (cptr && *cptr) ? ", ":""); free(cptr); - if(!conn->allocptr.te) + if(!data->state.aptr.te) return CURLE_OUT_OF_MEMORY; } #endif @@ -2281,7 +2198,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) te = "Transfer-Encoding: chunked\r\n"; } - Curl_safefree(conn->allocptr.host); + Curl_safefree(data->state.aptr.host); ptr = Curl_checkheaders(conn, "Host"); if(ptr && (!data->state.this_is_a_follow || @@ -2316,19 +2233,19 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(colon) *colon = 0; /* The host must not include an embedded port number */ } - Curl_safefree(conn->allocptr.cookiehost); - conn->allocptr.cookiehost = cookiehost; + Curl_safefree(data->state.aptr.cookiehost); + data->state.aptr.cookiehost = cookiehost; } #endif if(strcmp("Host:", ptr)) { - conn->allocptr.host = aprintf("Host:%s\r\n", &ptr[5]); - if(!conn->allocptr.host) + data->state.aptr.host = aprintf("Host:%s\r\n", &ptr[5]); + if(!data->state.aptr.host) return CURLE_OUT_OF_MEMORY; } else /* when clearing the header */ - conn->allocptr.host = NULL; + data->state.aptr.host = NULL; } else { /* When building Host: headers, we must put the host name within @@ -2340,18 +2257,18 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (conn->remote_port == PORT_HTTP)) ) /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include the port number in the host string */ - conn->allocptr.host = aprintf("Host: %s%s%s\r\n", + data->state.aptr.host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"", host, conn->bits.ipv6_ip?"]":""); else - conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n", + data->state.aptr.host = aprintf("Host: %s%s%s:%d\r\n", conn->bits.ipv6_ip?"[":"", host, conn->bits.ipv6_ip?"]":"", conn->remote_port); - if(!conn->allocptr.host) + if(!data->state.aptr.host) /* without Host: we can't make a nice request */ return CURLE_OUT_OF_MEMORY; } @@ -2432,7 +2349,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->set.prefer_ascii ? 'a' : 'i'); } } - if(conn->bits.user_passwd && !conn->bits.userpwd_in_url) + if(conn->bits.user_passwd) paste_ftp_userpwd = TRUE; } } @@ -2522,21 +2439,21 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && !Curl_checkheaders(conn, "Range")) { /* if a line like this was already allocated, free the previous one */ - free(conn->allocptr.rangeline); - conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", + free(data->state.aptr.rangeline); + data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n", data->state.range); } else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && !Curl_checkheaders(conn, "Content-Range")) { /* if a line like this was already allocated, free the previous one */ - free(conn->allocptr.rangeline); + free(data->state.aptr.rangeline); if(data->set.set_resume_from < 0) { /* Upload resume was asked for, but we don't know the size of the remote part so we tell the server (and act accordingly) that we upload the whole file (again) */ - conn->allocptr.rangeline = + data->state.aptr.rangeline = aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T "/%" CURL_FORMAT_CURL_OFF_T "\r\n", data->state.infilesize - 1, data->state.infilesize); @@ -2546,7 +2463,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* This is because "resume" was selected */ curl_off_t total_expected_size = data->state.resume_from + data->state.infilesize; - conn->allocptr.rangeline = + data->state.aptr.rangeline = aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T "/%" CURL_FORMAT_CURL_OFF_T "\r\n", data->state.range, total_expected_size-1, @@ -2555,11 +2472,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else { /* Range was selected and then we just pass the incoming range and append total size */ - conn->allocptr.rangeline = + data->state.aptr.rangeline = aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n", data->state.range, data->state.infilesize); } - if(!conn->allocptr.rangeline) + if(!data->state.aptr.rangeline) return CURLE_OUT_OF_MEMORY; } } @@ -2567,14 +2484,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) httpstring = get_http_string(data, conn); /* initialize a dynamic send-buffer */ - req_buffer = Curl_add_buffer_init(); - - if(!req_buffer) - return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&req, DYN_HTTP_REQUEST); /* add the main request stuff */ /* GET/HEAD/POST/PUT */ - result = Curl_add_bufferf(&req_buffer, "%s ", request); + result = Curl_dyn_addf(&req, "%s ", request); if(result) return result; @@ -2587,21 +2501,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* url */ if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { char *url = data->set.str[STRING_TEMP_URL]; - result = Curl_add_buffer(&req_buffer, url, strlen(url)); + result = Curl_dyn_add(&req, url); Curl_safefree(data->set.str[STRING_TEMP_URL]); } else #endif if(paste_ftp_userpwd) - result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s", - conn->user, conn->passwd, - path + sizeof("ftp://") - 1); + result = Curl_dyn_addf(&req, "ftp://%s:%s@%s", conn->user, conn->passwd, + path + sizeof("ftp://") - 1); else { - result = Curl_add_buffer(&req_buffer, path, strlen(path)); + result = Curl_dyn_add(&req, path); if(result) return result; if(query) - result = Curl_add_bufferf(&req_buffer, "?%s", query); + result = Curl_dyn_addf(&req, "?%s", query); } if(result) return result; @@ -2611,60 +2524,64 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) altused = aprintf("Alt-Used: %s:%d\r\n", conn->conn_to_host.name, conn->conn_to_port); if(!altused) { - Curl_add_buffer_free(&req_buffer); + Curl_dyn_free(&req); return CURLE_OUT_OF_MEMORY; } } #endif result = - Curl_add_bufferf(&req_buffer, - "%s" /* ftp typecode (;type=x) */ - " 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 */ - - ftp_typecode, - httpstring, - (conn->allocptr.host?conn->allocptr.host:""), - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - conn->allocptr.userpwd?conn->allocptr.userpwd:"", - (data->state.use_range && conn->allocptr.rangeline)? - conn->allocptr.rangeline:"", - (data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT] && - conn->allocptr.uagent)? - conn->allocptr.uagent:"", - http->p_accept?http->p_accept:"", - conn->allocptr.te?conn->allocptr.te:"", - (data->set.str[STRING_ENCODING] && - *data->set.str[STRING_ENCODING] && - conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)? - conn->allocptr.ref:"" /* Referer: */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !Curl_checkProxyheaders(conn, "Proxy-Connection"))? - "Proxy-Connection: Keep-Alive\r\n":"", - te, - altused ? altused : "" + Curl_dyn_addf(&req, + "%s" /* ftp typecode (;type=x) */ + " 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 */ + + ftp_typecode, + httpstring, + (data->state.aptr.host?data->state.aptr.host:""), + data->state.aptr.proxyuserpwd? + data->state.aptr.proxyuserpwd:"", + 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:"", + http->p_accept?http->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->change.referer && data->state.aptr.ref)? + data->state.aptr.ref:"" /* Referer: */, +#ifndef CURL_DISABLE_PROXY + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !Curl_checkProxyheaders(conn, "Proxy-Connection"))? + "Proxy-Connection: Keep-Alive\r\n":"", +#else + "", +#endif + te, + altused ? altused : "" ); /* clear userpwd and proxyuserpwd to avoid re-using old credentials * from re-used connections */ - Curl_safefree(conn->allocptr.userpwd); - Curl_safefree(conn->allocptr.proxyuserpwd); + Curl_safefree(data->state.aptr.userpwd); + Curl_safefree(data->state.aptr.proxyuserpwd); free(altused); if(result) @@ -2675,7 +2592,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (data->set.httpversion == CURL_HTTP_VERSION_2)) { /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done over SSL */ - result = Curl_http2_request_upgrade(req_buffer, conn); + result = Curl_http2_request_upgrade(&req, conn); if(result) return result; } @@ -2688,8 +2605,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(data->cookies && data->state.cookie_engine) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); co = Curl_cookie_getlist(data->cookies, - conn->allocptr.cookiehost? - conn->allocptr.cookiehost:host, + data->state.aptr.cookiehost? + data->state.aptr.cookiehost:host, data->state.up.path, (conn->handler->protocol&CURLPROTO_HTTPS)? TRUE:FALSE); @@ -2701,13 +2618,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) while(co) { if(co->value) { if(0 == count) { - result = Curl_add_bufferf(&req_buffer, "Cookie: "); + result = Curl_dyn_add(&req, "Cookie: "); if(result) break; } - result = Curl_add_bufferf(&req_buffer, - "%s%s=%s", count?"; ":"", - co->name, co->value); + result = Curl_dyn_addf(&req, "%s%s=%s", count?"; ":"", + co->name, co->value); if(result) break; count++; @@ -2718,26 +2634,25 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(addcookies && !result) { if(!count) - result = Curl_add_bufferf(&req_buffer, "Cookie: "); + result = Curl_dyn_add(&req, "Cookie: "); if(!result) { - result = Curl_add_bufferf(&req_buffer, "%s%s", count?"; ":"", - addcookies); + result = Curl_dyn_addf(&req, "%s%s", count?"; ":"", addcookies); count++; } } if(count && !result) - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; } #endif - result = Curl_add_timecondition(conn, req_buffer); + result = Curl_add_timecondition(conn, &req); if(result) return result; - result = Curl_add_custom_headers(conn, FALSE, req_buffer); + result = Curl_add_custom_headers(conn, FALSE, &req); if(result) return result; @@ -2760,20 +2675,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if((postsize != -1) && !data->req.upload_chunky && (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* only add Content-Length if not uploading chunked */ - result = Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); + result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } if(postsize != 0) { - result = expect100(data, conn, req_buffer); + result = expect100(data, conn, &req); if(result) return result; } - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers */ + /* end of headers */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; @@ -2781,8 +2696,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_pgrsSetUploadSize(data, postsize); /* this sends the buffer and frees all the buffer resources */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending PUT request"); else @@ -2798,12 +2713,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* This is form posting using mime data. */ if(conn->bits.authneg) { /* nothing to post! */ - result = Curl_add_bufferf(&req_buffer, "Content-Length: 0\r\n\r\n"); + result = Curl_dyn_add(&req, "Content-Length: 0\r\n\r\n"); if(result) return result; - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending POST request"); else @@ -2821,9 +2736,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ - result = Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); + result = Curl_dyn_addf(&req, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } @@ -2834,7 +2749,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) struct curl_slist *hdr; for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) { - result = Curl_add_bufferf(&req_buffer, "%s\r\n", hdr->data); + result = Curl_dyn_addf(&req, "%s\r\n", hdr->data); if(result) return result; } @@ -2851,7 +2766,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_compareheader(ptr, "Expect:", "100-continue"); } else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { - result = expect100(data, conn, req_buffer); + result = expect100(data, conn, &req); if(result) return result; } @@ -2859,7 +2774,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->state.expect100header = FALSE; /* make the request end in a true CRLF */ - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; @@ -2872,8 +2787,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->sending = HTTPSEND_BODY; /* this sends the buffer and frees all the buffer resources */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending POST request"); else @@ -2901,17 +2816,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ - result = Curl_add_bufferf(&req_buffer, - "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", postsize); + result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T + "\r\n", postsize); if(result) return result; } if(!Curl_checkheaders(conn, "Content-Type")) { - result = Curl_add_bufferf(&req_buffer, - "Content-Type: application/" - "x-www-form-urlencoded\r\n"); + result = Curl_dyn_add(&req, "Content-Type: application/" + "x-www-form-urlencoded\r\n"); if(result) return result; } @@ -2926,7 +2839,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_compareheader(ptr, "Expect:", "100-continue"); } else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { - result = expect100(data, conn, req_buffer); + result = expect100(data, conn, &req); if(result) return result; } @@ -2947,31 +2860,32 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) is no magic limit but only set to prevent really huge POSTs to get the data duplicated with malloc() and family. */ - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ + /* end of headers! */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; if(!data->req.upload_chunky) { /* We're not sending it 'chunked', append it to the request already now to reduce the number if send() calls */ - result = Curl_add_buffer(&req_buffer, data->set.postfields, - (size_t)postsize); + result = Curl_dyn_addn(&req, data->set.postfields, + (size_t)postsize); included_body = postsize; } else { if(postsize) { /* Append the POST data chunky-style */ - result = Curl_add_bufferf(&req_buffer, "%x\r\n", (int)postsize); + result = Curl_dyn_addf(&req, "%x\r\n", (int)postsize); if(!result) { - result = Curl_add_buffer(&req_buffer, data->set.postfields, - (size_t)postsize); + result = Curl_dyn_addn(&req, data->set.postfields, + (size_t)postsize); if(!result) - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); included_body = postsize + 2; } } if(!result) - result = Curl_add_buffer(&req_buffer, "\x30\x0d\x0a\x0d\x0a", 5); + result = Curl_dyn_add(&req, "\x30\x0d\x0a\x0d\x0a"); /* 0 CR LF CR LF */ included_body += 5; } @@ -2993,21 +2907,22 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, http->postsize); - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ + /* end of headers! */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; } } else { - result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */ + /* end of headers! */ + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; if(data->req.upload_chunky && conn->bits.authneg) { /* Chunky upload is selected and we're negotiating auth still, send end-of-data only */ - result = Curl_add_buffer(&req_buffer, - "\x30\x0d\x0a\x0d\x0a", 5); + result = Curl_dyn_add(&req, (char *)"\x30\x0d\x0a\x0d\x0a"); /* 0 CR LF CR LF */ if(result) return result; @@ -3027,8 +2942,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } /* issue the request */ - result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size, - (size_t)included_body, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, + (size_t)included_body, FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP POST request"); @@ -3038,13 +2953,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) break; default: - result = Curl_add_buffer(&req_buffer, "\r\n", 2); + result = Curl_dyn_add(&req, "\r\n"); if(result) return result; /* issue the request */ - result = Curl_add_buffer_send(&req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); + result = Curl_buffer_send(&req, conn, &data->info.request_size, 0, + FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP request"); @@ -3189,55 +3104,10 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, return checkhttpprefix(data, s, len); } -/* - * header_append() copies a chunk of data to the end of the already received - * header. We make sure that the full string fit in the allocated header - * buffer, or else we enlarge it. - */ -static CURLcode header_append(struct Curl_easy *data, - struct SingleRequest *k, - size_t length) -{ - /* length is at most the size of a full read buffer, for which the upper - bound is CURL_MAX_READ_SIZE. There is thus no chance of overflow in this - calculation. */ - size_t newsize = k->hbuflen + length; - if(newsize > CURL_MAX_HTTP_HEADER) { - /* The reason to have a max limit for this is to avoid the risk of a bad - server feeding libcurl with a never-ending header that will cause - reallocs infinitely */ - failf(data, "Rejected %zu bytes header (max is %d)!", newsize, - CURL_MAX_HTTP_HEADER); - return CURLE_OUT_OF_MEMORY; - } - if(newsize >= data->state.headersize) { - /* We enlarge the header buffer as it is too small */ - char *newbuff; - size_t hbufp_index; - - newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2); - hbufp_index = k->hbufp - data->state.headerbuff; - newbuff = realloc(data->state.headerbuff, newsize); - if(!newbuff) { - failf(data, "Failed to alloc memory for big header!"); - return CURLE_OUT_OF_MEMORY; - } - data->state.headersize = newsize; - data->state.headerbuff = newbuff; - k->hbufp = data->state.headerbuff + hbufp_index; - } - memcpy(k->hbufp, k->str_start, length); - k->hbufp += length; - k->hbuflen += length; - *k->hbufp = 0; - - return CURLE_OK; -} - static void print_http_error(struct Curl_easy *data) { struct SingleRequest *k = &data->req; - char *beg = k->p; + char *beg = Curl_dyn_ptr(&data->state.headerb); /* make sure that data->req.p points to the HTTP status line */ if(!strncmp(beg, "HTTP", 4)) { @@ -3275,14 +3145,17 @@ static void print_http_error(struct Curl_easy *data) * Read any HTTP header lines from the server and pass them to the client app. */ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, - struct connectdata *conn, - ssize_t *nread, - bool *stop_reading) + struct connectdata *conn, + ssize_t *nread, + bool *stop_reading) { CURLcode result; struct SingleRequest *k = &data->req; ssize_t onread = *nread; char *ostr = k->str; + char *headp; + char *str_start; + char *end_ptr; /* header line within buffer loop */ do { @@ -3291,22 +3164,25 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, int writetype; /* str_start is start of line within buf */ - k->str_start = k->str; + str_start = k->str; /* data is in network encoding so use 0x0a instead of '\n' */ - k->end_ptr = memchr(k->str_start, 0x0a, *nread); + end_ptr = memchr(str_start, 0x0a, *nread); - if(!k->end_ptr) { + if(!end_ptr) { /* Not a complete header line within buffer, append the data to the end of the headerbuff. */ - result = header_append(data, k, *nread); + result = Curl_dyn_addn(&data->state.headerb, str_start, *nread); if(result) return result; if(!k->headerline) { /* check if this looks like a protocol header */ - statusline st = checkprotoprefix(data, conn, data->state.headerbuff, - k->hbuflen); + statusline st = + checkprotoprefix(data, conn, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(st == STATUS_BAD) { /* this is not the beginning of a protocol first header line */ k->header = FALSE; @@ -3324,28 +3200,26 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } /* decrease the size of the remaining (supposed) header line */ - rest_length = (k->end_ptr - k->str) + 1; + rest_length = (end_ptr - k->str) + 1; *nread -= (ssize_t)rest_length; - k->str = k->end_ptr + 1; /* move past new line */ + k->str = end_ptr + 1; /* move past new line */ - full_length = k->str - k->str_start; + full_length = k->str - str_start; - result = header_append(data, k, full_length); + result = Curl_dyn_addn(&data->state.headerb, str_start, full_length); if(result) return result; - k->end_ptr = k->hbufp; - k->p = data->state.headerbuff; - /**** - * We now have a FULL header line that p points to + * We now have a FULL header line in 'headerb'. *****/ if(!k->headerline) { /* the first read header */ - statusline st = checkprotoprefix(data, conn, data->state.headerbuff, - k->hbuflen); + statusline st = checkprotoprefix(data, conn, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); if(st == STATUS_BAD) { streamclose(conn, "bad HTTP: No end-of-message indicator"); /* this is not the beginning of a protocol first header line */ @@ -3368,26 +3242,27 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } - /* headers are in network encoding so - use 0x0a and 0x0d instead of '\n' and '\r' */ - if((0x0a == *k->p) || (0x0d == *k->p)) { + /* headers are in network encoding so use 0x0a and 0x0d instead of '\n' + and '\r' */ + headp = Curl_dyn_ptr(&data->state.headerb); + if((0x0a == *headp) || (0x0d == *headp)) { size_t headerlen; /* Zero-length header line means end of headers! */ #ifdef CURL_DOES_CONVERSIONS - if(0x0d == *k->p) { - *k->p = '\r'; /* replace with CR in host encoding */ - k->p++; /* pass the CR byte */ + if(0x0d == *headp) { + *headp = '\r'; /* replace with CR in host encoding */ + headp++; /* pass the CR byte */ } - if(0x0a == *k->p) { - *k->p = '\n'; /* replace with LF in host encoding */ - k->p++; /* pass the LF byte */ + if(0x0a == *headp) { + *headp = '\n'; /* replace with LF in host encoding */ + headp++; /* pass the LF byte */ } #else - if('\r' == *k->p) - k->p++; /* pass the \r byte */ - if('\n' == *k->p) - k->p++; /* pass the \n byte */ + if('\r' == *headp) + headp++; /* pass the \r byte */ + if('\n' == *headp) + headp++; /* pass the \n byte */ #endif /* CURL_DOES_CONVERSIONS */ if(100 <= k->httpcode && 199 >= k->httpcode) { @@ -3448,7 +3323,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if((k->size == -1) && !k->chunk && !conn->bits.close && (conn->httpversion == 11) && !(conn->handler->protocol & CURLPROTO_RTSP) && - data->set.httpreq != HTTPREQ_HEAD) { + data->state.httpreq != HTTPREQ_HEAD) { /* On HTTP 1.1, when connection is not to get closed, but no Content-Length nor Transfer-Encoding chunked have been received, according to RFC2616 section 4.4 point 5, we @@ -3506,10 +3381,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if(data->set.include_header) writetype |= CLIENTWRITE_BODY; - headerlen = k->p - data->state.headerbuff; - + headerlen = Curl_dyn_len(&data->state.headerb); result = Curl_client_write(conn, writetype, - data->state.headerbuff, + Curl_dyn_ptr(&data->state.headerb), headerlen); if(result) return result; @@ -3544,7 +3418,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * continue sending even if it gets discarded */ - switch(data->set.httpreq) { + switch(data->state.httpreq) { case HTTPREQ_PUT: case HTTPREQ_POST: case HTTPREQ_POST_FORM: @@ -3662,14 +3536,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, - k->str_start, headerlen); + str_start, headerlen); break; /* exit header line loop */ } - /* We continue reading headers, so reset the line-based - header parsing variables hbufp && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; + /* We continue reading headers, reset the line-based header */ + Curl_dyn_reset(&data->state.headerb); continue; } @@ -3688,12 +3560,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #define SCRATCHSIZE 21 CURLcode res; char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */ - /* We can't really convert this yet because we - don't know if it's the 1st header line or the body. - So we do a partial conversion into a scratch area, - leaving the data at k->p as-is. + /* We can't really convert this yet because we don't know if it's the + 1st header line or the body. So we do a partial conversion into a + scratch area, leaving the data at 'headp' as-is. */ - strncpy(&scratch[0], k->p, SCRATCHSIZE); + strncpy(&scratch[0], headp, SCRATCHSIZE); scratch[SCRATCHSIZE] = 0; /* null terminate */ res = Curl_convert_from_network(data, &scratch[0], @@ -3702,7 +3573,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* Curl_convert_from_network calls failf if unsuccessful */ return res; #else -#define HEADER1 k->p /* no conversion needed, just use k->p */ +#define HEADER1 headp /* no conversion needed, just use headp */ #endif /* CURL_DOES_CONVERSIONS */ if(conn->handler->protocol & PROTO_FAMILY_HTTP) { @@ -3753,7 +3624,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, compare header line against list of aliases */ if(!nc) { - if(checkhttpprefix(data, k->p, k->hbuflen) == STATUS_DONE) { + statusline check = + checkhttpprefix(data, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(check == STATUS_DONE) { nc = 1; k->httpcode = 200; conn->httpversion = 10; @@ -3799,15 +3674,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * depending on how authentication is working. Other codes * are definitely errors, so give up here. */ - if(data->state.resume_from && data->set.httpreq == HTTPREQ_GET && + if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET && k->httpcode == 416) { /* "Requested Range Not Satisfiable", just proceed and pretend this is no error */ k->ignorebody = TRUE; /* Avoid appending error msg to good data. */ } else if(data->set.http_fail_on_error && (k->httpcode >= 400) && - ((k->httpcode != 401) || !conn->bits.user_passwd) && - ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) { + ((k->httpcode != 401) || !conn->bits.user_passwd) +#ifndef CURL_DISABLE_PROXY + && ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) +#endif + ) { /* serious error, go home! */ print_http_error(data); return CURLE_HTTP_RETURNED_ERROR; @@ -3823,9 +3701,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, else if(conn->httpversion == 20 || (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) { DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n")); - - /* HTTP/2 cannot blacklist multiplexing since it is a core - functionality of the protocol */ + /* HTTP/2 cannot avoid multiplexing since it is a core functionality + of the protocol */ conn->bundle->multiuse = BUNDLE_MULTIPLEX; } else if(conn->httpversion >= 11 && @@ -3865,16 +3742,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } - result = Curl_convert_from_network(data, k->p, strlen(k->p)); + result = Curl_convert_from_network(data, headp, strlen(headp)); /* Curl_convert_from_network calls failf if unsuccessful */ if(result) return result; /* Check for Content-Length: header lines to get size */ if(!k->http_bodyless && - !data->set.ignorecl && checkprefix("Content-Length:", k->p)) { + !data->set.ignorecl && checkprefix("Content-Length:", headp)) { curl_off_t contentlength; - CURLofft offt = curlx_strtoofft(k->p + 15, NULL, 10, &contentlength); + CURLofft offt = curlx_strtoofft(headp + 15, NULL, 10, &contentlength); if(offt == CURL_OFFT_OK) { if(data->set.max_filesize && @@ -3905,8 +3782,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } /* check for Content-Type: header lines to get the MIME-type */ - else if(checkprefix("Content-Type:", k->p)) { - char *contenttype = Curl_copy_header_value(k->p); + else if(checkprefix("Content-Type:", headp)) { + char *contenttype = Curl_copy_header_value(headp); if(!contenttype) return CURLE_OUT_OF_MEMORY; if(!*contenttype) @@ -3917,10 +3794,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, data->info.contenttype = contenttype; } } +#ifndef CURL_DISABLE_PROXY else if((conn->httpversion == 10) && conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "keep-alive")) { + Curl_compareheader(headp, "Proxy-Connection:", "keep-alive")) { /* * When a HTTP/1.0 reply comes when using a proxy, the * 'Proxy-Connection: keep-alive' line tells us the @@ -3932,8 +3809,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } else if((conn->httpversion == 11) && conn->bits.httpproxy && - Curl_compareheader(k->p, - "Proxy-Connection:", "close")) { + Curl_compareheader(headp, "Proxy-Connection:", "close")) { /* * We get a HTTP/1.1 response from a proxy and it says it'll * close down after this transfer. @@ -3941,8 +3817,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, connclose(conn, "Proxy-Connection: asked to close after done"); infof(data, "HTTP/1.1 proxy connection set close!\n"); } +#endif else if((conn->httpversion == 10) && - Curl_compareheader(k->p, "Connection:", "keep-alive")) { + Curl_compareheader(headp, "Connection:", "keep-alive")) { /* * A HTTP/1.0 reply with the 'Connection: keep-alive' line * tells us the connection will be kept alive for our @@ -3952,7 +3829,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, connkeep(conn, "Connection keep-alive"); infof(data, "HTTP/1.0 connection set to keep alive!\n"); } - else if(Curl_compareheader(k->p, "Connection:", "close")) { + else if(Curl_compareheader(headp, "Connection:", "close")) { /* * [RFC 2616, section 8.1.2.1] * "Connection: close" is HTTP/1.1 language and means that @@ -3961,7 +3838,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, */ streamclose(conn, "Connection: close used"); } - else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", k->p)) { + else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) { /* One or more encodings. We check for chunked and/or a compression algorithm. */ /* @@ -3973,11 +3850,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * of chunks, and a chunk-data set to zero signals the * end-of-chunks. */ - result = Curl_build_unencoding_stack(conn, k->p + 18, TRUE); + result = Curl_build_unencoding_stack(conn, headp + 18, TRUE); if(result) return result; } - else if(!k->http_bodyless && checkprefix("Content-Encoding:", k->p) && + else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) && data->set.str[STRING_ENCODING]) { /* * Process Content-Encoding. Look for the values: identity, @@ -3986,24 +3863,24 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * 2616). zlib cannot handle compress. However, errors are * handled further down when the response body is processed */ - result = Curl_build_unencoding_stack(conn, k->p + 17, FALSE); + result = Curl_build_unencoding_stack(conn, headp + 17, FALSE); if(result) return result; } - else if(checkprefix("Retry-After:", k->p)) { + else if(checkprefix("Retry-After:", headp)) { /* Retry-After = HTTP-date / delay-seconds */ curl_off_t retry_after = 0; /* zero for unknown or "now" */ - time_t date = Curl_getdate_capped(&k->p[12]); + time_t date = Curl_getdate_capped(&headp[12]); if(-1 == date) { /* not a date, try it as a decimal number */ - (void)curlx_strtoofft(&k->p[12], NULL, 10, &retry_after); + (void)curlx_strtoofft(&headp[12], NULL, 10, &retry_after); } else /* convert date to number of seconds into the future */ retry_after = date - time(NULL); data->info.retry_after = retry_after; /* store it */ } - else if(!k->http_bodyless && checkprefix("Content-Range:", k->p)) { + else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) { /* Content-Range: bytes [num]- Content-Range: bytes: [num]- Content-Range: [num]- @@ -4015,7 +3892,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, The forth means the requested range was unsatisfied. */ - char *ptr = k->p + 14; + char *ptr = headp + 14; /* Move forward until first digit or asterisk */ while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') @@ -4034,34 +3911,34 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #if !defined(CURL_DISABLE_COOKIES) else if(data->cookies && data->state.cookie_engine && - checkprefix("Set-Cookie:", k->p)) { + checkprefix("Set-Cookie:", headp)) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_add(data, - data->cookies, TRUE, FALSE, k->p + 11, + data->cookies, TRUE, FALSE, headp + 11, /* If there is a custom-set Host: name, use it here, or else use real peer host name. */ - conn->allocptr.cookiehost? - conn->allocptr.cookiehost:conn->host.name, + data->state.aptr.cookiehost? + data->state.aptr.cookiehost:conn->host.name, data->state.up.path, (conn->handler->protocol&CURLPROTO_HTTPS)? TRUE:FALSE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } #endif - else if(!k->http_bodyless && checkprefix("Last-Modified:", k->p) && + else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) && (data->set.timecondition || data->set.get_filetime) ) { - k->timeofdoc = Curl_getdate_capped(k->p + strlen("Last-Modified:")); + k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:")); if(data->set.get_filetime) data->info.filetime = k->timeofdoc; } - else if((checkprefix("WWW-Authenticate:", k->p) && + else if((checkprefix("WWW-Authenticate:", headp) && (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", k->p) && + (checkprefix("Proxy-authenticate:", headp) && (407 == k->httpcode))) { bool proxy = (k->httpcode == 407) ? TRUE : FALSE; - char *auth = Curl_copy_header_value(k->p); + char *auth = Curl_copy_header_value(headp); if(!auth) return CURLE_OUT_OF_MEMORY; @@ -4073,11 +3950,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return result; } #ifdef USE_SPNEGO - else if(checkprefix("Persistent-Auth", k->p)) { + else if(checkprefix("Persistent-Auth", headp)) { struct negotiatedata *negdata = &conn->negotiate; struct auth *authp = &data->state.authhost; if(authp->picked == CURLAUTH_NEGOTIATE) { - char *persistentauth = Curl_copy_header_value(k->p); + char *persistentauth = Curl_copy_header_value(headp); if(!persistentauth) return CURLE_OUT_OF_MEMORY; negdata->noauthpersist = checkprefix("false", persistentauth)? @@ -4090,10 +3967,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #endif else if((k->httpcode >= 300 && k->httpcode < 400) && - checkprefix("Location:", k->p) && + checkprefix("Location:", headp) && !data->req.location) { /* this is the URL that the server advises us to use instead */ - char *location = Curl_copy_header_value(k->p); + char *location = Curl_copy_header_value(headp); if(!location) return CURLE_OUT_OF_MEMORY; if(!*location) @@ -4118,7 +3995,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #ifdef USE_ALTSVC /* If enabled, the header is incoming and this is over HTTPS */ - else if(data->asi && checkprefix("Alt-Svc:", k->p) && + else if(data->asi && checkprefix("Alt-Svc:", headp) && ((conn->handler->flags & PROTOPT_SSL) || #ifdef CURLDEBUG /* allow debug builds to circumvent the HTTPS restriction */ @@ -4130,7 +4007,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* the ALPN of the current request */ enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1; result = Curl_altsvc_parse(data, data->asi, - &k->p[ strlen("Alt-Svc:") ], + &headp[ strlen("Alt-Svc:") ], id, conn->host.name, curlx_uitous(conn->remote_port)); if(result) @@ -4138,7 +4015,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } #endif else if(conn->handler->protocol & CURLPROTO_RTSP) { - result = Curl_rtsp_parseheader(conn, k->p); + result = Curl_rtsp_parseheader(conn, headp); if(result) return result; } @@ -4152,18 +4029,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, writetype |= CLIENTWRITE_BODY; if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, k->p, (size_t)k->hbuflen); + Curl_debug(data, CURLINFO_HEADER_IN, headp, + Curl_dyn_len(&data->state.headerb)); - result = Curl_client_write(conn, writetype, k->p, k->hbuflen); + result = Curl_client_write(conn, writetype, headp, + Curl_dyn_len(&data->state.headerb)); if(result) return result; - data->info.header_size += (long)k->hbuflen; - data->req.headerbytecount += (long)k->hbuflen; + data->info.header_size += Curl_dyn_len(&data->state.headerb); + data->req.headerbytecount += Curl_dyn_len(&data->state.headerb); - /* reset hbufp pointer && hbuflen */ - k->hbufp = data->state.headerbuff; - k->hbuflen = 0; + Curl_dyn_reset(&data->state.headerb); } while(*k->str); /* header line within buffer */ -- cgit v1.2.3