113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#ifndef CURL_DISABLE_HTTP 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 3013498266Sopenharmony_ci#include <netinet/in.h> 3113498266Sopenharmony_ci#endif 3213498266Sopenharmony_ci 3313498266Sopenharmony_ci#ifdef HAVE_NETDB_H 3413498266Sopenharmony_ci#include <netdb.h> 3513498266Sopenharmony_ci#endif 3613498266Sopenharmony_ci#ifdef HAVE_ARPA_INET_H 3713498266Sopenharmony_ci#include <arpa/inet.h> 3813498266Sopenharmony_ci#endif 3913498266Sopenharmony_ci#ifdef HAVE_NET_IF_H 4013498266Sopenharmony_ci#include <net/if.h> 4113498266Sopenharmony_ci#endif 4213498266Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 4313498266Sopenharmony_ci#include <sys/ioctl.h> 4413498266Sopenharmony_ci#endif 4513498266Sopenharmony_ci 4613498266Sopenharmony_ci#ifdef HAVE_SYS_PARAM_H 4713498266Sopenharmony_ci#include <sys/param.h> 4813498266Sopenharmony_ci#endif 4913498266Sopenharmony_ci 5013498266Sopenharmony_ci#ifdef USE_HYPER 5113498266Sopenharmony_ci#include <hyper.h> 5213498266Sopenharmony_ci#endif 5313498266Sopenharmony_ci 5413498266Sopenharmony_ci#include "urldata.h" 5513498266Sopenharmony_ci#include <curl/curl.h> 5613498266Sopenharmony_ci#include "transfer.h" 5713498266Sopenharmony_ci#include "sendf.h" 5813498266Sopenharmony_ci#include "formdata.h" 5913498266Sopenharmony_ci#include "mime.h" 6013498266Sopenharmony_ci#include "progress.h" 6113498266Sopenharmony_ci#include "curl_base64.h" 6213498266Sopenharmony_ci#include "cookie.h" 6313498266Sopenharmony_ci#include "vauth/vauth.h" 6413498266Sopenharmony_ci#include "vtls/vtls.h" 6513498266Sopenharmony_ci#include "vquic/vquic.h" 6613498266Sopenharmony_ci#include "http_digest.h" 6713498266Sopenharmony_ci#include "http_ntlm.h" 6813498266Sopenharmony_ci#include "curl_ntlm_wb.h" 6913498266Sopenharmony_ci#include "http_negotiate.h" 7013498266Sopenharmony_ci#include "http_aws_sigv4.h" 7113498266Sopenharmony_ci#include "url.h" 7213498266Sopenharmony_ci#include "share.h" 7313498266Sopenharmony_ci#include "hostip.h" 7413498266Sopenharmony_ci#include "dynhds.h" 7513498266Sopenharmony_ci#include "http.h" 7613498266Sopenharmony_ci#include "select.h" 7713498266Sopenharmony_ci#include "parsedate.h" /* for the week day and month names */ 7813498266Sopenharmony_ci#include "strtoofft.h" 7913498266Sopenharmony_ci#include "multiif.h" 8013498266Sopenharmony_ci#include "strcase.h" 8113498266Sopenharmony_ci#include "content_encoding.h" 8213498266Sopenharmony_ci#include "http_proxy.h" 8313498266Sopenharmony_ci#include "warnless.h" 8413498266Sopenharmony_ci#include "http2.h" 8513498266Sopenharmony_ci#include "cfilters.h" 8613498266Sopenharmony_ci#include "connect.h" 8713498266Sopenharmony_ci#include "strdup.h" 8813498266Sopenharmony_ci#include "altsvc.h" 8913498266Sopenharmony_ci#include "hsts.h" 9013498266Sopenharmony_ci#include "ws.h" 9113498266Sopenharmony_ci#include "c-hyper.h" 9213498266Sopenharmony_ci#include "curl_ctype.h" 9313498266Sopenharmony_ci 9413498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 9513498266Sopenharmony_ci#include "curl_printf.h" 9613498266Sopenharmony_ci#include "curl_memory.h" 9713498266Sopenharmony_ci#include "memdebug.h" 9813498266Sopenharmony_ci 9913498266Sopenharmony_ci/* 10013498266Sopenharmony_ci * Forward declarations. 10113498266Sopenharmony_ci */ 10213498266Sopenharmony_ci 10313498266Sopenharmony_cistatic bool http_should_fail(struct Curl_easy *data); 10413498266Sopenharmony_ci 10513498266Sopenharmony_ci/* 10613498266Sopenharmony_ci * HTTP handler interface. 10713498266Sopenharmony_ci */ 10813498266Sopenharmony_ciconst struct Curl_handler Curl_handler_http = { 10913498266Sopenharmony_ci "HTTP", /* scheme */ 11013498266Sopenharmony_ci Curl_http_setup_conn, /* setup_connection */ 11113498266Sopenharmony_ci Curl_http, /* do_it */ 11213498266Sopenharmony_ci Curl_http_done, /* done */ 11313498266Sopenharmony_ci ZERO_NULL, /* do_more */ 11413498266Sopenharmony_ci Curl_http_connect, /* connect_it */ 11513498266Sopenharmony_ci ZERO_NULL, /* connecting */ 11613498266Sopenharmony_ci ZERO_NULL, /* doing */ 11713498266Sopenharmony_ci ZERO_NULL, /* proto_getsock */ 11813498266Sopenharmony_ci Curl_http_getsock_do, /* doing_getsock */ 11913498266Sopenharmony_ci ZERO_NULL, /* domore_getsock */ 12013498266Sopenharmony_ci ZERO_NULL, /* perform_getsock */ 12113498266Sopenharmony_ci ZERO_NULL, /* disconnect */ 12213498266Sopenharmony_ci Curl_http_write_resp, /* write_resp */ 12313498266Sopenharmony_ci ZERO_NULL, /* connection_check */ 12413498266Sopenharmony_ci ZERO_NULL, /* attach connection */ 12513498266Sopenharmony_ci PORT_HTTP, /* defport */ 12613498266Sopenharmony_ci CURLPROTO_HTTP, /* protocol */ 12713498266Sopenharmony_ci CURLPROTO_HTTP, /* family */ 12813498266Sopenharmony_ci PROTOPT_CREDSPERREQUEST | /* flags */ 12913498266Sopenharmony_ci PROTOPT_USERPWDCTRL 13013498266Sopenharmony_ci}; 13113498266Sopenharmony_ci 13213498266Sopenharmony_ci#ifdef USE_SSL 13313498266Sopenharmony_ci/* 13413498266Sopenharmony_ci * HTTPS handler interface. 13513498266Sopenharmony_ci */ 13613498266Sopenharmony_ciconst struct Curl_handler Curl_handler_https = { 13713498266Sopenharmony_ci "HTTPS", /* scheme */ 13813498266Sopenharmony_ci Curl_http_setup_conn, /* setup_connection */ 13913498266Sopenharmony_ci Curl_http, /* do_it */ 14013498266Sopenharmony_ci Curl_http_done, /* done */ 14113498266Sopenharmony_ci ZERO_NULL, /* do_more */ 14213498266Sopenharmony_ci Curl_http_connect, /* connect_it */ 14313498266Sopenharmony_ci NULL, /* connecting */ 14413498266Sopenharmony_ci ZERO_NULL, /* doing */ 14513498266Sopenharmony_ci NULL, /* proto_getsock */ 14613498266Sopenharmony_ci Curl_http_getsock_do, /* doing_getsock */ 14713498266Sopenharmony_ci ZERO_NULL, /* domore_getsock */ 14813498266Sopenharmony_ci ZERO_NULL, /* perform_getsock */ 14913498266Sopenharmony_ci ZERO_NULL, /* disconnect */ 15013498266Sopenharmony_ci Curl_http_write_resp, /* write_resp */ 15113498266Sopenharmony_ci ZERO_NULL, /* connection_check */ 15213498266Sopenharmony_ci ZERO_NULL, /* attach connection */ 15313498266Sopenharmony_ci PORT_HTTPS, /* defport */ 15413498266Sopenharmony_ci CURLPROTO_HTTPS, /* protocol */ 15513498266Sopenharmony_ci CURLPROTO_HTTP, /* family */ 15613498266Sopenharmony_ci PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN | /* flags */ 15713498266Sopenharmony_ci PROTOPT_USERPWDCTRL 15813498266Sopenharmony_ci}; 15913498266Sopenharmony_ci 16013498266Sopenharmony_ci#endif 16113498266Sopenharmony_ci 16213498266Sopenharmony_ciCURLcode Curl_http_setup_conn(struct Curl_easy *data, 16313498266Sopenharmony_ci struct connectdata *conn) 16413498266Sopenharmony_ci{ 16513498266Sopenharmony_ci /* allocate the HTTP-specific struct for the Curl_easy, only to survive 16613498266Sopenharmony_ci during this request */ 16713498266Sopenharmony_ci struct HTTP *http; 16813498266Sopenharmony_ci DEBUGASSERT(data->req.p.http == NULL); 16913498266Sopenharmony_ci 17013498266Sopenharmony_ci http = calloc(1, sizeof(struct HTTP)); 17113498266Sopenharmony_ci if(!http) 17213498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 17313498266Sopenharmony_ci 17413498266Sopenharmony_ci data->req.p.http = http; 17513498266Sopenharmony_ci connkeep(conn, "HTTP default"); 17613498266Sopenharmony_ci 17713498266Sopenharmony_ci if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) { 17813498266Sopenharmony_ci CURLcode result = Curl_conn_may_http3(data, conn); 17913498266Sopenharmony_ci if(result) 18013498266Sopenharmony_ci return result; 18113498266Sopenharmony_ci } 18213498266Sopenharmony_ci 18313498266Sopenharmony_ci return CURLE_OK; 18413498266Sopenharmony_ci} 18513498266Sopenharmony_ci 18613498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 18713498266Sopenharmony_ci/* 18813498266Sopenharmony_ci * checkProxyHeaders() checks the linked list of custom proxy headers 18913498266Sopenharmony_ci * if proxy headers are not available, then it will lookup into http header 19013498266Sopenharmony_ci * link list 19113498266Sopenharmony_ci * 19213498266Sopenharmony_ci * It takes a connectdata struct as input to see if this is a proxy request or 19313498266Sopenharmony_ci * not, as it then might check a different header list. Provide the header 19413498266Sopenharmony_ci * prefix without colon! 19513498266Sopenharmony_ci */ 19613498266Sopenharmony_cichar *Curl_checkProxyheaders(struct Curl_easy *data, 19713498266Sopenharmony_ci const struct connectdata *conn, 19813498266Sopenharmony_ci const char *thisheader, 19913498266Sopenharmony_ci const size_t thislen) 20013498266Sopenharmony_ci{ 20113498266Sopenharmony_ci struct curl_slist *head; 20213498266Sopenharmony_ci 20313498266Sopenharmony_ci for(head = (conn->bits.proxy && data->set.sep_headers) ? 20413498266Sopenharmony_ci data->set.proxyheaders : data->set.headers; 20513498266Sopenharmony_ci head; head = head->next) { 20613498266Sopenharmony_ci if(strncasecompare(head->data, thisheader, thislen) && 20713498266Sopenharmony_ci Curl_headersep(head->data[thislen])) 20813498266Sopenharmony_ci return head->data; 20913498266Sopenharmony_ci } 21013498266Sopenharmony_ci 21113498266Sopenharmony_ci return NULL; 21213498266Sopenharmony_ci} 21313498266Sopenharmony_ci#else 21413498266Sopenharmony_ci/* disabled */ 21513498266Sopenharmony_ci#define Curl_checkProxyheaders(x,y,z,a) NULL 21613498266Sopenharmony_ci#endif 21713498266Sopenharmony_ci 21813498266Sopenharmony_ci/* 21913498266Sopenharmony_ci * Strip off leading and trailing whitespace from the value in the 22013498266Sopenharmony_ci * given HTTP header line and return a strdupped copy. Returns NULL in 22113498266Sopenharmony_ci * case of allocation failure. Returns an empty string if the header value 22213498266Sopenharmony_ci * consists entirely of whitespace. 22313498266Sopenharmony_ci */ 22413498266Sopenharmony_cichar *Curl_copy_header_value(const char *header) 22513498266Sopenharmony_ci{ 22613498266Sopenharmony_ci const char *start; 22713498266Sopenharmony_ci const char *end; 22813498266Sopenharmony_ci size_t len; 22913498266Sopenharmony_ci 23013498266Sopenharmony_ci /* Find the end of the header name */ 23113498266Sopenharmony_ci while(*header && (*header != ':')) 23213498266Sopenharmony_ci ++header; 23313498266Sopenharmony_ci 23413498266Sopenharmony_ci if(*header) 23513498266Sopenharmony_ci /* Skip over colon */ 23613498266Sopenharmony_ci ++header; 23713498266Sopenharmony_ci 23813498266Sopenharmony_ci /* Find the first non-space letter */ 23913498266Sopenharmony_ci start = header; 24013498266Sopenharmony_ci while(*start && ISSPACE(*start)) 24113498266Sopenharmony_ci start++; 24213498266Sopenharmony_ci 24313498266Sopenharmony_ci /* data is in the host encoding so 24413498266Sopenharmony_ci use '\r' and '\n' instead of 0x0d and 0x0a */ 24513498266Sopenharmony_ci end = strchr(start, '\r'); 24613498266Sopenharmony_ci if(!end) 24713498266Sopenharmony_ci end = strchr(start, '\n'); 24813498266Sopenharmony_ci if(!end) 24913498266Sopenharmony_ci end = strchr(start, '\0'); 25013498266Sopenharmony_ci if(!end) 25113498266Sopenharmony_ci return NULL; 25213498266Sopenharmony_ci 25313498266Sopenharmony_ci /* skip all trailing space letters */ 25413498266Sopenharmony_ci while((end > start) && ISSPACE(*end)) 25513498266Sopenharmony_ci end--; 25613498266Sopenharmony_ci 25713498266Sopenharmony_ci /* get length of the type */ 25813498266Sopenharmony_ci len = end - start + 1; 25913498266Sopenharmony_ci 26013498266Sopenharmony_ci return Curl_memdup0(start, len); 26113498266Sopenharmony_ci} 26213498266Sopenharmony_ci 26313498266Sopenharmony_ci#ifndef CURL_DISABLE_HTTP_AUTH 26413498266Sopenharmony_ci 26513498266Sopenharmony_ci#ifndef CURL_DISABLE_BASIC_AUTH 26613498266Sopenharmony_ci/* 26713498266Sopenharmony_ci * http_output_basic() sets up an Authorization: header (or the proxy version) 26813498266Sopenharmony_ci * for HTTP Basic authentication. 26913498266Sopenharmony_ci * 27013498266Sopenharmony_ci * Returns CURLcode. 27113498266Sopenharmony_ci */ 27213498266Sopenharmony_cistatic CURLcode http_output_basic(struct Curl_easy *data, bool proxy) 27313498266Sopenharmony_ci{ 27413498266Sopenharmony_ci size_t size = 0; 27513498266Sopenharmony_ci char *authorization = NULL; 27613498266Sopenharmony_ci char **userp; 27713498266Sopenharmony_ci const char *user; 27813498266Sopenharmony_ci const char *pwd; 27913498266Sopenharmony_ci CURLcode result; 28013498266Sopenharmony_ci char *out; 28113498266Sopenharmony_ci 28213498266Sopenharmony_ci /* credentials are unique per transfer for HTTP, do not use the ones for the 28313498266Sopenharmony_ci connection */ 28413498266Sopenharmony_ci if(proxy) { 28513498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 28613498266Sopenharmony_ci userp = &data->state.aptr.proxyuserpwd; 28713498266Sopenharmony_ci user = data->state.aptr.proxyuser; 28813498266Sopenharmony_ci pwd = data->state.aptr.proxypasswd; 28913498266Sopenharmony_ci#else 29013498266Sopenharmony_ci return CURLE_NOT_BUILT_IN; 29113498266Sopenharmony_ci#endif 29213498266Sopenharmony_ci } 29313498266Sopenharmony_ci else { 29413498266Sopenharmony_ci userp = &data->state.aptr.userpwd; 29513498266Sopenharmony_ci user = data->state.aptr.user; 29613498266Sopenharmony_ci pwd = data->state.aptr.passwd; 29713498266Sopenharmony_ci } 29813498266Sopenharmony_ci 29913498266Sopenharmony_ci out = aprintf("%s:%s", user ? user : "", pwd ? pwd : ""); 30013498266Sopenharmony_ci if(!out) 30113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 30213498266Sopenharmony_ci 30313498266Sopenharmony_ci result = Curl_base64_encode(out, strlen(out), &authorization, &size); 30413498266Sopenharmony_ci if(result) 30513498266Sopenharmony_ci goto fail; 30613498266Sopenharmony_ci 30713498266Sopenharmony_ci if(!authorization) { 30813498266Sopenharmony_ci result = CURLE_REMOTE_ACCESS_DENIED; 30913498266Sopenharmony_ci goto fail; 31013498266Sopenharmony_ci } 31113498266Sopenharmony_ci 31213498266Sopenharmony_ci free(*userp); 31313498266Sopenharmony_ci *userp = aprintf("%sAuthorization: Basic %s\r\n", 31413498266Sopenharmony_ci proxy ? "Proxy-" : "", 31513498266Sopenharmony_ci authorization); 31613498266Sopenharmony_ci free(authorization); 31713498266Sopenharmony_ci if(!*userp) { 31813498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 31913498266Sopenharmony_ci goto fail; 32013498266Sopenharmony_ci } 32113498266Sopenharmony_ci 32213498266Sopenharmony_cifail: 32313498266Sopenharmony_ci free(out); 32413498266Sopenharmony_ci return result; 32513498266Sopenharmony_ci} 32613498266Sopenharmony_ci 32713498266Sopenharmony_ci#endif 32813498266Sopenharmony_ci 32913498266Sopenharmony_ci#ifndef CURL_DISABLE_BEARER_AUTH 33013498266Sopenharmony_ci/* 33113498266Sopenharmony_ci * http_output_bearer() sets up an Authorization: header 33213498266Sopenharmony_ci * for HTTP Bearer authentication. 33313498266Sopenharmony_ci * 33413498266Sopenharmony_ci * Returns CURLcode. 33513498266Sopenharmony_ci */ 33613498266Sopenharmony_cistatic CURLcode http_output_bearer(struct Curl_easy *data) 33713498266Sopenharmony_ci{ 33813498266Sopenharmony_ci char **userp; 33913498266Sopenharmony_ci CURLcode result = CURLE_OK; 34013498266Sopenharmony_ci 34113498266Sopenharmony_ci userp = &data->state.aptr.userpwd; 34213498266Sopenharmony_ci free(*userp); 34313498266Sopenharmony_ci *userp = aprintf("Authorization: Bearer %s\r\n", 34413498266Sopenharmony_ci data->set.str[STRING_BEARER]); 34513498266Sopenharmony_ci 34613498266Sopenharmony_ci if(!*userp) { 34713498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 34813498266Sopenharmony_ci goto fail; 34913498266Sopenharmony_ci } 35013498266Sopenharmony_ci 35113498266Sopenharmony_cifail: 35213498266Sopenharmony_ci return result; 35313498266Sopenharmony_ci} 35413498266Sopenharmony_ci 35513498266Sopenharmony_ci#endif 35613498266Sopenharmony_ci 35713498266Sopenharmony_ci#endif 35813498266Sopenharmony_ci 35913498266Sopenharmony_ci/* pickoneauth() selects the most favourable authentication method from the 36013498266Sopenharmony_ci * ones available and the ones we want. 36113498266Sopenharmony_ci * 36213498266Sopenharmony_ci * return TRUE if one was picked 36313498266Sopenharmony_ci */ 36413498266Sopenharmony_cistatic bool pickoneauth(struct auth *pick, unsigned long mask) 36513498266Sopenharmony_ci{ 36613498266Sopenharmony_ci bool picked; 36713498266Sopenharmony_ci /* only deal with authentication we want */ 36813498266Sopenharmony_ci unsigned long avail = pick->avail & pick->want & mask; 36913498266Sopenharmony_ci picked = TRUE; 37013498266Sopenharmony_ci 37113498266Sopenharmony_ci /* The order of these checks is highly relevant, as this will be the order 37213498266Sopenharmony_ci of preference in case of the existence of multiple accepted types. */ 37313498266Sopenharmony_ci if(avail & CURLAUTH_NEGOTIATE) 37413498266Sopenharmony_ci pick->picked = CURLAUTH_NEGOTIATE; 37513498266Sopenharmony_ci#ifndef CURL_DISABLE_BEARER_AUTH 37613498266Sopenharmony_ci else if(avail & CURLAUTH_BEARER) 37713498266Sopenharmony_ci pick->picked = CURLAUTH_BEARER; 37813498266Sopenharmony_ci#endif 37913498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH 38013498266Sopenharmony_ci else if(avail & CURLAUTH_DIGEST) 38113498266Sopenharmony_ci pick->picked = CURLAUTH_DIGEST; 38213498266Sopenharmony_ci#endif 38313498266Sopenharmony_ci else if(avail & CURLAUTH_NTLM) 38413498266Sopenharmony_ci pick->picked = CURLAUTH_NTLM; 38513498266Sopenharmony_ci else if(avail & CURLAUTH_NTLM_WB) 38613498266Sopenharmony_ci pick->picked = CURLAUTH_NTLM_WB; 38713498266Sopenharmony_ci#ifndef CURL_DISABLE_BASIC_AUTH 38813498266Sopenharmony_ci else if(avail & CURLAUTH_BASIC) 38913498266Sopenharmony_ci pick->picked = CURLAUTH_BASIC; 39013498266Sopenharmony_ci#endif 39113498266Sopenharmony_ci#ifndef CURL_DISABLE_AWS 39213498266Sopenharmony_ci else if(avail & CURLAUTH_AWS_SIGV4) 39313498266Sopenharmony_ci pick->picked = CURLAUTH_AWS_SIGV4; 39413498266Sopenharmony_ci#endif 39513498266Sopenharmony_ci else { 39613498266Sopenharmony_ci pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */ 39713498266Sopenharmony_ci picked = FALSE; 39813498266Sopenharmony_ci } 39913498266Sopenharmony_ci pick->avail = CURLAUTH_NONE; /* clear it here */ 40013498266Sopenharmony_ci 40113498266Sopenharmony_ci return picked; 40213498266Sopenharmony_ci} 40313498266Sopenharmony_ci 40413498266Sopenharmony_ci/* 40513498266Sopenharmony_ci * http_perhapsrewind() 40613498266Sopenharmony_ci * 40713498266Sopenharmony_ci * If we are doing POST or PUT { 40813498266Sopenharmony_ci * If we have more data to send { 40913498266Sopenharmony_ci * If we are doing NTLM { 41013498266Sopenharmony_ci * Keep sending since we must not disconnect 41113498266Sopenharmony_ci * } 41213498266Sopenharmony_ci * else { 41313498266Sopenharmony_ci * If there is more than just a little data left to send, close 41413498266Sopenharmony_ci * the current connection by force. 41513498266Sopenharmony_ci * } 41613498266Sopenharmony_ci * } 41713498266Sopenharmony_ci * If we have sent any data { 41813498266Sopenharmony_ci * If we don't have track of all the data { 41913498266Sopenharmony_ci * call app to tell it to rewind 42013498266Sopenharmony_ci * } 42113498266Sopenharmony_ci * else { 42213498266Sopenharmony_ci * rewind internally so that the operation can restart fine 42313498266Sopenharmony_ci * } 42413498266Sopenharmony_ci * } 42513498266Sopenharmony_ci * } 42613498266Sopenharmony_ci */ 42713498266Sopenharmony_cistatic CURLcode http_perhapsrewind(struct Curl_easy *data, 42813498266Sopenharmony_ci struct connectdata *conn) 42913498266Sopenharmony_ci{ 43013498266Sopenharmony_ci struct HTTP *http = data->req.p.http; 43113498266Sopenharmony_ci curl_off_t bytessent; 43213498266Sopenharmony_ci curl_off_t expectsend = -1; /* default is unknown */ 43313498266Sopenharmony_ci 43413498266Sopenharmony_ci if(!http) 43513498266Sopenharmony_ci /* If this is still NULL, we have not reach very far and we can safely 43613498266Sopenharmony_ci skip this rewinding stuff */ 43713498266Sopenharmony_ci return CURLE_OK; 43813498266Sopenharmony_ci 43913498266Sopenharmony_ci switch(data->state.httpreq) { 44013498266Sopenharmony_ci case HTTPREQ_GET: 44113498266Sopenharmony_ci case HTTPREQ_HEAD: 44213498266Sopenharmony_ci return CURLE_OK; 44313498266Sopenharmony_ci default: 44413498266Sopenharmony_ci break; 44513498266Sopenharmony_ci } 44613498266Sopenharmony_ci 44713498266Sopenharmony_ci bytessent = data->req.writebytecount; 44813498266Sopenharmony_ci 44913498266Sopenharmony_ci if(conn->bits.authneg) { 45013498266Sopenharmony_ci /* This is a state where we are known to be negotiating and we don't send 45113498266Sopenharmony_ci any data then. */ 45213498266Sopenharmony_ci expectsend = 0; 45313498266Sopenharmony_ci } 45413498266Sopenharmony_ci else if(!conn->bits.protoconnstart) { 45513498266Sopenharmony_ci /* HTTP CONNECT in progress: there is no body */ 45613498266Sopenharmony_ci expectsend = 0; 45713498266Sopenharmony_ci } 45813498266Sopenharmony_ci else { 45913498266Sopenharmony_ci /* figure out how much data we are expected to send */ 46013498266Sopenharmony_ci switch(data->state.httpreq) { 46113498266Sopenharmony_ci case HTTPREQ_POST: 46213498266Sopenharmony_ci case HTTPREQ_PUT: 46313498266Sopenharmony_ci if(data->state.infilesize != -1) 46413498266Sopenharmony_ci expectsend = data->state.infilesize; 46513498266Sopenharmony_ci break; 46613498266Sopenharmony_ci case HTTPREQ_POST_FORM: 46713498266Sopenharmony_ci case HTTPREQ_POST_MIME: 46813498266Sopenharmony_ci expectsend = http->postsize; 46913498266Sopenharmony_ci break; 47013498266Sopenharmony_ci default: 47113498266Sopenharmony_ci break; 47213498266Sopenharmony_ci } 47313498266Sopenharmony_ci } 47413498266Sopenharmony_ci 47513498266Sopenharmony_ci data->state.rewindbeforesend = FALSE; /* default */ 47613498266Sopenharmony_ci 47713498266Sopenharmony_ci if((expectsend == -1) || (expectsend > bytessent)) { 47813498266Sopenharmony_ci#if defined(USE_NTLM) 47913498266Sopenharmony_ci /* There is still data left to send */ 48013498266Sopenharmony_ci if((data->state.authproxy.picked == CURLAUTH_NTLM) || 48113498266Sopenharmony_ci (data->state.authhost.picked == CURLAUTH_NTLM) || 48213498266Sopenharmony_ci (data->state.authproxy.picked == CURLAUTH_NTLM_WB) || 48313498266Sopenharmony_ci (data->state.authhost.picked == CURLAUTH_NTLM_WB)) { 48413498266Sopenharmony_ci if(((expectsend - bytessent) < 2000) || 48513498266Sopenharmony_ci (conn->http_ntlm_state != NTLMSTATE_NONE) || 48613498266Sopenharmony_ci (conn->proxy_ntlm_state != NTLMSTATE_NONE)) { 48713498266Sopenharmony_ci /* The NTLM-negotiation has started *OR* there is just a little (<2K) 48813498266Sopenharmony_ci data left to send, keep on sending. */ 48913498266Sopenharmony_ci 49013498266Sopenharmony_ci /* rewind data when completely done sending! */ 49113498266Sopenharmony_ci if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) { 49213498266Sopenharmony_ci data->state.rewindbeforesend = TRUE; 49313498266Sopenharmony_ci infof(data, "Rewind stream before next send"); 49413498266Sopenharmony_ci } 49513498266Sopenharmony_ci 49613498266Sopenharmony_ci return CURLE_OK; 49713498266Sopenharmony_ci } 49813498266Sopenharmony_ci 49913498266Sopenharmony_ci if(conn->bits.close) 50013498266Sopenharmony_ci /* this is already marked to get closed */ 50113498266Sopenharmony_ci return CURLE_OK; 50213498266Sopenharmony_ci 50313498266Sopenharmony_ci infof(data, "NTLM send, close instead of sending %" 50413498266Sopenharmony_ci CURL_FORMAT_CURL_OFF_T " bytes", 50513498266Sopenharmony_ci (curl_off_t)(expectsend - bytessent)); 50613498266Sopenharmony_ci } 50713498266Sopenharmony_ci#endif 50813498266Sopenharmony_ci#if defined(USE_SPNEGO) 50913498266Sopenharmony_ci /* There is still data left to send */ 51013498266Sopenharmony_ci if((data->state.authproxy.picked == CURLAUTH_NEGOTIATE) || 51113498266Sopenharmony_ci (data->state.authhost.picked == CURLAUTH_NEGOTIATE)) { 51213498266Sopenharmony_ci if(((expectsend - bytessent) < 2000) || 51313498266Sopenharmony_ci (conn->http_negotiate_state != GSS_AUTHNONE) || 51413498266Sopenharmony_ci (conn->proxy_negotiate_state != GSS_AUTHNONE)) { 51513498266Sopenharmony_ci /* The NEGOTIATE-negotiation has started *OR* 51613498266Sopenharmony_ci there is just a little (<2K) data left to send, keep on sending. */ 51713498266Sopenharmony_ci 51813498266Sopenharmony_ci /* rewind data when completely done sending! */ 51913498266Sopenharmony_ci if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) { 52013498266Sopenharmony_ci data->state.rewindbeforesend = TRUE; 52113498266Sopenharmony_ci infof(data, "Rewind stream before next send"); 52213498266Sopenharmony_ci } 52313498266Sopenharmony_ci 52413498266Sopenharmony_ci return CURLE_OK; 52513498266Sopenharmony_ci } 52613498266Sopenharmony_ci 52713498266Sopenharmony_ci if(conn->bits.close) 52813498266Sopenharmony_ci /* this is already marked to get closed */ 52913498266Sopenharmony_ci return CURLE_OK; 53013498266Sopenharmony_ci 53113498266Sopenharmony_ci infof(data, "NEGOTIATE send, close instead of sending %" 53213498266Sopenharmony_ci CURL_FORMAT_CURL_OFF_T " bytes", 53313498266Sopenharmony_ci (curl_off_t)(expectsend - bytessent)); 53413498266Sopenharmony_ci } 53513498266Sopenharmony_ci#endif 53613498266Sopenharmony_ci 53713498266Sopenharmony_ci /* This is not NEGOTIATE/NTLM or many bytes left to send: close */ 53813498266Sopenharmony_ci streamclose(conn, "Mid-auth HTTP and much data left to send"); 53913498266Sopenharmony_ci data->req.size = 0; /* don't download any more than 0 bytes */ 54013498266Sopenharmony_ci 54113498266Sopenharmony_ci /* There still is data left to send, but this connection is marked for 54213498266Sopenharmony_ci closure so we can safely do the rewind right now */ 54313498266Sopenharmony_ci } 54413498266Sopenharmony_ci 54513498266Sopenharmony_ci if(bytessent) { 54613498266Sopenharmony_ci /* mark for rewind since if we already sent something */ 54713498266Sopenharmony_ci data->state.rewindbeforesend = TRUE; 54813498266Sopenharmony_ci infof(data, "Please rewind output before next send"); 54913498266Sopenharmony_ci } 55013498266Sopenharmony_ci 55113498266Sopenharmony_ci return CURLE_OK; 55213498266Sopenharmony_ci} 55313498266Sopenharmony_ci 55413498266Sopenharmony_ci/* 55513498266Sopenharmony_ci * Curl_http_auth_act() gets called when all HTTP headers have been received 55613498266Sopenharmony_ci * and it checks what authentication methods that are available and decides 55713498266Sopenharmony_ci * which one (if any) to use. It will set 'newurl' if an auth method was 55813498266Sopenharmony_ci * picked. 55913498266Sopenharmony_ci */ 56013498266Sopenharmony_ci 56113498266Sopenharmony_ciCURLcode Curl_http_auth_act(struct Curl_easy *data) 56213498266Sopenharmony_ci{ 56313498266Sopenharmony_ci struct connectdata *conn = data->conn; 56413498266Sopenharmony_ci bool pickhost = FALSE; 56513498266Sopenharmony_ci bool pickproxy = FALSE; 56613498266Sopenharmony_ci CURLcode result = CURLE_OK; 56713498266Sopenharmony_ci unsigned long authmask = ~0ul; 56813498266Sopenharmony_ci 56913498266Sopenharmony_ci if(!data->set.str[STRING_BEARER]) 57013498266Sopenharmony_ci authmask &= (unsigned long)~CURLAUTH_BEARER; 57113498266Sopenharmony_ci 57213498266Sopenharmony_ci if(100 <= data->req.httpcode && data->req.httpcode <= 199) 57313498266Sopenharmony_ci /* this is a transient response code, ignore */ 57413498266Sopenharmony_ci return CURLE_OK; 57513498266Sopenharmony_ci 57613498266Sopenharmony_ci if(data->state.authproblem) 57713498266Sopenharmony_ci return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; 57813498266Sopenharmony_ci 57913498266Sopenharmony_ci if((data->state.aptr.user || data->set.str[STRING_BEARER]) && 58013498266Sopenharmony_ci ((data->req.httpcode == 401) || 58113498266Sopenharmony_ci (conn->bits.authneg && data->req.httpcode < 300))) { 58213498266Sopenharmony_ci pickhost = pickoneauth(&data->state.authhost, authmask); 58313498266Sopenharmony_ci if(!pickhost) 58413498266Sopenharmony_ci data->state.authproblem = TRUE; 58513498266Sopenharmony_ci if(data->state.authhost.picked == CURLAUTH_NTLM && 58613498266Sopenharmony_ci conn->httpversion > 11) { 58713498266Sopenharmony_ci infof(data, "Forcing HTTP/1.1 for NTLM"); 58813498266Sopenharmony_ci connclose(conn, "Force HTTP/1.1 connection"); 58913498266Sopenharmony_ci data->state.httpwant = CURL_HTTP_VERSION_1_1; 59013498266Sopenharmony_ci } 59113498266Sopenharmony_ci } 59213498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 59313498266Sopenharmony_ci if(conn->bits.proxy_user_passwd && 59413498266Sopenharmony_ci ((data->req.httpcode == 407) || 59513498266Sopenharmony_ci (conn->bits.authneg && data->req.httpcode < 300))) { 59613498266Sopenharmony_ci pickproxy = pickoneauth(&data->state.authproxy, 59713498266Sopenharmony_ci authmask & ~CURLAUTH_BEARER); 59813498266Sopenharmony_ci if(!pickproxy) 59913498266Sopenharmony_ci data->state.authproblem = TRUE; 60013498266Sopenharmony_ci } 60113498266Sopenharmony_ci#endif 60213498266Sopenharmony_ci 60313498266Sopenharmony_ci if(pickhost || pickproxy) { 60413498266Sopenharmony_ci if((data->state.httpreq != HTTPREQ_GET) && 60513498266Sopenharmony_ci (data->state.httpreq != HTTPREQ_HEAD) && 60613498266Sopenharmony_ci !data->state.rewindbeforesend) { 60713498266Sopenharmony_ci result = http_perhapsrewind(data, conn); 60813498266Sopenharmony_ci if(result) 60913498266Sopenharmony_ci return result; 61013498266Sopenharmony_ci } 61113498266Sopenharmony_ci /* In case this is GSS auth, the newurl field is already allocated so 61213498266Sopenharmony_ci we must make sure to free it before allocating a new one. As figured 61313498266Sopenharmony_ci out in bug #2284386 */ 61413498266Sopenharmony_ci Curl_safefree(data->req.newurl); 61513498266Sopenharmony_ci data->req.newurl = strdup(data->state.url); /* clone URL */ 61613498266Sopenharmony_ci if(!data->req.newurl) 61713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 61813498266Sopenharmony_ci } 61913498266Sopenharmony_ci else if((data->req.httpcode < 300) && 62013498266Sopenharmony_ci (!data->state.authhost.done) && 62113498266Sopenharmony_ci conn->bits.authneg) { 62213498266Sopenharmony_ci /* no (known) authentication available, 62313498266Sopenharmony_ci authentication is not "done" yet and 62413498266Sopenharmony_ci no authentication seems to be required and 62513498266Sopenharmony_ci we didn't try HEAD or GET */ 62613498266Sopenharmony_ci if((data->state.httpreq != HTTPREQ_GET) && 62713498266Sopenharmony_ci (data->state.httpreq != HTTPREQ_HEAD)) { 62813498266Sopenharmony_ci data->req.newurl = strdup(data->state.url); /* clone URL */ 62913498266Sopenharmony_ci if(!data->req.newurl) 63013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 63113498266Sopenharmony_ci data->state.authhost.done = TRUE; 63213498266Sopenharmony_ci } 63313498266Sopenharmony_ci } 63413498266Sopenharmony_ci if(http_should_fail(data)) { 63513498266Sopenharmony_ci failf(data, "The requested URL returned error: %d", 63613498266Sopenharmony_ci data->req.httpcode); 63713498266Sopenharmony_ci result = CURLE_HTTP_RETURNED_ERROR; 63813498266Sopenharmony_ci } 63913498266Sopenharmony_ci 64013498266Sopenharmony_ci return result; 64113498266Sopenharmony_ci} 64213498266Sopenharmony_ci 64313498266Sopenharmony_ci#ifndef CURL_DISABLE_HTTP_AUTH 64413498266Sopenharmony_ci/* 64513498266Sopenharmony_ci * Output the correct authentication header depending on the auth type 64613498266Sopenharmony_ci * and whether or not it is to a proxy. 64713498266Sopenharmony_ci */ 64813498266Sopenharmony_cistatic CURLcode 64913498266Sopenharmony_cioutput_auth_headers(struct Curl_easy *data, 65013498266Sopenharmony_ci struct connectdata *conn, 65113498266Sopenharmony_ci struct auth *authstatus, 65213498266Sopenharmony_ci const char *request, 65313498266Sopenharmony_ci const char *path, 65413498266Sopenharmony_ci bool proxy) 65513498266Sopenharmony_ci{ 65613498266Sopenharmony_ci const char *auth = NULL; 65713498266Sopenharmony_ci CURLcode result = CURLE_OK; 65813498266Sopenharmony_ci (void)conn; 65913498266Sopenharmony_ci 66013498266Sopenharmony_ci#ifdef CURL_DISABLE_DIGEST_AUTH 66113498266Sopenharmony_ci (void)request; 66213498266Sopenharmony_ci (void)path; 66313498266Sopenharmony_ci#endif 66413498266Sopenharmony_ci#ifndef CURL_DISABLE_AWS 66513498266Sopenharmony_ci if(authstatus->picked == CURLAUTH_AWS_SIGV4) { 66613498266Sopenharmony_ci auth = "AWS_SIGV4"; 66713498266Sopenharmony_ci result = Curl_output_aws_sigv4(data, proxy); 66813498266Sopenharmony_ci if(result) 66913498266Sopenharmony_ci return result; 67013498266Sopenharmony_ci } 67113498266Sopenharmony_ci else 67213498266Sopenharmony_ci#endif 67313498266Sopenharmony_ci#ifdef USE_SPNEGO 67413498266Sopenharmony_ci if(authstatus->picked == CURLAUTH_NEGOTIATE) { 67513498266Sopenharmony_ci auth = "Negotiate"; 67613498266Sopenharmony_ci result = Curl_output_negotiate(data, conn, proxy); 67713498266Sopenharmony_ci if(result) 67813498266Sopenharmony_ci return result; 67913498266Sopenharmony_ci } 68013498266Sopenharmony_ci else 68113498266Sopenharmony_ci#endif 68213498266Sopenharmony_ci#ifdef USE_NTLM 68313498266Sopenharmony_ci if(authstatus->picked == CURLAUTH_NTLM) { 68413498266Sopenharmony_ci auth = "NTLM"; 68513498266Sopenharmony_ci result = Curl_output_ntlm(data, proxy); 68613498266Sopenharmony_ci if(result) 68713498266Sopenharmony_ci return result; 68813498266Sopenharmony_ci } 68913498266Sopenharmony_ci else 69013498266Sopenharmony_ci#endif 69113498266Sopenharmony_ci#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) 69213498266Sopenharmony_ci if(authstatus->picked == CURLAUTH_NTLM_WB) { 69313498266Sopenharmony_ci auth = "NTLM_WB"; 69413498266Sopenharmony_ci result = Curl_output_ntlm_wb(data, conn, proxy); 69513498266Sopenharmony_ci if(result) 69613498266Sopenharmony_ci return result; 69713498266Sopenharmony_ci } 69813498266Sopenharmony_ci else 69913498266Sopenharmony_ci#endif 70013498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH 70113498266Sopenharmony_ci if(authstatus->picked == CURLAUTH_DIGEST) { 70213498266Sopenharmony_ci auth = "Digest"; 70313498266Sopenharmony_ci result = Curl_output_digest(data, 70413498266Sopenharmony_ci proxy, 70513498266Sopenharmony_ci (const unsigned char *)request, 70613498266Sopenharmony_ci (const unsigned char *)path); 70713498266Sopenharmony_ci if(result) 70813498266Sopenharmony_ci return result; 70913498266Sopenharmony_ci } 71013498266Sopenharmony_ci else 71113498266Sopenharmony_ci#endif 71213498266Sopenharmony_ci#ifndef CURL_DISABLE_BASIC_AUTH 71313498266Sopenharmony_ci if(authstatus->picked == CURLAUTH_BASIC) { 71413498266Sopenharmony_ci /* Basic */ 71513498266Sopenharmony_ci if( 71613498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 71713498266Sopenharmony_ci (proxy && conn->bits.proxy_user_passwd && 71813498266Sopenharmony_ci !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-authorization"))) || 71913498266Sopenharmony_ci#endif 72013498266Sopenharmony_ci (!proxy && data->state.aptr.user && 72113498266Sopenharmony_ci !Curl_checkheaders(data, STRCONST("Authorization")))) { 72213498266Sopenharmony_ci auth = "Basic"; 72313498266Sopenharmony_ci result = http_output_basic(data, proxy); 72413498266Sopenharmony_ci if(result) 72513498266Sopenharmony_ci return result; 72613498266Sopenharmony_ci } 72713498266Sopenharmony_ci 72813498266Sopenharmony_ci /* NOTE: this function should set 'done' TRUE, as the other auth 72913498266Sopenharmony_ci functions work that way */ 73013498266Sopenharmony_ci authstatus->done = TRUE; 73113498266Sopenharmony_ci } 73213498266Sopenharmony_ci#endif 73313498266Sopenharmony_ci#ifndef CURL_DISABLE_BEARER_AUTH 73413498266Sopenharmony_ci if(authstatus->picked == CURLAUTH_BEARER) { 73513498266Sopenharmony_ci /* Bearer */ 73613498266Sopenharmony_ci if((!proxy && data->set.str[STRING_BEARER] && 73713498266Sopenharmony_ci !Curl_checkheaders(data, STRCONST("Authorization")))) { 73813498266Sopenharmony_ci auth = "Bearer"; 73913498266Sopenharmony_ci result = http_output_bearer(data); 74013498266Sopenharmony_ci if(result) 74113498266Sopenharmony_ci return result; 74213498266Sopenharmony_ci } 74313498266Sopenharmony_ci 74413498266Sopenharmony_ci /* NOTE: this function should set 'done' TRUE, as the other auth 74513498266Sopenharmony_ci functions work that way */ 74613498266Sopenharmony_ci authstatus->done = TRUE; 74713498266Sopenharmony_ci } 74813498266Sopenharmony_ci#endif 74913498266Sopenharmony_ci 75013498266Sopenharmony_ci if(auth) { 75113498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 75213498266Sopenharmony_ci infof(data, "%s auth using %s with user '%s'", 75313498266Sopenharmony_ci proxy ? "Proxy" : "Server", auth, 75413498266Sopenharmony_ci proxy ? (data->state.aptr.proxyuser ? 75513498266Sopenharmony_ci data->state.aptr.proxyuser : "") : 75613498266Sopenharmony_ci (data->state.aptr.user ? 75713498266Sopenharmony_ci data->state.aptr.user : "")); 75813498266Sopenharmony_ci#else 75913498266Sopenharmony_ci (void)proxy; 76013498266Sopenharmony_ci infof(data, "Server auth using %s with user '%s'", 76113498266Sopenharmony_ci auth, data->state.aptr.user ? 76213498266Sopenharmony_ci data->state.aptr.user : ""); 76313498266Sopenharmony_ci#endif 76413498266Sopenharmony_ci authstatus->multipass = (!authstatus->done) ? TRUE : FALSE; 76513498266Sopenharmony_ci } 76613498266Sopenharmony_ci else 76713498266Sopenharmony_ci authstatus->multipass = FALSE; 76813498266Sopenharmony_ci 76913498266Sopenharmony_ci return result; 77013498266Sopenharmony_ci} 77113498266Sopenharmony_ci 77213498266Sopenharmony_ci/** 77313498266Sopenharmony_ci * Curl_http_output_auth() setups the authentication headers for the 77413498266Sopenharmony_ci * host/proxy and the correct authentication 77513498266Sopenharmony_ci * method. data->state.authdone is set to TRUE when authentication is 77613498266Sopenharmony_ci * done. 77713498266Sopenharmony_ci * 77813498266Sopenharmony_ci * @param conn all information about the current connection 77913498266Sopenharmony_ci * @param request pointer to the request keyword 78013498266Sopenharmony_ci * @param path pointer to the requested path; should include query part 78113498266Sopenharmony_ci * @param proxytunnel boolean if this is the request setting up a "proxy 78213498266Sopenharmony_ci * tunnel" 78313498266Sopenharmony_ci * 78413498266Sopenharmony_ci * @returns CURLcode 78513498266Sopenharmony_ci */ 78613498266Sopenharmony_ciCURLcode 78713498266Sopenharmony_ciCurl_http_output_auth(struct Curl_easy *data, 78813498266Sopenharmony_ci struct connectdata *conn, 78913498266Sopenharmony_ci const char *request, 79013498266Sopenharmony_ci Curl_HttpReq httpreq, 79113498266Sopenharmony_ci const char *path, 79213498266Sopenharmony_ci bool proxytunnel) /* TRUE if this is the request setting 79313498266Sopenharmony_ci up the proxy tunnel */ 79413498266Sopenharmony_ci{ 79513498266Sopenharmony_ci CURLcode result = CURLE_OK; 79613498266Sopenharmony_ci struct auth *authhost; 79713498266Sopenharmony_ci struct auth *authproxy; 79813498266Sopenharmony_ci 79913498266Sopenharmony_ci DEBUGASSERT(data); 80013498266Sopenharmony_ci 80113498266Sopenharmony_ci authhost = &data->state.authhost; 80213498266Sopenharmony_ci authproxy = &data->state.authproxy; 80313498266Sopenharmony_ci 80413498266Sopenharmony_ci if( 80513498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 80613498266Sopenharmony_ci (conn->bits.httpproxy && conn->bits.proxy_user_passwd) || 80713498266Sopenharmony_ci#endif 80813498266Sopenharmony_ci data->state.aptr.user || 80913498266Sopenharmony_ci#ifdef USE_SPNEGO 81013498266Sopenharmony_ci authhost->want & CURLAUTH_NEGOTIATE || 81113498266Sopenharmony_ci authproxy->want & CURLAUTH_NEGOTIATE || 81213498266Sopenharmony_ci#endif 81313498266Sopenharmony_ci data->set.str[STRING_BEARER]) 81413498266Sopenharmony_ci /* continue please */; 81513498266Sopenharmony_ci else { 81613498266Sopenharmony_ci authhost->done = TRUE; 81713498266Sopenharmony_ci authproxy->done = TRUE; 81813498266Sopenharmony_ci return CURLE_OK; /* no authentication with no user or password */ 81913498266Sopenharmony_ci } 82013498266Sopenharmony_ci 82113498266Sopenharmony_ci if(authhost->want && !authhost->picked) 82213498266Sopenharmony_ci /* The app has selected one or more methods, but none has been picked 82313498266Sopenharmony_ci so far by a server round-trip. Then we set the picked one to the 82413498266Sopenharmony_ci want one, and if this is one single bit it'll be used instantly. */ 82513498266Sopenharmony_ci authhost->picked = authhost->want; 82613498266Sopenharmony_ci 82713498266Sopenharmony_ci if(authproxy->want && !authproxy->picked) 82813498266Sopenharmony_ci /* The app has selected one or more methods, but none has been picked so 82913498266Sopenharmony_ci far by a proxy round-trip. Then we set the picked one to the want one, 83013498266Sopenharmony_ci and if this is one single bit it'll be used instantly. */ 83113498266Sopenharmony_ci authproxy->picked = authproxy->want; 83213498266Sopenharmony_ci 83313498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 83413498266Sopenharmony_ci /* Send proxy authentication header if needed */ 83513498266Sopenharmony_ci if(conn->bits.httpproxy && 83613498266Sopenharmony_ci (conn->bits.tunnel_proxy == (bit)proxytunnel)) { 83713498266Sopenharmony_ci result = output_auth_headers(data, conn, authproxy, request, path, TRUE); 83813498266Sopenharmony_ci if(result) 83913498266Sopenharmony_ci return result; 84013498266Sopenharmony_ci } 84113498266Sopenharmony_ci else 84213498266Sopenharmony_ci#else 84313498266Sopenharmony_ci (void)proxytunnel; 84413498266Sopenharmony_ci#endif /* CURL_DISABLE_PROXY */ 84513498266Sopenharmony_ci /* we have no proxy so let's pretend we're done authenticating 84613498266Sopenharmony_ci with it */ 84713498266Sopenharmony_ci authproxy->done = TRUE; 84813498266Sopenharmony_ci 84913498266Sopenharmony_ci /* To prevent the user+password to get sent to other than the original host 85013498266Sopenharmony_ci due to a location-follow */ 85113498266Sopenharmony_ci if(Curl_auth_allowed_to_host(data) 85213498266Sopenharmony_ci#ifndef CURL_DISABLE_NETRC 85313498266Sopenharmony_ci || conn->bits.netrc 85413498266Sopenharmony_ci#endif 85513498266Sopenharmony_ci ) 85613498266Sopenharmony_ci result = output_auth_headers(data, conn, authhost, request, path, FALSE); 85713498266Sopenharmony_ci else 85813498266Sopenharmony_ci authhost->done = TRUE; 85913498266Sopenharmony_ci 86013498266Sopenharmony_ci if(((authhost->multipass && !authhost->done) || 86113498266Sopenharmony_ci (authproxy->multipass && !authproxy->done)) && 86213498266Sopenharmony_ci (httpreq != HTTPREQ_GET) && 86313498266Sopenharmony_ci (httpreq != HTTPREQ_HEAD)) { 86413498266Sopenharmony_ci /* Auth is required and we are not authenticated yet. Make a PUT or POST 86513498266Sopenharmony_ci with content-length zero as a "probe". */ 86613498266Sopenharmony_ci conn->bits.authneg = TRUE; 86713498266Sopenharmony_ci } 86813498266Sopenharmony_ci else 86913498266Sopenharmony_ci conn->bits.authneg = FALSE; 87013498266Sopenharmony_ci 87113498266Sopenharmony_ci return result; 87213498266Sopenharmony_ci} 87313498266Sopenharmony_ci 87413498266Sopenharmony_ci#else 87513498266Sopenharmony_ci/* when disabled */ 87613498266Sopenharmony_ciCURLcode 87713498266Sopenharmony_ciCurl_http_output_auth(struct Curl_easy *data, 87813498266Sopenharmony_ci struct connectdata *conn, 87913498266Sopenharmony_ci const char *request, 88013498266Sopenharmony_ci Curl_HttpReq httpreq, 88113498266Sopenharmony_ci const char *path, 88213498266Sopenharmony_ci bool proxytunnel) 88313498266Sopenharmony_ci{ 88413498266Sopenharmony_ci (void)data; 88513498266Sopenharmony_ci (void)conn; 88613498266Sopenharmony_ci (void)request; 88713498266Sopenharmony_ci (void)httpreq; 88813498266Sopenharmony_ci (void)path; 88913498266Sopenharmony_ci (void)proxytunnel; 89013498266Sopenharmony_ci return CURLE_OK; 89113498266Sopenharmony_ci} 89213498266Sopenharmony_ci#endif 89313498266Sopenharmony_ci 89413498266Sopenharmony_ci#if defined(USE_SPNEGO) || defined(USE_NTLM) || \ 89513498266Sopenharmony_ci !defined(CURL_DISABLE_DIGEST_AUTH) || \ 89613498266Sopenharmony_ci !defined(CURL_DISABLE_BASIC_AUTH) || \ 89713498266Sopenharmony_ci !defined(CURL_DISABLE_BEARER_AUTH) 89813498266Sopenharmony_cistatic int is_valid_auth_separator(char ch) 89913498266Sopenharmony_ci{ 90013498266Sopenharmony_ci return ch == '\0' || ch == ',' || ISSPACE(ch); 90113498266Sopenharmony_ci} 90213498266Sopenharmony_ci#endif 90313498266Sopenharmony_ci 90413498266Sopenharmony_ci/* 90513498266Sopenharmony_ci * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: 90613498266Sopenharmony_ci * headers. They are dealt with both in the transfer.c main loop and in the 90713498266Sopenharmony_ci * proxy CONNECT loop. 90813498266Sopenharmony_ci */ 90913498266Sopenharmony_ciCURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, 91013498266Sopenharmony_ci const char *auth) /* the first non-space */ 91113498266Sopenharmony_ci{ 91213498266Sopenharmony_ci /* 91313498266Sopenharmony_ci * This resource requires authentication 91413498266Sopenharmony_ci */ 91513498266Sopenharmony_ci struct connectdata *conn = data->conn; 91613498266Sopenharmony_ci#ifdef USE_SPNEGO 91713498266Sopenharmony_ci curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state : 91813498266Sopenharmony_ci &conn->http_negotiate_state; 91913498266Sopenharmony_ci#endif 92013498266Sopenharmony_ci#if defined(USE_SPNEGO) || \ 92113498266Sopenharmony_ci defined(USE_NTLM) || \ 92213498266Sopenharmony_ci !defined(CURL_DISABLE_DIGEST_AUTH) || \ 92313498266Sopenharmony_ci !defined(CURL_DISABLE_BASIC_AUTH) || \ 92413498266Sopenharmony_ci !defined(CURL_DISABLE_BEARER_AUTH) 92513498266Sopenharmony_ci 92613498266Sopenharmony_ci unsigned long *availp; 92713498266Sopenharmony_ci struct auth *authp; 92813498266Sopenharmony_ci 92913498266Sopenharmony_ci if(proxy) { 93013498266Sopenharmony_ci availp = &data->info.proxyauthavail; 93113498266Sopenharmony_ci authp = &data->state.authproxy; 93213498266Sopenharmony_ci } 93313498266Sopenharmony_ci else { 93413498266Sopenharmony_ci availp = &data->info.httpauthavail; 93513498266Sopenharmony_ci authp = &data->state.authhost; 93613498266Sopenharmony_ci } 93713498266Sopenharmony_ci#else 93813498266Sopenharmony_ci (void) proxy; 93913498266Sopenharmony_ci#endif 94013498266Sopenharmony_ci 94113498266Sopenharmony_ci (void) conn; /* In case conditionals make it unused. */ 94213498266Sopenharmony_ci 94313498266Sopenharmony_ci /* 94413498266Sopenharmony_ci * Here we check if we want the specific single authentication (using ==) and 94513498266Sopenharmony_ci * if we do, we initiate usage of it. 94613498266Sopenharmony_ci * 94713498266Sopenharmony_ci * If the provided authentication is wanted as one out of several accepted 94813498266Sopenharmony_ci * types (using &), we OR this authentication type to the authavail 94913498266Sopenharmony_ci * variable. 95013498266Sopenharmony_ci * 95113498266Sopenharmony_ci * Note: 95213498266Sopenharmony_ci * 95313498266Sopenharmony_ci * ->picked is first set to the 'want' value (one or more bits) before the 95413498266Sopenharmony_ci * request is sent, and then it is again set _after_ all response 401/407 95513498266Sopenharmony_ci * headers have been received but then only to a single preferred method 95613498266Sopenharmony_ci * (bit). 95713498266Sopenharmony_ci */ 95813498266Sopenharmony_ci 95913498266Sopenharmony_ci while(*auth) { 96013498266Sopenharmony_ci#ifdef USE_SPNEGO 96113498266Sopenharmony_ci if(checkprefix("Negotiate", auth) && is_valid_auth_separator(auth[9])) { 96213498266Sopenharmony_ci if((authp->avail & CURLAUTH_NEGOTIATE) || 96313498266Sopenharmony_ci Curl_auth_is_spnego_supported()) { 96413498266Sopenharmony_ci *availp |= CURLAUTH_NEGOTIATE; 96513498266Sopenharmony_ci authp->avail |= CURLAUTH_NEGOTIATE; 96613498266Sopenharmony_ci 96713498266Sopenharmony_ci if(authp->picked == CURLAUTH_NEGOTIATE) { 96813498266Sopenharmony_ci CURLcode result = Curl_input_negotiate(data, conn, proxy, auth); 96913498266Sopenharmony_ci if(!result) { 97013498266Sopenharmony_ci free(data->req.newurl); 97113498266Sopenharmony_ci data->req.newurl = strdup(data->state.url); 97213498266Sopenharmony_ci if(!data->req.newurl) 97313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 97413498266Sopenharmony_ci data->state.authproblem = FALSE; 97513498266Sopenharmony_ci /* we received a GSS auth token and we dealt with it fine */ 97613498266Sopenharmony_ci *negstate = GSS_AUTHRECV; 97713498266Sopenharmony_ci } 97813498266Sopenharmony_ci else 97913498266Sopenharmony_ci data->state.authproblem = TRUE; 98013498266Sopenharmony_ci } 98113498266Sopenharmony_ci } 98213498266Sopenharmony_ci } 98313498266Sopenharmony_ci else 98413498266Sopenharmony_ci#endif 98513498266Sopenharmony_ci#ifdef USE_NTLM 98613498266Sopenharmony_ci /* NTLM support requires the SSL crypto libs */ 98713498266Sopenharmony_ci if(checkprefix("NTLM", auth) && is_valid_auth_separator(auth[4])) { 98813498266Sopenharmony_ci if((authp->avail & CURLAUTH_NTLM) || 98913498266Sopenharmony_ci (authp->avail & CURLAUTH_NTLM_WB) || 99013498266Sopenharmony_ci Curl_auth_is_ntlm_supported()) { 99113498266Sopenharmony_ci *availp |= CURLAUTH_NTLM; 99213498266Sopenharmony_ci authp->avail |= CURLAUTH_NTLM; 99313498266Sopenharmony_ci 99413498266Sopenharmony_ci if(authp->picked == CURLAUTH_NTLM || 99513498266Sopenharmony_ci authp->picked == CURLAUTH_NTLM_WB) { 99613498266Sopenharmony_ci /* NTLM authentication is picked and activated */ 99713498266Sopenharmony_ci CURLcode result = Curl_input_ntlm(data, proxy, auth); 99813498266Sopenharmony_ci if(!result) { 99913498266Sopenharmony_ci data->state.authproblem = FALSE; 100013498266Sopenharmony_ci#ifdef NTLM_WB_ENABLED 100113498266Sopenharmony_ci if(authp->picked == CURLAUTH_NTLM_WB) { 100213498266Sopenharmony_ci *availp &= ~CURLAUTH_NTLM; 100313498266Sopenharmony_ci authp->avail &= ~CURLAUTH_NTLM; 100413498266Sopenharmony_ci *availp |= CURLAUTH_NTLM_WB; 100513498266Sopenharmony_ci authp->avail |= CURLAUTH_NTLM_WB; 100613498266Sopenharmony_ci 100713498266Sopenharmony_ci result = Curl_input_ntlm_wb(data, conn, proxy, auth); 100813498266Sopenharmony_ci if(result) { 100913498266Sopenharmony_ci infof(data, "Authentication problem. Ignoring this."); 101013498266Sopenharmony_ci data->state.authproblem = TRUE; 101113498266Sopenharmony_ci } 101213498266Sopenharmony_ci } 101313498266Sopenharmony_ci#endif 101413498266Sopenharmony_ci } 101513498266Sopenharmony_ci else { 101613498266Sopenharmony_ci infof(data, "Authentication problem. Ignoring this."); 101713498266Sopenharmony_ci data->state.authproblem = TRUE; 101813498266Sopenharmony_ci } 101913498266Sopenharmony_ci } 102013498266Sopenharmony_ci } 102113498266Sopenharmony_ci } 102213498266Sopenharmony_ci else 102313498266Sopenharmony_ci#endif 102413498266Sopenharmony_ci#ifndef CURL_DISABLE_DIGEST_AUTH 102513498266Sopenharmony_ci if(checkprefix("Digest", auth) && is_valid_auth_separator(auth[6])) { 102613498266Sopenharmony_ci if((authp->avail & CURLAUTH_DIGEST) != 0) 102713498266Sopenharmony_ci infof(data, "Ignoring duplicate digest auth header."); 102813498266Sopenharmony_ci else if(Curl_auth_is_digest_supported()) { 102913498266Sopenharmony_ci CURLcode result; 103013498266Sopenharmony_ci 103113498266Sopenharmony_ci *availp |= CURLAUTH_DIGEST; 103213498266Sopenharmony_ci authp->avail |= CURLAUTH_DIGEST; 103313498266Sopenharmony_ci 103413498266Sopenharmony_ci /* We call this function on input Digest headers even if Digest 103513498266Sopenharmony_ci * authentication isn't activated yet, as we need to store the 103613498266Sopenharmony_ci * incoming data from this header in case we are going to use 103713498266Sopenharmony_ci * Digest */ 103813498266Sopenharmony_ci result = Curl_input_digest(data, proxy, auth); 103913498266Sopenharmony_ci if(result) { 104013498266Sopenharmony_ci infof(data, "Authentication problem. Ignoring this."); 104113498266Sopenharmony_ci data->state.authproblem = TRUE; 104213498266Sopenharmony_ci } 104313498266Sopenharmony_ci } 104413498266Sopenharmony_ci } 104513498266Sopenharmony_ci else 104613498266Sopenharmony_ci#endif 104713498266Sopenharmony_ci#ifndef CURL_DISABLE_BASIC_AUTH 104813498266Sopenharmony_ci if(checkprefix("Basic", auth) && 104913498266Sopenharmony_ci is_valid_auth_separator(auth[5])) { 105013498266Sopenharmony_ci *availp |= CURLAUTH_BASIC; 105113498266Sopenharmony_ci authp->avail |= CURLAUTH_BASIC; 105213498266Sopenharmony_ci if(authp->picked == CURLAUTH_BASIC) { 105313498266Sopenharmony_ci /* We asked for Basic authentication but got a 40X back 105413498266Sopenharmony_ci anyway, which basically means our name+password isn't 105513498266Sopenharmony_ci valid. */ 105613498266Sopenharmony_ci authp->avail = CURLAUTH_NONE; 105713498266Sopenharmony_ci infof(data, "Authentication problem. Ignoring this."); 105813498266Sopenharmony_ci data->state.authproblem = TRUE; 105913498266Sopenharmony_ci } 106013498266Sopenharmony_ci } 106113498266Sopenharmony_ci else 106213498266Sopenharmony_ci#endif 106313498266Sopenharmony_ci#ifndef CURL_DISABLE_BEARER_AUTH 106413498266Sopenharmony_ci if(checkprefix("Bearer", auth) && 106513498266Sopenharmony_ci is_valid_auth_separator(auth[6])) { 106613498266Sopenharmony_ci *availp |= CURLAUTH_BEARER; 106713498266Sopenharmony_ci authp->avail |= CURLAUTH_BEARER; 106813498266Sopenharmony_ci if(authp->picked == CURLAUTH_BEARER) { 106913498266Sopenharmony_ci /* We asked for Bearer authentication but got a 40X back 107013498266Sopenharmony_ci anyway, which basically means our token isn't valid. */ 107113498266Sopenharmony_ci authp->avail = CURLAUTH_NONE; 107213498266Sopenharmony_ci infof(data, "Authentication problem. Ignoring this."); 107313498266Sopenharmony_ci data->state.authproblem = TRUE; 107413498266Sopenharmony_ci } 107513498266Sopenharmony_ci } 107613498266Sopenharmony_ci#else 107713498266Sopenharmony_ci { 107813498266Sopenharmony_ci /* 107913498266Sopenharmony_ci * Empty block to terminate the if-else chain correctly. 108013498266Sopenharmony_ci * 108113498266Sopenharmony_ci * A semicolon would yield the same result here, but can cause a 108213498266Sopenharmony_ci * compiler warning when -Wextra is enabled. 108313498266Sopenharmony_ci */ 108413498266Sopenharmony_ci } 108513498266Sopenharmony_ci#endif 108613498266Sopenharmony_ci 108713498266Sopenharmony_ci /* there may be multiple methods on one line, so keep reading */ 108813498266Sopenharmony_ci while(*auth && *auth != ',') /* read up to the next comma */ 108913498266Sopenharmony_ci auth++; 109013498266Sopenharmony_ci if(*auth == ',') /* if we're on a comma, skip it */ 109113498266Sopenharmony_ci auth++; 109213498266Sopenharmony_ci while(*auth && ISSPACE(*auth)) 109313498266Sopenharmony_ci auth++; 109413498266Sopenharmony_ci } 109513498266Sopenharmony_ci 109613498266Sopenharmony_ci return CURLE_OK; 109713498266Sopenharmony_ci} 109813498266Sopenharmony_ci 109913498266Sopenharmony_ci/** 110013498266Sopenharmony_ci * http_should_fail() determines whether an HTTP response has gotten us 110113498266Sopenharmony_ci * into an error state or not. 110213498266Sopenharmony_ci * 110313498266Sopenharmony_ci * @retval FALSE communications should continue 110413498266Sopenharmony_ci * 110513498266Sopenharmony_ci * @retval TRUE communications should not continue 110613498266Sopenharmony_ci */ 110713498266Sopenharmony_cistatic bool http_should_fail(struct Curl_easy *data) 110813498266Sopenharmony_ci{ 110913498266Sopenharmony_ci int httpcode; 111013498266Sopenharmony_ci DEBUGASSERT(data); 111113498266Sopenharmony_ci DEBUGASSERT(data->conn); 111213498266Sopenharmony_ci 111313498266Sopenharmony_ci httpcode = data->req.httpcode; 111413498266Sopenharmony_ci 111513498266Sopenharmony_ci /* 111613498266Sopenharmony_ci ** If we haven't been asked to fail on error, 111713498266Sopenharmony_ci ** don't fail. 111813498266Sopenharmony_ci */ 111913498266Sopenharmony_ci if(!data->set.http_fail_on_error) 112013498266Sopenharmony_ci return FALSE; 112113498266Sopenharmony_ci 112213498266Sopenharmony_ci /* 112313498266Sopenharmony_ci ** Any code < 400 is never terminal. 112413498266Sopenharmony_ci */ 112513498266Sopenharmony_ci if(httpcode < 400) 112613498266Sopenharmony_ci return FALSE; 112713498266Sopenharmony_ci 112813498266Sopenharmony_ci /* 112913498266Sopenharmony_ci ** A 416 response to a resume request is presumably because the file is 113013498266Sopenharmony_ci ** already completely downloaded and thus not actually a fail. 113113498266Sopenharmony_ci */ 113213498266Sopenharmony_ci if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET && 113313498266Sopenharmony_ci httpcode == 416) 113413498266Sopenharmony_ci return FALSE; 113513498266Sopenharmony_ci 113613498266Sopenharmony_ci /* 113713498266Sopenharmony_ci ** Any code >= 400 that's not 401 or 407 is always 113813498266Sopenharmony_ci ** a terminal error 113913498266Sopenharmony_ci */ 114013498266Sopenharmony_ci if((httpcode != 401) && (httpcode != 407)) 114113498266Sopenharmony_ci return TRUE; 114213498266Sopenharmony_ci 114313498266Sopenharmony_ci /* 114413498266Sopenharmony_ci ** All we have left to deal with is 401 and 407 114513498266Sopenharmony_ci */ 114613498266Sopenharmony_ci DEBUGASSERT((httpcode == 401) || (httpcode == 407)); 114713498266Sopenharmony_ci 114813498266Sopenharmony_ci /* 114913498266Sopenharmony_ci ** Examine the current authentication state to see if this 115013498266Sopenharmony_ci ** is an error. The idea is for this function to get 115113498266Sopenharmony_ci ** called after processing all the headers in a response 115213498266Sopenharmony_ci ** message. So, if we've been to asked to authenticate a 115313498266Sopenharmony_ci ** particular stage, and we've done it, we're OK. But, if 115413498266Sopenharmony_ci ** we're already completely authenticated, it's not OK to 115513498266Sopenharmony_ci ** get another 401 or 407. 115613498266Sopenharmony_ci ** 115713498266Sopenharmony_ci ** It is possible for authentication to go stale such that 115813498266Sopenharmony_ci ** the client needs to reauthenticate. Once that info is 115913498266Sopenharmony_ci ** available, use it here. 116013498266Sopenharmony_ci */ 116113498266Sopenharmony_ci 116213498266Sopenharmony_ci /* 116313498266Sopenharmony_ci ** Either we're not authenticating, or we're supposed to 116413498266Sopenharmony_ci ** be authenticating something else. This is an error. 116513498266Sopenharmony_ci */ 116613498266Sopenharmony_ci if((httpcode == 401) && !data->state.aptr.user) 116713498266Sopenharmony_ci return TRUE; 116813498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 116913498266Sopenharmony_ci if((httpcode == 407) && !data->conn->bits.proxy_user_passwd) 117013498266Sopenharmony_ci return TRUE; 117113498266Sopenharmony_ci#endif 117213498266Sopenharmony_ci 117313498266Sopenharmony_ci return data->state.authproblem; 117413498266Sopenharmony_ci} 117513498266Sopenharmony_ci 117613498266Sopenharmony_ci/* 117713498266Sopenharmony_ci * readmoredata() is a "fread() emulation" to provide POST and/or request 117813498266Sopenharmony_ci * data. It is used when a huge POST is to be made and the entire chunk wasn't 117913498266Sopenharmony_ci * sent in the first send(). This function will then be called from the 118013498266Sopenharmony_ci * transfer.c loop when more data is to be sent to the peer. 118113498266Sopenharmony_ci * 118213498266Sopenharmony_ci * Returns the amount of bytes it filled the buffer with. 118313498266Sopenharmony_ci */ 118413498266Sopenharmony_cistatic size_t readmoredata(char *buffer, 118513498266Sopenharmony_ci size_t size, 118613498266Sopenharmony_ci size_t nitems, 118713498266Sopenharmony_ci void *userp) 118813498266Sopenharmony_ci{ 118913498266Sopenharmony_ci struct HTTP *http = (struct HTTP *)userp; 119013498266Sopenharmony_ci struct Curl_easy *data = http->backup.data; 119113498266Sopenharmony_ci size_t fullsize = size * nitems; 119213498266Sopenharmony_ci 119313498266Sopenharmony_ci if(!http->postsize) 119413498266Sopenharmony_ci /* nothing to return */ 119513498266Sopenharmony_ci return 0; 119613498266Sopenharmony_ci 119713498266Sopenharmony_ci /* make sure that an HTTP request is never sent away chunked! */ 119813498266Sopenharmony_ci data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE; 119913498266Sopenharmony_ci 120013498266Sopenharmony_ci if(data->set.max_send_speed && 120113498266Sopenharmony_ci (data->set.max_send_speed < (curl_off_t)fullsize) && 120213498266Sopenharmony_ci (data->set.max_send_speed < http->postsize)) 120313498266Sopenharmony_ci /* speed limit */ 120413498266Sopenharmony_ci fullsize = (size_t)data->set.max_send_speed; 120513498266Sopenharmony_ci 120613498266Sopenharmony_ci else if(http->postsize <= (curl_off_t)fullsize) { 120713498266Sopenharmony_ci memcpy(buffer, http->postdata, (size_t)http->postsize); 120813498266Sopenharmony_ci fullsize = (size_t)http->postsize; 120913498266Sopenharmony_ci 121013498266Sopenharmony_ci if(http->backup.postsize) { 121113498266Sopenharmony_ci /* move backup data into focus and continue on that */ 121213498266Sopenharmony_ci http->postdata = http->backup.postdata; 121313498266Sopenharmony_ci http->postsize = http->backup.postsize; 121413498266Sopenharmony_ci data->state.fread_func = http->backup.fread_func; 121513498266Sopenharmony_ci data->state.in = http->backup.fread_in; 121613498266Sopenharmony_ci 121713498266Sopenharmony_ci http->sending++; /* move one step up */ 121813498266Sopenharmony_ci 121913498266Sopenharmony_ci http->backup.postsize = 0; 122013498266Sopenharmony_ci } 122113498266Sopenharmony_ci else 122213498266Sopenharmony_ci http->postsize = 0; 122313498266Sopenharmony_ci 122413498266Sopenharmony_ci return fullsize; 122513498266Sopenharmony_ci } 122613498266Sopenharmony_ci 122713498266Sopenharmony_ci memcpy(buffer, http->postdata, fullsize); 122813498266Sopenharmony_ci http->postdata += fullsize; 122913498266Sopenharmony_ci http->postsize -= fullsize; 123013498266Sopenharmony_ci 123113498266Sopenharmony_ci return fullsize; 123213498266Sopenharmony_ci} 123313498266Sopenharmony_ci 123413498266Sopenharmony_ci/* 123513498266Sopenharmony_ci * Curl_buffer_send() sends a header buffer and frees all associated 123613498266Sopenharmony_ci * memory. Body data may be appended to the header data if desired. 123713498266Sopenharmony_ci * 123813498266Sopenharmony_ci * Returns CURLcode 123913498266Sopenharmony_ci */ 124013498266Sopenharmony_ciCURLcode Curl_buffer_send(struct dynbuf *in, 124113498266Sopenharmony_ci struct Curl_easy *data, 124213498266Sopenharmony_ci struct HTTP *http, 124313498266Sopenharmony_ci /* add the number of sent bytes to this 124413498266Sopenharmony_ci counter */ 124513498266Sopenharmony_ci curl_off_t *bytes_written, 124613498266Sopenharmony_ci /* how much of the buffer contains body data */ 124713498266Sopenharmony_ci curl_off_t included_body_bytes, 124813498266Sopenharmony_ci int sockindex) 124913498266Sopenharmony_ci{ 125013498266Sopenharmony_ci ssize_t amount; 125113498266Sopenharmony_ci CURLcode result; 125213498266Sopenharmony_ci char *ptr; 125313498266Sopenharmony_ci size_t size; 125413498266Sopenharmony_ci struct connectdata *conn = data->conn; 125513498266Sopenharmony_ci size_t sendsize; 125613498266Sopenharmony_ci size_t headersize; 125713498266Sopenharmony_ci 125813498266Sopenharmony_ci DEBUGASSERT(sockindex <= SECONDARYSOCKET && sockindex >= 0); 125913498266Sopenharmony_ci 126013498266Sopenharmony_ci /* The looping below is required since we use non-blocking sockets, but due 126113498266Sopenharmony_ci to the circumstances we will just loop and try again and again etc */ 126213498266Sopenharmony_ci 126313498266Sopenharmony_ci ptr = Curl_dyn_ptr(in); 126413498266Sopenharmony_ci size = Curl_dyn_len(in); 126513498266Sopenharmony_ci 126613498266Sopenharmony_ci headersize = size - (size_t)included_body_bytes; /* the initial part that 126713498266Sopenharmony_ci isn't body is header */ 126813498266Sopenharmony_ci 126913498266Sopenharmony_ci DEBUGASSERT(size > (size_t)included_body_bytes); 127013498266Sopenharmony_ci 127113498266Sopenharmony_ci if((conn->handler->flags & PROTOPT_SSL 127213498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 127313498266Sopenharmony_ci || IS_HTTPS_PROXY(conn->http_proxy.proxytype) 127413498266Sopenharmony_ci#endif 127513498266Sopenharmony_ci ) 127613498266Sopenharmony_ci && conn->httpversion < 20) { 127713498266Sopenharmony_ci /* Make sure this doesn't send more body bytes than what the max send 127813498266Sopenharmony_ci speed says. The request bytes do not count to the max speed. 127913498266Sopenharmony_ci */ 128013498266Sopenharmony_ci if(data->set.max_send_speed && 128113498266Sopenharmony_ci (included_body_bytes > data->set.max_send_speed)) { 128213498266Sopenharmony_ci curl_off_t overflow = included_body_bytes - data->set.max_send_speed; 128313498266Sopenharmony_ci DEBUGASSERT((size_t)overflow < size); 128413498266Sopenharmony_ci sendsize = size - (size_t)overflow; 128513498266Sopenharmony_ci } 128613498266Sopenharmony_ci else 128713498266Sopenharmony_ci sendsize = size; 128813498266Sopenharmony_ci 128913498266Sopenharmony_ci /* OpenSSL is very picky and we must send the SAME buffer pointer to the 129013498266Sopenharmony_ci library when we attempt to re-send this buffer. Sending the same data 129113498266Sopenharmony_ci is not enough, we must use the exact same address. For this reason, we 129213498266Sopenharmony_ci must copy the data to the uploadbuffer first, since that is the buffer 129313498266Sopenharmony_ci we will be using if this send is retried later. 129413498266Sopenharmony_ci */ 129513498266Sopenharmony_ci result = Curl_get_upload_buffer(data); 129613498266Sopenharmony_ci if(result) { 129713498266Sopenharmony_ci /* malloc failed, free memory and return to the caller */ 129813498266Sopenharmony_ci Curl_dyn_free(in); 129913498266Sopenharmony_ci return result; 130013498266Sopenharmony_ci } 130113498266Sopenharmony_ci /* We never send more than upload_buffer_size bytes in one single chunk 130213498266Sopenharmony_ci when we speak HTTPS, as if only a fraction of it is sent now, this data 130313498266Sopenharmony_ci needs to fit into the normal read-callback buffer later on and that 130413498266Sopenharmony_ci buffer is using this size. 130513498266Sopenharmony_ci */ 130613498266Sopenharmony_ci if(sendsize > (size_t)data->set.upload_buffer_size) 130713498266Sopenharmony_ci sendsize = (size_t)data->set.upload_buffer_size; 130813498266Sopenharmony_ci 130913498266Sopenharmony_ci memcpy(data->state.ulbuf, ptr, sendsize); 131013498266Sopenharmony_ci ptr = data->state.ulbuf; 131113498266Sopenharmony_ci } 131213498266Sopenharmony_ci else { 131313498266Sopenharmony_ci#ifdef CURLDEBUG 131413498266Sopenharmony_ci /* Allow debug builds to override this logic to force short initial 131513498266Sopenharmony_ci sends 131613498266Sopenharmony_ci */ 131713498266Sopenharmony_ci char *p = getenv("CURL_SMALLREQSEND"); 131813498266Sopenharmony_ci if(p) { 131913498266Sopenharmony_ci size_t altsize = (size_t)strtoul(p, NULL, 10); 132013498266Sopenharmony_ci if(altsize) 132113498266Sopenharmony_ci sendsize = CURLMIN(size, altsize); 132213498266Sopenharmony_ci else 132313498266Sopenharmony_ci sendsize = size; 132413498266Sopenharmony_ci } 132513498266Sopenharmony_ci else 132613498266Sopenharmony_ci#endif 132713498266Sopenharmony_ci { 132813498266Sopenharmony_ci /* Make sure this doesn't send more body bytes than what the max send 132913498266Sopenharmony_ci speed says. The request bytes do not count to the max speed. 133013498266Sopenharmony_ci */ 133113498266Sopenharmony_ci if(data->set.max_send_speed && 133213498266Sopenharmony_ci (included_body_bytes > data->set.max_send_speed)) { 133313498266Sopenharmony_ci curl_off_t overflow = included_body_bytes - data->set.max_send_speed; 133413498266Sopenharmony_ci DEBUGASSERT((size_t)overflow < size); 133513498266Sopenharmony_ci sendsize = size - (size_t)overflow; 133613498266Sopenharmony_ci } 133713498266Sopenharmony_ci else 133813498266Sopenharmony_ci sendsize = size; 133913498266Sopenharmony_ci } 134013498266Sopenharmony_ci 134113498266Sopenharmony_ci /* We currently cannot send more that this for http here: 134213498266Sopenharmony_ci * - if sending blocks, it return 0 as amount 134313498266Sopenharmony_ci * - we then whisk aside the `in` into the `http` struct 134413498266Sopenharmony_ci * and install our own `data->state.fread_func` that 134513498266Sopenharmony_ci * on subsequent calls reads `in` empty. 134613498266Sopenharmony_ci * - when the whisked away `in` is empty, the `fread_func` 134713498266Sopenharmony_ci * is restored to its original state. 134813498266Sopenharmony_ci * The problem is that `fread_func` can only return 134913498266Sopenharmony_ci * `upload_buffer_size` lengths. If the send we do here 135013498266Sopenharmony_ci * is larger and blocks, we do re-sending with smaller 135113498266Sopenharmony_ci * amounts of data and connection filters do not like 135213498266Sopenharmony_ci * that. 135313498266Sopenharmony_ci */ 135413498266Sopenharmony_ci if(http && (sendsize > (size_t)data->set.upload_buffer_size)) 135513498266Sopenharmony_ci sendsize = (size_t)data->set.upload_buffer_size; 135613498266Sopenharmony_ci } 135713498266Sopenharmony_ci 135813498266Sopenharmony_ci result = Curl_nwrite(data, sockindex, ptr, sendsize, &amount); 135913498266Sopenharmony_ci 136013498266Sopenharmony_ci if(!result) { 136113498266Sopenharmony_ci /* 136213498266Sopenharmony_ci * Note that we may not send the entire chunk at once, and we have a set 136313498266Sopenharmony_ci * number of data bytes at the end of the big buffer (out of which we may 136413498266Sopenharmony_ci * only send away a part). 136513498266Sopenharmony_ci */ 136613498266Sopenharmony_ci /* how much of the header that was sent */ 136713498266Sopenharmony_ci size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount; 136813498266Sopenharmony_ci size_t bodylen = amount - headlen; 136913498266Sopenharmony_ci 137013498266Sopenharmony_ci /* this data _may_ contain binary stuff */ 137113498266Sopenharmony_ci Curl_debug(data, CURLINFO_HEADER_OUT, ptr, headlen); 137213498266Sopenharmony_ci if(bodylen) 137313498266Sopenharmony_ci /* there was body data sent beyond the initial header part, pass that on 137413498266Sopenharmony_ci to the debug callback too */ 137513498266Sopenharmony_ci Curl_debug(data, CURLINFO_DATA_OUT, ptr + headlen, bodylen); 137613498266Sopenharmony_ci 137713498266Sopenharmony_ci /* 'amount' can never be a very large value here so typecasting it so a 137813498266Sopenharmony_ci signed 31 bit value should not cause problems even if ssize_t is 137913498266Sopenharmony_ci 64bit */ 138013498266Sopenharmony_ci *bytes_written += (long)amount; 138113498266Sopenharmony_ci 138213498266Sopenharmony_ci if(http) { 138313498266Sopenharmony_ci /* if we sent a piece of the body here, up the byte counter for it 138413498266Sopenharmony_ci accordingly */ 138513498266Sopenharmony_ci data->req.writebytecount += bodylen; 138613498266Sopenharmony_ci Curl_pgrsSetUploadCounter(data, data->req.writebytecount); 138713498266Sopenharmony_ci 138813498266Sopenharmony_ci if((size_t)amount != size) { 138913498266Sopenharmony_ci /* The whole request could not be sent in one system call. We must 139013498266Sopenharmony_ci queue it up and send it later when we get the chance. We must not 139113498266Sopenharmony_ci loop here and wait until it might work again. */ 139213498266Sopenharmony_ci 139313498266Sopenharmony_ci size -= amount; 139413498266Sopenharmony_ci 139513498266Sopenharmony_ci ptr = Curl_dyn_ptr(in) + amount; 139613498266Sopenharmony_ci 139713498266Sopenharmony_ci /* backup the currently set pointers */ 139813498266Sopenharmony_ci http->backup.fread_func = data->state.fread_func; 139913498266Sopenharmony_ci http->backup.fread_in = data->state.in; 140013498266Sopenharmony_ci http->backup.postdata = http->postdata; 140113498266Sopenharmony_ci http->backup.postsize = http->postsize; 140213498266Sopenharmony_ci http->backup.data = data; 140313498266Sopenharmony_ci 140413498266Sopenharmony_ci /* set the new pointers for the request-sending */ 140513498266Sopenharmony_ci data->state.fread_func = (curl_read_callback)readmoredata; 140613498266Sopenharmony_ci data->state.in = (void *)http; 140713498266Sopenharmony_ci http->postdata = ptr; 140813498266Sopenharmony_ci http->postsize = (curl_off_t)size; 140913498266Sopenharmony_ci 141013498266Sopenharmony_ci /* this much data is remaining header: */ 141113498266Sopenharmony_ci data->req.pendingheader = headersize - headlen; 141213498266Sopenharmony_ci 141313498266Sopenharmony_ci http->send_buffer = *in; /* copy the whole struct */ 141413498266Sopenharmony_ci http->sending = HTTPSEND_REQUEST; 141513498266Sopenharmony_ci return CURLE_OK; 141613498266Sopenharmony_ci } 141713498266Sopenharmony_ci http->sending = HTTPSEND_BODY; 141813498266Sopenharmony_ci /* the full buffer was sent, clean up and return */ 141913498266Sopenharmony_ci } 142013498266Sopenharmony_ci else { 142113498266Sopenharmony_ci if((size_t)amount != size) 142213498266Sopenharmony_ci /* We have no continue-send mechanism now, fail. This can only happen 142313498266Sopenharmony_ci when this function is used from the CONNECT sending function. We 142413498266Sopenharmony_ci currently (stupidly) assume that the whole request is always sent 142513498266Sopenharmony_ci away in the first single chunk. 142613498266Sopenharmony_ci 142713498266Sopenharmony_ci This needs FIXing. 142813498266Sopenharmony_ci */ 142913498266Sopenharmony_ci return CURLE_SEND_ERROR; 143013498266Sopenharmony_ci } 143113498266Sopenharmony_ci } 143213498266Sopenharmony_ci Curl_dyn_free(in); 143313498266Sopenharmony_ci 143413498266Sopenharmony_ci /* no remaining header data */ 143513498266Sopenharmony_ci data->req.pendingheader = 0; 143613498266Sopenharmony_ci return result; 143713498266Sopenharmony_ci} 143813498266Sopenharmony_ci 143913498266Sopenharmony_ci/* end of the add_buffer functions */ 144013498266Sopenharmony_ci/* ------------------------------------------------------------------------- */ 144113498266Sopenharmony_ci 144213498266Sopenharmony_ci 144313498266Sopenharmony_ci 144413498266Sopenharmony_ci/* 144513498266Sopenharmony_ci * Curl_compareheader() 144613498266Sopenharmony_ci * 144713498266Sopenharmony_ci * Returns TRUE if 'headerline' contains the 'header' with given 'content'. 144813498266Sopenharmony_ci * Pass headers WITH the colon. 144913498266Sopenharmony_ci */ 145013498266Sopenharmony_cibool 145113498266Sopenharmony_ciCurl_compareheader(const char *headerline, /* line to check */ 145213498266Sopenharmony_ci const char *header, /* header keyword _with_ colon */ 145313498266Sopenharmony_ci const size_t hlen, /* len of the keyword in bytes */ 145413498266Sopenharmony_ci const char *content, /* content string to find */ 145513498266Sopenharmony_ci const size_t clen) /* len of the content in bytes */ 145613498266Sopenharmony_ci{ 145713498266Sopenharmony_ci /* RFC2616, section 4.2 says: "Each header field consists of a name followed 145813498266Sopenharmony_ci * by a colon (":") and the field value. Field names are case-insensitive. 145913498266Sopenharmony_ci * The field value MAY be preceded by any amount of LWS, though a single SP 146013498266Sopenharmony_ci * is preferred." */ 146113498266Sopenharmony_ci 146213498266Sopenharmony_ci size_t len; 146313498266Sopenharmony_ci const char *start; 146413498266Sopenharmony_ci const char *end; 146513498266Sopenharmony_ci DEBUGASSERT(hlen); 146613498266Sopenharmony_ci DEBUGASSERT(clen); 146713498266Sopenharmony_ci DEBUGASSERT(header); 146813498266Sopenharmony_ci DEBUGASSERT(content); 146913498266Sopenharmony_ci 147013498266Sopenharmony_ci if(!strncasecompare(headerline, header, hlen)) 147113498266Sopenharmony_ci return FALSE; /* doesn't start with header */ 147213498266Sopenharmony_ci 147313498266Sopenharmony_ci /* pass the header */ 147413498266Sopenharmony_ci start = &headerline[hlen]; 147513498266Sopenharmony_ci 147613498266Sopenharmony_ci /* pass all whitespace */ 147713498266Sopenharmony_ci while(*start && ISSPACE(*start)) 147813498266Sopenharmony_ci start++; 147913498266Sopenharmony_ci 148013498266Sopenharmony_ci /* find the end of the header line */ 148113498266Sopenharmony_ci end = strchr(start, '\r'); /* lines end with CRLF */ 148213498266Sopenharmony_ci if(!end) { 148313498266Sopenharmony_ci /* in case there's a non-standard compliant line here */ 148413498266Sopenharmony_ci end = strchr(start, '\n'); 148513498266Sopenharmony_ci 148613498266Sopenharmony_ci if(!end) 148713498266Sopenharmony_ci /* hm, there's no line ending here, use the zero byte! */ 148813498266Sopenharmony_ci end = strchr(start, '\0'); 148913498266Sopenharmony_ci } 149013498266Sopenharmony_ci 149113498266Sopenharmony_ci len = end-start; /* length of the content part of the input line */ 149213498266Sopenharmony_ci 149313498266Sopenharmony_ci /* find the content string in the rest of the line */ 149413498266Sopenharmony_ci for(; len >= clen; len--, start++) { 149513498266Sopenharmony_ci if(strncasecompare(start, content, clen)) 149613498266Sopenharmony_ci return TRUE; /* match! */ 149713498266Sopenharmony_ci } 149813498266Sopenharmony_ci 149913498266Sopenharmony_ci return FALSE; /* no match */ 150013498266Sopenharmony_ci} 150113498266Sopenharmony_ci 150213498266Sopenharmony_ci/* 150313498266Sopenharmony_ci * Curl_http_connect() performs HTTP stuff to do at connect-time, called from 150413498266Sopenharmony_ci * the generic Curl_connect(). 150513498266Sopenharmony_ci */ 150613498266Sopenharmony_ciCURLcode Curl_http_connect(struct Curl_easy *data, bool *done) 150713498266Sopenharmony_ci{ 150813498266Sopenharmony_ci struct connectdata *conn = data->conn; 150913498266Sopenharmony_ci 151013498266Sopenharmony_ci /* We default to persistent connections. We set this already in this connect 151113498266Sopenharmony_ci function to make the reuse checks properly be able to check this bit. */ 151213498266Sopenharmony_ci connkeep(conn, "HTTP default"); 151313498266Sopenharmony_ci 151413498266Sopenharmony_ci return Curl_conn_connect(data, FIRSTSOCKET, FALSE, done); 151513498266Sopenharmony_ci} 151613498266Sopenharmony_ci 151713498266Sopenharmony_ci/* this returns the socket to wait for in the DO and DOING state for the multi 151813498266Sopenharmony_ci interface and then we're always _sending_ a request and thus we wait for 151913498266Sopenharmony_ci the single socket to become writable only */ 152013498266Sopenharmony_ciint Curl_http_getsock_do(struct Curl_easy *data, 152113498266Sopenharmony_ci struct connectdata *conn, 152213498266Sopenharmony_ci curl_socket_t *socks) 152313498266Sopenharmony_ci{ 152413498266Sopenharmony_ci /* write mode */ 152513498266Sopenharmony_ci (void)conn; 152613498266Sopenharmony_ci socks[0] = Curl_conn_get_socket(data, FIRSTSOCKET); 152713498266Sopenharmony_ci return GETSOCK_WRITESOCK(0); 152813498266Sopenharmony_ci} 152913498266Sopenharmony_ci 153013498266Sopenharmony_ci/* 153113498266Sopenharmony_ci * Curl_http_done() gets called after a single HTTP request has been 153213498266Sopenharmony_ci * performed. 153313498266Sopenharmony_ci */ 153413498266Sopenharmony_ci 153513498266Sopenharmony_ciCURLcode Curl_http_done(struct Curl_easy *data, 153613498266Sopenharmony_ci CURLcode status, bool premature) 153713498266Sopenharmony_ci{ 153813498266Sopenharmony_ci struct connectdata *conn = data->conn; 153913498266Sopenharmony_ci struct HTTP *http = data->req.p.http; 154013498266Sopenharmony_ci 154113498266Sopenharmony_ci /* Clear multipass flag. If authentication isn't done yet, then it will get 154213498266Sopenharmony_ci * a chance to be set back to true when we output the next auth header */ 154313498266Sopenharmony_ci data->state.authhost.multipass = FALSE; 154413498266Sopenharmony_ci data->state.authproxy.multipass = FALSE; 154513498266Sopenharmony_ci 154613498266Sopenharmony_ci /* set the proper values (possibly modified on POST) */ 154713498266Sopenharmony_ci conn->seek_func = data->set.seek_func; /* restore */ 154813498266Sopenharmony_ci conn->seek_client = data->set.seek_client; /* restore */ 154913498266Sopenharmony_ci 155013498266Sopenharmony_ci if(!http) 155113498266Sopenharmony_ci return CURLE_OK; 155213498266Sopenharmony_ci 155313498266Sopenharmony_ci Curl_dyn_free(&http->send_buffer); 155413498266Sopenharmony_ci Curl_dyn_reset(&data->state.headerb); 155513498266Sopenharmony_ci Curl_hyper_done(data); 155613498266Sopenharmony_ci Curl_ws_done(data); 155713498266Sopenharmony_ci 155813498266Sopenharmony_ci if(status) 155913498266Sopenharmony_ci return status; 156013498266Sopenharmony_ci 156113498266Sopenharmony_ci if(!premature && /* this check is pointless when DONE is called before the 156213498266Sopenharmony_ci entire operation is complete */ 156313498266Sopenharmony_ci !conn->bits.retry && 156413498266Sopenharmony_ci !data->set.connect_only && 156513498266Sopenharmony_ci (data->req.bytecount + 156613498266Sopenharmony_ci data->req.headerbytecount - 156713498266Sopenharmony_ci data->req.deductheadercount) <= 0) { 156813498266Sopenharmony_ci /* If this connection isn't simply closed to be retried, AND nothing was 156913498266Sopenharmony_ci read from the HTTP server (that counts), this can't be right so we 157013498266Sopenharmony_ci return an error here */ 157113498266Sopenharmony_ci failf(data, "Empty reply from server"); 157213498266Sopenharmony_ci /* Mark it as closed to avoid the "left intact" message */ 157313498266Sopenharmony_ci streamclose(conn, "Empty reply from server"); 157413498266Sopenharmony_ci return CURLE_GOT_NOTHING; 157513498266Sopenharmony_ci } 157613498266Sopenharmony_ci 157713498266Sopenharmony_ci return CURLE_OK; 157813498266Sopenharmony_ci} 157913498266Sopenharmony_ci 158013498266Sopenharmony_ci/* 158113498266Sopenharmony_ci * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons 158213498266Sopenharmony_ci * to avoid it include: 158313498266Sopenharmony_ci * 158413498266Sopenharmony_ci * - if the user specifically requested HTTP 1.0 158513498266Sopenharmony_ci * - if the server we are connected to only supports 1.0 158613498266Sopenharmony_ci * - if any server previously contacted to handle this request only supports 158713498266Sopenharmony_ci * 1.0. 158813498266Sopenharmony_ci */ 158913498266Sopenharmony_cibool Curl_use_http_1_1plus(const struct Curl_easy *data, 159013498266Sopenharmony_ci const struct connectdata *conn) 159113498266Sopenharmony_ci{ 159213498266Sopenharmony_ci if((data->state.httpversion == 10) || (conn->httpversion == 10)) 159313498266Sopenharmony_ci return FALSE; 159413498266Sopenharmony_ci if((data->state.httpwant == CURL_HTTP_VERSION_1_0) && 159513498266Sopenharmony_ci (conn->httpversion <= 10)) 159613498266Sopenharmony_ci return FALSE; 159713498266Sopenharmony_ci return ((data->state.httpwant == CURL_HTTP_VERSION_NONE) || 159813498266Sopenharmony_ci (data->state.httpwant >= CURL_HTTP_VERSION_1_1)); 159913498266Sopenharmony_ci} 160013498266Sopenharmony_ci 160113498266Sopenharmony_ci#ifndef USE_HYPER 160213498266Sopenharmony_cistatic const char *get_http_string(const struct Curl_easy *data, 160313498266Sopenharmony_ci const struct connectdata *conn) 160413498266Sopenharmony_ci{ 160513498266Sopenharmony_ci if(Curl_conn_is_http3(data, conn, FIRSTSOCKET)) 160613498266Sopenharmony_ci return "3"; 160713498266Sopenharmony_ci if(Curl_conn_is_http2(data, conn, FIRSTSOCKET)) 160813498266Sopenharmony_ci return "2"; 160913498266Sopenharmony_ci if(Curl_use_http_1_1plus(data, conn)) 161013498266Sopenharmony_ci return "1.1"; 161113498266Sopenharmony_ci 161213498266Sopenharmony_ci return "1.0"; 161313498266Sopenharmony_ci} 161413498266Sopenharmony_ci#endif 161513498266Sopenharmony_ci 161613498266Sopenharmony_ci/* check and possibly add an Expect: header */ 161713498266Sopenharmony_cistatic CURLcode expect100(struct Curl_easy *data, 161813498266Sopenharmony_ci struct connectdata *conn, 161913498266Sopenharmony_ci struct dynbuf *req) 162013498266Sopenharmony_ci{ 162113498266Sopenharmony_ci CURLcode result = CURLE_OK; 162213498266Sopenharmony_ci if(!data->state.disableexpect && Curl_use_http_1_1plus(data, conn) && 162313498266Sopenharmony_ci (conn->httpversion < 20)) { 162413498266Sopenharmony_ci /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an 162513498266Sopenharmony_ci Expect: 100-continue to the headers which actually speeds up post 162613498266Sopenharmony_ci operations (as there is one packet coming back from the web server) */ 162713498266Sopenharmony_ci const char *ptr = Curl_checkheaders(data, STRCONST("Expect")); 162813498266Sopenharmony_ci if(ptr) { 162913498266Sopenharmony_ci data->state.expect100header = 163013498266Sopenharmony_ci Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue")); 163113498266Sopenharmony_ci } 163213498266Sopenharmony_ci else { 163313498266Sopenharmony_ci result = Curl_dyn_addn(req, STRCONST("Expect: 100-continue\r\n")); 163413498266Sopenharmony_ci if(!result) 163513498266Sopenharmony_ci data->state.expect100header = TRUE; 163613498266Sopenharmony_ci } 163713498266Sopenharmony_ci } 163813498266Sopenharmony_ci 163913498266Sopenharmony_ci return result; 164013498266Sopenharmony_ci} 164113498266Sopenharmony_ci 164213498266Sopenharmony_cienum proxy_use { 164313498266Sopenharmony_ci HEADER_SERVER, /* direct to server */ 164413498266Sopenharmony_ci HEADER_PROXY, /* regular request to proxy */ 164513498266Sopenharmony_ci HEADER_CONNECT /* sending CONNECT to a proxy */ 164613498266Sopenharmony_ci}; 164713498266Sopenharmony_ci 164813498266Sopenharmony_ci/* used to compile the provided trailers into one buffer 164913498266Sopenharmony_ci will return an error code if one of the headers is 165013498266Sopenharmony_ci not formatted correctly */ 165113498266Sopenharmony_ciCURLcode Curl_http_compile_trailers(struct curl_slist *trailers, 165213498266Sopenharmony_ci struct dynbuf *b, 165313498266Sopenharmony_ci struct Curl_easy *handle) 165413498266Sopenharmony_ci{ 165513498266Sopenharmony_ci char *ptr = NULL; 165613498266Sopenharmony_ci CURLcode result = CURLE_OK; 165713498266Sopenharmony_ci const char *endofline_native = NULL; 165813498266Sopenharmony_ci const char *endofline_network = NULL; 165913498266Sopenharmony_ci 166013498266Sopenharmony_ci if( 166113498266Sopenharmony_ci#ifdef CURL_DO_LINEEND_CONV 166213498266Sopenharmony_ci (handle->state.prefer_ascii) || 166313498266Sopenharmony_ci#endif 166413498266Sopenharmony_ci (handle->set.crlf)) { 166513498266Sopenharmony_ci /* \n will become \r\n later on */ 166613498266Sopenharmony_ci endofline_native = "\n"; 166713498266Sopenharmony_ci endofline_network = "\x0a"; 166813498266Sopenharmony_ci } 166913498266Sopenharmony_ci else { 167013498266Sopenharmony_ci endofline_native = "\r\n"; 167113498266Sopenharmony_ci endofline_network = "\x0d\x0a"; 167213498266Sopenharmony_ci } 167313498266Sopenharmony_ci 167413498266Sopenharmony_ci while(trailers) { 167513498266Sopenharmony_ci /* only add correctly formatted trailers */ 167613498266Sopenharmony_ci ptr = strchr(trailers->data, ':'); 167713498266Sopenharmony_ci if(ptr && *(ptr + 1) == ' ') { 167813498266Sopenharmony_ci result = Curl_dyn_add(b, trailers->data); 167913498266Sopenharmony_ci if(result) 168013498266Sopenharmony_ci return result; 168113498266Sopenharmony_ci result = Curl_dyn_add(b, endofline_native); 168213498266Sopenharmony_ci if(result) 168313498266Sopenharmony_ci return result; 168413498266Sopenharmony_ci } 168513498266Sopenharmony_ci else 168613498266Sopenharmony_ci infof(handle, "Malformatted trailing header, skipping trailer"); 168713498266Sopenharmony_ci trailers = trailers->next; 168813498266Sopenharmony_ci } 168913498266Sopenharmony_ci result = Curl_dyn_add(b, endofline_network); 169013498266Sopenharmony_ci return result; 169113498266Sopenharmony_ci} 169213498266Sopenharmony_ci 169313498266Sopenharmony_cistatic bool hd_name_eq(const char *n1, size_t n1len, 169413498266Sopenharmony_ci const char *n2, size_t n2len) 169513498266Sopenharmony_ci{ 169613498266Sopenharmony_ci if(n1len == n2len) { 169713498266Sopenharmony_ci return strncasecompare(n1, n2, n1len); 169813498266Sopenharmony_ci } 169913498266Sopenharmony_ci return FALSE; 170013498266Sopenharmony_ci} 170113498266Sopenharmony_ci 170213498266Sopenharmony_ciCURLcode Curl_dynhds_add_custom(struct Curl_easy *data, 170313498266Sopenharmony_ci bool is_connect, 170413498266Sopenharmony_ci struct dynhds *hds) 170513498266Sopenharmony_ci{ 170613498266Sopenharmony_ci struct connectdata *conn = data->conn; 170713498266Sopenharmony_ci char *ptr; 170813498266Sopenharmony_ci struct curl_slist *h[2]; 170913498266Sopenharmony_ci struct curl_slist *headers; 171013498266Sopenharmony_ci int numlists = 1; /* by default */ 171113498266Sopenharmony_ci int i; 171213498266Sopenharmony_ci 171313498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 171413498266Sopenharmony_ci enum proxy_use proxy; 171513498266Sopenharmony_ci 171613498266Sopenharmony_ci if(is_connect) 171713498266Sopenharmony_ci proxy = HEADER_CONNECT; 171813498266Sopenharmony_ci else 171913498266Sopenharmony_ci proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? 172013498266Sopenharmony_ci HEADER_PROXY:HEADER_SERVER; 172113498266Sopenharmony_ci 172213498266Sopenharmony_ci switch(proxy) { 172313498266Sopenharmony_ci case HEADER_SERVER: 172413498266Sopenharmony_ci h[0] = data->set.headers; 172513498266Sopenharmony_ci break; 172613498266Sopenharmony_ci case HEADER_PROXY: 172713498266Sopenharmony_ci h[0] = data->set.headers; 172813498266Sopenharmony_ci if(data->set.sep_headers) { 172913498266Sopenharmony_ci h[1] = data->set.proxyheaders; 173013498266Sopenharmony_ci numlists++; 173113498266Sopenharmony_ci } 173213498266Sopenharmony_ci break; 173313498266Sopenharmony_ci case HEADER_CONNECT: 173413498266Sopenharmony_ci if(data->set.sep_headers) 173513498266Sopenharmony_ci h[0] = data->set.proxyheaders; 173613498266Sopenharmony_ci else 173713498266Sopenharmony_ci h[0] = data->set.headers; 173813498266Sopenharmony_ci break; 173913498266Sopenharmony_ci } 174013498266Sopenharmony_ci#else 174113498266Sopenharmony_ci (void)is_connect; 174213498266Sopenharmony_ci h[0] = data->set.headers; 174313498266Sopenharmony_ci#endif 174413498266Sopenharmony_ci 174513498266Sopenharmony_ci /* loop through one or two lists */ 174613498266Sopenharmony_ci for(i = 0; i < numlists; i++) { 174713498266Sopenharmony_ci for(headers = h[i]; headers; headers = headers->next) { 174813498266Sopenharmony_ci const char *name, *value; 174913498266Sopenharmony_ci size_t namelen, valuelen; 175013498266Sopenharmony_ci 175113498266Sopenharmony_ci /* There are 2 quirks in place for custom headers: 175213498266Sopenharmony_ci * 1. setting only 'name:' to suppress a header from being sent 175313498266Sopenharmony_ci * 2. setting only 'name;' to send an empty (illegal) header 175413498266Sopenharmony_ci */ 175513498266Sopenharmony_ci ptr = strchr(headers->data, ':'); 175613498266Sopenharmony_ci if(ptr) { 175713498266Sopenharmony_ci name = headers->data; 175813498266Sopenharmony_ci namelen = ptr - headers->data; 175913498266Sopenharmony_ci ptr++; /* pass the colon */ 176013498266Sopenharmony_ci while(*ptr && ISSPACE(*ptr)) 176113498266Sopenharmony_ci ptr++; 176213498266Sopenharmony_ci if(*ptr) { 176313498266Sopenharmony_ci value = ptr; 176413498266Sopenharmony_ci valuelen = strlen(value); 176513498266Sopenharmony_ci } 176613498266Sopenharmony_ci else { 176713498266Sopenharmony_ci /* quirk #1, suppress this header */ 176813498266Sopenharmony_ci continue; 176913498266Sopenharmony_ci } 177013498266Sopenharmony_ci } 177113498266Sopenharmony_ci else { 177213498266Sopenharmony_ci ptr = strchr(headers->data, ';'); 177313498266Sopenharmony_ci 177413498266Sopenharmony_ci if(!ptr) { 177513498266Sopenharmony_ci /* neither : nor ; in provided header value. We seem 177613498266Sopenharmony_ci * to ignore this silently */ 177713498266Sopenharmony_ci continue; 177813498266Sopenharmony_ci } 177913498266Sopenharmony_ci 178013498266Sopenharmony_ci name = headers->data; 178113498266Sopenharmony_ci namelen = ptr - headers->data; 178213498266Sopenharmony_ci ptr++; /* pass the semicolon */ 178313498266Sopenharmony_ci while(*ptr && ISSPACE(*ptr)) 178413498266Sopenharmony_ci ptr++; 178513498266Sopenharmony_ci if(!*ptr) { 178613498266Sopenharmony_ci /* quirk #2, send an empty header */ 178713498266Sopenharmony_ci value = ""; 178813498266Sopenharmony_ci valuelen = 0; 178913498266Sopenharmony_ci } 179013498266Sopenharmony_ci else { 179113498266Sopenharmony_ci /* this may be used for something else in the future, 179213498266Sopenharmony_ci * ignore this for now */ 179313498266Sopenharmony_ci continue; 179413498266Sopenharmony_ci } 179513498266Sopenharmony_ci } 179613498266Sopenharmony_ci 179713498266Sopenharmony_ci DEBUGASSERT(name && value); 179813498266Sopenharmony_ci if(data->state.aptr.host && 179913498266Sopenharmony_ci /* a Host: header was sent already, don't pass on any custom Host: 180013498266Sopenharmony_ci header as that will produce *two* in the same request! */ 180113498266Sopenharmony_ci hd_name_eq(name, namelen, STRCONST("Host:"))) 180213498266Sopenharmony_ci ; 180313498266Sopenharmony_ci else if(data->state.httpreq == HTTPREQ_POST_FORM && 180413498266Sopenharmony_ci /* this header (extended by formdata.c) is sent later */ 180513498266Sopenharmony_ci hd_name_eq(name, namelen, STRCONST("Content-Type:"))) 180613498266Sopenharmony_ci ; 180713498266Sopenharmony_ci else if(data->state.httpreq == HTTPREQ_POST_MIME && 180813498266Sopenharmony_ci /* this header is sent later */ 180913498266Sopenharmony_ci hd_name_eq(name, namelen, STRCONST("Content-Type:"))) 181013498266Sopenharmony_ci ; 181113498266Sopenharmony_ci else if(conn->bits.authneg && 181213498266Sopenharmony_ci /* while doing auth neg, don't allow the custom length since 181313498266Sopenharmony_ci we will force length zero then */ 181413498266Sopenharmony_ci hd_name_eq(name, namelen, STRCONST("Content-Length:"))) 181513498266Sopenharmony_ci ; 181613498266Sopenharmony_ci else if(data->state.aptr.te && 181713498266Sopenharmony_ci /* when asking for Transfer-Encoding, don't pass on a custom 181813498266Sopenharmony_ci Connection: */ 181913498266Sopenharmony_ci hd_name_eq(name, namelen, STRCONST("Connection:"))) 182013498266Sopenharmony_ci ; 182113498266Sopenharmony_ci else if((conn->httpversion >= 20) && 182213498266Sopenharmony_ci hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:"))) 182313498266Sopenharmony_ci /* HTTP/2 doesn't support chunked requests */ 182413498266Sopenharmony_ci ; 182513498266Sopenharmony_ci else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) || 182613498266Sopenharmony_ci hd_name_eq(name, namelen, STRCONST("Cookie:"))) && 182713498266Sopenharmony_ci /* be careful of sending this potentially sensitive header to 182813498266Sopenharmony_ci other hosts */ 182913498266Sopenharmony_ci !Curl_auth_allowed_to_host(data)) 183013498266Sopenharmony_ci ; 183113498266Sopenharmony_ci else { 183213498266Sopenharmony_ci CURLcode result; 183313498266Sopenharmony_ci 183413498266Sopenharmony_ci result = Curl_dynhds_add(hds, name, namelen, value, valuelen); 183513498266Sopenharmony_ci if(result) 183613498266Sopenharmony_ci return result; 183713498266Sopenharmony_ci } 183813498266Sopenharmony_ci } 183913498266Sopenharmony_ci } 184013498266Sopenharmony_ci 184113498266Sopenharmony_ci return CURLE_OK; 184213498266Sopenharmony_ci} 184313498266Sopenharmony_ci 184413498266Sopenharmony_ciCURLcode Curl_add_custom_headers(struct Curl_easy *data, 184513498266Sopenharmony_ci bool is_connect, 184613498266Sopenharmony_ci#ifndef USE_HYPER 184713498266Sopenharmony_ci struct dynbuf *req 184813498266Sopenharmony_ci#else 184913498266Sopenharmony_ci void *req 185013498266Sopenharmony_ci#endif 185113498266Sopenharmony_ci ) 185213498266Sopenharmony_ci{ 185313498266Sopenharmony_ci struct connectdata *conn = data->conn; 185413498266Sopenharmony_ci char *ptr; 185513498266Sopenharmony_ci struct curl_slist *h[2]; 185613498266Sopenharmony_ci struct curl_slist *headers; 185713498266Sopenharmony_ci int numlists = 1; /* by default */ 185813498266Sopenharmony_ci int i; 185913498266Sopenharmony_ci 186013498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 186113498266Sopenharmony_ci enum proxy_use proxy; 186213498266Sopenharmony_ci 186313498266Sopenharmony_ci if(is_connect) 186413498266Sopenharmony_ci proxy = HEADER_CONNECT; 186513498266Sopenharmony_ci else 186613498266Sopenharmony_ci proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy? 186713498266Sopenharmony_ci HEADER_PROXY:HEADER_SERVER; 186813498266Sopenharmony_ci 186913498266Sopenharmony_ci switch(proxy) { 187013498266Sopenharmony_ci case HEADER_SERVER: 187113498266Sopenharmony_ci h[0] = data->set.headers; 187213498266Sopenharmony_ci break; 187313498266Sopenharmony_ci case HEADER_PROXY: 187413498266Sopenharmony_ci h[0] = data->set.headers; 187513498266Sopenharmony_ci if(data->set.sep_headers) { 187613498266Sopenharmony_ci h[1] = data->set.proxyheaders; 187713498266Sopenharmony_ci numlists++; 187813498266Sopenharmony_ci } 187913498266Sopenharmony_ci break; 188013498266Sopenharmony_ci case HEADER_CONNECT: 188113498266Sopenharmony_ci if(data->set.sep_headers) 188213498266Sopenharmony_ci h[0] = data->set.proxyheaders; 188313498266Sopenharmony_ci else 188413498266Sopenharmony_ci h[0] = data->set.headers; 188513498266Sopenharmony_ci break; 188613498266Sopenharmony_ci } 188713498266Sopenharmony_ci#else 188813498266Sopenharmony_ci (void)is_connect; 188913498266Sopenharmony_ci h[0] = data->set.headers; 189013498266Sopenharmony_ci#endif 189113498266Sopenharmony_ci 189213498266Sopenharmony_ci /* loop through one or two lists */ 189313498266Sopenharmony_ci for(i = 0; i < numlists; i++) { 189413498266Sopenharmony_ci headers = h[i]; 189513498266Sopenharmony_ci 189613498266Sopenharmony_ci while(headers) { 189713498266Sopenharmony_ci char *semicolonp = NULL; 189813498266Sopenharmony_ci ptr = strchr(headers->data, ':'); 189913498266Sopenharmony_ci if(!ptr) { 190013498266Sopenharmony_ci char *optr; 190113498266Sopenharmony_ci /* no colon, semicolon? */ 190213498266Sopenharmony_ci ptr = strchr(headers->data, ';'); 190313498266Sopenharmony_ci if(ptr) { 190413498266Sopenharmony_ci optr = ptr; 190513498266Sopenharmony_ci ptr++; /* pass the semicolon */ 190613498266Sopenharmony_ci while(*ptr && ISSPACE(*ptr)) 190713498266Sopenharmony_ci ptr++; 190813498266Sopenharmony_ci 190913498266Sopenharmony_ci if(*ptr) { 191013498266Sopenharmony_ci /* this may be used for something else in the future */ 191113498266Sopenharmony_ci optr = NULL; 191213498266Sopenharmony_ci } 191313498266Sopenharmony_ci else { 191413498266Sopenharmony_ci if(*(--ptr) == ';') { 191513498266Sopenharmony_ci /* copy the source */ 191613498266Sopenharmony_ci semicolonp = strdup(headers->data); 191713498266Sopenharmony_ci if(!semicolonp) { 191813498266Sopenharmony_ci#ifndef USE_HYPER 191913498266Sopenharmony_ci Curl_dyn_free(req); 192013498266Sopenharmony_ci#endif 192113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 192213498266Sopenharmony_ci } 192313498266Sopenharmony_ci /* put a colon where the semicolon is */ 192413498266Sopenharmony_ci semicolonp[ptr - headers->data] = ':'; 192513498266Sopenharmony_ci /* point at the colon */ 192613498266Sopenharmony_ci optr = &semicolonp [ptr - headers->data]; 192713498266Sopenharmony_ci } 192813498266Sopenharmony_ci } 192913498266Sopenharmony_ci ptr = optr; 193013498266Sopenharmony_ci } 193113498266Sopenharmony_ci } 193213498266Sopenharmony_ci if(ptr && (ptr != headers->data)) { 193313498266Sopenharmony_ci /* we require a colon for this to be a true header */ 193413498266Sopenharmony_ci 193513498266Sopenharmony_ci ptr++; /* pass the colon */ 193613498266Sopenharmony_ci while(*ptr && ISSPACE(*ptr)) 193713498266Sopenharmony_ci ptr++; 193813498266Sopenharmony_ci 193913498266Sopenharmony_ci if(*ptr || semicolonp) { 194013498266Sopenharmony_ci /* only send this if the contents was non-blank or done special */ 194113498266Sopenharmony_ci CURLcode result = CURLE_OK; 194213498266Sopenharmony_ci char *compare = semicolonp ? semicolonp : headers->data; 194313498266Sopenharmony_ci 194413498266Sopenharmony_ci if(data->state.aptr.host && 194513498266Sopenharmony_ci /* a Host: header was sent already, don't pass on any custom Host: 194613498266Sopenharmony_ci header as that will produce *two* in the same request! */ 194713498266Sopenharmony_ci checkprefix("Host:", compare)) 194813498266Sopenharmony_ci ; 194913498266Sopenharmony_ci else if(data->state.httpreq == HTTPREQ_POST_FORM && 195013498266Sopenharmony_ci /* this header (extended by formdata.c) is sent later */ 195113498266Sopenharmony_ci checkprefix("Content-Type:", compare)) 195213498266Sopenharmony_ci ; 195313498266Sopenharmony_ci else if(data->state.httpreq == HTTPREQ_POST_MIME && 195413498266Sopenharmony_ci /* this header is sent later */ 195513498266Sopenharmony_ci checkprefix("Content-Type:", compare)) 195613498266Sopenharmony_ci ; 195713498266Sopenharmony_ci else if(conn->bits.authneg && 195813498266Sopenharmony_ci /* while doing auth neg, don't allow the custom length since 195913498266Sopenharmony_ci we will force length zero then */ 196013498266Sopenharmony_ci checkprefix("Content-Length:", compare)) 196113498266Sopenharmony_ci ; 196213498266Sopenharmony_ci else if(data->state.aptr.te && 196313498266Sopenharmony_ci /* when asking for Transfer-Encoding, don't pass on a custom 196413498266Sopenharmony_ci Connection: */ 196513498266Sopenharmony_ci checkprefix("Connection:", compare)) 196613498266Sopenharmony_ci ; 196713498266Sopenharmony_ci else if((conn->httpversion >= 20) && 196813498266Sopenharmony_ci checkprefix("Transfer-Encoding:", compare)) 196913498266Sopenharmony_ci /* HTTP/2 doesn't support chunked requests */ 197013498266Sopenharmony_ci ; 197113498266Sopenharmony_ci else if((checkprefix("Authorization:", compare) || 197213498266Sopenharmony_ci checkprefix("Cookie:", compare)) && 197313498266Sopenharmony_ci /* be careful of sending this potentially sensitive header to 197413498266Sopenharmony_ci other hosts */ 197513498266Sopenharmony_ci !Curl_auth_allowed_to_host(data)) 197613498266Sopenharmony_ci ; 197713498266Sopenharmony_ci else { 197813498266Sopenharmony_ci#ifdef USE_HYPER 197913498266Sopenharmony_ci result = Curl_hyper_header(data, req, compare); 198013498266Sopenharmony_ci#else 198113498266Sopenharmony_ci result = Curl_dyn_addf(req, "%s\r\n", compare); 198213498266Sopenharmony_ci#endif 198313498266Sopenharmony_ci } 198413498266Sopenharmony_ci if(semicolonp) 198513498266Sopenharmony_ci free(semicolonp); 198613498266Sopenharmony_ci if(result) 198713498266Sopenharmony_ci return result; 198813498266Sopenharmony_ci } 198913498266Sopenharmony_ci } 199013498266Sopenharmony_ci headers = headers->next; 199113498266Sopenharmony_ci } 199213498266Sopenharmony_ci } 199313498266Sopenharmony_ci 199413498266Sopenharmony_ci return CURLE_OK; 199513498266Sopenharmony_ci} 199613498266Sopenharmony_ci 199713498266Sopenharmony_ci#ifndef CURL_DISABLE_PARSEDATE 199813498266Sopenharmony_ciCURLcode Curl_add_timecondition(struct Curl_easy *data, 199913498266Sopenharmony_ci#ifndef USE_HYPER 200013498266Sopenharmony_ci struct dynbuf *req 200113498266Sopenharmony_ci#else 200213498266Sopenharmony_ci void *req 200313498266Sopenharmony_ci#endif 200413498266Sopenharmony_ci ) 200513498266Sopenharmony_ci{ 200613498266Sopenharmony_ci const struct tm *tm; 200713498266Sopenharmony_ci struct tm keeptime; 200813498266Sopenharmony_ci CURLcode result; 200913498266Sopenharmony_ci char datestr[80]; 201013498266Sopenharmony_ci const char *condp; 201113498266Sopenharmony_ci size_t len; 201213498266Sopenharmony_ci 201313498266Sopenharmony_ci if(data->set.timecondition == CURL_TIMECOND_NONE) 201413498266Sopenharmony_ci /* no condition was asked for */ 201513498266Sopenharmony_ci return CURLE_OK; 201613498266Sopenharmony_ci 201713498266Sopenharmony_ci result = Curl_gmtime(data->set.timevalue, &keeptime); 201813498266Sopenharmony_ci if(result) { 201913498266Sopenharmony_ci failf(data, "Invalid TIMEVALUE"); 202013498266Sopenharmony_ci return result; 202113498266Sopenharmony_ci } 202213498266Sopenharmony_ci tm = &keeptime; 202313498266Sopenharmony_ci 202413498266Sopenharmony_ci switch(data->set.timecondition) { 202513498266Sopenharmony_ci default: 202613498266Sopenharmony_ci DEBUGF(infof(data, "invalid time condition")); 202713498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 202813498266Sopenharmony_ci 202913498266Sopenharmony_ci case CURL_TIMECOND_IFMODSINCE: 203013498266Sopenharmony_ci condp = "If-Modified-Since"; 203113498266Sopenharmony_ci len = 17; 203213498266Sopenharmony_ci break; 203313498266Sopenharmony_ci case CURL_TIMECOND_IFUNMODSINCE: 203413498266Sopenharmony_ci condp = "If-Unmodified-Since"; 203513498266Sopenharmony_ci len = 19; 203613498266Sopenharmony_ci break; 203713498266Sopenharmony_ci case CURL_TIMECOND_LASTMOD: 203813498266Sopenharmony_ci condp = "Last-Modified"; 203913498266Sopenharmony_ci len = 13; 204013498266Sopenharmony_ci break; 204113498266Sopenharmony_ci } 204213498266Sopenharmony_ci 204313498266Sopenharmony_ci if(Curl_checkheaders(data, condp, len)) { 204413498266Sopenharmony_ci /* A custom header was specified; it will be sent instead. */ 204513498266Sopenharmony_ci return CURLE_OK; 204613498266Sopenharmony_ci } 204713498266Sopenharmony_ci 204813498266Sopenharmony_ci /* The If-Modified-Since header family should have their times set in 204913498266Sopenharmony_ci * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be 205013498266Sopenharmony_ci * represented in Greenwich Mean Time (GMT), without exception. For the 205113498266Sopenharmony_ci * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal 205213498266Sopenharmony_ci * Time)." (see page 20 of RFC2616). 205313498266Sopenharmony_ci */ 205413498266Sopenharmony_ci 205513498266Sopenharmony_ci /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ 205613498266Sopenharmony_ci msnprintf(datestr, sizeof(datestr), 205713498266Sopenharmony_ci "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", 205813498266Sopenharmony_ci condp, 205913498266Sopenharmony_ci Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], 206013498266Sopenharmony_ci tm->tm_mday, 206113498266Sopenharmony_ci Curl_month[tm->tm_mon], 206213498266Sopenharmony_ci tm->tm_year + 1900, 206313498266Sopenharmony_ci tm->tm_hour, 206413498266Sopenharmony_ci tm->tm_min, 206513498266Sopenharmony_ci tm->tm_sec); 206613498266Sopenharmony_ci 206713498266Sopenharmony_ci#ifndef USE_HYPER 206813498266Sopenharmony_ci result = Curl_dyn_add(req, datestr); 206913498266Sopenharmony_ci#else 207013498266Sopenharmony_ci result = Curl_hyper_header(data, req, datestr); 207113498266Sopenharmony_ci#endif 207213498266Sopenharmony_ci 207313498266Sopenharmony_ci return result; 207413498266Sopenharmony_ci} 207513498266Sopenharmony_ci#else 207613498266Sopenharmony_ci/* disabled */ 207713498266Sopenharmony_ciCURLcode Curl_add_timecondition(struct Curl_easy *data, 207813498266Sopenharmony_ci struct dynbuf *req) 207913498266Sopenharmony_ci{ 208013498266Sopenharmony_ci (void)data; 208113498266Sopenharmony_ci (void)req; 208213498266Sopenharmony_ci return CURLE_OK; 208313498266Sopenharmony_ci} 208413498266Sopenharmony_ci#endif 208513498266Sopenharmony_ci 208613498266Sopenharmony_civoid Curl_http_method(struct Curl_easy *data, struct connectdata *conn, 208713498266Sopenharmony_ci const char **method, Curl_HttpReq *reqp) 208813498266Sopenharmony_ci{ 208913498266Sopenharmony_ci Curl_HttpReq httpreq = (Curl_HttpReq)data->state.httpreq; 209013498266Sopenharmony_ci const char *request; 209113498266Sopenharmony_ci if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && 209213498266Sopenharmony_ci data->state.upload) 209313498266Sopenharmony_ci httpreq = HTTPREQ_PUT; 209413498266Sopenharmony_ci 209513498266Sopenharmony_ci /* Now set the 'request' pointer to the proper request string */ 209613498266Sopenharmony_ci if(data->set.str[STRING_CUSTOMREQUEST]) 209713498266Sopenharmony_ci request = data->set.str[STRING_CUSTOMREQUEST]; 209813498266Sopenharmony_ci else { 209913498266Sopenharmony_ci if(data->req.no_body) 210013498266Sopenharmony_ci request = "HEAD"; 210113498266Sopenharmony_ci else { 210213498266Sopenharmony_ci DEBUGASSERT((httpreq >= HTTPREQ_GET) && (httpreq <= HTTPREQ_HEAD)); 210313498266Sopenharmony_ci switch(httpreq) { 210413498266Sopenharmony_ci case HTTPREQ_POST: 210513498266Sopenharmony_ci case HTTPREQ_POST_FORM: 210613498266Sopenharmony_ci case HTTPREQ_POST_MIME: 210713498266Sopenharmony_ci request = "POST"; 210813498266Sopenharmony_ci break; 210913498266Sopenharmony_ci case HTTPREQ_PUT: 211013498266Sopenharmony_ci request = "PUT"; 211113498266Sopenharmony_ci break; 211213498266Sopenharmony_ci default: /* this should never happen */ 211313498266Sopenharmony_ci case HTTPREQ_GET: 211413498266Sopenharmony_ci request = "GET"; 211513498266Sopenharmony_ci break; 211613498266Sopenharmony_ci case HTTPREQ_HEAD: 211713498266Sopenharmony_ci request = "HEAD"; 211813498266Sopenharmony_ci break; 211913498266Sopenharmony_ci } 212013498266Sopenharmony_ci } 212113498266Sopenharmony_ci } 212213498266Sopenharmony_ci *method = request; 212313498266Sopenharmony_ci *reqp = httpreq; 212413498266Sopenharmony_ci} 212513498266Sopenharmony_ci 212613498266Sopenharmony_ciCURLcode Curl_http_useragent(struct Curl_easy *data) 212713498266Sopenharmony_ci{ 212813498266Sopenharmony_ci /* The User-Agent string might have been allocated in url.c already, because 212913498266Sopenharmony_ci it might have been used in the proxy connect, but if we have got a header 213013498266Sopenharmony_ci with the user-agent string specified, we erase the previously made string 213113498266Sopenharmony_ci here. */ 213213498266Sopenharmony_ci if(Curl_checkheaders(data, STRCONST("User-Agent"))) { 213313498266Sopenharmony_ci free(data->state.aptr.uagent); 213413498266Sopenharmony_ci data->state.aptr.uagent = NULL; 213513498266Sopenharmony_ci } 213613498266Sopenharmony_ci return CURLE_OK; 213713498266Sopenharmony_ci} 213813498266Sopenharmony_ci 213913498266Sopenharmony_ci 214013498266Sopenharmony_ciCURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn) 214113498266Sopenharmony_ci{ 214213498266Sopenharmony_ci const char *ptr; 214313498266Sopenharmony_ci struct dynamically_allocated_data *aptr = &data->state.aptr; 214413498266Sopenharmony_ci if(!data->state.this_is_a_follow) { 214513498266Sopenharmony_ci /* Free to avoid leaking memory on multiple requests */ 214613498266Sopenharmony_ci free(data->state.first_host); 214713498266Sopenharmony_ci 214813498266Sopenharmony_ci data->state.first_host = strdup(conn->host.name); 214913498266Sopenharmony_ci if(!data->state.first_host) 215013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 215113498266Sopenharmony_ci 215213498266Sopenharmony_ci data->state.first_remote_port = conn->remote_port; 215313498266Sopenharmony_ci data->state.first_remote_protocol = conn->handler->protocol; 215413498266Sopenharmony_ci } 215513498266Sopenharmony_ci Curl_safefree(aptr->host); 215613498266Sopenharmony_ci 215713498266Sopenharmony_ci ptr = Curl_checkheaders(data, STRCONST("Host")); 215813498266Sopenharmony_ci if(ptr && (!data->state.this_is_a_follow || 215913498266Sopenharmony_ci strcasecompare(data->state.first_host, conn->host.name))) { 216013498266Sopenharmony_ci#if !defined(CURL_DISABLE_COOKIES) 216113498266Sopenharmony_ci /* If we have a given custom Host: header, we extract the host name in 216213498266Sopenharmony_ci order to possibly use it for cookie reasons later on. We only allow the 216313498266Sopenharmony_ci custom Host: header if this is NOT a redirect, as setting Host: in the 216413498266Sopenharmony_ci redirected request is being out on thin ice. Except if the host name 216513498266Sopenharmony_ci is the same as the first one! */ 216613498266Sopenharmony_ci char *cookiehost = Curl_copy_header_value(ptr); 216713498266Sopenharmony_ci if(!cookiehost) 216813498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 216913498266Sopenharmony_ci if(!*cookiehost) 217013498266Sopenharmony_ci /* ignore empty data */ 217113498266Sopenharmony_ci free(cookiehost); 217213498266Sopenharmony_ci else { 217313498266Sopenharmony_ci /* If the host begins with '[', we start searching for the port after 217413498266Sopenharmony_ci the bracket has been closed */ 217513498266Sopenharmony_ci if(*cookiehost == '[') { 217613498266Sopenharmony_ci char *closingbracket; 217713498266Sopenharmony_ci /* since the 'cookiehost' is an allocated memory area that will be 217813498266Sopenharmony_ci freed later we cannot simply increment the pointer */ 217913498266Sopenharmony_ci memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1); 218013498266Sopenharmony_ci closingbracket = strchr(cookiehost, ']'); 218113498266Sopenharmony_ci if(closingbracket) 218213498266Sopenharmony_ci *closingbracket = 0; 218313498266Sopenharmony_ci } 218413498266Sopenharmony_ci else { 218513498266Sopenharmony_ci int startsearch = 0; 218613498266Sopenharmony_ci char *colon = strchr(cookiehost + startsearch, ':'); 218713498266Sopenharmony_ci if(colon) 218813498266Sopenharmony_ci *colon = 0; /* The host must not include an embedded port number */ 218913498266Sopenharmony_ci } 219013498266Sopenharmony_ci Curl_safefree(aptr->cookiehost); 219113498266Sopenharmony_ci aptr->cookiehost = cookiehost; 219213498266Sopenharmony_ci } 219313498266Sopenharmony_ci#endif 219413498266Sopenharmony_ci 219513498266Sopenharmony_ci if(!strcasecompare("Host:", ptr)) { 219613498266Sopenharmony_ci aptr->host = aprintf("Host:%s\r\n", &ptr[5]); 219713498266Sopenharmony_ci if(!aptr->host) 219813498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 219913498266Sopenharmony_ci } 220013498266Sopenharmony_ci } 220113498266Sopenharmony_ci else { 220213498266Sopenharmony_ci /* When building Host: headers, we must put the host name within 220313498266Sopenharmony_ci [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ 220413498266Sopenharmony_ci const char *host = conn->host.name; 220513498266Sopenharmony_ci 220613498266Sopenharmony_ci if(((conn->given->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS)) && 220713498266Sopenharmony_ci (conn->remote_port == PORT_HTTPS)) || 220813498266Sopenharmony_ci ((conn->given->protocol&(CURLPROTO_HTTP|CURLPROTO_WS)) && 220913498266Sopenharmony_ci (conn->remote_port == PORT_HTTP)) ) 221013498266Sopenharmony_ci /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include 221113498266Sopenharmony_ci the port number in the host string */ 221213498266Sopenharmony_ci aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"", 221313498266Sopenharmony_ci host, conn->bits.ipv6_ip?"]":""); 221413498266Sopenharmony_ci else 221513498266Sopenharmony_ci aptr->host = aprintf("Host: %s%s%s:%d\r\n", conn->bits.ipv6_ip?"[":"", 221613498266Sopenharmony_ci host, conn->bits.ipv6_ip?"]":"", 221713498266Sopenharmony_ci conn->remote_port); 221813498266Sopenharmony_ci 221913498266Sopenharmony_ci if(!aptr->host) 222013498266Sopenharmony_ci /* without Host: we can't make a nice request */ 222113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 222213498266Sopenharmony_ci } 222313498266Sopenharmony_ci return CURLE_OK; 222413498266Sopenharmony_ci} 222513498266Sopenharmony_ci 222613498266Sopenharmony_ci/* 222713498266Sopenharmony_ci * Append the request-target to the HTTP request 222813498266Sopenharmony_ci */ 222913498266Sopenharmony_ciCURLcode Curl_http_target(struct Curl_easy *data, 223013498266Sopenharmony_ci struct connectdata *conn, 223113498266Sopenharmony_ci struct dynbuf *r) 223213498266Sopenharmony_ci{ 223313498266Sopenharmony_ci CURLcode result = CURLE_OK; 223413498266Sopenharmony_ci const char *path = data->state.up.path; 223513498266Sopenharmony_ci const char *query = data->state.up.query; 223613498266Sopenharmony_ci 223713498266Sopenharmony_ci if(data->set.str[STRING_TARGET]) { 223813498266Sopenharmony_ci path = data->set.str[STRING_TARGET]; 223913498266Sopenharmony_ci query = NULL; 224013498266Sopenharmony_ci } 224113498266Sopenharmony_ci 224213498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 224313498266Sopenharmony_ci if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { 224413498266Sopenharmony_ci /* Using a proxy but does not tunnel through it */ 224513498266Sopenharmony_ci 224613498266Sopenharmony_ci /* The path sent to the proxy is in fact the entire URL. But if the remote 224713498266Sopenharmony_ci host is a IDN-name, we must make sure that the request we produce only 224813498266Sopenharmony_ci uses the encoded host name! */ 224913498266Sopenharmony_ci 225013498266Sopenharmony_ci /* and no fragment part */ 225113498266Sopenharmony_ci CURLUcode uc; 225213498266Sopenharmony_ci char *url; 225313498266Sopenharmony_ci CURLU *h = curl_url_dup(data->state.uh); 225413498266Sopenharmony_ci if(!h) 225513498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 225613498266Sopenharmony_ci 225713498266Sopenharmony_ci if(conn->host.dispname != conn->host.name) { 225813498266Sopenharmony_ci uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0); 225913498266Sopenharmony_ci if(uc) { 226013498266Sopenharmony_ci curl_url_cleanup(h); 226113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 226213498266Sopenharmony_ci } 226313498266Sopenharmony_ci } 226413498266Sopenharmony_ci uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0); 226513498266Sopenharmony_ci if(uc) { 226613498266Sopenharmony_ci curl_url_cleanup(h); 226713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 226813498266Sopenharmony_ci } 226913498266Sopenharmony_ci 227013498266Sopenharmony_ci if(strcasecompare("http", data->state.up.scheme)) { 227113498266Sopenharmony_ci /* when getting HTTP, we don't want the userinfo the URL */ 227213498266Sopenharmony_ci uc = curl_url_set(h, CURLUPART_USER, NULL, 0); 227313498266Sopenharmony_ci if(uc) { 227413498266Sopenharmony_ci curl_url_cleanup(h); 227513498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 227613498266Sopenharmony_ci } 227713498266Sopenharmony_ci uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0); 227813498266Sopenharmony_ci if(uc) { 227913498266Sopenharmony_ci curl_url_cleanup(h); 228013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 228113498266Sopenharmony_ci } 228213498266Sopenharmony_ci } 228313498266Sopenharmony_ci /* Extract the URL to use in the request. */ 228413498266Sopenharmony_ci uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT); 228513498266Sopenharmony_ci if(uc) { 228613498266Sopenharmony_ci curl_url_cleanup(h); 228713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 228813498266Sopenharmony_ci } 228913498266Sopenharmony_ci 229013498266Sopenharmony_ci curl_url_cleanup(h); 229113498266Sopenharmony_ci 229213498266Sopenharmony_ci /* target or url */ 229313498266Sopenharmony_ci result = Curl_dyn_add(r, data->set.str[STRING_TARGET]? 229413498266Sopenharmony_ci data->set.str[STRING_TARGET]:url); 229513498266Sopenharmony_ci free(url); 229613498266Sopenharmony_ci if(result) 229713498266Sopenharmony_ci return (result); 229813498266Sopenharmony_ci 229913498266Sopenharmony_ci if(strcasecompare("ftp", data->state.up.scheme)) { 230013498266Sopenharmony_ci if(data->set.proxy_transfer_mode) { 230113498266Sopenharmony_ci /* when doing ftp, append ;type=<a|i> if not present */ 230213498266Sopenharmony_ci char *type = strstr(path, ";type="); 230313498266Sopenharmony_ci if(type && type[6] && type[7] == 0) { 230413498266Sopenharmony_ci switch(Curl_raw_toupper(type[6])) { 230513498266Sopenharmony_ci case 'A': 230613498266Sopenharmony_ci case 'D': 230713498266Sopenharmony_ci case 'I': 230813498266Sopenharmony_ci break; 230913498266Sopenharmony_ci default: 231013498266Sopenharmony_ci type = NULL; 231113498266Sopenharmony_ci } 231213498266Sopenharmony_ci } 231313498266Sopenharmony_ci if(!type) { 231413498266Sopenharmony_ci result = Curl_dyn_addf(r, ";type=%c", 231513498266Sopenharmony_ci data->state.prefer_ascii ? 'a' : 'i'); 231613498266Sopenharmony_ci if(result) 231713498266Sopenharmony_ci return result; 231813498266Sopenharmony_ci } 231913498266Sopenharmony_ci } 232013498266Sopenharmony_ci } 232113498266Sopenharmony_ci } 232213498266Sopenharmony_ci 232313498266Sopenharmony_ci else 232413498266Sopenharmony_ci#else 232513498266Sopenharmony_ci (void)conn; /* not used in disabled-proxy builds */ 232613498266Sopenharmony_ci#endif 232713498266Sopenharmony_ci { 232813498266Sopenharmony_ci result = Curl_dyn_add(r, path); 232913498266Sopenharmony_ci if(result) 233013498266Sopenharmony_ci return result; 233113498266Sopenharmony_ci if(query) 233213498266Sopenharmony_ci result = Curl_dyn_addf(r, "?%s", query); 233313498266Sopenharmony_ci } 233413498266Sopenharmony_ci 233513498266Sopenharmony_ci return result; 233613498266Sopenharmony_ci} 233713498266Sopenharmony_ci 233813498266Sopenharmony_ciCURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn, 233913498266Sopenharmony_ci Curl_HttpReq httpreq, const char **tep) 234013498266Sopenharmony_ci{ 234113498266Sopenharmony_ci CURLcode result = CURLE_OK; 234213498266Sopenharmony_ci const char *ptr; 234313498266Sopenharmony_ci struct HTTP *http = data->req.p.http; 234413498266Sopenharmony_ci http->postsize = 0; 234513498266Sopenharmony_ci 234613498266Sopenharmony_ci switch(httpreq) { 234713498266Sopenharmony_ci case HTTPREQ_POST_MIME: 234813498266Sopenharmony_ci data->state.mimepost = &data->set.mimepost; 234913498266Sopenharmony_ci break; 235013498266Sopenharmony_ci#ifndef CURL_DISABLE_FORM_API 235113498266Sopenharmony_ci case HTTPREQ_POST_FORM: 235213498266Sopenharmony_ci /* Convert the form structure into a mime structure, then keep 235313498266Sopenharmony_ci the conversion */ 235413498266Sopenharmony_ci if(!data->state.formp) { 235513498266Sopenharmony_ci data->state.formp = calloc(1, sizeof(curl_mimepart)); 235613498266Sopenharmony_ci if(!data->state.formp) 235713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 235813498266Sopenharmony_ci Curl_mime_cleanpart(data->state.formp); 235913498266Sopenharmony_ci result = Curl_getformdata(data, data->state.formp, data->set.httppost, 236013498266Sopenharmony_ci data->state.fread_func); 236113498266Sopenharmony_ci if(result) { 236213498266Sopenharmony_ci Curl_safefree(data->state.formp); 236313498266Sopenharmony_ci return result; 236413498266Sopenharmony_ci } 236513498266Sopenharmony_ci data->state.mimepost = data->state.formp; 236613498266Sopenharmony_ci } 236713498266Sopenharmony_ci break; 236813498266Sopenharmony_ci#endif 236913498266Sopenharmony_ci default: 237013498266Sopenharmony_ci data->state.mimepost = NULL; 237113498266Sopenharmony_ci } 237213498266Sopenharmony_ci 237313498266Sopenharmony_ci#ifndef CURL_DISABLE_MIME 237413498266Sopenharmony_ci if(data->state.mimepost) { 237513498266Sopenharmony_ci const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type")); 237613498266Sopenharmony_ci 237713498266Sopenharmony_ci /* Read and seek body only. */ 237813498266Sopenharmony_ci data->state.mimepost->flags |= MIME_BODY_ONLY; 237913498266Sopenharmony_ci 238013498266Sopenharmony_ci /* Prepare the mime structure headers & set content type. */ 238113498266Sopenharmony_ci 238213498266Sopenharmony_ci if(cthdr) 238313498266Sopenharmony_ci for(cthdr += 13; *cthdr == ' '; cthdr++) 238413498266Sopenharmony_ci ; 238513498266Sopenharmony_ci else if(data->state.mimepost->kind == MIMEKIND_MULTIPART) 238613498266Sopenharmony_ci cthdr = "multipart/form-data"; 238713498266Sopenharmony_ci 238813498266Sopenharmony_ci curl_mime_headers(data->state.mimepost, data->set.headers, 0); 238913498266Sopenharmony_ci result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr, 239013498266Sopenharmony_ci NULL, MIMESTRATEGY_FORM); 239113498266Sopenharmony_ci curl_mime_headers(data->state.mimepost, NULL, 0); 239213498266Sopenharmony_ci if(!result) 239313498266Sopenharmony_ci result = Curl_mime_rewind(data->state.mimepost); 239413498266Sopenharmony_ci if(result) 239513498266Sopenharmony_ci return result; 239613498266Sopenharmony_ci http->postsize = Curl_mime_size(data->state.mimepost); 239713498266Sopenharmony_ci } 239813498266Sopenharmony_ci#endif 239913498266Sopenharmony_ci 240013498266Sopenharmony_ci ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding")); 240113498266Sopenharmony_ci if(ptr) { 240213498266Sopenharmony_ci /* Some kind of TE is requested, check if 'chunked' is chosen */ 240313498266Sopenharmony_ci data->req.upload_chunky = 240413498266Sopenharmony_ci Curl_compareheader(ptr, 240513498266Sopenharmony_ci STRCONST("Transfer-Encoding:"), STRCONST("chunked")); 240613498266Sopenharmony_ci } 240713498266Sopenharmony_ci else { 240813498266Sopenharmony_ci if((conn->handler->protocol & PROTO_FAMILY_HTTP) && 240913498266Sopenharmony_ci (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && 241013498266Sopenharmony_ci http->postsize < 0) || 241113498266Sopenharmony_ci ((data->state.upload || httpreq == HTTPREQ_POST) && 241213498266Sopenharmony_ci data->state.infilesize == -1))) { 241313498266Sopenharmony_ci if(conn->bits.authneg) 241413498266Sopenharmony_ci /* don't enable chunked during auth neg */ 241513498266Sopenharmony_ci ; 241613498266Sopenharmony_ci else if(Curl_use_http_1_1plus(data, conn)) { 241713498266Sopenharmony_ci if(conn->httpversion < 20) 241813498266Sopenharmony_ci /* HTTP, upload, unknown file size and not HTTP 1.0 */ 241913498266Sopenharmony_ci data->req.upload_chunky = TRUE; 242013498266Sopenharmony_ci } 242113498266Sopenharmony_ci else { 242213498266Sopenharmony_ci failf(data, "Chunky upload is not supported by HTTP 1.0"); 242313498266Sopenharmony_ci return CURLE_UPLOAD_FAILED; 242413498266Sopenharmony_ci } 242513498266Sopenharmony_ci } 242613498266Sopenharmony_ci else { 242713498266Sopenharmony_ci /* else, no chunky upload */ 242813498266Sopenharmony_ci data->req.upload_chunky = FALSE; 242913498266Sopenharmony_ci } 243013498266Sopenharmony_ci 243113498266Sopenharmony_ci if(data->req.upload_chunky) 243213498266Sopenharmony_ci *tep = "Transfer-Encoding: chunked\r\n"; 243313498266Sopenharmony_ci } 243413498266Sopenharmony_ci return result; 243513498266Sopenharmony_ci} 243613498266Sopenharmony_ci 243713498266Sopenharmony_cistatic CURLcode addexpect(struct Curl_easy *data, struct connectdata *conn, 243813498266Sopenharmony_ci struct dynbuf *r) 243913498266Sopenharmony_ci{ 244013498266Sopenharmony_ci data->state.expect100header = FALSE; 244113498266Sopenharmony_ci /* Avoid Expect: 100-continue if Upgrade: is used */ 244213498266Sopenharmony_ci if(data->req.upgr101 == UPGR101_INIT) { 244313498266Sopenharmony_ci struct HTTP *http = data->req.p.http; 244413498266Sopenharmony_ci /* For really small puts we don't use Expect: headers at all, and for 244513498266Sopenharmony_ci the somewhat bigger ones we allow the app to disable it. Just make 244613498266Sopenharmony_ci sure that the expect100header is always set to the preferred value 244713498266Sopenharmony_ci here. */ 244813498266Sopenharmony_ci char *ptr = Curl_checkheaders(data, STRCONST("Expect")); 244913498266Sopenharmony_ci if(ptr) { 245013498266Sopenharmony_ci data->state.expect100header = 245113498266Sopenharmony_ci Curl_compareheader(ptr, STRCONST("Expect:"), 245213498266Sopenharmony_ci STRCONST("100-continue")); 245313498266Sopenharmony_ci } 245413498266Sopenharmony_ci else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) 245513498266Sopenharmony_ci return expect100(data, conn, r); 245613498266Sopenharmony_ci } 245713498266Sopenharmony_ci return CURLE_OK; 245813498266Sopenharmony_ci} 245913498266Sopenharmony_ci 246013498266Sopenharmony_ciCURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, 246113498266Sopenharmony_ci struct dynbuf *r, Curl_HttpReq httpreq) 246213498266Sopenharmony_ci{ 246313498266Sopenharmony_ci#ifndef USE_HYPER 246413498266Sopenharmony_ci /* Hyper always handles the body separately */ 246513498266Sopenharmony_ci curl_off_t included_body = 0; 246613498266Sopenharmony_ci#else 246713498266Sopenharmony_ci /* from this point down, this function should not be used */ 246813498266Sopenharmony_ci#define Curl_buffer_send(a,b,c,d,e,f) CURLE_OK 246913498266Sopenharmony_ci#endif 247013498266Sopenharmony_ci CURLcode result = CURLE_OK; 247113498266Sopenharmony_ci struct HTTP *http = data->req.p.http; 247213498266Sopenharmony_ci 247313498266Sopenharmony_ci switch(httpreq) { 247413498266Sopenharmony_ci case HTTPREQ_PUT: /* Let's PUT the data to the server! */ 247513498266Sopenharmony_ci 247613498266Sopenharmony_ci if(conn->bits.authneg) 247713498266Sopenharmony_ci http->postsize = 0; 247813498266Sopenharmony_ci else 247913498266Sopenharmony_ci http->postsize = data->state.infilesize; 248013498266Sopenharmony_ci 248113498266Sopenharmony_ci if((http->postsize != -1) && !data->req.upload_chunky && 248213498266Sopenharmony_ci (conn->bits.authneg || 248313498266Sopenharmony_ci !Curl_checkheaders(data, STRCONST("Content-Length")))) { 248413498266Sopenharmony_ci /* only add Content-Length if not uploading chunked */ 248513498266Sopenharmony_ci result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T 248613498266Sopenharmony_ci "\r\n", http->postsize); 248713498266Sopenharmony_ci if(result) 248813498266Sopenharmony_ci return result; 248913498266Sopenharmony_ci } 249013498266Sopenharmony_ci 249113498266Sopenharmony_ci result = addexpect(data, conn, r); 249213498266Sopenharmony_ci if(result) 249313498266Sopenharmony_ci return result; 249413498266Sopenharmony_ci 249513498266Sopenharmony_ci /* end of headers */ 249613498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("\r\n")); 249713498266Sopenharmony_ci if(result) 249813498266Sopenharmony_ci return result; 249913498266Sopenharmony_ci 250013498266Sopenharmony_ci /* set the upload size to the progress meter */ 250113498266Sopenharmony_ci Curl_pgrsSetUploadSize(data, http->postsize); 250213498266Sopenharmony_ci 250313498266Sopenharmony_ci /* this sends the buffer and frees all the buffer resources */ 250413498266Sopenharmony_ci result = Curl_buffer_send(r, data, data->req.p.http, 250513498266Sopenharmony_ci &data->info.request_size, 0, 250613498266Sopenharmony_ci FIRSTSOCKET); 250713498266Sopenharmony_ci if(result) 250813498266Sopenharmony_ci failf(data, "Failed sending PUT request"); 250913498266Sopenharmony_ci else 251013498266Sopenharmony_ci /* prepare for transfer */ 251113498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, 251213498266Sopenharmony_ci http->postsize?FIRSTSOCKET:-1); 251313498266Sopenharmony_ci if(result) 251413498266Sopenharmony_ci return result; 251513498266Sopenharmony_ci break; 251613498266Sopenharmony_ci 251713498266Sopenharmony_ci case HTTPREQ_POST_FORM: 251813498266Sopenharmony_ci case HTTPREQ_POST_MIME: 251913498266Sopenharmony_ci /* This is form posting using mime data. */ 252013498266Sopenharmony_ci if(conn->bits.authneg) { 252113498266Sopenharmony_ci /* nothing to post! */ 252213498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("Content-Length: 0\r\n\r\n")); 252313498266Sopenharmony_ci if(result) 252413498266Sopenharmony_ci return result; 252513498266Sopenharmony_ci 252613498266Sopenharmony_ci result = Curl_buffer_send(r, data, data->req.p.http, 252713498266Sopenharmony_ci &data->info.request_size, 0, 252813498266Sopenharmony_ci FIRSTSOCKET); 252913498266Sopenharmony_ci if(result) 253013498266Sopenharmony_ci failf(data, "Failed sending POST request"); 253113498266Sopenharmony_ci else 253213498266Sopenharmony_ci /* setup variables for the upcoming transfer */ 253313498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); 253413498266Sopenharmony_ci break; 253513498266Sopenharmony_ci } 253613498266Sopenharmony_ci 253713498266Sopenharmony_ci data->state.infilesize = http->postsize; 253813498266Sopenharmony_ci 253913498266Sopenharmony_ci /* We only set Content-Length and allow a custom Content-Length if 254013498266Sopenharmony_ci we don't upload data chunked, as RFC2616 forbids us to set both 254113498266Sopenharmony_ci kinds of headers (Transfer-Encoding: chunked and Content-Length) */ 254213498266Sopenharmony_ci if(http->postsize != -1 && !data->req.upload_chunky && 254313498266Sopenharmony_ci (!Curl_checkheaders(data, STRCONST("Content-Length")))) { 254413498266Sopenharmony_ci /* we allow replacing this header if not during auth negotiation, 254513498266Sopenharmony_ci although it isn't very wise to actually set your own */ 254613498266Sopenharmony_ci result = Curl_dyn_addf(r, 254713498266Sopenharmony_ci "Content-Length: %" CURL_FORMAT_CURL_OFF_T 254813498266Sopenharmony_ci "\r\n", http->postsize); 254913498266Sopenharmony_ci if(result) 255013498266Sopenharmony_ci return result; 255113498266Sopenharmony_ci } 255213498266Sopenharmony_ci 255313498266Sopenharmony_ci#ifndef CURL_DISABLE_MIME 255413498266Sopenharmony_ci /* Output mime-generated headers. */ 255513498266Sopenharmony_ci { 255613498266Sopenharmony_ci struct curl_slist *hdr; 255713498266Sopenharmony_ci 255813498266Sopenharmony_ci for(hdr = data->state.mimepost->curlheaders; hdr; hdr = hdr->next) { 255913498266Sopenharmony_ci result = Curl_dyn_addf(r, "%s\r\n", hdr->data); 256013498266Sopenharmony_ci if(result) 256113498266Sopenharmony_ci return result; 256213498266Sopenharmony_ci } 256313498266Sopenharmony_ci } 256413498266Sopenharmony_ci#endif 256513498266Sopenharmony_ci 256613498266Sopenharmony_ci result = addexpect(data, conn, r); 256713498266Sopenharmony_ci if(result) 256813498266Sopenharmony_ci return result; 256913498266Sopenharmony_ci 257013498266Sopenharmony_ci /* make the request end in a true CRLF */ 257113498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("\r\n")); 257213498266Sopenharmony_ci if(result) 257313498266Sopenharmony_ci return result; 257413498266Sopenharmony_ci 257513498266Sopenharmony_ci /* set the upload size to the progress meter */ 257613498266Sopenharmony_ci Curl_pgrsSetUploadSize(data, http->postsize); 257713498266Sopenharmony_ci 257813498266Sopenharmony_ci /* Read from mime structure. */ 257913498266Sopenharmony_ci data->state.fread_func = (curl_read_callback) Curl_mime_read; 258013498266Sopenharmony_ci data->state.in = (void *) data->state.mimepost; 258113498266Sopenharmony_ci http->sending = HTTPSEND_BODY; 258213498266Sopenharmony_ci 258313498266Sopenharmony_ci /* this sends the buffer and frees all the buffer resources */ 258413498266Sopenharmony_ci result = Curl_buffer_send(r, data, data->req.p.http, 258513498266Sopenharmony_ci &data->info.request_size, 0, 258613498266Sopenharmony_ci FIRSTSOCKET); 258713498266Sopenharmony_ci if(result) 258813498266Sopenharmony_ci failf(data, "Failed sending POST request"); 258913498266Sopenharmony_ci else 259013498266Sopenharmony_ci /* prepare for transfer */ 259113498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, 259213498266Sopenharmony_ci http->postsize?FIRSTSOCKET:-1); 259313498266Sopenharmony_ci if(result) 259413498266Sopenharmony_ci return result; 259513498266Sopenharmony_ci 259613498266Sopenharmony_ci break; 259713498266Sopenharmony_ci 259813498266Sopenharmony_ci case HTTPREQ_POST: 259913498266Sopenharmony_ci /* this is the simple POST, using x-www-form-urlencoded style */ 260013498266Sopenharmony_ci 260113498266Sopenharmony_ci if(conn->bits.authneg) 260213498266Sopenharmony_ci http->postsize = 0; 260313498266Sopenharmony_ci else 260413498266Sopenharmony_ci /* the size of the post body */ 260513498266Sopenharmony_ci http->postsize = data->state.infilesize; 260613498266Sopenharmony_ci 260713498266Sopenharmony_ci /* We only set Content-Length and allow a custom Content-Length if 260813498266Sopenharmony_ci we don't upload data chunked, as RFC2616 forbids us to set both 260913498266Sopenharmony_ci kinds of headers (Transfer-Encoding: chunked and Content-Length) */ 261013498266Sopenharmony_ci if((http->postsize != -1) && !data->req.upload_chunky && 261113498266Sopenharmony_ci (conn->bits.authneg || 261213498266Sopenharmony_ci !Curl_checkheaders(data, STRCONST("Content-Length")))) { 261313498266Sopenharmony_ci /* we allow replacing this header if not during auth negotiation, 261413498266Sopenharmony_ci although it isn't very wise to actually set your own */ 261513498266Sopenharmony_ci result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T 261613498266Sopenharmony_ci "\r\n", http->postsize); 261713498266Sopenharmony_ci if(result) 261813498266Sopenharmony_ci return result; 261913498266Sopenharmony_ci } 262013498266Sopenharmony_ci 262113498266Sopenharmony_ci if(!Curl_checkheaders(data, STRCONST("Content-Type"))) { 262213498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("Content-Type: application/" 262313498266Sopenharmony_ci "x-www-form-urlencoded\r\n")); 262413498266Sopenharmony_ci if(result) 262513498266Sopenharmony_ci return result; 262613498266Sopenharmony_ci } 262713498266Sopenharmony_ci 262813498266Sopenharmony_ci result = addexpect(data, conn, r); 262913498266Sopenharmony_ci if(result) 263013498266Sopenharmony_ci return result; 263113498266Sopenharmony_ci 263213498266Sopenharmony_ci#ifndef USE_HYPER 263313498266Sopenharmony_ci /* With Hyper the body is always passed on separately */ 263413498266Sopenharmony_ci if(data->set.postfields) { 263513498266Sopenharmony_ci if(!data->state.expect100header && 263613498266Sopenharmony_ci (http->postsize < MAX_INITIAL_POST_SIZE)) { 263713498266Sopenharmony_ci /* if we don't use expect: 100 AND 263813498266Sopenharmony_ci postsize is less than MAX_INITIAL_POST_SIZE 263913498266Sopenharmony_ci 264013498266Sopenharmony_ci then append the post data to the HTTP request header. This limit 264113498266Sopenharmony_ci is no magic limit but only set to prevent really huge POSTs to 264213498266Sopenharmony_ci get the data duplicated with malloc() and family. */ 264313498266Sopenharmony_ci 264413498266Sopenharmony_ci /* end of headers! */ 264513498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("\r\n")); 264613498266Sopenharmony_ci if(result) 264713498266Sopenharmony_ci return result; 264813498266Sopenharmony_ci 264913498266Sopenharmony_ci if(!data->req.upload_chunky) { 265013498266Sopenharmony_ci /* We're not sending it 'chunked', append it to the request 265113498266Sopenharmony_ci already now to reduce the number of send() calls */ 265213498266Sopenharmony_ci result = Curl_dyn_addn(r, data->set.postfields, 265313498266Sopenharmony_ci (size_t)http->postsize); 265413498266Sopenharmony_ci included_body = http->postsize; 265513498266Sopenharmony_ci } 265613498266Sopenharmony_ci else { 265713498266Sopenharmony_ci if(http->postsize) { 265813498266Sopenharmony_ci char chunk[16]; 265913498266Sopenharmony_ci /* Append the POST data chunky-style */ 266013498266Sopenharmony_ci msnprintf(chunk, sizeof(chunk), "%x\r\n", (int)http->postsize); 266113498266Sopenharmony_ci result = Curl_dyn_add(r, chunk); 266213498266Sopenharmony_ci if(!result) { 266313498266Sopenharmony_ci included_body = http->postsize + strlen(chunk); 266413498266Sopenharmony_ci result = Curl_dyn_addn(r, data->set.postfields, 266513498266Sopenharmony_ci (size_t)http->postsize); 266613498266Sopenharmony_ci if(!result) 266713498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("\r\n")); 266813498266Sopenharmony_ci included_body += 2; 266913498266Sopenharmony_ci } 267013498266Sopenharmony_ci } 267113498266Sopenharmony_ci if(!result) { 267213498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("\x30\x0d\x0a\x0d\x0a")); 267313498266Sopenharmony_ci /* 0 CR LF CR LF */ 267413498266Sopenharmony_ci included_body += 5; 267513498266Sopenharmony_ci } 267613498266Sopenharmony_ci } 267713498266Sopenharmony_ci if(result) 267813498266Sopenharmony_ci return result; 267913498266Sopenharmony_ci /* Make sure the progress information is accurate */ 268013498266Sopenharmony_ci Curl_pgrsSetUploadSize(data, http->postsize); 268113498266Sopenharmony_ci } 268213498266Sopenharmony_ci else { 268313498266Sopenharmony_ci /* A huge POST coming up, do data separate from the request */ 268413498266Sopenharmony_ci http->postdata = data->set.postfields; 268513498266Sopenharmony_ci http->sending = HTTPSEND_BODY; 268613498266Sopenharmony_ci http->backup.data = data; 268713498266Sopenharmony_ci data->state.fread_func = (curl_read_callback)readmoredata; 268813498266Sopenharmony_ci data->state.in = (void *)http; 268913498266Sopenharmony_ci 269013498266Sopenharmony_ci /* set the upload size to the progress meter */ 269113498266Sopenharmony_ci Curl_pgrsSetUploadSize(data, http->postsize); 269213498266Sopenharmony_ci 269313498266Sopenharmony_ci /* end of headers! */ 269413498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("\r\n")); 269513498266Sopenharmony_ci if(result) 269613498266Sopenharmony_ci return result; 269713498266Sopenharmony_ci } 269813498266Sopenharmony_ci } 269913498266Sopenharmony_ci else 270013498266Sopenharmony_ci#endif 270113498266Sopenharmony_ci { 270213498266Sopenharmony_ci /* end of headers! */ 270313498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("\r\n")); 270413498266Sopenharmony_ci if(result) 270513498266Sopenharmony_ci return result; 270613498266Sopenharmony_ci 270713498266Sopenharmony_ci if(data->req.upload_chunky && conn->bits.authneg) { 270813498266Sopenharmony_ci /* Chunky upload is selected and we're negotiating auth still, send 270913498266Sopenharmony_ci end-of-data only */ 271013498266Sopenharmony_ci result = Curl_dyn_addn(r, (char *)STRCONST("\x30\x0d\x0a\x0d\x0a")); 271113498266Sopenharmony_ci /* 0 CR LF CR LF */ 271213498266Sopenharmony_ci if(result) 271313498266Sopenharmony_ci return result; 271413498266Sopenharmony_ci } 271513498266Sopenharmony_ci 271613498266Sopenharmony_ci else if(data->state.infilesize) { 271713498266Sopenharmony_ci /* set the upload size to the progress meter */ 271813498266Sopenharmony_ci Curl_pgrsSetUploadSize(data, http->postsize?http->postsize:-1); 271913498266Sopenharmony_ci 272013498266Sopenharmony_ci /* set the pointer to mark that we will send the post body using the 272113498266Sopenharmony_ci read callback, but only if we're not in authenticate negotiation */ 272213498266Sopenharmony_ci if(!conn->bits.authneg) 272313498266Sopenharmony_ci http->postdata = (char *)&http->postdata; 272413498266Sopenharmony_ci } 272513498266Sopenharmony_ci } 272613498266Sopenharmony_ci /* issue the request */ 272713498266Sopenharmony_ci result = Curl_buffer_send(r, data, data->req.p.http, 272813498266Sopenharmony_ci &data->info.request_size, included_body, 272913498266Sopenharmony_ci FIRSTSOCKET); 273013498266Sopenharmony_ci 273113498266Sopenharmony_ci if(result) 273213498266Sopenharmony_ci failf(data, "Failed sending HTTP POST request"); 273313498266Sopenharmony_ci else 273413498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, 273513498266Sopenharmony_ci http->postdata?FIRSTSOCKET:-1); 273613498266Sopenharmony_ci break; 273713498266Sopenharmony_ci 273813498266Sopenharmony_ci default: 273913498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("\r\n")); 274013498266Sopenharmony_ci if(result) 274113498266Sopenharmony_ci return result; 274213498266Sopenharmony_ci 274313498266Sopenharmony_ci /* issue the request */ 274413498266Sopenharmony_ci result = Curl_buffer_send(r, data, data->req.p.http, 274513498266Sopenharmony_ci &data->info.request_size, 0, 274613498266Sopenharmony_ci FIRSTSOCKET); 274713498266Sopenharmony_ci if(result) 274813498266Sopenharmony_ci failf(data, "Failed sending HTTP request"); 274913498266Sopenharmony_ci#ifdef USE_WEBSOCKETS 275013498266Sopenharmony_ci else if((conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) && 275113498266Sopenharmony_ci !(data->set.connect_only)) 275213498266Sopenharmony_ci /* Set up the transfer for two-way since without CONNECT_ONLY set, this 275313498266Sopenharmony_ci request probably wants to send data too post upgrade */ 275413498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET); 275513498266Sopenharmony_ci#endif 275613498266Sopenharmony_ci else 275713498266Sopenharmony_ci /* HTTP GET/HEAD download: */ 275813498266Sopenharmony_ci Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); 275913498266Sopenharmony_ci } 276013498266Sopenharmony_ci 276113498266Sopenharmony_ci return result; 276213498266Sopenharmony_ci} 276313498266Sopenharmony_ci 276413498266Sopenharmony_ci#if !defined(CURL_DISABLE_COOKIES) 276513498266Sopenharmony_ci 276613498266Sopenharmony_ciCURLcode Curl_http_cookies(struct Curl_easy *data, 276713498266Sopenharmony_ci struct connectdata *conn, 276813498266Sopenharmony_ci struct dynbuf *r) 276913498266Sopenharmony_ci{ 277013498266Sopenharmony_ci CURLcode result = CURLE_OK; 277113498266Sopenharmony_ci char *addcookies = NULL; 277213498266Sopenharmony_ci bool linecap = FALSE; 277313498266Sopenharmony_ci if(data->set.str[STRING_COOKIE] && 277413498266Sopenharmony_ci !Curl_checkheaders(data, STRCONST("Cookie"))) 277513498266Sopenharmony_ci addcookies = data->set.str[STRING_COOKIE]; 277613498266Sopenharmony_ci 277713498266Sopenharmony_ci if(data->cookies || addcookies) { 277813498266Sopenharmony_ci struct Cookie *co = NULL; /* no cookies from start */ 277913498266Sopenharmony_ci int count = 0; 278013498266Sopenharmony_ci 278113498266Sopenharmony_ci if(data->cookies && data->state.cookie_engine) { 278213498266Sopenharmony_ci const char *host = data->state.aptr.cookiehost ? 278313498266Sopenharmony_ci data->state.aptr.cookiehost : conn->host.name; 278413498266Sopenharmony_ci const bool secure_context = 278513498266Sopenharmony_ci conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || 278613498266Sopenharmony_ci strcasecompare("localhost", host) || 278713498266Sopenharmony_ci !strcmp(host, "127.0.0.1") || 278813498266Sopenharmony_ci !strcmp(host, "::1") ? TRUE : FALSE; 278913498266Sopenharmony_ci Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); 279013498266Sopenharmony_ci co = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path, 279113498266Sopenharmony_ci secure_context); 279213498266Sopenharmony_ci Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); 279313498266Sopenharmony_ci } 279413498266Sopenharmony_ci if(co) { 279513498266Sopenharmony_ci struct Cookie *store = co; 279613498266Sopenharmony_ci size_t clen = 8; /* hold the size of the generated Cookie: header */ 279713498266Sopenharmony_ci /* now loop through all cookies that matched */ 279813498266Sopenharmony_ci while(co) { 279913498266Sopenharmony_ci if(co->value) { 280013498266Sopenharmony_ci size_t add; 280113498266Sopenharmony_ci if(!count) { 280213498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("Cookie: ")); 280313498266Sopenharmony_ci if(result) 280413498266Sopenharmony_ci break; 280513498266Sopenharmony_ci } 280613498266Sopenharmony_ci add = strlen(co->name) + strlen(co->value) + 1; 280713498266Sopenharmony_ci if(clen + add >= MAX_COOKIE_HEADER_LEN) { 280813498266Sopenharmony_ci infof(data, "Restricted outgoing cookies due to header size, " 280913498266Sopenharmony_ci "'%s' not sent", co->name); 281013498266Sopenharmony_ci linecap = TRUE; 281113498266Sopenharmony_ci break; 281213498266Sopenharmony_ci } 281313498266Sopenharmony_ci result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"", 281413498266Sopenharmony_ci co->name, co->value); 281513498266Sopenharmony_ci if(result) 281613498266Sopenharmony_ci break; 281713498266Sopenharmony_ci clen += add + (count ? 2 : 0); 281813498266Sopenharmony_ci count++; 281913498266Sopenharmony_ci } 282013498266Sopenharmony_ci co = co->next; /* next cookie please */ 282113498266Sopenharmony_ci } 282213498266Sopenharmony_ci Curl_cookie_freelist(store); 282313498266Sopenharmony_ci } 282413498266Sopenharmony_ci if(addcookies && !result && !linecap) { 282513498266Sopenharmony_ci if(!count) 282613498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("Cookie: ")); 282713498266Sopenharmony_ci if(!result) { 282813498266Sopenharmony_ci result = Curl_dyn_addf(r, "%s%s", count?"; ":"", addcookies); 282913498266Sopenharmony_ci count++; 283013498266Sopenharmony_ci } 283113498266Sopenharmony_ci } 283213498266Sopenharmony_ci if(count && !result) 283313498266Sopenharmony_ci result = Curl_dyn_addn(r, STRCONST("\r\n")); 283413498266Sopenharmony_ci 283513498266Sopenharmony_ci if(result) 283613498266Sopenharmony_ci return result; 283713498266Sopenharmony_ci } 283813498266Sopenharmony_ci return result; 283913498266Sopenharmony_ci} 284013498266Sopenharmony_ci#endif 284113498266Sopenharmony_ci 284213498266Sopenharmony_ciCURLcode Curl_http_range(struct Curl_easy *data, 284313498266Sopenharmony_ci Curl_HttpReq httpreq) 284413498266Sopenharmony_ci{ 284513498266Sopenharmony_ci if(data->state.use_range) { 284613498266Sopenharmony_ci /* 284713498266Sopenharmony_ci * A range is selected. We use different headers whether we're downloading 284813498266Sopenharmony_ci * or uploading and we always let customized headers override our internal 284913498266Sopenharmony_ci * ones if any such are specified. 285013498266Sopenharmony_ci */ 285113498266Sopenharmony_ci if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && 285213498266Sopenharmony_ci !Curl_checkheaders(data, STRCONST("Range"))) { 285313498266Sopenharmony_ci /* if a line like this was already allocated, free the previous one */ 285413498266Sopenharmony_ci free(data->state.aptr.rangeline); 285513498266Sopenharmony_ci data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n", 285613498266Sopenharmony_ci data->state.range); 285713498266Sopenharmony_ci } 285813498266Sopenharmony_ci else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && 285913498266Sopenharmony_ci !Curl_checkheaders(data, STRCONST("Content-Range"))) { 286013498266Sopenharmony_ci 286113498266Sopenharmony_ci /* if a line like this was already allocated, free the previous one */ 286213498266Sopenharmony_ci free(data->state.aptr.rangeline); 286313498266Sopenharmony_ci 286413498266Sopenharmony_ci if(data->set.set_resume_from < 0) { 286513498266Sopenharmony_ci /* Upload resume was asked for, but we don't know the size of the 286613498266Sopenharmony_ci remote part so we tell the server (and act accordingly) that we 286713498266Sopenharmony_ci upload the whole file (again) */ 286813498266Sopenharmony_ci data->state.aptr.rangeline = 286913498266Sopenharmony_ci aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T 287013498266Sopenharmony_ci "/%" CURL_FORMAT_CURL_OFF_T "\r\n", 287113498266Sopenharmony_ci data->state.infilesize - 1, data->state.infilesize); 287213498266Sopenharmony_ci 287313498266Sopenharmony_ci } 287413498266Sopenharmony_ci else if(data->state.resume_from) { 287513498266Sopenharmony_ci /* This is because "resume" was selected */ 287613498266Sopenharmony_ci curl_off_t total_expected_size = 287713498266Sopenharmony_ci data->state.resume_from + data->state.infilesize; 287813498266Sopenharmony_ci data->state.aptr.rangeline = 287913498266Sopenharmony_ci aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T 288013498266Sopenharmony_ci "/%" CURL_FORMAT_CURL_OFF_T "\r\n", 288113498266Sopenharmony_ci data->state.range, total_expected_size-1, 288213498266Sopenharmony_ci total_expected_size); 288313498266Sopenharmony_ci } 288413498266Sopenharmony_ci else { 288513498266Sopenharmony_ci /* Range was selected and then we just pass the incoming range and 288613498266Sopenharmony_ci append total size */ 288713498266Sopenharmony_ci data->state.aptr.rangeline = 288813498266Sopenharmony_ci aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n", 288913498266Sopenharmony_ci data->state.range, data->state.infilesize); 289013498266Sopenharmony_ci } 289113498266Sopenharmony_ci if(!data->state.aptr.rangeline) 289213498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 289313498266Sopenharmony_ci } 289413498266Sopenharmony_ci } 289513498266Sopenharmony_ci return CURLE_OK; 289613498266Sopenharmony_ci} 289713498266Sopenharmony_ci 289813498266Sopenharmony_ciCURLcode Curl_http_resume(struct Curl_easy *data, 289913498266Sopenharmony_ci struct connectdata *conn, 290013498266Sopenharmony_ci Curl_HttpReq httpreq) 290113498266Sopenharmony_ci{ 290213498266Sopenharmony_ci if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) && 290313498266Sopenharmony_ci data->state.resume_from) { 290413498266Sopenharmony_ci /********************************************************************** 290513498266Sopenharmony_ci * Resuming upload in HTTP means that we PUT or POST and that we have 290613498266Sopenharmony_ci * got a resume_from value set. The resume value has already created 290713498266Sopenharmony_ci * a Range: header that will be passed along. We need to "fast forward" 290813498266Sopenharmony_ci * the file the given number of bytes and decrease the assume upload 290913498266Sopenharmony_ci * file size before we continue this venture in the dark lands of HTTP. 291013498266Sopenharmony_ci * Resuming mime/form posting at an offset > 0 has no sense and is ignored. 291113498266Sopenharmony_ci *********************************************************************/ 291213498266Sopenharmony_ci 291313498266Sopenharmony_ci if(data->state.resume_from < 0) { 291413498266Sopenharmony_ci /* 291513498266Sopenharmony_ci * This is meant to get the size of the present remote-file by itself. 291613498266Sopenharmony_ci * We don't support this now. Bail out! 291713498266Sopenharmony_ci */ 291813498266Sopenharmony_ci data->state.resume_from = 0; 291913498266Sopenharmony_ci } 292013498266Sopenharmony_ci 292113498266Sopenharmony_ci if(data->state.resume_from && !data->state.followlocation) { 292213498266Sopenharmony_ci /* only act on the first request */ 292313498266Sopenharmony_ci 292413498266Sopenharmony_ci /* Now, let's read off the proper amount of bytes from the 292513498266Sopenharmony_ci input. */ 292613498266Sopenharmony_ci int seekerr = CURL_SEEKFUNC_CANTSEEK; 292713498266Sopenharmony_ci if(conn->seek_func) { 292813498266Sopenharmony_ci Curl_set_in_callback(data, true); 292913498266Sopenharmony_ci seekerr = conn->seek_func(conn->seek_client, data->state.resume_from, 293013498266Sopenharmony_ci SEEK_SET); 293113498266Sopenharmony_ci Curl_set_in_callback(data, false); 293213498266Sopenharmony_ci } 293313498266Sopenharmony_ci 293413498266Sopenharmony_ci if(seekerr != CURL_SEEKFUNC_OK) { 293513498266Sopenharmony_ci curl_off_t passed = 0; 293613498266Sopenharmony_ci 293713498266Sopenharmony_ci if(seekerr != CURL_SEEKFUNC_CANTSEEK) { 293813498266Sopenharmony_ci failf(data, "Could not seek stream"); 293913498266Sopenharmony_ci return CURLE_READ_ERROR; 294013498266Sopenharmony_ci } 294113498266Sopenharmony_ci /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ 294213498266Sopenharmony_ci do { 294313498266Sopenharmony_ci char scratch[4*1024]; 294413498266Sopenharmony_ci size_t readthisamountnow = 294513498266Sopenharmony_ci (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ? 294613498266Sopenharmony_ci sizeof(scratch) : 294713498266Sopenharmony_ci curlx_sotouz(data->state.resume_from - passed); 294813498266Sopenharmony_ci 294913498266Sopenharmony_ci size_t actuallyread = 295013498266Sopenharmony_ci data->state.fread_func(scratch, 1, readthisamountnow, 295113498266Sopenharmony_ci data->state.in); 295213498266Sopenharmony_ci 295313498266Sopenharmony_ci passed += actuallyread; 295413498266Sopenharmony_ci if((actuallyread == 0) || (actuallyread > readthisamountnow)) { 295513498266Sopenharmony_ci /* this checks for greater-than only to make sure that the 295613498266Sopenharmony_ci CURL_READFUNC_ABORT return code still aborts */ 295713498266Sopenharmony_ci failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T 295813498266Sopenharmony_ci " bytes from the input", passed); 295913498266Sopenharmony_ci return CURLE_READ_ERROR; 296013498266Sopenharmony_ci } 296113498266Sopenharmony_ci } while(passed < data->state.resume_from); 296213498266Sopenharmony_ci } 296313498266Sopenharmony_ci 296413498266Sopenharmony_ci /* now, decrease the size of the read */ 296513498266Sopenharmony_ci if(data->state.infilesize>0) { 296613498266Sopenharmony_ci data->state.infilesize -= data->state.resume_from; 296713498266Sopenharmony_ci 296813498266Sopenharmony_ci if(data->state.infilesize <= 0) { 296913498266Sopenharmony_ci failf(data, "File already completely uploaded"); 297013498266Sopenharmony_ci return CURLE_PARTIAL_FILE; 297113498266Sopenharmony_ci } 297213498266Sopenharmony_ci } 297313498266Sopenharmony_ci /* we've passed, proceed as normal */ 297413498266Sopenharmony_ci } 297513498266Sopenharmony_ci } 297613498266Sopenharmony_ci return CURLE_OK; 297713498266Sopenharmony_ci} 297813498266Sopenharmony_ci 297913498266Sopenharmony_ciCURLcode Curl_http_firstwrite(struct Curl_easy *data, 298013498266Sopenharmony_ci struct connectdata *conn, 298113498266Sopenharmony_ci bool *done) 298213498266Sopenharmony_ci{ 298313498266Sopenharmony_ci struct SingleRequest *k = &data->req; 298413498266Sopenharmony_ci 298513498266Sopenharmony_ci *done = FALSE; 298613498266Sopenharmony_ci if(data->req.newurl) { 298713498266Sopenharmony_ci if(conn->bits.close) { 298813498266Sopenharmony_ci /* Abort after the headers if "follow Location" is set 298913498266Sopenharmony_ci and we're set to close anyway. */ 299013498266Sopenharmony_ci k->keepon &= ~KEEP_RECV; 299113498266Sopenharmony_ci *done = TRUE; 299213498266Sopenharmony_ci return CURLE_OK; 299313498266Sopenharmony_ci } 299413498266Sopenharmony_ci /* We have a new url to load, but since we want to be able to reuse this 299513498266Sopenharmony_ci connection properly, we read the full response in "ignore more" */ 299613498266Sopenharmony_ci k->ignorebody = TRUE; 299713498266Sopenharmony_ci infof(data, "Ignoring the response-body"); 299813498266Sopenharmony_ci } 299913498266Sopenharmony_ci if(data->state.resume_from && !k->content_range && 300013498266Sopenharmony_ci (data->state.httpreq == HTTPREQ_GET) && 300113498266Sopenharmony_ci !k->ignorebody) { 300213498266Sopenharmony_ci 300313498266Sopenharmony_ci if(k->size == data->state.resume_from) { 300413498266Sopenharmony_ci /* The resume point is at the end of file, consider this fine even if it 300513498266Sopenharmony_ci doesn't allow resume from here. */ 300613498266Sopenharmony_ci infof(data, "The entire document is already downloaded"); 300713498266Sopenharmony_ci streamclose(conn, "already downloaded"); 300813498266Sopenharmony_ci /* Abort download */ 300913498266Sopenharmony_ci k->keepon &= ~KEEP_RECV; 301013498266Sopenharmony_ci *done = TRUE; 301113498266Sopenharmony_ci return CURLE_OK; 301213498266Sopenharmony_ci } 301313498266Sopenharmony_ci 301413498266Sopenharmony_ci /* we wanted to resume a download, although the server doesn't seem to 301513498266Sopenharmony_ci * support this and we did this with a GET (if it wasn't a GET we did a 301613498266Sopenharmony_ci * POST or PUT resume) */ 301713498266Sopenharmony_ci failf(data, "HTTP server doesn't seem to support " 301813498266Sopenharmony_ci "byte ranges. Cannot resume."); 301913498266Sopenharmony_ci return CURLE_RANGE_ERROR; 302013498266Sopenharmony_ci } 302113498266Sopenharmony_ci 302213498266Sopenharmony_ci if(data->set.timecondition && !data->state.range) { 302313498266Sopenharmony_ci /* A time condition has been set AND no ranges have been requested. This 302413498266Sopenharmony_ci seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct 302513498266Sopenharmony_ci action for an HTTP/1.1 client */ 302613498266Sopenharmony_ci 302713498266Sopenharmony_ci if(!Curl_meets_timecondition(data, k->timeofdoc)) { 302813498266Sopenharmony_ci *done = TRUE; 302913498266Sopenharmony_ci /* We're simulating an HTTP 304 from server so we return 303013498266Sopenharmony_ci what should have been returned from the server */ 303113498266Sopenharmony_ci data->info.httpcode = 304; 303213498266Sopenharmony_ci infof(data, "Simulate an HTTP 304 response"); 303313498266Sopenharmony_ci /* we abort the transfer before it is completed == we ruin the 303413498266Sopenharmony_ci reuse ability. Close the connection */ 303513498266Sopenharmony_ci streamclose(conn, "Simulated 304 handling"); 303613498266Sopenharmony_ci return CURLE_OK; 303713498266Sopenharmony_ci } 303813498266Sopenharmony_ci } /* we have a time condition */ 303913498266Sopenharmony_ci 304013498266Sopenharmony_ci return CURLE_OK; 304113498266Sopenharmony_ci} 304213498266Sopenharmony_ci 304313498266Sopenharmony_ci#ifdef HAVE_LIBZ 304413498266Sopenharmony_ciCURLcode Curl_transferencode(struct Curl_easy *data) 304513498266Sopenharmony_ci{ 304613498266Sopenharmony_ci if(!Curl_checkheaders(data, STRCONST("TE")) && 304713498266Sopenharmony_ci data->set.http_transfer_encoding) { 304813498266Sopenharmony_ci /* When we are to insert a TE: header in the request, we must also insert 304913498266Sopenharmony_ci TE in a Connection: header, so we need to merge the custom provided 305013498266Sopenharmony_ci Connection: header and prevent the original to get sent. Note that if 305113498266Sopenharmony_ci the user has inserted his/her own TE: header we don't do this magic 305213498266Sopenharmony_ci but then assume that the user will handle it all! */ 305313498266Sopenharmony_ci char *cptr = Curl_checkheaders(data, STRCONST("Connection")); 305413498266Sopenharmony_ci#define TE_HEADER "TE: gzip\r\n" 305513498266Sopenharmony_ci 305613498266Sopenharmony_ci Curl_safefree(data->state.aptr.te); 305713498266Sopenharmony_ci 305813498266Sopenharmony_ci if(cptr) { 305913498266Sopenharmony_ci cptr = Curl_copy_header_value(cptr); 306013498266Sopenharmony_ci if(!cptr) 306113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 306213498266Sopenharmony_ci } 306313498266Sopenharmony_ci 306413498266Sopenharmony_ci /* Create the (updated) Connection: header */ 306513498266Sopenharmony_ci data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, 306613498266Sopenharmony_ci cptr ? cptr : "", (cptr && *cptr) ? ", ":""); 306713498266Sopenharmony_ci 306813498266Sopenharmony_ci free(cptr); 306913498266Sopenharmony_ci if(!data->state.aptr.te) 307013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 307113498266Sopenharmony_ci } 307213498266Sopenharmony_ci return CURLE_OK; 307313498266Sopenharmony_ci} 307413498266Sopenharmony_ci#endif 307513498266Sopenharmony_ci 307613498266Sopenharmony_ci#ifndef USE_HYPER 307713498266Sopenharmony_ci/* 307813498266Sopenharmony_ci * Curl_http() gets called from the generic multi_do() function when an HTTP 307913498266Sopenharmony_ci * request is to be performed. This creates and sends a properly constructed 308013498266Sopenharmony_ci * HTTP request. 308113498266Sopenharmony_ci */ 308213498266Sopenharmony_ciCURLcode Curl_http(struct Curl_easy *data, bool *done) 308313498266Sopenharmony_ci{ 308413498266Sopenharmony_ci struct connectdata *conn = data->conn; 308513498266Sopenharmony_ci CURLcode result = CURLE_OK; 308613498266Sopenharmony_ci struct HTTP *http; 308713498266Sopenharmony_ci Curl_HttpReq httpreq; 308813498266Sopenharmony_ci const char *te = ""; /* transfer-encoding */ 308913498266Sopenharmony_ci const char *request; 309013498266Sopenharmony_ci const char *httpstring; 309113498266Sopenharmony_ci struct dynbuf req; 309213498266Sopenharmony_ci char *altused = NULL; 309313498266Sopenharmony_ci const char *p_accept; /* Accept: string */ 309413498266Sopenharmony_ci 309513498266Sopenharmony_ci /* Always consider the DO phase done after this function call, even if there 309613498266Sopenharmony_ci may be parts of the request that are not yet sent, since we can deal with 309713498266Sopenharmony_ci the rest of the request in the PERFORM phase. */ 309813498266Sopenharmony_ci *done = TRUE; 309913498266Sopenharmony_ci 310013498266Sopenharmony_ci switch(conn->alpn) { 310113498266Sopenharmony_ci case CURL_HTTP_VERSION_3: 310213498266Sopenharmony_ci DEBUGASSERT(Curl_conn_is_http3(data, conn, FIRSTSOCKET)); 310313498266Sopenharmony_ci break; 310413498266Sopenharmony_ci case CURL_HTTP_VERSION_2: 310513498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 310613498266Sopenharmony_ci if(!Curl_conn_is_http2(data, conn, FIRSTSOCKET) && 310713498266Sopenharmony_ci conn->bits.proxy && !conn->bits.tunnel_proxy 310813498266Sopenharmony_ci ) { 310913498266Sopenharmony_ci result = Curl_http2_switch(data, conn, FIRSTSOCKET); 311013498266Sopenharmony_ci if(result) 311113498266Sopenharmony_ci goto fail; 311213498266Sopenharmony_ci } 311313498266Sopenharmony_ci else 311413498266Sopenharmony_ci#endif 311513498266Sopenharmony_ci DEBUGASSERT(Curl_conn_is_http2(data, conn, FIRSTSOCKET)); 311613498266Sopenharmony_ci break; 311713498266Sopenharmony_ci case CURL_HTTP_VERSION_1_1: 311813498266Sopenharmony_ci /* continue with HTTP/1.x when explicitly requested */ 311913498266Sopenharmony_ci break; 312013498266Sopenharmony_ci default: 312113498266Sopenharmony_ci /* Check if user wants to use HTTP/2 with clear TCP */ 312213498266Sopenharmony_ci if(Curl_http2_may_switch(data, conn, FIRSTSOCKET)) { 312313498266Sopenharmony_ci DEBUGF(infof(data, "HTTP/2 over clean TCP")); 312413498266Sopenharmony_ci result = Curl_http2_switch(data, conn, FIRSTSOCKET); 312513498266Sopenharmony_ci if(result) 312613498266Sopenharmony_ci goto fail; 312713498266Sopenharmony_ci } 312813498266Sopenharmony_ci break; 312913498266Sopenharmony_ci } 313013498266Sopenharmony_ci 313113498266Sopenharmony_ci http = data->req.p.http; 313213498266Sopenharmony_ci DEBUGASSERT(http); 313313498266Sopenharmony_ci 313413498266Sopenharmony_ci result = Curl_http_host(data, conn); 313513498266Sopenharmony_ci if(result) 313613498266Sopenharmony_ci goto fail; 313713498266Sopenharmony_ci 313813498266Sopenharmony_ci result = Curl_http_useragent(data); 313913498266Sopenharmony_ci if(result) 314013498266Sopenharmony_ci goto fail; 314113498266Sopenharmony_ci 314213498266Sopenharmony_ci Curl_http_method(data, conn, &request, &httpreq); 314313498266Sopenharmony_ci 314413498266Sopenharmony_ci /* setup the authentication headers */ 314513498266Sopenharmony_ci { 314613498266Sopenharmony_ci char *pq = NULL; 314713498266Sopenharmony_ci if(data->state.up.query) { 314813498266Sopenharmony_ci pq = aprintf("%s?%s", data->state.up.path, data->state.up.query); 314913498266Sopenharmony_ci if(!pq) 315013498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 315113498266Sopenharmony_ci } 315213498266Sopenharmony_ci result = Curl_http_output_auth(data, conn, request, httpreq, 315313498266Sopenharmony_ci (pq ? pq : data->state.up.path), FALSE); 315413498266Sopenharmony_ci free(pq); 315513498266Sopenharmony_ci if(result) 315613498266Sopenharmony_ci goto fail; 315713498266Sopenharmony_ci } 315813498266Sopenharmony_ci 315913498266Sopenharmony_ci Curl_safefree(data->state.aptr.ref); 316013498266Sopenharmony_ci if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) { 316113498266Sopenharmony_ci data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer); 316213498266Sopenharmony_ci if(!data->state.aptr.ref) 316313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 316413498266Sopenharmony_ci } 316513498266Sopenharmony_ci 316613498266Sopenharmony_ci if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) && 316713498266Sopenharmony_ci data->set.str[STRING_ENCODING]) { 316813498266Sopenharmony_ci Curl_safefree(data->state.aptr.accept_encoding); 316913498266Sopenharmony_ci data->state.aptr.accept_encoding = 317013498266Sopenharmony_ci aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); 317113498266Sopenharmony_ci if(!data->state.aptr.accept_encoding) 317213498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 317313498266Sopenharmony_ci } 317413498266Sopenharmony_ci else 317513498266Sopenharmony_ci Curl_safefree(data->state.aptr.accept_encoding); 317613498266Sopenharmony_ci 317713498266Sopenharmony_ci#ifdef HAVE_LIBZ 317813498266Sopenharmony_ci /* we only consider transfer-encoding magic if libz support is built-in */ 317913498266Sopenharmony_ci result = Curl_transferencode(data); 318013498266Sopenharmony_ci if(result) 318113498266Sopenharmony_ci goto fail; 318213498266Sopenharmony_ci#endif 318313498266Sopenharmony_ci 318413498266Sopenharmony_ci result = Curl_http_body(data, conn, httpreq, &te); 318513498266Sopenharmony_ci if(result) 318613498266Sopenharmony_ci goto fail; 318713498266Sopenharmony_ci 318813498266Sopenharmony_ci p_accept = Curl_checkheaders(data, 318913498266Sopenharmony_ci STRCONST("Accept"))?NULL:"Accept: */*\r\n"; 319013498266Sopenharmony_ci 319113498266Sopenharmony_ci result = Curl_http_resume(data, conn, httpreq); 319213498266Sopenharmony_ci if(result) 319313498266Sopenharmony_ci goto fail; 319413498266Sopenharmony_ci 319513498266Sopenharmony_ci result = Curl_http_range(data, httpreq); 319613498266Sopenharmony_ci if(result) 319713498266Sopenharmony_ci goto fail; 319813498266Sopenharmony_ci 319913498266Sopenharmony_ci httpstring = get_http_string(data, conn); 320013498266Sopenharmony_ci 320113498266Sopenharmony_ci /* initialize a dynamic send-buffer */ 320213498266Sopenharmony_ci Curl_dyn_init(&req, DYN_HTTP_REQUEST); 320313498266Sopenharmony_ci 320413498266Sopenharmony_ci /* make sure the header buffer is reset - if there are leftovers from a 320513498266Sopenharmony_ci previous transfer */ 320613498266Sopenharmony_ci Curl_dyn_reset(&data->state.headerb); 320713498266Sopenharmony_ci 320813498266Sopenharmony_ci /* add the main request stuff */ 320913498266Sopenharmony_ci /* GET/HEAD/POST/PUT */ 321013498266Sopenharmony_ci result = Curl_dyn_addf(&req, "%s ", request); 321113498266Sopenharmony_ci if(!result) 321213498266Sopenharmony_ci result = Curl_http_target(data, conn, &req); 321313498266Sopenharmony_ci if(result) { 321413498266Sopenharmony_ci Curl_dyn_free(&req); 321513498266Sopenharmony_ci goto fail; 321613498266Sopenharmony_ci } 321713498266Sopenharmony_ci 321813498266Sopenharmony_ci#ifndef CURL_DISABLE_ALTSVC 321913498266Sopenharmony_ci if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) { 322013498266Sopenharmony_ci altused = aprintf("Alt-Used: %s:%d\r\n", 322113498266Sopenharmony_ci conn->conn_to_host.name, conn->conn_to_port); 322213498266Sopenharmony_ci if(!altused) { 322313498266Sopenharmony_ci Curl_dyn_free(&req); 322413498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 322513498266Sopenharmony_ci } 322613498266Sopenharmony_ci } 322713498266Sopenharmony_ci#endif 322813498266Sopenharmony_ci result = 322913498266Sopenharmony_ci Curl_dyn_addf(&req, 323013498266Sopenharmony_ci " HTTP/%s\r\n" /* HTTP version */ 323113498266Sopenharmony_ci "%s" /* host */ 323213498266Sopenharmony_ci "%s" /* proxyuserpwd */ 323313498266Sopenharmony_ci "%s" /* userpwd */ 323413498266Sopenharmony_ci "%s" /* range */ 323513498266Sopenharmony_ci "%s" /* user agent */ 323613498266Sopenharmony_ci "%s" /* accept */ 323713498266Sopenharmony_ci "%s" /* TE: */ 323813498266Sopenharmony_ci "%s" /* accept-encoding */ 323913498266Sopenharmony_ci "%s" /* referer */ 324013498266Sopenharmony_ci "%s" /* Proxy-Connection */ 324113498266Sopenharmony_ci "%s" /* transfer-encoding */ 324213498266Sopenharmony_ci "%s",/* Alt-Used */ 324313498266Sopenharmony_ci 324413498266Sopenharmony_ci httpstring, 324513498266Sopenharmony_ci (data->state.aptr.host?data->state.aptr.host:""), 324613498266Sopenharmony_ci data->state.aptr.proxyuserpwd? 324713498266Sopenharmony_ci data->state.aptr.proxyuserpwd:"", 324813498266Sopenharmony_ci data->state.aptr.userpwd?data->state.aptr.userpwd:"", 324913498266Sopenharmony_ci (data->state.use_range && data->state.aptr.rangeline)? 325013498266Sopenharmony_ci data->state.aptr.rangeline:"", 325113498266Sopenharmony_ci (data->set.str[STRING_USERAGENT] && 325213498266Sopenharmony_ci *data->set.str[STRING_USERAGENT] && 325313498266Sopenharmony_ci data->state.aptr.uagent)? 325413498266Sopenharmony_ci data->state.aptr.uagent:"", 325513498266Sopenharmony_ci p_accept?p_accept:"", 325613498266Sopenharmony_ci data->state.aptr.te?data->state.aptr.te:"", 325713498266Sopenharmony_ci (data->set.str[STRING_ENCODING] && 325813498266Sopenharmony_ci *data->set.str[STRING_ENCODING] && 325913498266Sopenharmony_ci data->state.aptr.accept_encoding)? 326013498266Sopenharmony_ci data->state.aptr.accept_encoding:"", 326113498266Sopenharmony_ci (data->state.referer && data->state.aptr.ref)? 326213498266Sopenharmony_ci data->state.aptr.ref:"" /* Referer: <data> */, 326313498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 326413498266Sopenharmony_ci (conn->bits.httpproxy && 326513498266Sopenharmony_ci !conn->bits.tunnel_proxy && 326613498266Sopenharmony_ci !Curl_checkheaders(data, STRCONST("Proxy-Connection")) && 326713498266Sopenharmony_ci !Curl_checkProxyheaders(data, 326813498266Sopenharmony_ci conn, 326913498266Sopenharmony_ci STRCONST("Proxy-Connection")))? 327013498266Sopenharmony_ci "Proxy-Connection: Keep-Alive\r\n":"", 327113498266Sopenharmony_ci#else 327213498266Sopenharmony_ci "", 327313498266Sopenharmony_ci#endif 327413498266Sopenharmony_ci te, 327513498266Sopenharmony_ci altused ? altused : "" 327613498266Sopenharmony_ci ); 327713498266Sopenharmony_ci 327813498266Sopenharmony_ci /* clear userpwd and proxyuserpwd to avoid reusing old credentials 327913498266Sopenharmony_ci * from reused connections */ 328013498266Sopenharmony_ci Curl_safefree(data->state.aptr.userpwd); 328113498266Sopenharmony_ci Curl_safefree(data->state.aptr.proxyuserpwd); 328213498266Sopenharmony_ci free(altused); 328313498266Sopenharmony_ci 328413498266Sopenharmony_ci if(result) { 328513498266Sopenharmony_ci Curl_dyn_free(&req); 328613498266Sopenharmony_ci goto fail; 328713498266Sopenharmony_ci } 328813498266Sopenharmony_ci 328913498266Sopenharmony_ci if(!(conn->handler->flags&PROTOPT_SSL) && 329013498266Sopenharmony_ci conn->httpversion < 20 && 329113498266Sopenharmony_ci (data->state.httpwant == CURL_HTTP_VERSION_2)) { 329213498266Sopenharmony_ci /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done 329313498266Sopenharmony_ci over SSL */ 329413498266Sopenharmony_ci result = Curl_http2_request_upgrade(&req, data); 329513498266Sopenharmony_ci if(result) { 329613498266Sopenharmony_ci Curl_dyn_free(&req); 329713498266Sopenharmony_ci return result; 329813498266Sopenharmony_ci } 329913498266Sopenharmony_ci } 330013498266Sopenharmony_ci 330113498266Sopenharmony_ci result = Curl_http_cookies(data, conn, &req); 330213498266Sopenharmony_ci#ifdef USE_WEBSOCKETS 330313498266Sopenharmony_ci if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) 330413498266Sopenharmony_ci result = Curl_ws_request(data, &req); 330513498266Sopenharmony_ci#endif 330613498266Sopenharmony_ci if(!result) 330713498266Sopenharmony_ci result = Curl_add_timecondition(data, &req); 330813498266Sopenharmony_ci if(!result) 330913498266Sopenharmony_ci result = Curl_add_custom_headers(data, FALSE, &req); 331013498266Sopenharmony_ci 331113498266Sopenharmony_ci if(!result) { 331213498266Sopenharmony_ci http->postdata = NULL; /* nothing to post at this point */ 331313498266Sopenharmony_ci if((httpreq == HTTPREQ_GET) || 331413498266Sopenharmony_ci (httpreq == HTTPREQ_HEAD)) 331513498266Sopenharmony_ci Curl_pgrsSetUploadSize(data, 0); /* nothing */ 331613498266Sopenharmony_ci 331713498266Sopenharmony_ci /* bodysend takes ownership of the 'req' memory on success */ 331813498266Sopenharmony_ci result = Curl_http_bodysend(data, conn, &req, httpreq); 331913498266Sopenharmony_ci } 332013498266Sopenharmony_ci if(result) { 332113498266Sopenharmony_ci Curl_dyn_free(&req); 332213498266Sopenharmony_ci goto fail; 332313498266Sopenharmony_ci } 332413498266Sopenharmony_ci 332513498266Sopenharmony_ci if((http->postsize > -1) && 332613498266Sopenharmony_ci (http->postsize <= data->req.writebytecount) && 332713498266Sopenharmony_ci (http->sending != HTTPSEND_REQUEST)) 332813498266Sopenharmony_ci data->req.upload_done = TRUE; 332913498266Sopenharmony_ci 333013498266Sopenharmony_ci if(data->req.writebytecount) { 333113498266Sopenharmony_ci /* if a request-body has been sent off, we make sure this progress is noted 333213498266Sopenharmony_ci properly */ 333313498266Sopenharmony_ci Curl_pgrsSetUploadCounter(data, data->req.writebytecount); 333413498266Sopenharmony_ci if(Curl_pgrsUpdate(data)) 333513498266Sopenharmony_ci result = CURLE_ABORTED_BY_CALLBACK; 333613498266Sopenharmony_ci 333713498266Sopenharmony_ci if(!http->postsize) { 333813498266Sopenharmony_ci /* already sent the entire request body, mark the "upload" as 333913498266Sopenharmony_ci complete */ 334013498266Sopenharmony_ci infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T 334113498266Sopenharmony_ci " out of %" CURL_FORMAT_CURL_OFF_T " bytes", 334213498266Sopenharmony_ci data->req.writebytecount, http->postsize); 334313498266Sopenharmony_ci data->req.upload_done = TRUE; 334413498266Sopenharmony_ci data->req.keepon &= ~KEEP_SEND; /* we're done writing */ 334513498266Sopenharmony_ci data->req.exp100 = EXP100_SEND_DATA; /* already sent */ 334613498266Sopenharmony_ci Curl_expire_done(data, EXPIRE_100_TIMEOUT); 334713498266Sopenharmony_ci } 334813498266Sopenharmony_ci } 334913498266Sopenharmony_ci 335013498266Sopenharmony_ci if(data->req.upload_done) 335113498266Sopenharmony_ci Curl_conn_ev_data_done_send(data); 335213498266Sopenharmony_ci 335313498266Sopenharmony_ci if((conn->httpversion >= 20) && data->req.upload_chunky) 335413498266Sopenharmony_ci /* upload_chunky was set above to set up the request in a chunky fashion, 335513498266Sopenharmony_ci but is disabled here again to avoid that the chunked encoded version is 335613498266Sopenharmony_ci actually used when sending the request body over h2 */ 335713498266Sopenharmony_ci data->req.upload_chunky = FALSE; 335813498266Sopenharmony_cifail: 335913498266Sopenharmony_ci if(CURLE_TOO_LARGE == result) 336013498266Sopenharmony_ci failf(data, "HTTP request too large"); 336113498266Sopenharmony_ci return result; 336213498266Sopenharmony_ci} 336313498266Sopenharmony_ci 336413498266Sopenharmony_ci#endif /* USE_HYPER */ 336513498266Sopenharmony_ci 336613498266Sopenharmony_citypedef enum { 336713498266Sopenharmony_ci STATUS_UNKNOWN, /* not enough data to tell yet */ 336813498266Sopenharmony_ci STATUS_DONE, /* a status line was read */ 336913498266Sopenharmony_ci STATUS_BAD /* not a status line */ 337013498266Sopenharmony_ci} statusline; 337113498266Sopenharmony_ci 337213498266Sopenharmony_ci 337313498266Sopenharmony_ci/* Check a string for a prefix. Check no more than 'len' bytes */ 337413498266Sopenharmony_cistatic bool checkprefixmax(const char *prefix, const char *buffer, size_t len) 337513498266Sopenharmony_ci{ 337613498266Sopenharmony_ci size_t ch = CURLMIN(strlen(prefix), len); 337713498266Sopenharmony_ci return curl_strnequal(prefix, buffer, ch); 337813498266Sopenharmony_ci} 337913498266Sopenharmony_ci 338013498266Sopenharmony_ci/* 338113498266Sopenharmony_ci * checkhttpprefix() 338213498266Sopenharmony_ci * 338313498266Sopenharmony_ci * Returns TRUE if member of the list matches prefix of string 338413498266Sopenharmony_ci */ 338513498266Sopenharmony_cistatic statusline 338613498266Sopenharmony_cicheckhttpprefix(struct Curl_easy *data, 338713498266Sopenharmony_ci const char *s, size_t len) 338813498266Sopenharmony_ci{ 338913498266Sopenharmony_ci struct curl_slist *head = data->set.http200aliases; 339013498266Sopenharmony_ci statusline rc = STATUS_BAD; 339113498266Sopenharmony_ci statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN; 339213498266Sopenharmony_ci 339313498266Sopenharmony_ci while(head) { 339413498266Sopenharmony_ci if(checkprefixmax(head->data, s, len)) { 339513498266Sopenharmony_ci rc = onmatch; 339613498266Sopenharmony_ci break; 339713498266Sopenharmony_ci } 339813498266Sopenharmony_ci head = head->next; 339913498266Sopenharmony_ci } 340013498266Sopenharmony_ci 340113498266Sopenharmony_ci if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len))) 340213498266Sopenharmony_ci rc = onmatch; 340313498266Sopenharmony_ci 340413498266Sopenharmony_ci return rc; 340513498266Sopenharmony_ci} 340613498266Sopenharmony_ci 340713498266Sopenharmony_ci#ifndef CURL_DISABLE_RTSP 340813498266Sopenharmony_cistatic statusline 340913498266Sopenharmony_cicheckrtspprefix(struct Curl_easy *data, 341013498266Sopenharmony_ci const char *s, size_t len) 341113498266Sopenharmony_ci{ 341213498266Sopenharmony_ci statusline result = STATUS_BAD; 341313498266Sopenharmony_ci statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN; 341413498266Sopenharmony_ci (void)data; /* unused */ 341513498266Sopenharmony_ci if(checkprefixmax("RTSP/", s, len)) 341613498266Sopenharmony_ci result = onmatch; 341713498266Sopenharmony_ci 341813498266Sopenharmony_ci return result; 341913498266Sopenharmony_ci} 342013498266Sopenharmony_ci#endif /* CURL_DISABLE_RTSP */ 342113498266Sopenharmony_ci 342213498266Sopenharmony_cistatic statusline 342313498266Sopenharmony_cicheckprotoprefix(struct Curl_easy *data, struct connectdata *conn, 342413498266Sopenharmony_ci const char *s, size_t len) 342513498266Sopenharmony_ci{ 342613498266Sopenharmony_ci#ifndef CURL_DISABLE_RTSP 342713498266Sopenharmony_ci if(conn->handler->protocol & CURLPROTO_RTSP) 342813498266Sopenharmony_ci return checkrtspprefix(data, s, len); 342913498266Sopenharmony_ci#else 343013498266Sopenharmony_ci (void)conn; 343113498266Sopenharmony_ci#endif /* CURL_DISABLE_RTSP */ 343213498266Sopenharmony_ci 343313498266Sopenharmony_ci return checkhttpprefix(data, s, len); 343413498266Sopenharmony_ci} 343513498266Sopenharmony_ci 343613498266Sopenharmony_ci/* 343713498266Sopenharmony_ci * Curl_http_header() parses a single response header. 343813498266Sopenharmony_ci */ 343913498266Sopenharmony_ciCURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, 344013498266Sopenharmony_ci char *headp) 344113498266Sopenharmony_ci{ 344213498266Sopenharmony_ci CURLcode result; 344313498266Sopenharmony_ci struct SingleRequest *k = &data->req; 344413498266Sopenharmony_ci /* Check for Content-Length: header lines to get size */ 344513498266Sopenharmony_ci if(!k->http_bodyless && 344613498266Sopenharmony_ci !data->set.ignorecl && checkprefix("Content-Length:", headp)) { 344713498266Sopenharmony_ci curl_off_t contentlength; 344813498266Sopenharmony_ci CURLofft offt = curlx_strtoofft(headp + strlen("Content-Length:"), 344913498266Sopenharmony_ci NULL, 10, &contentlength); 345013498266Sopenharmony_ci 345113498266Sopenharmony_ci if(offt == CURL_OFFT_OK) { 345213498266Sopenharmony_ci k->size = contentlength; 345313498266Sopenharmony_ci k->maxdownload = k->size; 345413498266Sopenharmony_ci } 345513498266Sopenharmony_ci else if(offt == CURL_OFFT_FLOW) { 345613498266Sopenharmony_ci /* out of range */ 345713498266Sopenharmony_ci if(data->set.max_filesize) { 345813498266Sopenharmony_ci failf(data, "Maximum file size exceeded"); 345913498266Sopenharmony_ci return CURLE_FILESIZE_EXCEEDED; 346013498266Sopenharmony_ci } 346113498266Sopenharmony_ci streamclose(conn, "overflow content-length"); 346213498266Sopenharmony_ci infof(data, "Overflow Content-Length: value"); 346313498266Sopenharmony_ci } 346413498266Sopenharmony_ci else { 346513498266Sopenharmony_ci /* negative or just rubbish - bad HTTP */ 346613498266Sopenharmony_ci failf(data, "Invalid Content-Length: value"); 346713498266Sopenharmony_ci return CURLE_WEIRD_SERVER_REPLY; 346813498266Sopenharmony_ci } 346913498266Sopenharmony_ci } 347013498266Sopenharmony_ci /* check for Content-Type: header lines to get the MIME-type */ 347113498266Sopenharmony_ci else if(checkprefix("Content-Type:", headp)) { 347213498266Sopenharmony_ci char *contenttype = Curl_copy_header_value(headp); 347313498266Sopenharmony_ci if(!contenttype) 347413498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 347513498266Sopenharmony_ci if(!*contenttype) 347613498266Sopenharmony_ci /* ignore empty data */ 347713498266Sopenharmony_ci free(contenttype); 347813498266Sopenharmony_ci else { 347913498266Sopenharmony_ci Curl_safefree(data->info.contenttype); 348013498266Sopenharmony_ci data->info.contenttype = contenttype; 348113498266Sopenharmony_ci } 348213498266Sopenharmony_ci } 348313498266Sopenharmony_ci#ifndef CURL_DISABLE_PROXY 348413498266Sopenharmony_ci else if((conn->httpversion == 10) && 348513498266Sopenharmony_ci conn->bits.httpproxy && 348613498266Sopenharmony_ci Curl_compareheader(headp, 348713498266Sopenharmony_ci STRCONST("Proxy-Connection:"), 348813498266Sopenharmony_ci STRCONST("keep-alive"))) { 348913498266Sopenharmony_ci /* 349013498266Sopenharmony_ci * When an HTTP/1.0 reply comes when using a proxy, the 349113498266Sopenharmony_ci * 'Proxy-Connection: keep-alive' line tells us the 349213498266Sopenharmony_ci * connection will be kept alive for our pleasure. 349313498266Sopenharmony_ci * Default action for 1.0 is to close. 349413498266Sopenharmony_ci */ 349513498266Sopenharmony_ci connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */ 349613498266Sopenharmony_ci infof(data, "HTTP/1.0 proxy connection set to keep alive"); 349713498266Sopenharmony_ci } 349813498266Sopenharmony_ci else if((conn->httpversion == 11) && 349913498266Sopenharmony_ci conn->bits.httpproxy && 350013498266Sopenharmony_ci Curl_compareheader(headp, 350113498266Sopenharmony_ci STRCONST("Proxy-Connection:"), 350213498266Sopenharmony_ci STRCONST("close"))) { 350313498266Sopenharmony_ci /* 350413498266Sopenharmony_ci * We get an HTTP/1.1 response from a proxy and it says it'll 350513498266Sopenharmony_ci * close down after this transfer. 350613498266Sopenharmony_ci */ 350713498266Sopenharmony_ci connclose(conn, "Proxy-Connection: asked to close after done"); 350813498266Sopenharmony_ci infof(data, "HTTP/1.1 proxy connection set close"); 350913498266Sopenharmony_ci } 351013498266Sopenharmony_ci#endif 351113498266Sopenharmony_ci else if((conn->httpversion == 10) && 351213498266Sopenharmony_ci Curl_compareheader(headp, 351313498266Sopenharmony_ci STRCONST("Connection:"), 351413498266Sopenharmony_ci STRCONST("keep-alive"))) { 351513498266Sopenharmony_ci /* 351613498266Sopenharmony_ci * An HTTP/1.0 reply with the 'Connection: keep-alive' line 351713498266Sopenharmony_ci * tells us the connection will be kept alive for our 351813498266Sopenharmony_ci * pleasure. Default action for 1.0 is to close. 351913498266Sopenharmony_ci * 352013498266Sopenharmony_ci * [RFC2068, section 19.7.1] */ 352113498266Sopenharmony_ci connkeep(conn, "Connection keep-alive"); 352213498266Sopenharmony_ci infof(data, "HTTP/1.0 connection set to keep alive"); 352313498266Sopenharmony_ci } 352413498266Sopenharmony_ci else if(Curl_compareheader(headp, 352513498266Sopenharmony_ci STRCONST("Connection:"), STRCONST("close"))) { 352613498266Sopenharmony_ci /* 352713498266Sopenharmony_ci * [RFC 2616, section 8.1.2.1] 352813498266Sopenharmony_ci * "Connection: close" is HTTP/1.1 language and means that 352913498266Sopenharmony_ci * the connection will close when this request has been 353013498266Sopenharmony_ci * served. 353113498266Sopenharmony_ci */ 353213498266Sopenharmony_ci streamclose(conn, "Connection: close used"); 353313498266Sopenharmony_ci } 353413498266Sopenharmony_ci else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) { 353513498266Sopenharmony_ci /* One or more encodings. We check for chunked and/or a compression 353613498266Sopenharmony_ci algorithm. */ 353713498266Sopenharmony_ci /* 353813498266Sopenharmony_ci * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding 353913498266Sopenharmony_ci * means that the server will send a series of "chunks". Each 354013498266Sopenharmony_ci * chunk starts with line with info (including size of the 354113498266Sopenharmony_ci * coming block) (terminated with CRLF), then a block of data 354213498266Sopenharmony_ci * with the previously mentioned size. There can be any amount 354313498266Sopenharmony_ci * of chunks, and a chunk-data set to zero signals the 354413498266Sopenharmony_ci * end-of-chunks. */ 354513498266Sopenharmony_ci 354613498266Sopenharmony_ci result = Curl_build_unencoding_stack(data, 354713498266Sopenharmony_ci headp + strlen("Transfer-Encoding:"), 354813498266Sopenharmony_ci TRUE); 354913498266Sopenharmony_ci if(result) 355013498266Sopenharmony_ci return result; 355113498266Sopenharmony_ci if(!k->chunk && data->set.http_transfer_encoding) { 355213498266Sopenharmony_ci /* if this isn't chunked, only close can signal the end of this transfer 355313498266Sopenharmony_ci as Content-Length is said not to be trusted for transfer-encoding! */ 355413498266Sopenharmony_ci connclose(conn, "HTTP/1.1 transfer-encoding without chunks"); 355513498266Sopenharmony_ci k->ignore_cl = TRUE; 355613498266Sopenharmony_ci } 355713498266Sopenharmony_ci } 355813498266Sopenharmony_ci else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) && 355913498266Sopenharmony_ci data->set.str[STRING_ENCODING]) { 356013498266Sopenharmony_ci /* 356113498266Sopenharmony_ci * Process Content-Encoding. Look for the values: identity, 356213498266Sopenharmony_ci * gzip, deflate, compress, x-gzip and x-compress. x-gzip and 356313498266Sopenharmony_ci * x-compress are the same as gzip and compress. (Sec 3.5 RFC 356413498266Sopenharmony_ci * 2616). zlib cannot handle compress. However, errors are 356513498266Sopenharmony_ci * handled further down when the response body is processed 356613498266Sopenharmony_ci */ 356713498266Sopenharmony_ci result = Curl_build_unencoding_stack(data, 356813498266Sopenharmony_ci headp + strlen("Content-Encoding:"), 356913498266Sopenharmony_ci FALSE); 357013498266Sopenharmony_ci if(result) 357113498266Sopenharmony_ci return result; 357213498266Sopenharmony_ci } 357313498266Sopenharmony_ci else if(checkprefix("Retry-After:", headp)) { 357413498266Sopenharmony_ci /* Retry-After = HTTP-date / delay-seconds */ 357513498266Sopenharmony_ci curl_off_t retry_after = 0; /* zero for unknown or "now" */ 357613498266Sopenharmony_ci /* Try it as a decimal number, if it works it is not a date */ 357713498266Sopenharmony_ci (void)curlx_strtoofft(headp + strlen("Retry-After:"), 357813498266Sopenharmony_ci NULL, 10, &retry_after); 357913498266Sopenharmony_ci if(!retry_after) { 358013498266Sopenharmony_ci time_t date = Curl_getdate_capped(headp + strlen("Retry-After:")); 358113498266Sopenharmony_ci if(-1 != date) 358213498266Sopenharmony_ci /* convert date to number of seconds into the future */ 358313498266Sopenharmony_ci retry_after = date - time(NULL); 358413498266Sopenharmony_ci } 358513498266Sopenharmony_ci data->info.retry_after = retry_after; /* store it */ 358613498266Sopenharmony_ci } 358713498266Sopenharmony_ci else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) { 358813498266Sopenharmony_ci /* Content-Range: bytes [num]- 358913498266Sopenharmony_ci Content-Range: bytes: [num]- 359013498266Sopenharmony_ci Content-Range: [num]- 359113498266Sopenharmony_ci Content-Range: [asterisk]/[total] 359213498266Sopenharmony_ci 359313498266Sopenharmony_ci The second format was added since Sun's webserver 359413498266Sopenharmony_ci JavaWebServer/1.1.1 obviously sends the header this way! 359513498266Sopenharmony_ci The third added since some servers use that! 359613498266Sopenharmony_ci The fourth means the requested range was unsatisfied. 359713498266Sopenharmony_ci */ 359813498266Sopenharmony_ci 359913498266Sopenharmony_ci char *ptr = headp + strlen("Content-Range:"); 360013498266Sopenharmony_ci 360113498266Sopenharmony_ci /* Move forward until first digit or asterisk */ 360213498266Sopenharmony_ci while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') 360313498266Sopenharmony_ci ptr++; 360413498266Sopenharmony_ci 360513498266Sopenharmony_ci /* if it truly stopped on a digit */ 360613498266Sopenharmony_ci if(ISDIGIT(*ptr)) { 360713498266Sopenharmony_ci if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) { 360813498266Sopenharmony_ci if(data->state.resume_from == k->offset) 360913498266Sopenharmony_ci /* we asked for a resume and we got it */ 361013498266Sopenharmony_ci k->content_range = TRUE; 361113498266Sopenharmony_ci } 361213498266Sopenharmony_ci } 361313498266Sopenharmony_ci else if(k->httpcode < 300) 361413498266Sopenharmony_ci data->state.resume_from = 0; /* get everything */ 361513498266Sopenharmony_ci } 361613498266Sopenharmony_ci#if !defined(CURL_DISABLE_COOKIES) 361713498266Sopenharmony_ci else if(data->cookies && data->state.cookie_engine && 361813498266Sopenharmony_ci checkprefix("Set-Cookie:", headp)) { 361913498266Sopenharmony_ci /* If there is a custom-set Host: name, use it here, or else use real peer 362013498266Sopenharmony_ci host name. */ 362113498266Sopenharmony_ci const char *host = data->state.aptr.cookiehost? 362213498266Sopenharmony_ci data->state.aptr.cookiehost:conn->host.name; 362313498266Sopenharmony_ci const bool secure_context = 362413498266Sopenharmony_ci conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || 362513498266Sopenharmony_ci strcasecompare("localhost", host) || 362613498266Sopenharmony_ci !strcmp(host, "127.0.0.1") || 362713498266Sopenharmony_ci !strcmp(host, "::1") ? TRUE : FALSE; 362813498266Sopenharmony_ci 362913498266Sopenharmony_ci Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, 363013498266Sopenharmony_ci CURL_LOCK_ACCESS_SINGLE); 363113498266Sopenharmony_ci Curl_cookie_add(data, data->cookies, TRUE, FALSE, 363213498266Sopenharmony_ci headp + strlen("Set-Cookie:"), host, 363313498266Sopenharmony_ci data->state.up.path, secure_context); 363413498266Sopenharmony_ci Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); 363513498266Sopenharmony_ci } 363613498266Sopenharmony_ci#endif 363713498266Sopenharmony_ci else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) && 363813498266Sopenharmony_ci (data->set.timecondition || data->set.get_filetime) ) { 363913498266Sopenharmony_ci k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:")); 364013498266Sopenharmony_ci if(data->set.get_filetime) 364113498266Sopenharmony_ci data->info.filetime = k->timeofdoc; 364213498266Sopenharmony_ci } 364313498266Sopenharmony_ci else if((checkprefix("WWW-Authenticate:", headp) && 364413498266Sopenharmony_ci (401 == k->httpcode)) || 364513498266Sopenharmony_ci (checkprefix("Proxy-authenticate:", headp) && 364613498266Sopenharmony_ci (407 == k->httpcode))) { 364713498266Sopenharmony_ci 364813498266Sopenharmony_ci bool proxy = (k->httpcode == 407) ? TRUE : FALSE; 364913498266Sopenharmony_ci char *auth = Curl_copy_header_value(headp); 365013498266Sopenharmony_ci if(!auth) 365113498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 365213498266Sopenharmony_ci 365313498266Sopenharmony_ci result = Curl_http_input_auth(data, proxy, auth); 365413498266Sopenharmony_ci 365513498266Sopenharmony_ci free(auth); 365613498266Sopenharmony_ci 365713498266Sopenharmony_ci if(result) 365813498266Sopenharmony_ci return result; 365913498266Sopenharmony_ci } 366013498266Sopenharmony_ci#ifdef USE_SPNEGO 366113498266Sopenharmony_ci else if(checkprefix("Persistent-Auth:", headp)) { 366213498266Sopenharmony_ci struct negotiatedata *negdata = &conn->negotiate; 366313498266Sopenharmony_ci struct auth *authp = &data->state.authhost; 366413498266Sopenharmony_ci if(authp->picked == CURLAUTH_NEGOTIATE) { 366513498266Sopenharmony_ci char *persistentauth = Curl_copy_header_value(headp); 366613498266Sopenharmony_ci if(!persistentauth) 366713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 366813498266Sopenharmony_ci negdata->noauthpersist = checkprefix("false", persistentauth)? 366913498266Sopenharmony_ci TRUE:FALSE; 367013498266Sopenharmony_ci negdata->havenoauthpersist = TRUE; 367113498266Sopenharmony_ci infof(data, "Negotiate: noauthpersist -> %d, header part: %s", 367213498266Sopenharmony_ci negdata->noauthpersist, persistentauth); 367313498266Sopenharmony_ci free(persistentauth); 367413498266Sopenharmony_ci } 367513498266Sopenharmony_ci } 367613498266Sopenharmony_ci#endif 367713498266Sopenharmony_ci else if((k->httpcode >= 300 && k->httpcode < 400) && 367813498266Sopenharmony_ci checkprefix("Location:", headp) && 367913498266Sopenharmony_ci !data->req.location) { 368013498266Sopenharmony_ci /* this is the URL that the server advises us to use instead */ 368113498266Sopenharmony_ci char *location = Curl_copy_header_value(headp); 368213498266Sopenharmony_ci if(!location) 368313498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 368413498266Sopenharmony_ci if(!*location) 368513498266Sopenharmony_ci /* ignore empty data */ 368613498266Sopenharmony_ci free(location); 368713498266Sopenharmony_ci else { 368813498266Sopenharmony_ci data->req.location = location; 368913498266Sopenharmony_ci 369013498266Sopenharmony_ci if(data->set.http_follow_location) { 369113498266Sopenharmony_ci DEBUGASSERT(!data->req.newurl); 369213498266Sopenharmony_ci data->req.newurl = strdup(data->req.location); /* clone */ 369313498266Sopenharmony_ci if(!data->req.newurl) 369413498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 369513498266Sopenharmony_ci 369613498266Sopenharmony_ci /* some cases of POST and PUT etc needs to rewind the data 369713498266Sopenharmony_ci stream at this point */ 369813498266Sopenharmony_ci result = http_perhapsrewind(data, conn); 369913498266Sopenharmony_ci if(result) 370013498266Sopenharmony_ci return result; 370113498266Sopenharmony_ci 370213498266Sopenharmony_ci /* mark the next request as a followed location: */ 370313498266Sopenharmony_ci data->state.this_is_a_follow = TRUE; 370413498266Sopenharmony_ci } 370513498266Sopenharmony_ci } 370613498266Sopenharmony_ci } 370713498266Sopenharmony_ci 370813498266Sopenharmony_ci#ifndef CURL_DISABLE_HSTS 370913498266Sopenharmony_ci /* If enabled, the header is incoming and this is over HTTPS */ 371013498266Sopenharmony_ci else if(data->hsts && checkprefix("Strict-Transport-Security:", headp) && 371113498266Sopenharmony_ci ((conn->handler->flags & PROTOPT_SSL) || 371213498266Sopenharmony_ci#ifdef CURLDEBUG 371313498266Sopenharmony_ci /* allow debug builds to circumvent the HTTPS restriction */ 371413498266Sopenharmony_ci getenv("CURL_HSTS_HTTP") 371513498266Sopenharmony_ci#else 371613498266Sopenharmony_ci 0 371713498266Sopenharmony_ci#endif 371813498266Sopenharmony_ci )) { 371913498266Sopenharmony_ci CURLcode check = 372013498266Sopenharmony_ci Curl_hsts_parse(data->hsts, conn->host.name, 372113498266Sopenharmony_ci headp + strlen("Strict-Transport-Security:")); 372213498266Sopenharmony_ci if(check) 372313498266Sopenharmony_ci infof(data, "Illegal STS header skipped"); 372413498266Sopenharmony_ci#ifdef DEBUGBUILD 372513498266Sopenharmony_ci else 372613498266Sopenharmony_ci infof(data, "Parsed STS header fine (%zu entries)", 372713498266Sopenharmony_ci data->hsts->list.size); 372813498266Sopenharmony_ci#endif 372913498266Sopenharmony_ci } 373013498266Sopenharmony_ci#endif 373113498266Sopenharmony_ci#ifndef CURL_DISABLE_ALTSVC 373213498266Sopenharmony_ci /* If enabled, the header is incoming and this is over HTTPS */ 373313498266Sopenharmony_ci else if(data->asi && checkprefix("Alt-Svc:", headp) && 373413498266Sopenharmony_ci ((conn->handler->flags & PROTOPT_SSL) || 373513498266Sopenharmony_ci#ifdef CURLDEBUG 373613498266Sopenharmony_ci /* allow debug builds to circumvent the HTTPS restriction */ 373713498266Sopenharmony_ci getenv("CURL_ALTSVC_HTTP") 373813498266Sopenharmony_ci#else 373913498266Sopenharmony_ci 0 374013498266Sopenharmony_ci#endif 374113498266Sopenharmony_ci )) { 374213498266Sopenharmony_ci /* the ALPN of the current request */ 374313498266Sopenharmony_ci enum alpnid id = (conn->httpversion == 30)? ALPN_h3 : 374413498266Sopenharmony_ci (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1; 374513498266Sopenharmony_ci result = Curl_altsvc_parse(data, data->asi, 374613498266Sopenharmony_ci headp + strlen("Alt-Svc:"), 374713498266Sopenharmony_ci id, conn->host.name, 374813498266Sopenharmony_ci curlx_uitous((unsigned int)conn->remote_port)); 374913498266Sopenharmony_ci if(result) 375013498266Sopenharmony_ci return result; 375113498266Sopenharmony_ci } 375213498266Sopenharmony_ci#endif 375313498266Sopenharmony_ci else if(conn->handler->protocol & CURLPROTO_RTSP) { 375413498266Sopenharmony_ci result = Curl_rtsp_parseheader(data, headp); 375513498266Sopenharmony_ci if(result) 375613498266Sopenharmony_ci return result; 375713498266Sopenharmony_ci } 375813498266Sopenharmony_ci return CURLE_OK; 375913498266Sopenharmony_ci} 376013498266Sopenharmony_ci 376113498266Sopenharmony_ci/* 376213498266Sopenharmony_ci * Called after the first HTTP response line (the status line) has been 376313498266Sopenharmony_ci * received and parsed. 376413498266Sopenharmony_ci */ 376513498266Sopenharmony_ci 376613498266Sopenharmony_ciCURLcode Curl_http_statusline(struct Curl_easy *data, 376713498266Sopenharmony_ci struct connectdata *conn) 376813498266Sopenharmony_ci{ 376913498266Sopenharmony_ci struct SingleRequest *k = &data->req; 377013498266Sopenharmony_ci data->info.httpcode = k->httpcode; 377113498266Sopenharmony_ci 377213498266Sopenharmony_ci data->info.httpversion = conn->httpversion; 377313498266Sopenharmony_ci if(!data->state.httpversion || 377413498266Sopenharmony_ci data->state.httpversion > conn->httpversion) 377513498266Sopenharmony_ci /* store the lowest server version we encounter */ 377613498266Sopenharmony_ci data->state.httpversion = conn->httpversion; 377713498266Sopenharmony_ci 377813498266Sopenharmony_ci /* 377913498266Sopenharmony_ci * This code executes as part of processing the header. As a 378013498266Sopenharmony_ci * result, it's not totally clear how to interpret the 378113498266Sopenharmony_ci * response code yet as that depends on what other headers may 378213498266Sopenharmony_ci * be present. 401 and 407 may be errors, but may be OK 378313498266Sopenharmony_ci * depending on how authentication is working. Other codes 378413498266Sopenharmony_ci * are definitely errors, so give up here. 378513498266Sopenharmony_ci */ 378613498266Sopenharmony_ci if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET && 378713498266Sopenharmony_ci k->httpcode == 416) { 378813498266Sopenharmony_ci /* "Requested Range Not Satisfiable", just proceed and 378913498266Sopenharmony_ci pretend this is no error */ 379013498266Sopenharmony_ci k->ignorebody = TRUE; /* Avoid appending error msg to good data. */ 379113498266Sopenharmony_ci } 379213498266Sopenharmony_ci 379313498266Sopenharmony_ci if(conn->httpversion == 10) { 379413498266Sopenharmony_ci /* Default action for HTTP/1.0 must be to close, unless 379513498266Sopenharmony_ci we get one of those fancy headers that tell us the 379613498266Sopenharmony_ci server keeps it open for us! */ 379713498266Sopenharmony_ci infof(data, "HTTP 1.0, assume close after body"); 379813498266Sopenharmony_ci connclose(conn, "HTTP/1.0 close after body"); 379913498266Sopenharmony_ci } 380013498266Sopenharmony_ci else if(conn->httpversion == 20 || 380113498266Sopenharmony_ci (k->upgr101 == UPGR101_H2 && k->httpcode == 101)) { 380213498266Sopenharmony_ci DEBUGF(infof(data, "HTTP/2 found, allow multiplexing")); 380313498266Sopenharmony_ci /* HTTP/2 cannot avoid multiplexing since it is a core functionality 380413498266Sopenharmony_ci of the protocol */ 380513498266Sopenharmony_ci conn->bundle->multiuse = BUNDLE_MULTIPLEX; 380613498266Sopenharmony_ci } 380713498266Sopenharmony_ci else if(conn->httpversion >= 11 && 380813498266Sopenharmony_ci !conn->bits.close) { 380913498266Sopenharmony_ci /* If HTTP version is >= 1.1 and connection is persistent */ 381013498266Sopenharmony_ci DEBUGF(infof(data, 381113498266Sopenharmony_ci "HTTP 1.1 or later with persistent connection")); 381213498266Sopenharmony_ci } 381313498266Sopenharmony_ci 381413498266Sopenharmony_ci k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200; 381513498266Sopenharmony_ci switch(k->httpcode) { 381613498266Sopenharmony_ci case 304: 381713498266Sopenharmony_ci /* (quote from RFC2616, section 10.3.5): The 304 response 381813498266Sopenharmony_ci * MUST NOT contain a message-body, and thus is always 381913498266Sopenharmony_ci * terminated by the first empty line after the header 382013498266Sopenharmony_ci * fields. */ 382113498266Sopenharmony_ci if(data->set.timecondition) 382213498266Sopenharmony_ci data->info.timecond = TRUE; 382313498266Sopenharmony_ci FALLTHROUGH(); 382413498266Sopenharmony_ci case 204: 382513498266Sopenharmony_ci /* (quote from RFC2616, section 10.2.5): The server has 382613498266Sopenharmony_ci * fulfilled the request but does not need to return an 382713498266Sopenharmony_ci * entity-body ... The 204 response MUST NOT include a 382813498266Sopenharmony_ci * message-body, and thus is always terminated by the first 382913498266Sopenharmony_ci * empty line after the header fields. */ 383013498266Sopenharmony_ci k->size = 0; 383113498266Sopenharmony_ci k->maxdownload = 0; 383213498266Sopenharmony_ci k->http_bodyless = TRUE; 383313498266Sopenharmony_ci break; 383413498266Sopenharmony_ci default: 383513498266Sopenharmony_ci break; 383613498266Sopenharmony_ci } 383713498266Sopenharmony_ci return CURLE_OK; 383813498266Sopenharmony_ci} 383913498266Sopenharmony_ci 384013498266Sopenharmony_ci/* Content-Length must be ignored if any Transfer-Encoding is present in the 384113498266Sopenharmony_ci response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is 384213498266Sopenharmony_ci figured out here after all headers have been received but before the final 384313498266Sopenharmony_ci call to the user's header callback, so that a valid content length can be 384413498266Sopenharmony_ci retrieved by the user in the final call. */ 384513498266Sopenharmony_ciCURLcode Curl_http_size(struct Curl_easy *data) 384613498266Sopenharmony_ci{ 384713498266Sopenharmony_ci struct SingleRequest *k = &data->req; 384813498266Sopenharmony_ci if(data->req.ignore_cl || k->chunk) { 384913498266Sopenharmony_ci k->size = k->maxdownload = -1; 385013498266Sopenharmony_ci } 385113498266Sopenharmony_ci else if(k->size != -1) { 385213498266Sopenharmony_ci if(data->set.max_filesize && 385313498266Sopenharmony_ci k->size > data->set.max_filesize) { 385413498266Sopenharmony_ci failf(data, "Maximum file size exceeded"); 385513498266Sopenharmony_ci return CURLE_FILESIZE_EXCEEDED; 385613498266Sopenharmony_ci } 385713498266Sopenharmony_ci Curl_pgrsSetDownloadSize(data, k->size); 385813498266Sopenharmony_ci k->maxdownload = k->size; 385913498266Sopenharmony_ci } 386013498266Sopenharmony_ci return CURLE_OK; 386113498266Sopenharmony_ci} 386213498266Sopenharmony_ci 386313498266Sopenharmony_cistatic CURLcode verify_header(struct Curl_easy *data) 386413498266Sopenharmony_ci{ 386513498266Sopenharmony_ci struct SingleRequest *k = &data->req; 386613498266Sopenharmony_ci const char *header = Curl_dyn_ptr(&data->state.headerb); 386713498266Sopenharmony_ci size_t hlen = Curl_dyn_len(&data->state.headerb); 386813498266Sopenharmony_ci char *ptr = memchr(header, 0x00, hlen); 386913498266Sopenharmony_ci if(ptr) { 387013498266Sopenharmony_ci /* this is bad, bail out */ 387113498266Sopenharmony_ci failf(data, "Nul byte in header"); 387213498266Sopenharmony_ci return CURLE_WEIRD_SERVER_REPLY; 387313498266Sopenharmony_ci } 387413498266Sopenharmony_ci if(k->headerline < 2) 387513498266Sopenharmony_ci /* the first "header" is the status-line and it has no colon */ 387613498266Sopenharmony_ci return CURLE_OK; 387713498266Sopenharmony_ci if(((header[0] == ' ') || (header[0] == '\t')) && k->headerline > 2) 387813498266Sopenharmony_ci /* line folding, can't happen on line 2 */ 387913498266Sopenharmony_ci ; 388013498266Sopenharmony_ci else { 388113498266Sopenharmony_ci ptr = memchr(header, ':', hlen); 388213498266Sopenharmony_ci if(!ptr) { 388313498266Sopenharmony_ci /* this is bad, bail out */ 388413498266Sopenharmony_ci failf(data, "Header without colon"); 388513498266Sopenharmony_ci return CURLE_WEIRD_SERVER_REPLY; 388613498266Sopenharmony_ci } 388713498266Sopenharmony_ci } 388813498266Sopenharmony_ci return CURLE_OK; 388913498266Sopenharmony_ci} 389013498266Sopenharmony_ci 389113498266Sopenharmony_ciCURLcode Curl_bump_headersize(struct Curl_easy *data, 389213498266Sopenharmony_ci size_t delta, 389313498266Sopenharmony_ci bool connect_only) 389413498266Sopenharmony_ci{ 389513498266Sopenharmony_ci size_t bad = 0; 389613498266Sopenharmony_ci unsigned int max = MAX_HTTP_RESP_HEADER_SIZE; 389713498266Sopenharmony_ci if(delta < MAX_HTTP_RESP_HEADER_SIZE) { 389813498266Sopenharmony_ci data->info.header_size += (unsigned int)delta; 389913498266Sopenharmony_ci data->req.allheadercount += (unsigned int)delta; 390013498266Sopenharmony_ci if(!connect_only) 390113498266Sopenharmony_ci data->req.headerbytecount += (unsigned int)delta; 390213498266Sopenharmony_ci if(data->req.allheadercount > max) 390313498266Sopenharmony_ci bad = data->req.allheadercount; 390413498266Sopenharmony_ci else if(data->info.header_size > (max * 20)) { 390513498266Sopenharmony_ci bad = data->info.header_size; 390613498266Sopenharmony_ci max *= 20; 390713498266Sopenharmony_ci } 390813498266Sopenharmony_ci } 390913498266Sopenharmony_ci else 391013498266Sopenharmony_ci bad = data->req.allheadercount + delta; 391113498266Sopenharmony_ci if(bad) { 391213498266Sopenharmony_ci failf(data, "Too large response headers: %zu > %u", bad, max); 391313498266Sopenharmony_ci return CURLE_RECV_ERROR; 391413498266Sopenharmony_ci } 391513498266Sopenharmony_ci return CURLE_OK; 391613498266Sopenharmony_ci} 391713498266Sopenharmony_ci 391813498266Sopenharmony_ci 391913498266Sopenharmony_ci/* 392013498266Sopenharmony_ci * Read any HTTP header lines from the server and pass them to the client app. 392113498266Sopenharmony_ci */ 392213498266Sopenharmony_cistatic CURLcode http_rw_headers(struct Curl_easy *data, 392313498266Sopenharmony_ci const char *buf, size_t blen, 392413498266Sopenharmony_ci size_t *pconsumed) 392513498266Sopenharmony_ci{ 392613498266Sopenharmony_ci struct connectdata *conn = data->conn; 392713498266Sopenharmony_ci CURLcode result = CURLE_OK; 392813498266Sopenharmony_ci struct SingleRequest *k = &data->req; 392913498266Sopenharmony_ci char *headp; 393013498266Sopenharmony_ci char *end_ptr; 393113498266Sopenharmony_ci bool leftover_body = FALSE; 393213498266Sopenharmony_ci 393313498266Sopenharmony_ci /* header line within buffer loop */ 393413498266Sopenharmony_ci *pconsumed = 0; 393513498266Sopenharmony_ci do { 393613498266Sopenharmony_ci size_t line_length; 393713498266Sopenharmony_ci int writetype; 393813498266Sopenharmony_ci 393913498266Sopenharmony_ci /* data is in network encoding so use 0x0a instead of '\n' */ 394013498266Sopenharmony_ci end_ptr = memchr(buf, 0x0a, blen); 394113498266Sopenharmony_ci 394213498266Sopenharmony_ci if(!end_ptr) { 394313498266Sopenharmony_ci /* Not a complete header line within buffer, append the data to 394413498266Sopenharmony_ci the end of the headerbuff. */ 394513498266Sopenharmony_ci result = Curl_dyn_addn(&data->state.headerb, buf, blen); 394613498266Sopenharmony_ci if(result) 394713498266Sopenharmony_ci return result; 394813498266Sopenharmony_ci *pconsumed += blen; 394913498266Sopenharmony_ci 395013498266Sopenharmony_ci if(!k->headerline) { 395113498266Sopenharmony_ci /* check if this looks like a protocol header */ 395213498266Sopenharmony_ci statusline st = 395313498266Sopenharmony_ci checkprotoprefix(data, conn, 395413498266Sopenharmony_ci Curl_dyn_ptr(&data->state.headerb), 395513498266Sopenharmony_ci Curl_dyn_len(&data->state.headerb)); 395613498266Sopenharmony_ci 395713498266Sopenharmony_ci if(st == STATUS_BAD) { 395813498266Sopenharmony_ci /* this is not the beginning of a protocol first header line */ 395913498266Sopenharmony_ci k->header = FALSE; 396013498266Sopenharmony_ci streamclose(conn, "bad HTTP: No end-of-message indicator"); 396113498266Sopenharmony_ci if(!data->set.http09_allowed) { 396213498266Sopenharmony_ci failf(data, "Received HTTP/0.9 when not allowed"); 396313498266Sopenharmony_ci return CURLE_UNSUPPORTED_PROTOCOL; 396413498266Sopenharmony_ci } 396513498266Sopenharmony_ci leftover_body = TRUE; 396613498266Sopenharmony_ci goto out; 396713498266Sopenharmony_ci } 396813498266Sopenharmony_ci } 396913498266Sopenharmony_ci goto out; /* read more and try again */ 397013498266Sopenharmony_ci } 397113498266Sopenharmony_ci 397213498266Sopenharmony_ci /* decrease the size of the remaining (supposed) header line */ 397313498266Sopenharmony_ci line_length = (end_ptr - buf) + 1; 397413498266Sopenharmony_ci result = Curl_dyn_addn(&data->state.headerb, buf, line_length); 397513498266Sopenharmony_ci if(result) 397613498266Sopenharmony_ci return result; 397713498266Sopenharmony_ci 397813498266Sopenharmony_ci blen -= line_length; 397913498266Sopenharmony_ci buf += line_length; 398013498266Sopenharmony_ci *pconsumed += line_length; 398113498266Sopenharmony_ci 398213498266Sopenharmony_ci /**** 398313498266Sopenharmony_ci * We now have a FULL header line in 'headerb'. 398413498266Sopenharmony_ci *****/ 398513498266Sopenharmony_ci 398613498266Sopenharmony_ci if(!k->headerline) { 398713498266Sopenharmony_ci /* the first read header */ 398813498266Sopenharmony_ci statusline st = checkprotoprefix(data, conn, 398913498266Sopenharmony_ci Curl_dyn_ptr(&data->state.headerb), 399013498266Sopenharmony_ci Curl_dyn_len(&data->state.headerb)); 399113498266Sopenharmony_ci if(st == STATUS_BAD) { 399213498266Sopenharmony_ci streamclose(conn, "bad HTTP: No end-of-message indicator"); 399313498266Sopenharmony_ci /* this is not the beginning of a protocol first header line */ 399413498266Sopenharmony_ci if(!data->set.http09_allowed) { 399513498266Sopenharmony_ci failf(data, "Received HTTP/0.9 when not allowed"); 399613498266Sopenharmony_ci return CURLE_UNSUPPORTED_PROTOCOL; 399713498266Sopenharmony_ci } 399813498266Sopenharmony_ci k->header = FALSE; 399913498266Sopenharmony_ci leftover_body = TRUE; 400013498266Sopenharmony_ci goto out; 400113498266Sopenharmony_ci } 400213498266Sopenharmony_ci } 400313498266Sopenharmony_ci 400413498266Sopenharmony_ci /* headers are in network encoding so use 0x0a and 0x0d instead of '\n' 400513498266Sopenharmony_ci and '\r' */ 400613498266Sopenharmony_ci headp = Curl_dyn_ptr(&data->state.headerb); 400713498266Sopenharmony_ci if((0x0a == *headp) || (0x0d == *headp)) { 400813498266Sopenharmony_ci size_t headerlen; 400913498266Sopenharmony_ci bool switch_to_h2 = FALSE; 401013498266Sopenharmony_ci /* Zero-length header line means end of headers! */ 401113498266Sopenharmony_ci 401213498266Sopenharmony_ci if('\r' == *headp) 401313498266Sopenharmony_ci headp++; /* pass the \r byte */ 401413498266Sopenharmony_ci if('\n' == *headp) 401513498266Sopenharmony_ci headp++; /* pass the \n byte */ 401613498266Sopenharmony_ci 401713498266Sopenharmony_ci if(100 <= k->httpcode && 199 >= k->httpcode) { 401813498266Sopenharmony_ci /* "A user agent MAY ignore unexpected 1xx status responses." */ 401913498266Sopenharmony_ci switch(k->httpcode) { 402013498266Sopenharmony_ci case 100: 402113498266Sopenharmony_ci /* 402213498266Sopenharmony_ci * We have made an HTTP PUT or POST and this is 1.1-lingo 402313498266Sopenharmony_ci * that tells us that the server is OK with this and ready 402413498266Sopenharmony_ci * to receive the data. 402513498266Sopenharmony_ci * However, we'll get more headers now so we must get 402613498266Sopenharmony_ci * back into the header-parsing state! 402713498266Sopenharmony_ci */ 402813498266Sopenharmony_ci k->header = TRUE; 402913498266Sopenharmony_ci k->headerline = 0; /* restart the header line counter */ 403013498266Sopenharmony_ci 403113498266Sopenharmony_ci /* if we did wait for this do enable write now! */ 403213498266Sopenharmony_ci if(k->exp100 > EXP100_SEND_DATA) { 403313498266Sopenharmony_ci k->exp100 = EXP100_SEND_DATA; 403413498266Sopenharmony_ci k->keepon |= KEEP_SEND; 403513498266Sopenharmony_ci Curl_expire_done(data, EXPIRE_100_TIMEOUT); 403613498266Sopenharmony_ci } 403713498266Sopenharmony_ci break; 403813498266Sopenharmony_ci case 101: 403913498266Sopenharmony_ci if(conn->httpversion == 11) { 404013498266Sopenharmony_ci /* Switching Protocols only allowed from HTTP/1.1 */ 404113498266Sopenharmony_ci if(k->upgr101 == UPGR101_H2) { 404213498266Sopenharmony_ci /* Switching to HTTP/2 */ 404313498266Sopenharmony_ci infof(data, "Received 101, Switching to HTTP/2"); 404413498266Sopenharmony_ci k->upgr101 = UPGR101_RECEIVED; 404513498266Sopenharmony_ci 404613498266Sopenharmony_ci /* we'll get more headers (HTTP/2 response) */ 404713498266Sopenharmony_ci k->header = TRUE; 404813498266Sopenharmony_ci k->headerline = 0; /* restart the header line counter */ 404913498266Sopenharmony_ci switch_to_h2 = TRUE; 405013498266Sopenharmony_ci } 405113498266Sopenharmony_ci#ifdef USE_WEBSOCKETS 405213498266Sopenharmony_ci else if(k->upgr101 == UPGR101_WS) { 405313498266Sopenharmony_ci /* verify the response */ 405413498266Sopenharmony_ci result = Curl_ws_accept(data, buf, blen); 405513498266Sopenharmony_ci if(result) 405613498266Sopenharmony_ci return result; 405713498266Sopenharmony_ci k->header = FALSE; /* no more header to parse! */ 405813498266Sopenharmony_ci *pconsumed += blen; /* ws accept handled the data */ 405913498266Sopenharmony_ci blen = 0; 406013498266Sopenharmony_ci if(data->set.connect_only) 406113498266Sopenharmony_ci k->keepon &= ~KEEP_RECV; /* read no more content */ 406213498266Sopenharmony_ci } 406313498266Sopenharmony_ci#endif 406413498266Sopenharmony_ci else { 406513498266Sopenharmony_ci /* Not switching to another protocol */ 406613498266Sopenharmony_ci k->header = FALSE; /* no more header to parse! */ 406713498266Sopenharmony_ci } 406813498266Sopenharmony_ci } 406913498266Sopenharmony_ci else { 407013498266Sopenharmony_ci /* invalid for other HTTP versions */ 407113498266Sopenharmony_ci failf(data, "unexpected 101 response code"); 407213498266Sopenharmony_ci return CURLE_WEIRD_SERVER_REPLY; 407313498266Sopenharmony_ci } 407413498266Sopenharmony_ci break; 407513498266Sopenharmony_ci default: 407613498266Sopenharmony_ci /* the status code 1xx indicates a provisional response, so 407713498266Sopenharmony_ci we'll get another set of headers */ 407813498266Sopenharmony_ci k->header = TRUE; 407913498266Sopenharmony_ci k->headerline = 0; /* restart the header line counter */ 408013498266Sopenharmony_ci break; 408113498266Sopenharmony_ci } 408213498266Sopenharmony_ci } 408313498266Sopenharmony_ci else { 408413498266Sopenharmony_ci if(k->upgr101 == UPGR101_H2) { 408513498266Sopenharmony_ci /* A requested upgrade was denied, poke the multi handle to possibly 408613498266Sopenharmony_ci allow a pending pipewait to continue */ 408713498266Sopenharmony_ci Curl_multi_connchanged(data->multi); 408813498266Sopenharmony_ci } 408913498266Sopenharmony_ci k->header = FALSE; /* no more header to parse! */ 409013498266Sopenharmony_ci 409113498266Sopenharmony_ci if((k->size == -1) && !k->chunk && !conn->bits.close && 409213498266Sopenharmony_ci (conn->httpversion == 11) && 409313498266Sopenharmony_ci !(conn->handler->protocol & CURLPROTO_RTSP) && 409413498266Sopenharmony_ci data->state.httpreq != HTTPREQ_HEAD) { 409513498266Sopenharmony_ci /* On HTTP 1.1, when connection is not to get closed, but no 409613498266Sopenharmony_ci Content-Length nor Transfer-Encoding chunked have been 409713498266Sopenharmony_ci received, according to RFC2616 section 4.4 point 5, we 409813498266Sopenharmony_ci assume that the server will close the connection to 409913498266Sopenharmony_ci signal the end of the document. */ 410013498266Sopenharmony_ci infof(data, "no chunk, no close, no size. Assume close to " 410113498266Sopenharmony_ci "signal end"); 410213498266Sopenharmony_ci streamclose(conn, "HTTP: No end-of-message indicator"); 410313498266Sopenharmony_ci } 410413498266Sopenharmony_ci } 410513498266Sopenharmony_ci 410613498266Sopenharmony_ci if(!k->header) { 410713498266Sopenharmony_ci result = Curl_http_size(data); 410813498266Sopenharmony_ci if(result) 410913498266Sopenharmony_ci return result; 411013498266Sopenharmony_ci } 411113498266Sopenharmony_ci 411213498266Sopenharmony_ci /* At this point we have some idea about the fate of the connection. 411313498266Sopenharmony_ci If we are closing the connection it may result auth failure. */ 411413498266Sopenharmony_ci#if defined(USE_NTLM) 411513498266Sopenharmony_ci if(conn->bits.close && 411613498266Sopenharmony_ci (((data->req.httpcode == 401) && 411713498266Sopenharmony_ci (conn->http_ntlm_state == NTLMSTATE_TYPE2)) || 411813498266Sopenharmony_ci ((data->req.httpcode == 407) && 411913498266Sopenharmony_ci (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) { 412013498266Sopenharmony_ci infof(data, "Connection closure while negotiating auth (HTTP 1.0?)"); 412113498266Sopenharmony_ci data->state.authproblem = TRUE; 412213498266Sopenharmony_ci } 412313498266Sopenharmony_ci#endif 412413498266Sopenharmony_ci#if defined(USE_SPNEGO) 412513498266Sopenharmony_ci if(conn->bits.close && 412613498266Sopenharmony_ci (((data->req.httpcode == 401) && 412713498266Sopenharmony_ci (conn->http_negotiate_state == GSS_AUTHRECV)) || 412813498266Sopenharmony_ci ((data->req.httpcode == 407) && 412913498266Sopenharmony_ci (conn->proxy_negotiate_state == GSS_AUTHRECV)))) { 413013498266Sopenharmony_ci infof(data, "Connection closure while negotiating auth (HTTP 1.0?)"); 413113498266Sopenharmony_ci data->state.authproblem = TRUE; 413213498266Sopenharmony_ci } 413313498266Sopenharmony_ci if((conn->http_negotiate_state == GSS_AUTHDONE) && 413413498266Sopenharmony_ci (data->req.httpcode != 401)) { 413513498266Sopenharmony_ci conn->http_negotiate_state = GSS_AUTHSUCC; 413613498266Sopenharmony_ci } 413713498266Sopenharmony_ci if((conn->proxy_negotiate_state == GSS_AUTHDONE) && 413813498266Sopenharmony_ci (data->req.httpcode != 407)) { 413913498266Sopenharmony_ci conn->proxy_negotiate_state = GSS_AUTHSUCC; 414013498266Sopenharmony_ci } 414113498266Sopenharmony_ci#endif 414213498266Sopenharmony_ci 414313498266Sopenharmony_ci /* now, only output this if the header AND body are requested: 414413498266Sopenharmony_ci */ 414513498266Sopenharmony_ci writetype = CLIENTWRITE_HEADER | 414613498266Sopenharmony_ci ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0); 414713498266Sopenharmony_ci 414813498266Sopenharmony_ci headerlen = Curl_dyn_len(&data->state.headerb); 414913498266Sopenharmony_ci result = Curl_client_write(data, writetype, 415013498266Sopenharmony_ci Curl_dyn_ptr(&data->state.headerb), 415113498266Sopenharmony_ci headerlen); 415213498266Sopenharmony_ci if(result) 415313498266Sopenharmony_ci return result; 415413498266Sopenharmony_ci 415513498266Sopenharmony_ci result = Curl_bump_headersize(data, headerlen, FALSE); 415613498266Sopenharmony_ci if(result) 415713498266Sopenharmony_ci return result; 415813498266Sopenharmony_ci 415913498266Sopenharmony_ci /* 416013498266Sopenharmony_ci * When all the headers have been parsed, see if we should give 416113498266Sopenharmony_ci * up and return an error. 416213498266Sopenharmony_ci */ 416313498266Sopenharmony_ci if(http_should_fail(data)) { 416413498266Sopenharmony_ci failf(data, "The requested URL returned error: %d", 416513498266Sopenharmony_ci k->httpcode); 416613498266Sopenharmony_ci return CURLE_HTTP_RETURNED_ERROR; 416713498266Sopenharmony_ci } 416813498266Sopenharmony_ci 416913498266Sopenharmony_ci#ifdef USE_WEBSOCKETS 417013498266Sopenharmony_ci /* All non-101 HTTP status codes are bad when wanting to upgrade to 417113498266Sopenharmony_ci websockets */ 417213498266Sopenharmony_ci if(data->req.upgr101 == UPGR101_WS) { 417313498266Sopenharmony_ci failf(data, "Refused WebSockets upgrade: %d", k->httpcode); 417413498266Sopenharmony_ci return CURLE_HTTP_RETURNED_ERROR; 417513498266Sopenharmony_ci } 417613498266Sopenharmony_ci#endif 417713498266Sopenharmony_ci 417813498266Sopenharmony_ci 417913498266Sopenharmony_ci data->req.deductheadercount = 418013498266Sopenharmony_ci (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0; 418113498266Sopenharmony_ci 418213498266Sopenharmony_ci /* Curl_http_auth_act() checks what authentication methods 418313498266Sopenharmony_ci * that are available and decides which one (if any) to 418413498266Sopenharmony_ci * use. It will set 'newurl' if an auth method was picked. */ 418513498266Sopenharmony_ci result = Curl_http_auth_act(data); 418613498266Sopenharmony_ci 418713498266Sopenharmony_ci if(result) 418813498266Sopenharmony_ci return result; 418913498266Sopenharmony_ci 419013498266Sopenharmony_ci if(k->httpcode >= 300) { 419113498266Sopenharmony_ci if((!conn->bits.authneg) && !conn->bits.close && 419213498266Sopenharmony_ci !data->state.rewindbeforesend) { 419313498266Sopenharmony_ci /* 419413498266Sopenharmony_ci * General treatment of errors when about to send data. Including : 419513498266Sopenharmony_ci * "417 Expectation Failed", while waiting for 100-continue. 419613498266Sopenharmony_ci * 419713498266Sopenharmony_ci * The check for close above is done simply because of something 419813498266Sopenharmony_ci * else has already deemed the connection to get closed then 419913498266Sopenharmony_ci * something else should've considered the big picture and we 420013498266Sopenharmony_ci * avoid this check. 420113498266Sopenharmony_ci * 420213498266Sopenharmony_ci * rewindbeforesend indicates that something has told libcurl to 420313498266Sopenharmony_ci * continue sending even if it gets discarded 420413498266Sopenharmony_ci */ 420513498266Sopenharmony_ci 420613498266Sopenharmony_ci switch(data->state.httpreq) { 420713498266Sopenharmony_ci case HTTPREQ_PUT: 420813498266Sopenharmony_ci case HTTPREQ_POST: 420913498266Sopenharmony_ci case HTTPREQ_POST_FORM: 421013498266Sopenharmony_ci case HTTPREQ_POST_MIME: 421113498266Sopenharmony_ci /* We got an error response. If this happened before the whole 421213498266Sopenharmony_ci * request body has been sent we stop sending and mark the 421313498266Sopenharmony_ci * connection for closure after we've read the entire response. 421413498266Sopenharmony_ci */ 421513498266Sopenharmony_ci Curl_expire_done(data, EXPIRE_100_TIMEOUT); 421613498266Sopenharmony_ci if(!k->upload_done) { 421713498266Sopenharmony_ci if((k->httpcode == 417) && data->state.expect100header) { 421813498266Sopenharmony_ci /* 417 Expectation Failed - try again without the Expect 421913498266Sopenharmony_ci header */ 422013498266Sopenharmony_ci if(!k->writebytecount && 422113498266Sopenharmony_ci k->exp100 == EXP100_AWAITING_CONTINUE) { 422213498266Sopenharmony_ci infof(data, "Got HTTP failure 417 while waiting for a 100"); 422313498266Sopenharmony_ci } 422413498266Sopenharmony_ci else { 422513498266Sopenharmony_ci infof(data, "Got HTTP failure 417 while sending data"); 422613498266Sopenharmony_ci streamclose(conn, 422713498266Sopenharmony_ci "Stop sending data before everything sent"); 422813498266Sopenharmony_ci result = http_perhapsrewind(data, conn); 422913498266Sopenharmony_ci if(result) 423013498266Sopenharmony_ci return result; 423113498266Sopenharmony_ci } 423213498266Sopenharmony_ci data->state.disableexpect = TRUE; 423313498266Sopenharmony_ci DEBUGASSERT(!data->req.newurl); 423413498266Sopenharmony_ci data->req.newurl = strdup(data->state.url); 423513498266Sopenharmony_ci Curl_done_sending(data, k); 423613498266Sopenharmony_ci } 423713498266Sopenharmony_ci else if(data->set.http_keep_sending_on_error) { 423813498266Sopenharmony_ci infof(data, "HTTP error before end of send, keep sending"); 423913498266Sopenharmony_ci if(k->exp100 > EXP100_SEND_DATA) { 424013498266Sopenharmony_ci k->exp100 = EXP100_SEND_DATA; 424113498266Sopenharmony_ci k->keepon |= KEEP_SEND; 424213498266Sopenharmony_ci } 424313498266Sopenharmony_ci } 424413498266Sopenharmony_ci else { 424513498266Sopenharmony_ci infof(data, "HTTP error before end of send, stop sending"); 424613498266Sopenharmony_ci streamclose(conn, "Stop sending data before everything sent"); 424713498266Sopenharmony_ci result = Curl_done_sending(data, k); 424813498266Sopenharmony_ci if(result) 424913498266Sopenharmony_ci return result; 425013498266Sopenharmony_ci k->upload_done = TRUE; 425113498266Sopenharmony_ci if(data->state.expect100header) 425213498266Sopenharmony_ci k->exp100 = EXP100_FAILED; 425313498266Sopenharmony_ci } 425413498266Sopenharmony_ci } 425513498266Sopenharmony_ci break; 425613498266Sopenharmony_ci 425713498266Sopenharmony_ci default: /* default label present to avoid compiler warnings */ 425813498266Sopenharmony_ci break; 425913498266Sopenharmony_ci } 426013498266Sopenharmony_ci } 426113498266Sopenharmony_ci 426213498266Sopenharmony_ci if(data->state.rewindbeforesend && 426313498266Sopenharmony_ci (conn->writesockfd != CURL_SOCKET_BAD)) { 426413498266Sopenharmony_ci /* We rewind before next send, continue sending now */ 426513498266Sopenharmony_ci infof(data, "Keep sending data to get tossed away"); 426613498266Sopenharmony_ci k->keepon |= KEEP_SEND; 426713498266Sopenharmony_ci } 426813498266Sopenharmony_ci } 426913498266Sopenharmony_ci 427013498266Sopenharmony_ci if(!k->header) { 427113498266Sopenharmony_ci /* 427213498266Sopenharmony_ci * really end-of-headers. 427313498266Sopenharmony_ci * 427413498266Sopenharmony_ci * If we requested a "no body", this is a good time to get 427513498266Sopenharmony_ci * out and return home. 427613498266Sopenharmony_ci */ 427713498266Sopenharmony_ci if(data->req.no_body) 427813498266Sopenharmony_ci k->download_done = TRUE; 427913498266Sopenharmony_ci 428013498266Sopenharmony_ci /* If max download size is *zero* (nothing) we already have 428113498266Sopenharmony_ci nothing and can safely return ok now! But for HTTP/2, we'd 428213498266Sopenharmony_ci like to call http2_handle_stream_close to properly close a 428313498266Sopenharmony_ci stream. In order to do this, we keep reading until we 428413498266Sopenharmony_ci close the stream. */ 428513498266Sopenharmony_ci if(0 == k->maxdownload 428613498266Sopenharmony_ci && !Curl_conn_is_http2(data, conn, FIRSTSOCKET) 428713498266Sopenharmony_ci && !Curl_conn_is_http3(data, conn, FIRSTSOCKET)) 428813498266Sopenharmony_ci k->download_done = TRUE; 428913498266Sopenharmony_ci 429013498266Sopenharmony_ci Curl_debug(data, CURLINFO_HEADER_IN, 429113498266Sopenharmony_ci Curl_dyn_ptr(&data->state.headerb), 429213498266Sopenharmony_ci Curl_dyn_len(&data->state.headerb)); 429313498266Sopenharmony_ci goto out; /* exit header line loop */ 429413498266Sopenharmony_ci } 429513498266Sopenharmony_ci 429613498266Sopenharmony_ci /* We continue reading headers, reset the line-based header */ 429713498266Sopenharmony_ci Curl_dyn_reset(&data->state.headerb); 429813498266Sopenharmony_ci if(switch_to_h2) { 429913498266Sopenharmony_ci /* Having handled the headers, we can do the HTTP/2 switch. 430013498266Sopenharmony_ci * Any remaining `buf` bytes are already HTTP/2 and passed to 430113498266Sopenharmony_ci * be processed. */ 430213498266Sopenharmony_ci result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen); 430313498266Sopenharmony_ci if(result) 430413498266Sopenharmony_ci return result; 430513498266Sopenharmony_ci *pconsumed += blen; 430613498266Sopenharmony_ci blen = 0; 430713498266Sopenharmony_ci } 430813498266Sopenharmony_ci 430913498266Sopenharmony_ci continue; 431013498266Sopenharmony_ci } 431113498266Sopenharmony_ci 431213498266Sopenharmony_ci /* 431313498266Sopenharmony_ci * Checks for special headers coming up. 431413498266Sopenharmony_ci */ 431513498266Sopenharmony_ci 431613498266Sopenharmony_ci writetype = CLIENTWRITE_HEADER; 431713498266Sopenharmony_ci if(!k->headerline++) { 431813498266Sopenharmony_ci /* This is the first header, it MUST be the error code line 431913498266Sopenharmony_ci or else we consider this to be the body right away! */ 432013498266Sopenharmony_ci bool fine_statusline = FALSE; 432113498266Sopenharmony_ci if(conn->handler->protocol & PROTO_FAMILY_HTTP) { 432213498266Sopenharmony_ci /* 432313498266Sopenharmony_ci * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2 432413498266Sopenharmony_ci * 432513498266Sopenharmony_ci * The response code is always a three-digit number in HTTP as the spec 432613498266Sopenharmony_ci * says. We allow any three-digit number here, but we cannot make 432713498266Sopenharmony_ci * guarantees on future behaviors since it isn't within the protocol. 432813498266Sopenharmony_ci */ 432913498266Sopenharmony_ci int httpversion = 0; 433013498266Sopenharmony_ci char *p = headp; 433113498266Sopenharmony_ci 433213498266Sopenharmony_ci while(*p && ISBLANK(*p)) 433313498266Sopenharmony_ci p++; 433413498266Sopenharmony_ci if(!strncmp(p, "HTTP/", 5)) { 433513498266Sopenharmony_ci p += 5; 433613498266Sopenharmony_ci switch(*p) { 433713498266Sopenharmony_ci case '1': 433813498266Sopenharmony_ci p++; 433913498266Sopenharmony_ci if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) { 434013498266Sopenharmony_ci if(ISBLANK(p[2])) { 434113498266Sopenharmony_ci httpversion = 10 + (p[1] - '0'); 434213498266Sopenharmony_ci p += 3; 434313498266Sopenharmony_ci if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { 434413498266Sopenharmony_ci k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + 434513498266Sopenharmony_ci (p[2] - '0'); 434613498266Sopenharmony_ci p += 3; 434713498266Sopenharmony_ci if(ISSPACE(*p)) 434813498266Sopenharmony_ci fine_statusline = TRUE; 434913498266Sopenharmony_ci } 435013498266Sopenharmony_ci } 435113498266Sopenharmony_ci } 435213498266Sopenharmony_ci if(!fine_statusline) { 435313498266Sopenharmony_ci failf(data, "Unsupported HTTP/1 subversion in response"); 435413498266Sopenharmony_ci return CURLE_UNSUPPORTED_PROTOCOL; 435513498266Sopenharmony_ci } 435613498266Sopenharmony_ci break; 435713498266Sopenharmony_ci case '2': 435813498266Sopenharmony_ci case '3': 435913498266Sopenharmony_ci if(!ISBLANK(p[1])) 436013498266Sopenharmony_ci break; 436113498266Sopenharmony_ci httpversion = (*p - '0') * 10; 436213498266Sopenharmony_ci p += 2; 436313498266Sopenharmony_ci if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { 436413498266Sopenharmony_ci k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + 436513498266Sopenharmony_ci (p[2] - '0'); 436613498266Sopenharmony_ci p += 3; 436713498266Sopenharmony_ci if(!ISSPACE(*p)) 436813498266Sopenharmony_ci break; 436913498266Sopenharmony_ci fine_statusline = TRUE; 437013498266Sopenharmony_ci } 437113498266Sopenharmony_ci break; 437213498266Sopenharmony_ci default: /* unsupported */ 437313498266Sopenharmony_ci failf(data, "Unsupported HTTP version in response"); 437413498266Sopenharmony_ci return CURLE_UNSUPPORTED_PROTOCOL; 437513498266Sopenharmony_ci } 437613498266Sopenharmony_ci } 437713498266Sopenharmony_ci 437813498266Sopenharmony_ci if(fine_statusline) { 437913498266Sopenharmony_ci if(k->httpcode < 100) { 438013498266Sopenharmony_ci failf(data, "Unsupported response code in HTTP response"); 438113498266Sopenharmony_ci return CURLE_UNSUPPORTED_PROTOCOL; 438213498266Sopenharmony_ci } 438313498266Sopenharmony_ci switch(httpversion) { 438413498266Sopenharmony_ci case 10: 438513498266Sopenharmony_ci case 11: 438613498266Sopenharmony_ci#ifdef USE_HTTP2 438713498266Sopenharmony_ci case 20: 438813498266Sopenharmony_ci#endif 438913498266Sopenharmony_ci#ifdef ENABLE_QUIC 439013498266Sopenharmony_ci case 30: 439113498266Sopenharmony_ci#endif 439213498266Sopenharmony_ci conn->httpversion = (unsigned char)httpversion; 439313498266Sopenharmony_ci break; 439413498266Sopenharmony_ci default: 439513498266Sopenharmony_ci failf(data, "Unsupported HTTP version (%u.%d) in response", 439613498266Sopenharmony_ci httpversion/10, httpversion%10); 439713498266Sopenharmony_ci return CURLE_UNSUPPORTED_PROTOCOL; 439813498266Sopenharmony_ci } 439913498266Sopenharmony_ci 440013498266Sopenharmony_ci if(k->upgr101 == UPGR101_RECEIVED) { 440113498266Sopenharmony_ci /* supposedly upgraded to http2 now */ 440213498266Sopenharmony_ci if(conn->httpversion != 20) 440313498266Sopenharmony_ci infof(data, "Lying server, not serving HTTP/2"); 440413498266Sopenharmony_ci } 440513498266Sopenharmony_ci if(conn->httpversion < 20) { 440613498266Sopenharmony_ci conn->bundle->multiuse = BUNDLE_NO_MULTIUSE; 440713498266Sopenharmony_ci } 440813498266Sopenharmony_ci } 440913498266Sopenharmony_ci else { 441013498266Sopenharmony_ci /* If user has set option HTTP200ALIASES, 441113498266Sopenharmony_ci compare header line against list of aliases 441213498266Sopenharmony_ci */ 441313498266Sopenharmony_ci statusline check = 441413498266Sopenharmony_ci checkhttpprefix(data, 441513498266Sopenharmony_ci Curl_dyn_ptr(&data->state.headerb), 441613498266Sopenharmony_ci Curl_dyn_len(&data->state.headerb)); 441713498266Sopenharmony_ci if(check == STATUS_DONE) { 441813498266Sopenharmony_ci fine_statusline = TRUE; 441913498266Sopenharmony_ci k->httpcode = 200; 442013498266Sopenharmony_ci conn->httpversion = 10; 442113498266Sopenharmony_ci } 442213498266Sopenharmony_ci } 442313498266Sopenharmony_ci } 442413498266Sopenharmony_ci else if(conn->handler->protocol & CURLPROTO_RTSP) { 442513498266Sopenharmony_ci char *p = headp; 442613498266Sopenharmony_ci while(*p && ISBLANK(*p)) 442713498266Sopenharmony_ci p++; 442813498266Sopenharmony_ci if(!strncmp(p, "RTSP/", 5)) { 442913498266Sopenharmony_ci p += 5; 443013498266Sopenharmony_ci if(ISDIGIT(*p)) { 443113498266Sopenharmony_ci p++; 443213498266Sopenharmony_ci if((p[0] == '.') && ISDIGIT(p[1])) { 443313498266Sopenharmony_ci if(ISBLANK(p[2])) { 443413498266Sopenharmony_ci p += 3; 443513498266Sopenharmony_ci if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { 443613498266Sopenharmony_ci k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + 443713498266Sopenharmony_ci (p[2] - '0'); 443813498266Sopenharmony_ci p += 3; 443913498266Sopenharmony_ci if(ISSPACE(*p)) { 444013498266Sopenharmony_ci fine_statusline = TRUE; 444113498266Sopenharmony_ci conn->httpversion = 11; /* RTSP acts like HTTP 1.1 */ 444213498266Sopenharmony_ci } 444313498266Sopenharmony_ci } 444413498266Sopenharmony_ci } 444513498266Sopenharmony_ci } 444613498266Sopenharmony_ci } 444713498266Sopenharmony_ci if(!fine_statusline) 444813498266Sopenharmony_ci return CURLE_WEIRD_SERVER_REPLY; 444913498266Sopenharmony_ci } 445013498266Sopenharmony_ci } 445113498266Sopenharmony_ci 445213498266Sopenharmony_ci if(fine_statusline) { 445313498266Sopenharmony_ci result = Curl_http_statusline(data, conn); 445413498266Sopenharmony_ci if(result) 445513498266Sopenharmony_ci return result; 445613498266Sopenharmony_ci writetype |= CLIENTWRITE_STATUS; 445713498266Sopenharmony_ci } 445813498266Sopenharmony_ci else { 445913498266Sopenharmony_ci k->header = FALSE; /* this is not a header line */ 446013498266Sopenharmony_ci break; 446113498266Sopenharmony_ci } 446213498266Sopenharmony_ci } 446313498266Sopenharmony_ci 446413498266Sopenharmony_ci result = verify_header(data); 446513498266Sopenharmony_ci if(result) 446613498266Sopenharmony_ci return result; 446713498266Sopenharmony_ci 446813498266Sopenharmony_ci result = Curl_http_header(data, conn, headp); 446913498266Sopenharmony_ci if(result) 447013498266Sopenharmony_ci return result; 447113498266Sopenharmony_ci 447213498266Sopenharmony_ci /* 447313498266Sopenharmony_ci * End of header-checks. Write them to the client. 447413498266Sopenharmony_ci */ 447513498266Sopenharmony_ci if(k->httpcode/100 == 1) 447613498266Sopenharmony_ci writetype |= CLIENTWRITE_1XX; 447713498266Sopenharmony_ci 447813498266Sopenharmony_ci Curl_debug(data, CURLINFO_HEADER_IN, headp, 447913498266Sopenharmony_ci Curl_dyn_len(&data->state.headerb)); 448013498266Sopenharmony_ci 448113498266Sopenharmony_ci result = Curl_client_write(data, writetype, headp, 448213498266Sopenharmony_ci Curl_dyn_len(&data->state.headerb)); 448313498266Sopenharmony_ci if(result) 448413498266Sopenharmony_ci return result; 448513498266Sopenharmony_ci 448613498266Sopenharmony_ci result = Curl_bump_headersize(data, Curl_dyn_len(&data->state.headerb), 448713498266Sopenharmony_ci FALSE); 448813498266Sopenharmony_ci if(result) 448913498266Sopenharmony_ci return result; 449013498266Sopenharmony_ci 449113498266Sopenharmony_ci Curl_dyn_reset(&data->state.headerb); 449213498266Sopenharmony_ci } 449313498266Sopenharmony_ci while(blen); 449413498266Sopenharmony_ci 449513498266Sopenharmony_ci /* We might have reached the end of the header part here, but 449613498266Sopenharmony_ci there might be a non-header part left in the end of the read 449713498266Sopenharmony_ci buffer. */ 449813498266Sopenharmony_ciout: 449913498266Sopenharmony_ci if(!k->header && !leftover_body) { 450013498266Sopenharmony_ci Curl_dyn_free(&data->state.headerb); 450113498266Sopenharmony_ci } 450213498266Sopenharmony_ci return CURLE_OK; 450313498266Sopenharmony_ci} 450413498266Sopenharmony_ci 450513498266Sopenharmony_ci/* 450613498266Sopenharmony_ci * HTTP protocol `write_resp` implementation. Will parse headers 450713498266Sopenharmony_ci * when not done yet and otherwise return without consuming data. 450813498266Sopenharmony_ci */ 450913498266Sopenharmony_ciCURLcode Curl_http_write_resp_hds(struct Curl_easy *data, 451013498266Sopenharmony_ci const char *buf, size_t blen, 451113498266Sopenharmony_ci size_t *pconsumed, 451213498266Sopenharmony_ci bool *done) 451313498266Sopenharmony_ci{ 451413498266Sopenharmony_ci *done = FALSE; 451513498266Sopenharmony_ci if(!data->req.header) { 451613498266Sopenharmony_ci *pconsumed = 0; 451713498266Sopenharmony_ci return CURLE_OK; 451813498266Sopenharmony_ci } 451913498266Sopenharmony_ci else { 452013498266Sopenharmony_ci CURLcode result; 452113498266Sopenharmony_ci 452213498266Sopenharmony_ci result = http_rw_headers(data, buf, blen, pconsumed); 452313498266Sopenharmony_ci if(!result && !data->req.header) { 452413498266Sopenharmony_ci /* we have successfully finished parsing the HEADERs */ 452513498266Sopenharmony_ci result = Curl_http_firstwrite(data, data->conn, done); 452613498266Sopenharmony_ci 452713498266Sopenharmony_ci if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) { 452813498266Sopenharmony_ci /* leftover from parsing something that turned out not 452913498266Sopenharmony_ci * to be a header, only happens if we allow for 453013498266Sopenharmony_ci * HTTP/0.9 like responses */ 453113498266Sopenharmony_ci result = Curl_client_write(data, CLIENTWRITE_BODY, 453213498266Sopenharmony_ci Curl_dyn_ptr(&data->state.headerb), 453313498266Sopenharmony_ci Curl_dyn_len(&data->state.headerb)); 453413498266Sopenharmony_ci } 453513498266Sopenharmony_ci Curl_dyn_free(&data->state.headerb); 453613498266Sopenharmony_ci } 453713498266Sopenharmony_ci return result; 453813498266Sopenharmony_ci } 453913498266Sopenharmony_ci} 454013498266Sopenharmony_ci 454113498266Sopenharmony_ciCURLcode Curl_http_write_resp(struct Curl_easy *data, 454213498266Sopenharmony_ci const char *buf, size_t blen, 454313498266Sopenharmony_ci bool is_eos, 454413498266Sopenharmony_ci bool *done) 454513498266Sopenharmony_ci{ 454613498266Sopenharmony_ci CURLcode result; 454713498266Sopenharmony_ci size_t consumed; 454813498266Sopenharmony_ci int flags; 454913498266Sopenharmony_ci 455013498266Sopenharmony_ci *done = FALSE; 455113498266Sopenharmony_ci result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done); 455213498266Sopenharmony_ci if(result || *done) 455313498266Sopenharmony_ci goto out; 455413498266Sopenharmony_ci 455513498266Sopenharmony_ci DEBUGASSERT(consumed <= blen); 455613498266Sopenharmony_ci blen -= consumed; 455713498266Sopenharmony_ci buf += consumed; 455813498266Sopenharmony_ci /* either all was consumed in header parsing, or we have data left 455913498266Sopenharmony_ci * and are done with heders, e.g. it is BODY data */ 456013498266Sopenharmony_ci DEBUGASSERT(!blen || !data->req.header); 456113498266Sopenharmony_ci if(!data->req.header && (blen || is_eos)) { 456213498266Sopenharmony_ci /* BODY data after header been parsed, write and consume */ 456313498266Sopenharmony_ci flags = CLIENTWRITE_BODY; 456413498266Sopenharmony_ci if(is_eos) 456513498266Sopenharmony_ci flags |= CLIENTWRITE_EOS; 456613498266Sopenharmony_ci result = Curl_client_write(data, flags, (char *)buf, blen); 456713498266Sopenharmony_ci } 456813498266Sopenharmony_ciout: 456913498266Sopenharmony_ci return result; 457013498266Sopenharmony_ci} 457113498266Sopenharmony_ci 457213498266Sopenharmony_ci/* Decode HTTP status code string. */ 457313498266Sopenharmony_ciCURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len) 457413498266Sopenharmony_ci{ 457513498266Sopenharmony_ci CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; 457613498266Sopenharmony_ci int status = 0; 457713498266Sopenharmony_ci int i; 457813498266Sopenharmony_ci 457913498266Sopenharmony_ci if(len != 3) 458013498266Sopenharmony_ci goto out; 458113498266Sopenharmony_ci 458213498266Sopenharmony_ci for(i = 0; i < 3; ++i) { 458313498266Sopenharmony_ci char c = s[i]; 458413498266Sopenharmony_ci 458513498266Sopenharmony_ci if(c < '0' || c > '9') 458613498266Sopenharmony_ci goto out; 458713498266Sopenharmony_ci 458813498266Sopenharmony_ci status *= 10; 458913498266Sopenharmony_ci status += c - '0'; 459013498266Sopenharmony_ci } 459113498266Sopenharmony_ci result = CURLE_OK; 459213498266Sopenharmony_ciout: 459313498266Sopenharmony_ci *pstatus = result? -1 : status; 459413498266Sopenharmony_ci return result; 459513498266Sopenharmony_ci} 459613498266Sopenharmony_ci 459713498266Sopenharmony_ciCURLcode Curl_http_req_make(struct httpreq **preq, 459813498266Sopenharmony_ci const char *method, size_t m_len, 459913498266Sopenharmony_ci const char *scheme, size_t s_len, 460013498266Sopenharmony_ci const char *authority, size_t a_len, 460113498266Sopenharmony_ci const char *path, size_t p_len) 460213498266Sopenharmony_ci{ 460313498266Sopenharmony_ci struct httpreq *req; 460413498266Sopenharmony_ci CURLcode result = CURLE_OUT_OF_MEMORY; 460513498266Sopenharmony_ci 460613498266Sopenharmony_ci DEBUGASSERT(method); 460713498266Sopenharmony_ci if(m_len + 1 > sizeof(req->method)) 460813498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 460913498266Sopenharmony_ci 461013498266Sopenharmony_ci req = calloc(1, sizeof(*req)); 461113498266Sopenharmony_ci if(!req) 461213498266Sopenharmony_ci goto out; 461313498266Sopenharmony_ci memcpy(req->method, method, m_len); 461413498266Sopenharmony_ci if(scheme) { 461513498266Sopenharmony_ci req->scheme = Curl_memdup0(scheme, s_len); 461613498266Sopenharmony_ci if(!req->scheme) 461713498266Sopenharmony_ci goto out; 461813498266Sopenharmony_ci } 461913498266Sopenharmony_ci if(authority) { 462013498266Sopenharmony_ci req->authority = Curl_memdup0(authority, a_len); 462113498266Sopenharmony_ci if(!req->authority) 462213498266Sopenharmony_ci goto out; 462313498266Sopenharmony_ci } 462413498266Sopenharmony_ci if(path) { 462513498266Sopenharmony_ci req->path = Curl_memdup0(path, p_len); 462613498266Sopenharmony_ci if(!req->path) 462713498266Sopenharmony_ci goto out; 462813498266Sopenharmony_ci } 462913498266Sopenharmony_ci Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST); 463013498266Sopenharmony_ci Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST); 463113498266Sopenharmony_ci result = CURLE_OK; 463213498266Sopenharmony_ci 463313498266Sopenharmony_ciout: 463413498266Sopenharmony_ci if(result && req) 463513498266Sopenharmony_ci Curl_http_req_free(req); 463613498266Sopenharmony_ci *preq = result? NULL : req; 463713498266Sopenharmony_ci return result; 463813498266Sopenharmony_ci} 463913498266Sopenharmony_ci 464013498266Sopenharmony_cistatic CURLcode req_assign_url_authority(struct httpreq *req, CURLU *url) 464113498266Sopenharmony_ci{ 464213498266Sopenharmony_ci char *user, *pass, *host, *port; 464313498266Sopenharmony_ci struct dynbuf buf; 464413498266Sopenharmony_ci CURLUcode uc; 464513498266Sopenharmony_ci CURLcode result = CURLE_URL_MALFORMAT; 464613498266Sopenharmony_ci 464713498266Sopenharmony_ci user = pass = host = port = NULL; 464813498266Sopenharmony_ci Curl_dyn_init(&buf, DYN_HTTP_REQUEST); 464913498266Sopenharmony_ci 465013498266Sopenharmony_ci uc = curl_url_get(url, CURLUPART_HOST, &host, 0); 465113498266Sopenharmony_ci if(uc && uc != CURLUE_NO_HOST) 465213498266Sopenharmony_ci goto out; 465313498266Sopenharmony_ci if(!host) { 465413498266Sopenharmony_ci req->authority = NULL; 465513498266Sopenharmony_ci result = CURLE_OK; 465613498266Sopenharmony_ci goto out; 465713498266Sopenharmony_ci } 465813498266Sopenharmony_ci 465913498266Sopenharmony_ci uc = curl_url_get(url, CURLUPART_PORT, &port, CURLU_NO_DEFAULT_PORT); 466013498266Sopenharmony_ci if(uc && uc != CURLUE_NO_PORT) 466113498266Sopenharmony_ci goto out; 466213498266Sopenharmony_ci uc = curl_url_get(url, CURLUPART_USER, &user, 0); 466313498266Sopenharmony_ci if(uc && uc != CURLUE_NO_USER) 466413498266Sopenharmony_ci goto out; 466513498266Sopenharmony_ci if(user) { 466613498266Sopenharmony_ci uc = curl_url_get(url, CURLUPART_PASSWORD, &pass, 0); 466713498266Sopenharmony_ci if(uc && uc != CURLUE_NO_PASSWORD) 466813498266Sopenharmony_ci goto out; 466913498266Sopenharmony_ci } 467013498266Sopenharmony_ci 467113498266Sopenharmony_ci if(user) { 467213498266Sopenharmony_ci result = Curl_dyn_add(&buf, user); 467313498266Sopenharmony_ci if(result) 467413498266Sopenharmony_ci goto out; 467513498266Sopenharmony_ci if(pass) { 467613498266Sopenharmony_ci result = Curl_dyn_addf(&buf, ":%s", pass); 467713498266Sopenharmony_ci if(result) 467813498266Sopenharmony_ci goto out; 467913498266Sopenharmony_ci } 468013498266Sopenharmony_ci result = Curl_dyn_add(&buf, "@"); 468113498266Sopenharmony_ci if(result) 468213498266Sopenharmony_ci goto out; 468313498266Sopenharmony_ci } 468413498266Sopenharmony_ci result = Curl_dyn_add(&buf, host); 468513498266Sopenharmony_ci if(result) 468613498266Sopenharmony_ci goto out; 468713498266Sopenharmony_ci if(port) { 468813498266Sopenharmony_ci result = Curl_dyn_addf(&buf, ":%s", port); 468913498266Sopenharmony_ci if(result) 469013498266Sopenharmony_ci goto out; 469113498266Sopenharmony_ci } 469213498266Sopenharmony_ci req->authority = strdup(Curl_dyn_ptr(&buf)); 469313498266Sopenharmony_ci if(!req->authority) 469413498266Sopenharmony_ci goto out; 469513498266Sopenharmony_ci result = CURLE_OK; 469613498266Sopenharmony_ci 469713498266Sopenharmony_ciout: 469813498266Sopenharmony_ci free(user); 469913498266Sopenharmony_ci free(pass); 470013498266Sopenharmony_ci free(host); 470113498266Sopenharmony_ci free(port); 470213498266Sopenharmony_ci Curl_dyn_free(&buf); 470313498266Sopenharmony_ci return result; 470413498266Sopenharmony_ci} 470513498266Sopenharmony_ci 470613498266Sopenharmony_cistatic CURLcode req_assign_url_path(struct httpreq *req, CURLU *url) 470713498266Sopenharmony_ci{ 470813498266Sopenharmony_ci char *path, *query; 470913498266Sopenharmony_ci struct dynbuf buf; 471013498266Sopenharmony_ci CURLUcode uc; 471113498266Sopenharmony_ci CURLcode result = CURLE_URL_MALFORMAT; 471213498266Sopenharmony_ci 471313498266Sopenharmony_ci path = query = NULL; 471413498266Sopenharmony_ci Curl_dyn_init(&buf, DYN_HTTP_REQUEST); 471513498266Sopenharmony_ci 471613498266Sopenharmony_ci uc = curl_url_get(url, CURLUPART_PATH, &path, CURLU_PATH_AS_IS); 471713498266Sopenharmony_ci if(uc) 471813498266Sopenharmony_ci goto out; 471913498266Sopenharmony_ci uc = curl_url_get(url, CURLUPART_QUERY, &query, 0); 472013498266Sopenharmony_ci if(uc && uc != CURLUE_NO_QUERY) 472113498266Sopenharmony_ci goto out; 472213498266Sopenharmony_ci 472313498266Sopenharmony_ci if(!path && !query) { 472413498266Sopenharmony_ci req->path = NULL; 472513498266Sopenharmony_ci } 472613498266Sopenharmony_ci else if(path && !query) { 472713498266Sopenharmony_ci req->path = path; 472813498266Sopenharmony_ci path = NULL; 472913498266Sopenharmony_ci } 473013498266Sopenharmony_ci else { 473113498266Sopenharmony_ci if(path) { 473213498266Sopenharmony_ci result = Curl_dyn_add(&buf, path); 473313498266Sopenharmony_ci if(result) 473413498266Sopenharmony_ci goto out; 473513498266Sopenharmony_ci } 473613498266Sopenharmony_ci if(query) { 473713498266Sopenharmony_ci result = Curl_dyn_addf(&buf, "?%s", query); 473813498266Sopenharmony_ci if(result) 473913498266Sopenharmony_ci goto out; 474013498266Sopenharmony_ci } 474113498266Sopenharmony_ci req->path = strdup(Curl_dyn_ptr(&buf)); 474213498266Sopenharmony_ci if(!req->path) 474313498266Sopenharmony_ci goto out; 474413498266Sopenharmony_ci } 474513498266Sopenharmony_ci result = CURLE_OK; 474613498266Sopenharmony_ci 474713498266Sopenharmony_ciout: 474813498266Sopenharmony_ci free(path); 474913498266Sopenharmony_ci free(query); 475013498266Sopenharmony_ci Curl_dyn_free(&buf); 475113498266Sopenharmony_ci return result; 475213498266Sopenharmony_ci} 475313498266Sopenharmony_ci 475413498266Sopenharmony_ciCURLcode Curl_http_req_make2(struct httpreq **preq, 475513498266Sopenharmony_ci const char *method, size_t m_len, 475613498266Sopenharmony_ci CURLU *url, const char *scheme_default) 475713498266Sopenharmony_ci{ 475813498266Sopenharmony_ci struct httpreq *req; 475913498266Sopenharmony_ci CURLcode result = CURLE_OUT_OF_MEMORY; 476013498266Sopenharmony_ci CURLUcode uc; 476113498266Sopenharmony_ci 476213498266Sopenharmony_ci DEBUGASSERT(method); 476313498266Sopenharmony_ci if(m_len + 1 > sizeof(req->method)) 476413498266Sopenharmony_ci return CURLE_BAD_FUNCTION_ARGUMENT; 476513498266Sopenharmony_ci 476613498266Sopenharmony_ci req = calloc(1, sizeof(*req)); 476713498266Sopenharmony_ci if(!req) 476813498266Sopenharmony_ci goto out; 476913498266Sopenharmony_ci memcpy(req->method, method, m_len); 477013498266Sopenharmony_ci 477113498266Sopenharmony_ci uc = curl_url_get(url, CURLUPART_SCHEME, &req->scheme, 0); 477213498266Sopenharmony_ci if(uc && uc != CURLUE_NO_SCHEME) 477313498266Sopenharmony_ci goto out; 477413498266Sopenharmony_ci if(!req->scheme && scheme_default) { 477513498266Sopenharmony_ci req->scheme = strdup(scheme_default); 477613498266Sopenharmony_ci if(!req->scheme) 477713498266Sopenharmony_ci goto out; 477813498266Sopenharmony_ci } 477913498266Sopenharmony_ci 478013498266Sopenharmony_ci result = req_assign_url_authority(req, url); 478113498266Sopenharmony_ci if(result) 478213498266Sopenharmony_ci goto out; 478313498266Sopenharmony_ci result = req_assign_url_path(req, url); 478413498266Sopenharmony_ci if(result) 478513498266Sopenharmony_ci goto out; 478613498266Sopenharmony_ci 478713498266Sopenharmony_ci Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST); 478813498266Sopenharmony_ci Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST); 478913498266Sopenharmony_ci result = CURLE_OK; 479013498266Sopenharmony_ci 479113498266Sopenharmony_ciout: 479213498266Sopenharmony_ci if(result && req) 479313498266Sopenharmony_ci Curl_http_req_free(req); 479413498266Sopenharmony_ci *preq = result? NULL : req; 479513498266Sopenharmony_ci return result; 479613498266Sopenharmony_ci} 479713498266Sopenharmony_ci 479813498266Sopenharmony_civoid Curl_http_req_free(struct httpreq *req) 479913498266Sopenharmony_ci{ 480013498266Sopenharmony_ci if(req) { 480113498266Sopenharmony_ci free(req->scheme); 480213498266Sopenharmony_ci free(req->authority); 480313498266Sopenharmony_ci free(req->path); 480413498266Sopenharmony_ci Curl_dynhds_free(&req->headers); 480513498266Sopenharmony_ci Curl_dynhds_free(&req->trailers); 480613498266Sopenharmony_ci free(req); 480713498266Sopenharmony_ci } 480813498266Sopenharmony_ci} 480913498266Sopenharmony_ci 481013498266Sopenharmony_cistruct name_const { 481113498266Sopenharmony_ci const char *name; 481213498266Sopenharmony_ci size_t namelen; 481313498266Sopenharmony_ci}; 481413498266Sopenharmony_ci 481513498266Sopenharmony_cistatic struct name_const H2_NON_FIELD[] = { 481613498266Sopenharmony_ci { STRCONST("Host") }, 481713498266Sopenharmony_ci { STRCONST("Upgrade") }, 481813498266Sopenharmony_ci { STRCONST("Connection") }, 481913498266Sopenharmony_ci { STRCONST("Keep-Alive") }, 482013498266Sopenharmony_ci { STRCONST("Proxy-Connection") }, 482113498266Sopenharmony_ci { STRCONST("Transfer-Encoding") }, 482213498266Sopenharmony_ci}; 482313498266Sopenharmony_ci 482413498266Sopenharmony_cistatic bool h2_non_field(const char *name, size_t namelen) 482513498266Sopenharmony_ci{ 482613498266Sopenharmony_ci size_t i; 482713498266Sopenharmony_ci for(i = 0; i < sizeof(H2_NON_FIELD)/sizeof(H2_NON_FIELD[0]); ++i) { 482813498266Sopenharmony_ci if(namelen < H2_NON_FIELD[i].namelen) 482913498266Sopenharmony_ci return FALSE; 483013498266Sopenharmony_ci if(namelen == H2_NON_FIELD[i].namelen && 483113498266Sopenharmony_ci strcasecompare(H2_NON_FIELD[i].name, name)) 483213498266Sopenharmony_ci return TRUE; 483313498266Sopenharmony_ci } 483413498266Sopenharmony_ci return FALSE; 483513498266Sopenharmony_ci} 483613498266Sopenharmony_ci 483713498266Sopenharmony_ciCURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, 483813498266Sopenharmony_ci struct httpreq *req, struct Curl_easy *data) 483913498266Sopenharmony_ci{ 484013498266Sopenharmony_ci const char *scheme = NULL, *authority = NULL; 484113498266Sopenharmony_ci struct dynhds_entry *e; 484213498266Sopenharmony_ci size_t i; 484313498266Sopenharmony_ci CURLcode result; 484413498266Sopenharmony_ci 484513498266Sopenharmony_ci DEBUGASSERT(req); 484613498266Sopenharmony_ci DEBUGASSERT(h2_headers); 484713498266Sopenharmony_ci 484813498266Sopenharmony_ci if(req->scheme) { 484913498266Sopenharmony_ci scheme = req->scheme; 485013498266Sopenharmony_ci } 485113498266Sopenharmony_ci else if(strcmp("CONNECT", req->method)) { 485213498266Sopenharmony_ci scheme = Curl_checkheaders(data, STRCONST(HTTP_PSEUDO_SCHEME)); 485313498266Sopenharmony_ci if(scheme) { 485413498266Sopenharmony_ci scheme += sizeof(HTTP_PSEUDO_SCHEME); 485513498266Sopenharmony_ci while(*scheme && ISBLANK(*scheme)) 485613498266Sopenharmony_ci scheme++; 485713498266Sopenharmony_ci infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme); 485813498266Sopenharmony_ci } 485913498266Sopenharmony_ci else { 486013498266Sopenharmony_ci scheme = (data->conn && data->conn->handler->flags & PROTOPT_SSL)? 486113498266Sopenharmony_ci "https" : "http"; 486213498266Sopenharmony_ci } 486313498266Sopenharmony_ci } 486413498266Sopenharmony_ci 486513498266Sopenharmony_ci if(req->authority) { 486613498266Sopenharmony_ci authority = req->authority; 486713498266Sopenharmony_ci } 486813498266Sopenharmony_ci else { 486913498266Sopenharmony_ci e = Curl_dynhds_get(&req->headers, STRCONST("Host")); 487013498266Sopenharmony_ci if(e) 487113498266Sopenharmony_ci authority = e->value; 487213498266Sopenharmony_ci } 487313498266Sopenharmony_ci 487413498266Sopenharmony_ci Curl_dynhds_reset(h2_headers); 487513498266Sopenharmony_ci Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE); 487613498266Sopenharmony_ci result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD), 487713498266Sopenharmony_ci req->method, strlen(req->method)); 487813498266Sopenharmony_ci if(!result && scheme) { 487913498266Sopenharmony_ci result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), 488013498266Sopenharmony_ci scheme, strlen(scheme)); 488113498266Sopenharmony_ci } 488213498266Sopenharmony_ci if(!result && authority) { 488313498266Sopenharmony_ci result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY), 488413498266Sopenharmony_ci authority, strlen(authority)); 488513498266Sopenharmony_ci } 488613498266Sopenharmony_ci if(!result && req->path) { 488713498266Sopenharmony_ci result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), 488813498266Sopenharmony_ci req->path, strlen(req->path)); 488913498266Sopenharmony_ci } 489013498266Sopenharmony_ci for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) { 489113498266Sopenharmony_ci e = Curl_dynhds_getn(&req->headers, i); 489213498266Sopenharmony_ci if(!h2_non_field(e->name, e->namelen)) { 489313498266Sopenharmony_ci result = Curl_dynhds_add(h2_headers, e->name, e->namelen, 489413498266Sopenharmony_ci e->value, e->valuelen); 489513498266Sopenharmony_ci } 489613498266Sopenharmony_ci } 489713498266Sopenharmony_ci 489813498266Sopenharmony_ci return result; 489913498266Sopenharmony_ci} 490013498266Sopenharmony_ci 490113498266Sopenharmony_ciCURLcode Curl_http_resp_make(struct http_resp **presp, 490213498266Sopenharmony_ci int status, 490313498266Sopenharmony_ci const char *description) 490413498266Sopenharmony_ci{ 490513498266Sopenharmony_ci struct http_resp *resp; 490613498266Sopenharmony_ci CURLcode result = CURLE_OUT_OF_MEMORY; 490713498266Sopenharmony_ci 490813498266Sopenharmony_ci resp = calloc(1, sizeof(*resp)); 490913498266Sopenharmony_ci if(!resp) 491013498266Sopenharmony_ci goto out; 491113498266Sopenharmony_ci 491213498266Sopenharmony_ci resp->status = status; 491313498266Sopenharmony_ci if(description) { 491413498266Sopenharmony_ci resp->description = strdup(description); 491513498266Sopenharmony_ci if(!resp->description) 491613498266Sopenharmony_ci goto out; 491713498266Sopenharmony_ci } 491813498266Sopenharmony_ci Curl_dynhds_init(&resp->headers, 0, DYN_HTTP_REQUEST); 491913498266Sopenharmony_ci Curl_dynhds_init(&resp->trailers, 0, DYN_HTTP_REQUEST); 492013498266Sopenharmony_ci result = CURLE_OK; 492113498266Sopenharmony_ci 492213498266Sopenharmony_ciout: 492313498266Sopenharmony_ci if(result && resp) 492413498266Sopenharmony_ci Curl_http_resp_free(resp); 492513498266Sopenharmony_ci *presp = result? NULL : resp; 492613498266Sopenharmony_ci return result; 492713498266Sopenharmony_ci} 492813498266Sopenharmony_ci 492913498266Sopenharmony_civoid Curl_http_resp_free(struct http_resp *resp) 493013498266Sopenharmony_ci{ 493113498266Sopenharmony_ci if(resp) { 493213498266Sopenharmony_ci free(resp->description); 493313498266Sopenharmony_ci Curl_dynhds_free(&resp->headers); 493413498266Sopenharmony_ci Curl_dynhds_free(&resp->trailers); 493513498266Sopenharmony_ci if(resp->prev) 493613498266Sopenharmony_ci Curl_http_resp_free(resp->prev); 493713498266Sopenharmony_ci free(resp); 493813498266Sopenharmony_ci } 493913498266Sopenharmony_ci} 494013498266Sopenharmony_ci 494113498266Sopenharmony_ci#endif /* CURL_DISABLE_HTTP */ 4942