VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/http.c@ 98341

最後變更 在這個檔案從98341是 95312,由 vboxsync 提交於 3 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • 屬性 svn:eol-style 設為 native
檔案大小: 136.6 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#ifndef CURL_DISABLE_HTTP
26
27#ifdef HAVE_NETINET_IN_H
28#include <netinet/in.h>
29#endif
30
31#ifdef HAVE_NETDB_H
32#include <netdb.h>
33#endif
34#ifdef HAVE_ARPA_INET_H
35#include <arpa/inet.h>
36#endif
37#ifdef HAVE_NET_IF_H
38#include <net/if.h>
39#endif
40#ifdef HAVE_SYS_IOCTL_H
41#include <sys/ioctl.h>
42#endif
43
44#ifdef HAVE_SYS_PARAM_H
45#include <sys/param.h>
46#endif
47
48#ifdef USE_HYPER
49#include <hyper.h>
50#endif
51
52#include "urldata.h"
53#include <curl/curl.h>
54#include "transfer.h"
55#include "sendf.h"
56#include "formdata.h"
57#include "mime.h"
58#include "progress.h"
59#include "curl_base64.h"
60#include "cookie.h"
61#include "vauth/vauth.h"
62#include "vtls/vtls.h"
63#include "http_digest.h"
64#include "http_ntlm.h"
65#include "curl_ntlm_wb.h"
66#include "http_negotiate.h"
67#include "http_aws_sigv4.h"
68#include "url.h"
69#include "share.h"
70#include "hostip.h"
71#include "http.h"
72#include "select.h"
73#include "parsedate.h" /* for the week day and month names */
74#include "strtoofft.h"
75#include "multiif.h"
76#include "strcase.h"
77#include "content_encoding.h"
78#include "http_proxy.h"
79#include "warnless.h"
80#include "http2.h"
81#include "connect.h"
82#include "strdup.h"
83#include "altsvc.h"
84#include "hsts.h"
85#include "c-hyper.h"
86
87/* The last 3 #include files should be in this order */
88#include "curl_printf.h"
89#include "curl_memory.h"
90#include "memdebug.h"
91
92/*
93 * Forward declarations.
94 */
95
96static int http_getsock_do(struct Curl_easy *data,
97 struct connectdata *conn,
98 curl_socket_t *socks);
99static bool http_should_fail(struct Curl_easy *data);
100
101#ifndef CURL_DISABLE_PROXY
102static CURLcode add_haproxy_protocol_header(struct Curl_easy *data);
103#endif
104
105#ifdef USE_SSL
106static CURLcode https_connecting(struct Curl_easy *data, bool *done);
107static int https_getsock(struct Curl_easy *data,
108 struct connectdata *conn,
109 curl_socket_t *socks);
110#else
111#define https_connecting(x,y) CURLE_COULDNT_CONNECT
112#endif
113static CURLcode http_setup_conn(struct Curl_easy *data,
114 struct connectdata *conn);
115
116/*
117 * HTTP handler interface.
118 */
119const struct Curl_handler Curl_handler_http = {
120 "HTTP", /* scheme */
121 http_setup_conn, /* setup_connection */
122 Curl_http, /* do_it */
123 Curl_http_done, /* done */
124 ZERO_NULL, /* do_more */
125 Curl_http_connect, /* connect_it */
126 ZERO_NULL, /* connecting */
127 ZERO_NULL, /* doing */
128 ZERO_NULL, /* proto_getsock */
129 http_getsock_do, /* doing_getsock */
130 ZERO_NULL, /* domore_getsock */
131 ZERO_NULL, /* perform_getsock */
132 ZERO_NULL, /* disconnect */
133 ZERO_NULL, /* readwrite */
134 ZERO_NULL, /* connection_check */
135 ZERO_NULL, /* attach connection */
136 PORT_HTTP, /* defport */
137 CURLPROTO_HTTP, /* protocol */
138 CURLPROTO_HTTP, /* family */
139 PROTOPT_CREDSPERREQUEST | /* flags */
140 PROTOPT_USERPWDCTRL
141};
142
143#ifdef USE_SSL
144/*
145 * HTTPS handler interface.
146 */
147const struct Curl_handler Curl_handler_https = {
148 "HTTPS", /* scheme */
149 http_setup_conn, /* setup_connection */
150 Curl_http, /* do_it */
151 Curl_http_done, /* done */
152 ZERO_NULL, /* do_more */
153 Curl_http_connect, /* connect_it */
154 https_connecting, /* connecting */
155 ZERO_NULL, /* doing */
156 https_getsock, /* proto_getsock */
157 http_getsock_do, /* doing_getsock */
158 ZERO_NULL, /* domore_getsock */
159 ZERO_NULL, /* perform_getsock */
160 ZERO_NULL, /* disconnect */
161 ZERO_NULL, /* readwrite */
162 ZERO_NULL, /* connection_check */
163 ZERO_NULL, /* attach connection */
164 PORT_HTTPS, /* defport */
165 CURLPROTO_HTTPS, /* protocol */
166 CURLPROTO_HTTP, /* family */
167 PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN | /* flags */
168 PROTOPT_USERPWDCTRL
169};
170#endif
171
172static CURLcode http_setup_conn(struct Curl_easy *data,
173 struct connectdata *conn)
174{
175 /* allocate the HTTP-specific struct for the Curl_easy, only to survive
176 during this request */
177 struct HTTP *http;
178 DEBUGASSERT(data->req.p.http == NULL);
179
180 http = calloc(1, sizeof(struct HTTP));
181 if(!http)
182 return CURLE_OUT_OF_MEMORY;
183
184 Curl_mime_initpart(&http->form, data);
185 data->req.p.http = http;
186
187 if(data->state.httpwant == CURL_HTTP_VERSION_3) {
188 if(conn->handler->flags & PROTOPT_SSL)
189 /* Only go HTTP/3 directly on HTTPS URLs. It needs a UDP socket and does
190 the QUIC dance. */
191 conn->transport = TRNSPRT_QUIC;
192 else {
193 failf(data, "HTTP/3 requested for non-HTTPS URL");
194 return CURLE_URL_MALFORMAT;
195 }
196 }
197 else {
198 if(!CONN_INUSE(conn))
199 /* if not already multi-using, setup connection details */
200 Curl_http2_setup_conn(conn);
201 Curl_http2_setup_req(data);
202 }
203 return CURLE_OK;
204}
205
206#ifndef CURL_DISABLE_PROXY
207/*
208 * checkProxyHeaders() checks the linked list of custom proxy headers
209 * if proxy headers are not available, then it will lookup into http header
210 * link list
211 *
212 * It takes a connectdata struct as input to see if this is a proxy request or
213 * not, as it then might check a different header list. Provide the header
214 * prefix without colon!
215 */
216char *Curl_checkProxyheaders(struct Curl_easy *data,
217 const struct connectdata *conn,
218 const char *thisheader,
219 const size_t thislen)
220{
221 struct curl_slist *head;
222
223 for(head = (conn->bits.proxy && data->set.sep_headers) ?
224 data->set.proxyheaders : data->set.headers;
225 head; head = head->next) {
226 if(strncasecompare(head->data, thisheader, thislen) &&
227 Curl_headersep(head->data[thislen]))
228 return head->data;
229 }
230
231 return NULL;
232}
233#else
234/* disabled */
235#define Curl_checkProxyheaders(x,y,z,a) NULL
236#endif
237
238/*
239 * Strip off leading and trailing whitespace from the value in the
240 * given HTTP header line and return a strdupped copy. Returns NULL in
241 * case of allocation failure. Returns an empty string if the header value
242 * consists entirely of whitespace.
243 */
244char *Curl_copy_header_value(const char *header)
245{
246 const char *start;
247 const char *end;
248 char *value;
249 size_t len;
250
251 /* Find the end of the header name */
252 while(*header && (*header != ':'))
253 ++header;
254
255 if(*header)
256 /* Skip over colon */
257 ++header;
258
259 /* Find the first non-space letter */
260 start = header;
261 while(*start && ISSPACE(*start))
262 start++;
263
264 /* data is in the host encoding so
265 use '\r' and '\n' instead of 0x0d and 0x0a */
266 end = strchr(start, '\r');
267 if(!end)
268 end = strchr(start, '\n');
269 if(!end)
270 end = strchr(start, '\0');
271 if(!end)
272 return NULL;
273
274 /* skip all trailing space letters */
275 while((end > start) && ISSPACE(*end))
276 end--;
277
278 /* get length of the type */
279 len = end - start + 1;
280
281 value = malloc(len + 1);
282 if(!value)
283 return NULL;
284
285 memcpy(value, start, len);
286 value[len] = 0; /* null-terminate */
287
288 return value;
289}
290
291#ifndef CURL_DISABLE_HTTP_AUTH
292/*
293 * http_output_basic() sets up an Authorization: header (or the proxy version)
294 * for HTTP Basic authentication.
295 *
296 * Returns CURLcode.
297 */
298static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
299{
300 size_t size = 0;
301 char *authorization = NULL;
302 char **userp;
303 const char *user;
304 const char *pwd;
305 CURLcode result;
306 char *out;
307
308 /* credentials are unique per transfer for HTTP, do not use the ones for the
309 connection */
310 if(proxy) {
311#ifndef CURL_DISABLE_PROXY
312 userp = &data->state.aptr.proxyuserpwd;
313 user = data->state.aptr.proxyuser;
314 pwd = data->state.aptr.proxypasswd;
315#else
316 return CURLE_NOT_BUILT_IN;
317#endif
318 }
319 else {
320 userp = &data->state.aptr.userpwd;
321 user = data->state.aptr.user;
322 pwd = data->state.aptr.passwd;
323 }
324
325 out = aprintf("%s:%s", user ? user : "", pwd ? pwd : "");
326 if(!out)
327 return CURLE_OUT_OF_MEMORY;
328
329 result = Curl_base64_encode(out, strlen(out), &authorization, &size);
330 if(result)
331 goto fail;
332
333 if(!authorization) {
334 result = CURLE_REMOTE_ACCESS_DENIED;
335 goto fail;
336 }
337
338 free(*userp);
339 *userp = aprintf("%sAuthorization: Basic %s\r\n",
340 proxy ? "Proxy-" : "",
341 authorization);
342 free(authorization);
343 if(!*userp) {
344 result = CURLE_OUT_OF_MEMORY;
345 goto fail;
346 }
347
348 fail:
349 free(out);
350 return result;
351}
352
353/*
354 * http_output_bearer() sets up an Authorization: header
355 * for HTTP Bearer authentication.
356 *
357 * Returns CURLcode.
358 */
359static CURLcode http_output_bearer(struct Curl_easy *data)
360{
361 char **userp;
362 CURLcode result = CURLE_OK;
363
364 userp = &data->state.aptr.userpwd;
365 free(*userp);
366 *userp = aprintf("Authorization: Bearer %s\r\n",
367 data->set.str[STRING_BEARER]);
368
369 if(!*userp) {
370 result = CURLE_OUT_OF_MEMORY;
371 goto fail;
372 }
373
374 fail:
375 return result;
376}
377
378#endif
379
380/* pickoneauth() selects the most favourable authentication method from the
381 * ones available and the ones we want.
382 *
383 * return TRUE if one was picked
384 */
385static bool pickoneauth(struct auth *pick, unsigned long mask)
386{
387 bool picked;
388 /* only deal with authentication we want */
389 unsigned long avail = pick->avail & pick->want & mask;
390 picked = TRUE;
391
392 /* The order of these checks is highly relevant, as this will be the order
393 of preference in case of the existence of multiple accepted types. */
394 if(avail & CURLAUTH_NEGOTIATE)
395 pick->picked = CURLAUTH_NEGOTIATE;
396 else if(avail & CURLAUTH_BEARER)
397 pick->picked = CURLAUTH_BEARER;
398 else if(avail & CURLAUTH_DIGEST)
399 pick->picked = CURLAUTH_DIGEST;
400 else if(avail & CURLAUTH_NTLM)
401 pick->picked = CURLAUTH_NTLM;
402 else if(avail & CURLAUTH_NTLM_WB)
403 pick->picked = CURLAUTH_NTLM_WB;
404 else if(avail & CURLAUTH_BASIC)
405 pick->picked = CURLAUTH_BASIC;
406 else if(avail & CURLAUTH_AWS_SIGV4)
407 pick->picked = CURLAUTH_AWS_SIGV4;
408 else {
409 pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
410 picked = FALSE;
411 }
412 pick->avail = CURLAUTH_NONE; /* clear it here */
413
414 return picked;
415}
416
417/*
418 * http_perhapsrewind()
419 *
420 * If we are doing POST or PUT {
421 * If we have more data to send {
422 * If we are doing NTLM {
423 * Keep sending since we must not disconnect
424 * }
425 * else {
426 * If there is more than just a little data left to send, close
427 * the current connection by force.
428 * }
429 * }
430 * If we have sent any data {
431 * If we don't have track of all the data {
432 * call app to tell it to rewind
433 * }
434 * else {
435 * rewind internally so that the operation can restart fine
436 * }
437 * }
438 * }
439 */
440static CURLcode http_perhapsrewind(struct Curl_easy *data,
441 struct connectdata *conn)
442{
443 struct HTTP *http = data->req.p.http;
444 curl_off_t bytessent;
445 curl_off_t expectsend = -1; /* default is unknown */
446
447 if(!http)
448 /* If this is still NULL, we have not reach very far and we can safely
449 skip this rewinding stuff */
450 return CURLE_OK;
451
452 switch(data->state.httpreq) {
453 case HTTPREQ_GET:
454 case HTTPREQ_HEAD:
455 return CURLE_OK;
456 default:
457 break;
458 }
459
460 bytessent = data->req.writebytecount;
461
462 if(conn->bits.authneg) {
463 /* This is a state where we are known to be negotiating and we don't send
464 any data then. */
465 expectsend = 0;
466 }
467 else if(!conn->bits.protoconnstart) {
468 /* HTTP CONNECT in progress: there is no body */
469 expectsend = 0;
470 }
471 else {
472 /* figure out how much data we are expected to send */
473 switch(data->state.httpreq) {
474 case HTTPREQ_POST:
475 case HTTPREQ_PUT:
476 if(data->state.infilesize != -1)
477 expectsend = data->state.infilesize;
478 break;
479 case HTTPREQ_POST_FORM:
480 case HTTPREQ_POST_MIME:
481 expectsend = http->postsize;
482 break;
483 default:
484 break;
485 }
486 }
487
488 conn->bits.rewindaftersend = FALSE; /* default */
489
490 if((expectsend == -1) || (expectsend > bytessent)) {
491#if defined(USE_NTLM)
492 /* There is still data left to send */
493 if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
494 (data->state.authhost.picked == CURLAUTH_NTLM) ||
495 (data->state.authproxy.picked == CURLAUTH_NTLM_WB) ||
496 (data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
497 if(((expectsend - bytessent) < 2000) ||
498 (conn->http_ntlm_state != NTLMSTATE_NONE) ||
499 (conn->proxy_ntlm_state != NTLMSTATE_NONE)) {
500 /* The NTLM-negotiation has started *OR* there is just a little (<2K)
501 data left to send, keep on sending. */
502
503 /* rewind data when completely done sending! */
504 if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
505 conn->bits.rewindaftersend = TRUE;
506 infof(data, "Rewind stream after send");
507 }
508
509 return CURLE_OK;
510 }
511
512 if(conn->bits.close)
513 /* this is already marked to get closed */
514 return CURLE_OK;
515
516 infof(data, "NTLM send, close instead of sending %"
517 CURL_FORMAT_CURL_OFF_T " bytes",
518 (curl_off_t)(expectsend - bytessent));
519 }
520#endif
521#if defined(USE_SPNEGO)
522 /* There is still data left to send */
523 if((data->state.authproxy.picked == CURLAUTH_NEGOTIATE) ||
524 (data->state.authhost.picked == CURLAUTH_NEGOTIATE)) {
525 if(((expectsend - bytessent) < 2000) ||
526 (conn->http_negotiate_state != GSS_AUTHNONE) ||
527 (conn->proxy_negotiate_state != GSS_AUTHNONE)) {
528 /* The NEGOTIATE-negotiation has started *OR*
529 there is just a little (<2K) data left to send, keep on sending. */
530
531 /* rewind data when completely done sending! */
532 if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
533 conn->bits.rewindaftersend = TRUE;
534 infof(data, "Rewind stream after send");
535 }
536
537 return CURLE_OK;
538 }
539
540 if(conn->bits.close)
541 /* this is already marked to get closed */
542 return CURLE_OK;
543
544 infof(data, "NEGOTIATE send, close instead of sending %"
545 CURL_FORMAT_CURL_OFF_T " bytes",
546 (curl_off_t)(expectsend - bytessent));
547 }
548#endif
549
550 /* This is not NEGOTIATE/NTLM or many bytes left to send: close */
551 streamclose(conn, "Mid-auth HTTP and much data left to send");
552 data->req.size = 0; /* don't download any more than 0 bytes */
553
554 /* There still is data left to send, but this connection is marked for
555 closure so we can safely do the rewind right now */
556 }
557
558 if(bytessent)
559 /* we rewind now at once since if we already sent something */
560 return Curl_readrewind(data);
561
562 return CURLE_OK;
563}
564
565/*
566 * Curl_http_auth_act() gets called when all HTTP headers have been received
567 * and it checks what authentication methods that are available and decides
568 * which one (if any) to use. It will set 'newurl' if an auth method was
569 * picked.
570 */
571
572CURLcode Curl_http_auth_act(struct Curl_easy *data)
573{
574 struct connectdata *conn = data->conn;
575 bool pickhost = FALSE;
576 bool pickproxy = FALSE;
577 CURLcode result = CURLE_OK;
578 unsigned long authmask = ~0ul;
579
580 if(!data->set.str[STRING_BEARER])
581 authmask &= (unsigned long)~CURLAUTH_BEARER;
582
583 if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
584 /* this is a transient response code, ignore */
585 return CURLE_OK;
586
587 if(data->state.authproblem)
588 return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
589
590 if((data->state.aptr.user || data->set.str[STRING_BEARER]) &&
591 ((data->req.httpcode == 401) ||
592 (conn->bits.authneg && data->req.httpcode < 300))) {
593 pickhost = pickoneauth(&data->state.authhost, authmask);
594 if(!pickhost)
595 data->state.authproblem = TRUE;
596 if(data->state.authhost.picked == CURLAUTH_NTLM &&
597 conn->httpversion > 11) {
598 infof(data, "Forcing HTTP/1.1 for NTLM");
599 connclose(conn, "Force HTTP/1.1 connection");
600 data->state.httpwant = CURL_HTTP_VERSION_1_1;
601 }
602 }
603#ifndef CURL_DISABLE_PROXY
604 if(conn->bits.proxy_user_passwd &&
605 ((data->req.httpcode == 407) ||
606 (conn->bits.authneg && data->req.httpcode < 300))) {
607 pickproxy = pickoneauth(&data->state.authproxy,
608 authmask & ~CURLAUTH_BEARER);
609 if(!pickproxy)
610 data->state.authproblem = TRUE;
611 }
612#endif
613
614 if(pickhost || pickproxy) {
615 if((data->state.httpreq != HTTPREQ_GET) &&
616 (data->state.httpreq != HTTPREQ_HEAD) &&
617 !conn->bits.rewindaftersend) {
618 result = http_perhapsrewind(data, conn);
619 if(result)
620 return result;
621 }
622 /* In case this is GSS auth, the newurl field is already allocated so
623 we must make sure to free it before allocating a new one. As figured
624 out in bug #2284386 */
625 Curl_safefree(data->req.newurl);
626 data->req.newurl = strdup(data->state.url); /* clone URL */
627 if(!data->req.newurl)
628 return CURLE_OUT_OF_MEMORY;
629 }
630 else if((data->req.httpcode < 300) &&
631 (!data->state.authhost.done) &&
632 conn->bits.authneg) {
633 /* no (known) authentication available,
634 authentication is not "done" yet and
635 no authentication seems to be required and
636 we didn't try HEAD or GET */
637 if((data->state.httpreq != HTTPREQ_GET) &&
638 (data->state.httpreq != HTTPREQ_HEAD)) {
639 data->req.newurl = strdup(data->state.url); /* clone URL */
640 if(!data->req.newurl)
641 return CURLE_OUT_OF_MEMORY;
642 data->state.authhost.done = TRUE;
643 }
644 }
645 if(http_should_fail(data)) {
646 failf(data, "The requested URL returned error: %d",
647 data->req.httpcode);
648 result = CURLE_HTTP_RETURNED_ERROR;
649 }
650
651 return result;
652}
653
654/*
655 * Curl_allow_auth_to_host() tells if authentication, cookies or other
656 * "sensitive data" can (still) be sent to this host.
657 */
658bool Curl_allow_auth_to_host(struct Curl_easy *data)
659{
660 struct connectdata *conn = data->conn;
661 return (!data->state.this_is_a_follow ||
662 data->set.allow_auth_to_other_hosts ||
663 (data->state.first_host &&
664 strcasecompare(data->state.first_host, conn->host.name) &&
665 (data->state.first_remote_port == conn->remote_port) &&
666 (data->state.first_remote_protocol == conn->handler->protocol)));
667}
668
669#ifndef CURL_DISABLE_HTTP_AUTH
670/*
671 * Output the correct authentication header depending on the auth type
672 * and whether or not it is to a proxy.
673 */
674static CURLcode
675output_auth_headers(struct Curl_easy *data,
676 struct connectdata *conn,
677 struct auth *authstatus,
678 const char *request,
679 const char *path,
680 bool proxy)
681{
682 const char *auth = NULL;
683 CURLcode result = CURLE_OK;
684 (void)conn;
685
686#ifdef CURL_DISABLE_CRYPTO_AUTH
687 (void)request;
688 (void)path;
689#endif
690#ifndef CURL_DISABLE_CRYPTO_AUTH
691 if(authstatus->picked == CURLAUTH_AWS_SIGV4) {
692 auth = "AWS_SIGV4";
693 result = Curl_output_aws_sigv4(data, proxy);
694 if(result)
695 return result;
696 }
697 else
698#endif
699#ifdef USE_SPNEGO
700 if(authstatus->picked == CURLAUTH_NEGOTIATE) {
701 auth = "Negotiate";
702 result = Curl_output_negotiate(data, conn, proxy);
703 if(result)
704 return result;
705 }
706 else
707#endif
708#ifdef USE_NTLM
709 if(authstatus->picked == CURLAUTH_NTLM) {
710 auth = "NTLM";
711 result = Curl_output_ntlm(data, proxy);
712 if(result)
713 return result;
714 }
715 else
716#endif
717#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
718 if(authstatus->picked == CURLAUTH_NTLM_WB) {
719 auth = "NTLM_WB";
720 result = Curl_output_ntlm_wb(data, conn, proxy);
721 if(result)
722 return result;
723 }
724 else
725#endif
726#ifndef CURL_DISABLE_CRYPTO_AUTH
727 if(authstatus->picked == CURLAUTH_DIGEST) {
728 auth = "Digest";
729 result = Curl_output_digest(data,
730 proxy,
731 (const unsigned char *)request,
732 (const unsigned char *)path);
733 if(result)
734 return result;
735 }
736 else
737#endif
738 if(authstatus->picked == CURLAUTH_BASIC) {
739 /* Basic */
740 if(
741#ifndef CURL_DISABLE_PROXY
742 (proxy && conn->bits.proxy_user_passwd &&
743 !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-authorization"))) ||
744#endif
745 (!proxy && data->state.aptr.user &&
746 !Curl_checkheaders(data, STRCONST("Authorization")))) {
747 auth = "Basic";
748 result = http_output_basic(data, proxy);
749 if(result)
750 return result;
751 }
752
753 /* NOTE: this function should set 'done' TRUE, as the other auth
754 functions work that way */
755 authstatus->done = TRUE;
756 }
757 if(authstatus->picked == CURLAUTH_BEARER) {
758 /* Bearer */
759 if((!proxy && data->set.str[STRING_BEARER] &&
760 !Curl_checkheaders(data, STRCONST("Authorization")))) {
761 auth = "Bearer";
762 result = http_output_bearer(data);
763 if(result)
764 return result;
765 }
766
767 /* NOTE: this function should set 'done' TRUE, as the other auth
768 functions work that way */
769 authstatus->done = TRUE;
770 }
771
772 if(auth) {
773#ifndef CURL_DISABLE_PROXY
774 infof(data, "%s auth using %s with user '%s'",
775 proxy ? "Proxy" : "Server", auth,
776 proxy ? (data->state.aptr.proxyuser ?
777 data->state.aptr.proxyuser : "") :
778 (data->state.aptr.user ?
779 data->state.aptr.user : ""));
780#else
781 infof(data, "Server auth using %s with user '%s'",
782 auth, data->state.aptr.user ?
783 data->state.aptr.user : "");
784#endif
785 authstatus->multipass = (!authstatus->done) ? TRUE : FALSE;
786 }
787 else
788 authstatus->multipass = FALSE;
789
790 return CURLE_OK;
791}
792
793/**
794 * Curl_http_output_auth() setups the authentication headers for the
795 * host/proxy and the correct authentication
796 * method. data->state.authdone is set to TRUE when authentication is
797 * done.
798 *
799 * @param conn all information about the current connection
800 * @param request pointer to the request keyword
801 * @param path pointer to the requested path; should include query part
802 * @param proxytunnel boolean if this is the request setting up a "proxy
803 * tunnel"
804 *
805 * @returns CURLcode
806 */
807CURLcode
808Curl_http_output_auth(struct Curl_easy *data,
809 struct connectdata *conn,
810 const char *request,
811 Curl_HttpReq httpreq,
812 const char *path,
813 bool proxytunnel) /* TRUE if this is the request setting
814 up the proxy tunnel */
815{
816 CURLcode result = CURLE_OK;
817 struct auth *authhost;
818 struct auth *authproxy;
819
820 DEBUGASSERT(data);
821
822 authhost = &data->state.authhost;
823 authproxy = &data->state.authproxy;
824
825 if(
826#ifndef CURL_DISABLE_PROXY
827 (conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
828#endif
829 data->state.aptr.user || data->set.str[STRING_BEARER])
830 /* continue please */;
831 else {
832 authhost->done = TRUE;
833 authproxy->done = TRUE;
834 return CURLE_OK; /* no authentication with no user or password */
835 }
836
837 if(authhost->want && !authhost->picked)
838 /* The app has selected one or more methods, but none has been picked
839 so far by a server round-trip. Then we set the picked one to the
840 want one, and if this is one single bit it'll be used instantly. */
841 authhost->picked = authhost->want;
842
843 if(authproxy->want && !authproxy->picked)
844 /* The app has selected one or more methods, but none has been picked so
845 far by a proxy round-trip. Then we set the picked one to the want one,
846 and if this is one single bit it'll be used instantly. */
847 authproxy->picked = authproxy->want;
848
849#ifndef CURL_DISABLE_PROXY
850 /* Send proxy authentication header if needed */
851 if(conn->bits.httpproxy &&
852 (conn->bits.tunnel_proxy == (bit)proxytunnel)) {
853 result = output_auth_headers(data, conn, authproxy, request, path, TRUE);
854 if(result)
855 return result;
856 }
857 else
858#else
859 (void)proxytunnel;
860#endif /* CURL_DISABLE_PROXY */
861 /* we have no proxy so let's pretend we're done authenticating
862 with it */
863 authproxy->done = TRUE;
864
865 /* To prevent the user+password to get sent to other than the original host
866 due to a location-follow */
867 if(Curl_allow_auth_to_host(data)
868#ifndef CURL_DISABLE_NETRC
869 || conn->bits.netrc
870#endif
871 )
872 result = output_auth_headers(data, conn, authhost, request, path, FALSE);
873 else
874 authhost->done = TRUE;
875
876 if(((authhost->multipass && !authhost->done) ||
877 (authproxy->multipass && !authproxy->done)) &&
878 (httpreq != HTTPREQ_GET) &&
879 (httpreq != HTTPREQ_HEAD)) {
880 /* Auth is required and we are not authenticated yet. Make a PUT or POST
881 with content-length zero as a "probe". */
882 conn->bits.authneg = TRUE;
883 }
884 else
885 conn->bits.authneg = FALSE;
886
887 return result;
888}
889
890#else
891/* when disabled */
892CURLcode
893Curl_http_output_auth(struct Curl_easy *data,
894 struct connectdata *conn,
895 const char *request,
896 Curl_HttpReq httpreq,
897 const char *path,
898 bool proxytunnel)
899{
900 (void)data;
901 (void)conn;
902 (void)request;
903 (void)httpreq;
904 (void)path;
905 (void)proxytunnel;
906 return CURLE_OK;
907}
908#endif
909
910/*
911 * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
912 * headers. They are dealt with both in the transfer.c main loop and in the
913 * proxy CONNECT loop.
914 */
915
916static int is_valid_auth_separator(char ch)
917{
918 return ch == '\0' || ch == ',' || ISSPACE(ch);
919}
920
921CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
922 const char *auth) /* the first non-space */
923{
924 /*
925 * This resource requires authentication
926 */
927 struct connectdata *conn = data->conn;
928#ifdef USE_SPNEGO
929 curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state :
930 &conn->http_negotiate_state;
931#endif
932 unsigned long *availp;
933 struct auth *authp;
934
935 (void) conn; /* In case conditionals make it unused. */
936
937 if(proxy) {
938 availp = &data->info.proxyauthavail;
939 authp = &data->state.authproxy;
940 }
941 else {
942 availp = &data->info.httpauthavail;
943 authp = &data->state.authhost;
944 }
945
946 /*
947 * Here we check if we want the specific single authentication (using ==) and
948 * if we do, we initiate usage of it.
949 *
950 * If the provided authentication is wanted as one out of several accepted
951 * types (using &), we OR this authentication type to the authavail
952 * variable.
953 *
954 * Note:
955 *
956 * ->picked is first set to the 'want' value (one or more bits) before the
957 * request is sent, and then it is again set _after_ all response 401/407
958 * headers have been received but then only to a single preferred method
959 * (bit).
960 */
961
962 while(*auth) {
963#ifdef USE_SPNEGO
964 if(checkprefix("Negotiate", auth) && is_valid_auth_separator(auth[9])) {
965 if((authp->avail & CURLAUTH_NEGOTIATE) ||
966 Curl_auth_is_spnego_supported()) {
967 *availp |= CURLAUTH_NEGOTIATE;
968 authp->avail |= CURLAUTH_NEGOTIATE;
969
970 if(authp->picked == CURLAUTH_NEGOTIATE) {
971 CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
972 if(!result) {
973 DEBUGASSERT(!data->req.newurl);
974 data->req.newurl = strdup(data->state.url);
975 if(!data->req.newurl)
976 return CURLE_OUT_OF_MEMORY;
977 data->state.authproblem = FALSE;
978 /* we received a GSS auth token and we dealt with it fine */
979 *negstate = GSS_AUTHRECV;
980 }
981 else
982 data->state.authproblem = TRUE;
983 }
984 }
985 }
986 else
987#endif
988#ifdef USE_NTLM
989 /* NTLM support requires the SSL crypto libs */
990 if(checkprefix("NTLM", auth) && is_valid_auth_separator(auth[4])) {
991 if((authp->avail & CURLAUTH_NTLM) ||
992 (authp->avail & CURLAUTH_NTLM_WB) ||
993 Curl_auth_is_ntlm_supported()) {
994 *availp |= CURLAUTH_NTLM;
995 authp->avail |= CURLAUTH_NTLM;
996
997 if(authp->picked == CURLAUTH_NTLM ||
998 authp->picked == CURLAUTH_NTLM_WB) {
999 /* NTLM authentication is picked and activated */
1000 CURLcode result = Curl_input_ntlm(data, proxy, auth);
1001 if(!result) {
1002 data->state.authproblem = FALSE;
1003#ifdef NTLM_WB_ENABLED
1004 if(authp->picked == CURLAUTH_NTLM_WB) {
1005 *availp &= ~CURLAUTH_NTLM;
1006 authp->avail &= ~CURLAUTH_NTLM;
1007 *availp |= CURLAUTH_NTLM_WB;
1008 authp->avail |= CURLAUTH_NTLM_WB;
1009
1010 result = Curl_input_ntlm_wb(data, conn, proxy, auth);
1011 if(result) {
1012 infof(data, "Authentication problem. Ignoring this.");
1013 data->state.authproblem = TRUE;
1014 }
1015 }
1016#endif
1017 }
1018 else {
1019 infof(data, "Authentication problem. Ignoring this.");
1020 data->state.authproblem = TRUE;
1021 }
1022 }
1023 }
1024 }
1025 else
1026#endif
1027#ifndef CURL_DISABLE_CRYPTO_AUTH
1028 if(checkprefix("Digest", auth) && is_valid_auth_separator(auth[6])) {
1029 if((authp->avail & CURLAUTH_DIGEST) != 0)
1030 infof(data, "Ignoring duplicate digest auth header.");
1031 else if(Curl_auth_is_digest_supported()) {
1032 CURLcode result;
1033
1034 *availp |= CURLAUTH_DIGEST;
1035 authp->avail |= CURLAUTH_DIGEST;
1036
1037 /* We call this function on input Digest headers even if Digest
1038 * authentication isn't activated yet, as we need to store the
1039 * incoming data from this header in case we are going to use
1040 * Digest */
1041 result = Curl_input_digest(data, proxy, auth);
1042 if(result) {
1043 infof(data, "Authentication problem. Ignoring this.");
1044 data->state.authproblem = TRUE;
1045 }
1046 }
1047 }
1048 else
1049#endif
1050 if(checkprefix("Basic", auth) &&
1051 is_valid_auth_separator(auth[5])) {
1052 *availp |= CURLAUTH_BASIC;
1053 authp->avail |= CURLAUTH_BASIC;
1054 if(authp->picked == CURLAUTH_BASIC) {
1055 /* We asked for Basic authentication but got a 40X back
1056 anyway, which basically means our name+password isn't
1057 valid. */
1058 authp->avail = CURLAUTH_NONE;
1059 infof(data, "Authentication problem. Ignoring this.");
1060 data->state.authproblem = TRUE;
1061 }
1062 }
1063 else
1064 if(checkprefix("Bearer", auth) &&
1065 is_valid_auth_separator(auth[6])) {
1066 *availp |= CURLAUTH_BEARER;
1067 authp->avail |= CURLAUTH_BEARER;
1068 if(authp->picked == CURLAUTH_BEARER) {
1069 /* We asked for Bearer authentication but got a 40X back
1070 anyway, which basically means our token isn't valid. */
1071 authp->avail = CURLAUTH_NONE;
1072 infof(data, "Authentication problem. Ignoring this.");
1073 data->state.authproblem = TRUE;
1074 }
1075 }
1076
1077 /* there may be multiple methods on one line, so keep reading */
1078 while(*auth && *auth != ',') /* read up to the next comma */
1079 auth++;
1080 if(*auth == ',') /* if we're on a comma, skip it */
1081 auth++;
1082 while(*auth && ISSPACE(*auth))
1083 auth++;
1084 }
1085
1086 return CURLE_OK;
1087}
1088
1089/**
1090 * http_should_fail() determines whether an HTTP response has gotten us
1091 * into an error state or not.
1092 *
1093 * @param conn all information about the current connection
1094 *
1095 * @retval FALSE communications should continue
1096 *
1097 * @retval TRUE communications should not continue
1098 */
1099static bool http_should_fail(struct Curl_easy *data)
1100{
1101 int httpcode;
1102 DEBUGASSERT(data);
1103 DEBUGASSERT(data->conn);
1104
1105 httpcode = data->req.httpcode;
1106
1107 /*
1108 ** If we haven't been asked to fail on error,
1109 ** don't fail.
1110 */
1111 if(!data->set.http_fail_on_error)
1112 return FALSE;
1113
1114 /*
1115 ** Any code < 400 is never terminal.
1116 */
1117 if(httpcode < 400)
1118 return FALSE;
1119
1120 /*
1121 ** A 416 response to a resume request is presumably because the file is
1122 ** already completely downloaded and thus not actually a fail.
1123 */
1124 if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
1125 httpcode == 416)
1126 return FALSE;
1127
1128 /*
1129 ** Any code >= 400 that's not 401 or 407 is always
1130 ** a terminal error
1131 */
1132 if((httpcode != 401) && (httpcode != 407))
1133 return TRUE;
1134
1135 /*
1136 ** All we have left to deal with is 401 and 407
1137 */
1138 DEBUGASSERT((httpcode == 401) || (httpcode == 407));
1139
1140 /*
1141 ** Examine the current authentication state to see if this
1142 ** is an error. The idea is for this function to get
1143 ** called after processing all the headers in a response
1144 ** message. So, if we've been to asked to authenticate a
1145 ** particular stage, and we've done it, we're OK. But, if
1146 ** we're already completely authenticated, it's not OK to
1147 ** get another 401 or 407.
1148 **
1149 ** It is possible for authentication to go stale such that
1150 ** the client needs to reauthenticate. Once that info is
1151 ** available, use it here.
1152 */
1153
1154 /*
1155 ** Either we're not authenticating, or we're supposed to
1156 ** be authenticating something else. This is an error.
1157 */
1158 if((httpcode == 401) && !data->state.aptr.user)
1159 return TRUE;
1160#ifndef CURL_DISABLE_PROXY
1161 if((httpcode == 407) && !data->conn->bits.proxy_user_passwd)
1162 return TRUE;
1163#endif
1164
1165 return data->state.authproblem;
1166}
1167
1168/*
1169 * readmoredata() is a "fread() emulation" to provide POST and/or request
1170 * data. It is used when a huge POST is to be made and the entire chunk wasn't
1171 * sent in the first send(). This function will then be called from the
1172 * transfer.c loop when more data is to be sent to the peer.
1173 *
1174 * Returns the amount of bytes it filled the buffer with.
1175 */
1176static size_t readmoredata(char *buffer,
1177 size_t size,
1178 size_t nitems,
1179 void *userp)
1180{
1181 struct Curl_easy *data = (struct Curl_easy *)userp;
1182 struct HTTP *http = data->req.p.http;
1183 size_t fullsize = size * nitems;
1184
1185 if(!http->postsize)
1186 /* nothing to return */
1187 return 0;
1188
1189 /* make sure that a HTTP request is never sent away chunked! */
1190 data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
1191
1192 if(data->set.max_send_speed &&
1193 (data->set.max_send_speed < (curl_off_t)fullsize) &&
1194 (data->set.max_send_speed < http->postsize))
1195 /* speed limit */
1196 fullsize = (size_t)data->set.max_send_speed;
1197
1198 else if(http->postsize <= (curl_off_t)fullsize) {
1199 memcpy(buffer, http->postdata, (size_t)http->postsize);
1200 fullsize = (size_t)http->postsize;
1201
1202 if(http->backup.postsize) {
1203 /* move backup data into focus and continue on that */
1204 http->postdata = http->backup.postdata;
1205 http->postsize = http->backup.postsize;
1206 data->state.fread_func = http->backup.fread_func;
1207 data->state.in = http->backup.fread_in;
1208
1209 http->sending++; /* move one step up */
1210
1211 http->backup.postsize = 0;
1212 }
1213 else
1214 http->postsize = 0;
1215
1216 return fullsize;
1217 }
1218
1219 memcpy(buffer, http->postdata, fullsize);
1220 http->postdata += fullsize;
1221 http->postsize -= fullsize;
1222
1223 return fullsize;
1224}
1225
1226/*
1227 * Curl_buffer_send() sends a header buffer and frees all associated
1228 * memory. Body data may be appended to the header data if desired.
1229 *
1230 * Returns CURLcode
1231 */
1232CURLcode Curl_buffer_send(struct dynbuf *in,
1233 struct Curl_easy *data,
1234 /* add the number of sent bytes to this
1235 counter */
1236 curl_off_t *bytes_written,
1237 /* how much of the buffer contains body data */
1238 curl_off_t included_body_bytes,
1239 int socketindex)
1240{
1241 ssize_t amount;
1242 CURLcode result;
1243 char *ptr;
1244 size_t size;
1245 struct connectdata *conn = data->conn;
1246 struct HTTP *http = data->req.p.http;
1247 size_t sendsize;
1248 curl_socket_t sockfd;
1249 size_t headersize;
1250
1251 DEBUGASSERT(socketindex <= SECONDARYSOCKET);
1252
1253 sockfd = conn->sock[socketindex];
1254
1255 /* The looping below is required since we use non-blocking sockets, but due
1256 to the circumstances we will just loop and try again and again etc */
1257
1258 ptr = Curl_dyn_ptr(in);
1259 size = Curl_dyn_len(in);
1260
1261 headersize = size - (size_t)included_body_bytes; /* the initial part that
1262 isn't body is header */
1263
1264 DEBUGASSERT(size > (size_t)included_body_bytes);
1265
1266 if((conn->handler->flags & PROTOPT_SSL
1267#ifndef CURL_DISABLE_PROXY
1268 || conn->http_proxy.proxytype == CURLPROXY_HTTPS
1269#endif
1270 )
1271 && conn->httpversion != 20) {
1272 /* Make sure this doesn't send more body bytes than what the max send
1273 speed says. The request bytes do not count to the max speed.
1274 */
1275 if(data->set.max_send_speed &&
1276 (included_body_bytes > data->set.max_send_speed)) {
1277 curl_off_t overflow = included_body_bytes - data->set.max_send_speed;
1278 DEBUGASSERT((size_t)overflow < size);
1279 sendsize = size - (size_t)overflow;
1280 }
1281 else
1282 sendsize = size;
1283
1284 /* OpenSSL is very picky and we must send the SAME buffer pointer to the
1285 library when we attempt to re-send this buffer. Sending the same data
1286 is not enough, we must use the exact same address. For this reason, we
1287 must copy the data to the uploadbuffer first, since that is the buffer
1288 we will be using if this send is retried later.
1289 */
1290 result = Curl_get_upload_buffer(data);
1291 if(result) {
1292 /* malloc failed, free memory and return to the caller */
1293 Curl_dyn_free(in);
1294 return result;
1295 }
1296 /* We never send more than upload_buffer_size bytes in one single chunk
1297 when we speak HTTPS, as if only a fraction of it is sent now, this data
1298 needs to fit into the normal read-callback buffer later on and that
1299 buffer is using this size.
1300 */
1301 if(sendsize > (size_t)data->set.upload_buffer_size)
1302 sendsize = (size_t)data->set.upload_buffer_size;
1303
1304 memcpy(data->state.ulbuf, ptr, sendsize);
1305 ptr = data->state.ulbuf;
1306 }
1307 else {
1308#ifdef CURLDEBUG
1309 /* Allow debug builds to override this logic to force short initial
1310 sends
1311 */
1312 char *p = getenv("CURL_SMALLREQSEND");
1313 if(p) {
1314 size_t altsize = (size_t)strtoul(p, NULL, 10);
1315 if(altsize)
1316 sendsize = CURLMIN(size, altsize);
1317 else
1318 sendsize = size;
1319 }
1320 else
1321#endif
1322 {
1323 /* Make sure this doesn't send more body bytes than what the max send
1324 speed says. The request bytes do not count to the max speed.
1325 */
1326 if(data->set.max_send_speed &&
1327 (included_body_bytes > data->set.max_send_speed)) {
1328 curl_off_t overflow = included_body_bytes - data->set.max_send_speed;
1329 DEBUGASSERT((size_t)overflow < size);
1330 sendsize = size - (size_t)overflow;
1331 }
1332 else
1333 sendsize = size;
1334 }
1335 }
1336
1337 result = Curl_write(data, sockfd, ptr, sendsize, &amount);
1338
1339 if(!result) {
1340 /*
1341 * Note that we may not send the entire chunk at once, and we have a set
1342 * number of data bytes at the end of the big buffer (out of which we may
1343 * only send away a part).
1344 */
1345 /* how much of the header that was sent */
1346 size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount;
1347 size_t bodylen = amount - headlen;
1348
1349 /* this data _may_ contain binary stuff */
1350 Curl_debug(data, CURLINFO_HEADER_OUT, ptr, headlen);
1351 if(bodylen)
1352 /* there was body data sent beyond the initial header part, pass that on
1353 to the debug callback too */
1354 Curl_debug(data, CURLINFO_DATA_OUT, ptr + headlen, bodylen);
1355
1356 /* 'amount' can never be a very large value here so typecasting it so a
1357 signed 31 bit value should not cause problems even if ssize_t is
1358 64bit */
1359 *bytes_written += (long)amount;
1360
1361 if(http) {
1362 /* if we sent a piece of the body here, up the byte counter for it
1363 accordingly */
1364 data->req.writebytecount += bodylen;
1365 Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
1366
1367 if((size_t)amount != size) {
1368 /* The whole request could not be sent in one system call. We must
1369 queue it up and send it later when we get the chance. We must not
1370 loop here and wait until it might work again. */
1371
1372 size -= amount;
1373
1374 ptr = Curl_dyn_ptr(in) + amount;
1375
1376 /* backup the currently set pointers */
1377 http->backup.fread_func = data->state.fread_func;
1378 http->backup.fread_in = data->state.in;
1379 http->backup.postdata = http->postdata;
1380 http->backup.postsize = http->postsize;
1381
1382 /* set the new pointers for the request-sending */
1383 data->state.fread_func = (curl_read_callback)readmoredata;
1384 data->state.in = (void *)data;
1385 http->postdata = ptr;
1386 http->postsize = (curl_off_t)size;
1387
1388 /* this much data is remaining header: */
1389 data->req.pendingheader = headersize - headlen;
1390
1391 http->send_buffer = *in; /* copy the whole struct */
1392 http->sending = HTTPSEND_REQUEST;
1393
1394 return CURLE_OK;
1395 }
1396 http->sending = HTTPSEND_BODY;
1397 /* the full buffer was sent, clean up and return */
1398 }
1399 else {
1400 if((size_t)amount != size)
1401 /* We have no continue-send mechanism now, fail. This can only happen
1402 when this function is used from the CONNECT sending function. We
1403 currently (stupidly) assume that the whole request is always sent
1404 away in the first single chunk.
1405
1406 This needs FIXing.
1407 */
1408 return CURLE_SEND_ERROR;
1409 }
1410 }
1411 Curl_dyn_free(in);
1412
1413 /* no remaining header data */
1414 data->req.pendingheader = 0;
1415 return result;
1416}
1417
1418/* end of the add_buffer functions */
1419/* ------------------------------------------------------------------------- */
1420
1421
1422
1423/*
1424 * Curl_compareheader()
1425 *
1426 * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
1427 * Pass headers WITH the colon.
1428 */
1429bool
1430Curl_compareheader(const char *headerline, /* line to check */
1431 const char *header, /* header keyword _with_ colon */
1432 const size_t hlen, /* len of the keyword in bytes */
1433 const char *content, /* content string to find */
1434 const size_t clen) /* len of the content in bytes */
1435{
1436 /* RFC2616, section 4.2 says: "Each header field consists of a name followed
1437 * by a colon (":") and the field value. Field names are case-insensitive.
1438 * The field value MAY be preceded by any amount of LWS, though a single SP
1439 * is preferred." */
1440
1441 size_t len;
1442 const char *start;
1443 const char *end;
1444 DEBUGASSERT(hlen);
1445 DEBUGASSERT(clen);
1446 DEBUGASSERT(header);
1447 DEBUGASSERT(content);
1448
1449 if(!strncasecompare(headerline, header, hlen))
1450 return FALSE; /* doesn't start with header */
1451
1452 /* pass the header */
1453 start = &headerline[hlen];
1454
1455 /* pass all whitespace */
1456 while(*start && ISSPACE(*start))
1457 start++;
1458
1459 /* find the end of the header line */
1460 end = strchr(start, '\r'); /* lines end with CRLF */
1461 if(!end) {
1462 /* in case there's a non-standard compliant line here */
1463 end = strchr(start, '\n');
1464
1465 if(!end)
1466 /* hm, there's no line ending here, use the zero byte! */
1467 end = strchr(start, '\0');
1468 }
1469
1470 len = end-start; /* length of the content part of the input line */
1471
1472 /* find the content string in the rest of the line */
1473 for(; len >= clen; len--, start++) {
1474 if(strncasecompare(start, content, clen))
1475 return TRUE; /* match! */
1476 }
1477
1478 return FALSE; /* no match */
1479}
1480
1481/*
1482 * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
1483 * the generic Curl_connect().
1484 */
1485CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
1486{
1487 CURLcode result;
1488 struct connectdata *conn = data->conn;
1489
1490 /* We default to persistent connections. We set this already in this connect
1491 function to make the re-use checks properly be able to check this bit. */
1492 connkeep(conn, "HTTP default");
1493
1494#ifndef CURL_DISABLE_PROXY
1495 /* the CONNECT procedure might not have been completed */
1496 result = Curl_proxy_connect(data, FIRSTSOCKET);
1497 if(result)
1498 return result;
1499
1500 if(conn->bits.proxy_connect_closed)
1501 /* this is not an error, just part of the connection negotiation */
1502 return CURLE_OK;
1503
1504 if(CONNECT_FIRSTSOCKET_PROXY_SSL())
1505 return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */
1506
1507 if(Curl_connect_ongoing(conn))
1508 /* nothing else to do except wait right now - we're not done here. */
1509 return CURLE_OK;
1510
1511 if(data->set.haproxyprotocol) {
1512 /* add HAProxy PROXY protocol header */
1513 result = add_haproxy_protocol_header(data);
1514 if(result)
1515 return result;
1516 }
1517#endif
1518
1519 if(conn->given->protocol & CURLPROTO_HTTPS) {
1520 /* perform SSL initialization */
1521 result = https_connecting(data, done);
1522 if(result)
1523 return result;
1524 }
1525 else
1526 *done = TRUE;
1527
1528 return CURLE_OK;
1529}
1530
1531/* this returns the socket to wait for in the DO and DOING state for the multi
1532 interface and then we're always _sending_ a request and thus we wait for
1533 the single socket to become writable only */
1534static int http_getsock_do(struct Curl_easy *data,
1535 struct connectdata *conn,
1536 curl_socket_t *socks)
1537{
1538 /* write mode */
1539 (void)data;
1540 socks[0] = conn->sock[FIRSTSOCKET];
1541 return GETSOCK_WRITESOCK(0);
1542}
1543
1544#ifndef CURL_DISABLE_PROXY
1545static CURLcode add_haproxy_protocol_header(struct Curl_easy *data)
1546{
1547 struct dynbuf req;
1548 CURLcode result;
1549 const char *tcp_version;
1550 DEBUGASSERT(data->conn);
1551 Curl_dyn_init(&req, DYN_HAXPROXY);
1552
1553#ifdef USE_UNIX_SOCKETS
1554 if(data->conn->unix_domain_socket)
1555 /* the buffer is large enough to hold this! */
1556 result = Curl_dyn_addn(&req, STRCONST("PROXY UNKNOWN\r\n"));
1557 else {
1558#endif
1559 /* Emit the correct prefix for IPv6 */
1560 tcp_version = data->conn->bits.ipv6 ? "TCP6" : "TCP4";
1561
1562 result = Curl_dyn_addf(&req, "PROXY %s %s %s %i %i\r\n",
1563 tcp_version,
1564 data->info.conn_local_ip,
1565 data->info.conn_primary_ip,
1566 data->info.conn_local_port,
1567 data->info.conn_primary_port);
1568
1569#ifdef USE_UNIX_SOCKETS
1570 }
1571#endif
1572
1573 if(!result)
1574 result = Curl_buffer_send(&req, data, &data->info.request_size,
1575 0, FIRSTSOCKET);
1576 return result;
1577}
1578#endif
1579
1580#ifdef USE_SSL
1581static CURLcode https_connecting(struct Curl_easy *data, bool *done)
1582{
1583 CURLcode result;
1584 struct connectdata *conn = data->conn;
1585 DEBUGASSERT((data) && (data->conn->handler->flags & PROTOPT_SSL));
1586
1587#ifdef ENABLE_QUIC
1588 if(conn->transport == TRNSPRT_QUIC) {
1589 *done = TRUE;
1590 return CURLE_OK;
1591 }
1592#endif
1593
1594 /* perform SSL initialization for this socket */
1595 result = Curl_ssl_connect_nonblocking(data, conn, FALSE, FIRSTSOCKET, done);
1596 if(result)
1597 connclose(conn, "Failed HTTPS connection");
1598
1599 return result;
1600}
1601
1602static int https_getsock(struct Curl_easy *data,
1603 struct connectdata *conn,
1604 curl_socket_t *socks)
1605{
1606 (void)data;
1607 if(conn->handler->flags & PROTOPT_SSL)
1608 return Curl_ssl->getsock(conn, socks);
1609 return GETSOCK_BLANK;
1610}
1611#endif /* USE_SSL */
1612
1613/*
1614 * Curl_http_done() gets called after a single HTTP request has been
1615 * performed.
1616 */
1617
1618CURLcode Curl_http_done(struct Curl_easy *data,
1619 CURLcode status, bool premature)
1620{
1621 struct connectdata *conn = data->conn;
1622 struct HTTP *http = data->req.p.http;
1623
1624 /* Clear multipass flag. If authentication isn't done yet, then it will get
1625 * a chance to be set back to true when we output the next auth header */
1626 data->state.authhost.multipass = FALSE;
1627 data->state.authproxy.multipass = FALSE;
1628
1629 Curl_unencode_cleanup(data);
1630
1631 /* set the proper values (possibly modified on POST) */
1632 conn->seek_func = data->set.seek_func; /* restore */
1633 conn->seek_client = data->set.seek_client; /* restore */
1634
1635 if(!http)
1636 return CURLE_OK;
1637
1638 Curl_dyn_free(&http->send_buffer);
1639 Curl_http2_done(data, premature);
1640 Curl_quic_done(data, premature);
1641 Curl_mime_cleanpart(&http->form);
1642 Curl_dyn_reset(&data->state.headerb);
1643 Curl_hyper_done(data);
1644
1645 if(status)
1646 return status;
1647
1648 if(!premature && /* this check is pointless when DONE is called before the
1649 entire operation is complete */
1650 !conn->bits.retry &&
1651 !data->set.connect_only &&
1652 (data->req.bytecount +
1653 data->req.headerbytecount -
1654 data->req.deductheadercount) <= 0) {
1655 /* If this connection isn't simply closed to be retried, AND nothing was
1656 read from the HTTP server (that counts), this can't be right so we
1657 return an error here */
1658 failf(data, "Empty reply from server");
1659 /* Mark it as closed to avoid the "left intact" message */
1660 streamclose(conn, "Empty reply from server");
1661 return CURLE_GOT_NOTHING;
1662 }
1663
1664 return CURLE_OK;
1665}
1666
1667/*
1668 * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons
1669 * to avoid it include:
1670 *
1671 * - if the user specifically requested HTTP 1.0
1672 * - if the server we are connected to only supports 1.0
1673 * - if any server previously contacted to handle this request only supports
1674 * 1.0.
1675 */
1676bool Curl_use_http_1_1plus(const struct Curl_easy *data,
1677 const struct connectdata *conn)
1678{
1679 if((data->state.httpversion == 10) || (conn->httpversion == 10))
1680 return FALSE;
1681 if((data->state.httpwant == CURL_HTTP_VERSION_1_0) &&
1682 (conn->httpversion <= 10))
1683 return FALSE;
1684 return ((data->state.httpwant == CURL_HTTP_VERSION_NONE) ||
1685 (data->state.httpwant >= CURL_HTTP_VERSION_1_1));
1686}
1687
1688#ifndef USE_HYPER
1689static const char *get_http_string(const struct Curl_easy *data,
1690 const struct connectdata *conn)
1691{
1692#ifdef ENABLE_QUIC
1693 if((data->state.httpwant == CURL_HTTP_VERSION_3) ||
1694 (conn->httpversion == 30))
1695 return "3";
1696#endif
1697
1698#ifdef USE_NGHTTP2
1699 if(conn->proto.httpc.h2)
1700 return "2";
1701#endif
1702
1703 if(Curl_use_http_1_1plus(data, conn))
1704 return "1.1";
1705
1706 return "1.0";
1707}
1708#endif
1709
1710/* check and possibly add an Expect: header */
1711static CURLcode expect100(struct Curl_easy *data,
1712 struct connectdata *conn,
1713 struct dynbuf *req)
1714{
1715 CURLcode result = CURLE_OK;
1716 data->state.expect100header = FALSE; /* default to false unless it is set
1717 to TRUE below */
1718 if(!data->state.disableexpect && Curl_use_http_1_1plus(data, conn) &&
1719 (conn->httpversion < 20)) {
1720 /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
1721 Expect: 100-continue to the headers which actually speeds up post
1722 operations (as there is one packet coming back from the web server) */
1723 const char *ptr = Curl_checkheaders(data, STRCONST("Expect"));
1724 if(ptr) {
1725 data->state.expect100header =
1726 Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
1727 }
1728 else {
1729 result = Curl_dyn_addn(req, STRCONST("Expect: 100-continue\r\n"));
1730 if(!result)
1731 data->state.expect100header = TRUE;
1732 }
1733 }
1734
1735 return result;
1736}
1737
1738enum proxy_use {
1739 HEADER_SERVER, /* direct to server */
1740 HEADER_PROXY, /* regular request to proxy */
1741 HEADER_CONNECT /* sending CONNECT to a proxy */
1742};
1743
1744/* used to compile the provided trailers into one buffer
1745 will return an error code if one of the headers is
1746 not formatted correctly */
1747CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
1748 struct dynbuf *b,
1749 struct Curl_easy *handle)
1750{
1751 char *ptr = NULL;
1752 CURLcode result = CURLE_OK;
1753 const char *endofline_native = NULL;
1754 const char *endofline_network = NULL;
1755
1756 if(
1757#ifdef CURL_DO_LINEEND_CONV
1758 (handle->state.prefer_ascii) ||
1759#endif
1760 (handle->set.crlf)) {
1761 /* \n will become \r\n later on */
1762 endofline_native = "\n";
1763 endofline_network = "\x0a";
1764 }
1765 else {
1766 endofline_native = "\r\n";
1767 endofline_network = "\x0d\x0a";
1768 }
1769
1770 while(trailers) {
1771 /* only add correctly formatted trailers */
1772 ptr = strchr(trailers->data, ':');
1773 if(ptr && *(ptr + 1) == ' ') {
1774 result = Curl_dyn_add(b, trailers->data);
1775 if(result)
1776 return result;
1777 result = Curl_dyn_add(b, endofline_native);
1778 if(result)
1779 return result;
1780 }
1781 else
1782 infof(handle, "Malformatted trailing header, skipping trailer");
1783 trailers = trailers->next;
1784 }
1785 result = Curl_dyn_add(b, endofline_network);
1786 return result;
1787}
1788
1789CURLcode Curl_add_custom_headers(struct Curl_easy *data,
1790 bool is_connect,
1791#ifndef USE_HYPER
1792 struct dynbuf *req
1793#else
1794 void *req
1795#endif
1796 )
1797{
1798 struct connectdata *conn = data->conn;
1799 char *ptr;
1800 struct curl_slist *h[2];
1801 struct curl_slist *headers;
1802 int numlists = 1; /* by default */
1803 int i;
1804
1805#ifndef CURL_DISABLE_PROXY
1806 enum proxy_use proxy;
1807
1808 if(is_connect)
1809 proxy = HEADER_CONNECT;
1810 else
1811 proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy?
1812 HEADER_PROXY:HEADER_SERVER;
1813
1814 switch(proxy) {
1815 case HEADER_SERVER:
1816 h[0] = data->set.headers;
1817 break;
1818 case HEADER_PROXY:
1819 h[0] = data->set.headers;
1820 if(data->set.sep_headers) {
1821 h[1] = data->set.proxyheaders;
1822 numlists++;
1823 }
1824 break;
1825 case HEADER_CONNECT:
1826 if(data->set.sep_headers)
1827 h[0] = data->set.proxyheaders;
1828 else
1829 h[0] = data->set.headers;
1830 break;
1831 }
1832#else
1833 (void)is_connect;
1834 h[0] = data->set.headers;
1835#endif
1836
1837 /* loop through one or two lists */
1838 for(i = 0; i < numlists; i++) {
1839 headers = h[i];
1840
1841 while(headers) {
1842 char *semicolonp = NULL;
1843 ptr = strchr(headers->data, ':');
1844 if(!ptr) {
1845 char *optr;
1846 /* no colon, semicolon? */
1847 ptr = strchr(headers->data, ';');
1848 if(ptr) {
1849 optr = ptr;
1850 ptr++; /* pass the semicolon */
1851 while(*ptr && ISSPACE(*ptr))
1852 ptr++;
1853
1854 if(*ptr) {
1855 /* this may be used for something else in the future */
1856 optr = NULL;
1857 }
1858 else {
1859 if(*(--ptr) == ';') {
1860 /* copy the source */
1861 semicolonp = strdup(headers->data);
1862 if(!semicolonp) {
1863#ifndef USE_HYPER
1864 Curl_dyn_free(req);
1865#endif
1866 return CURLE_OUT_OF_MEMORY;
1867 }
1868 /* put a colon where the semicolon is */
1869 semicolonp[ptr - headers->data] = ':';
1870 /* point at the colon */
1871 optr = &semicolonp [ptr - headers->data];
1872 }
1873 }
1874 ptr = optr;
1875 }
1876 }
1877 if(ptr && (ptr != headers->data)) {
1878 /* we require a colon for this to be a true header */
1879
1880 ptr++; /* pass the colon */
1881 while(*ptr && ISSPACE(*ptr))
1882 ptr++;
1883
1884 if(*ptr || semicolonp) {
1885 /* only send this if the contents was non-blank or done special */
1886 CURLcode result = CURLE_OK;
1887 char *compare = semicolonp ? semicolonp : headers->data;
1888
1889 if(data->state.aptr.host &&
1890 /* a Host: header was sent already, don't pass on any custom Host:
1891 header as that will produce *two* in the same request! */
1892 checkprefix("Host:", compare))
1893 ;
1894 else if(data->state.httpreq == HTTPREQ_POST_FORM &&
1895 /* this header (extended by formdata.c) is sent later */
1896 checkprefix("Content-Type:", compare))
1897 ;
1898 else if(data->state.httpreq == HTTPREQ_POST_MIME &&
1899 /* this header is sent later */
1900 checkprefix("Content-Type:", compare))
1901 ;
1902 else if(conn->bits.authneg &&
1903 /* while doing auth neg, don't allow the custom length since
1904 we will force length zero then */
1905 checkprefix("Content-Length:", compare))
1906 ;
1907 else if(data->state.aptr.te &&
1908 /* when asking for Transfer-Encoding, don't pass on a custom
1909 Connection: */
1910 checkprefix("Connection:", compare))
1911 ;
1912 else if((conn->httpversion >= 20) &&
1913 checkprefix("Transfer-Encoding:", compare))
1914 /* HTTP/2 doesn't support chunked requests */
1915 ;
1916 else if((checkprefix("Authorization:", compare) ||
1917 checkprefix("Cookie:", compare)) &&
1918 /* be careful of sending this potentially sensitive header to
1919 other hosts */
1920 !Curl_allow_auth_to_host(data))
1921 ;
1922 else {
1923#ifdef USE_HYPER
1924 result = Curl_hyper_header(data, req, compare);
1925#else
1926 result = Curl_dyn_addf(req, "%s\r\n", compare);
1927#endif
1928 }
1929 if(semicolonp)
1930 free(semicolonp);
1931 if(result)
1932 return result;
1933 }
1934 }
1935 headers = headers->next;
1936 }
1937 }
1938
1939 return CURLE_OK;
1940}
1941
1942#ifndef CURL_DISABLE_PARSEDATE
1943CURLcode Curl_add_timecondition(struct Curl_easy *data,
1944#ifndef USE_HYPER
1945 struct dynbuf *req
1946#else
1947 void *req
1948#endif
1949 )
1950{
1951 const struct tm *tm;
1952 struct tm keeptime;
1953 CURLcode result;
1954 char datestr[80];
1955 const char *condp;
1956 size_t len;
1957
1958 if(data->set.timecondition == CURL_TIMECOND_NONE)
1959 /* no condition was asked for */
1960 return CURLE_OK;
1961
1962 result = Curl_gmtime(data->set.timevalue, &keeptime);
1963 if(result) {
1964 failf(data, "Invalid TIMEVALUE");
1965 return result;
1966 }
1967 tm = &keeptime;
1968
1969 switch(data->set.timecondition) {
1970 default:
1971 return CURLE_BAD_FUNCTION_ARGUMENT;
1972
1973 case CURL_TIMECOND_IFMODSINCE:
1974 condp = "If-Modified-Since";
1975 len = 17;
1976 break;
1977 case CURL_TIMECOND_IFUNMODSINCE:
1978 condp = "If-Unmodified-Since";
1979 len = 19;
1980 break;
1981 case CURL_TIMECOND_LASTMOD:
1982 condp = "Last-Modified";
1983 len = 13;
1984 break;
1985 }
1986
1987 if(Curl_checkheaders(data, condp, len)) {
1988 /* A custom header was specified; it will be sent instead. */
1989 return CURLE_OK;
1990 }
1991
1992 /* The If-Modified-Since header family should have their times set in
1993 * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
1994 * represented in Greenwich Mean Time (GMT), without exception. For the
1995 * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
1996 * Time)." (see page 20 of RFC2616).
1997 */
1998
1999 /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
2000 msnprintf(datestr, sizeof(datestr),
2001 "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
2002 condp,
2003 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
2004 tm->tm_mday,
2005 Curl_month[tm->tm_mon],
2006 tm->tm_year + 1900,
2007 tm->tm_hour,
2008 tm->tm_min,
2009 tm->tm_sec);
2010
2011#ifndef USE_HYPER
2012 result = Curl_dyn_add(req, datestr);
2013#else
2014 result = Curl_hyper_header(data, req, datestr);
2015#endif
2016
2017 return result;
2018}
2019#else
2020/* disabled */
2021CURLcode Curl_add_timecondition(struct Curl_easy *data,
2022 struct dynbuf *req)
2023{
2024 (void)data;
2025 (void)req;
2026 return CURLE_OK;
2027}
2028#endif
2029
2030void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
2031 const char **method, Curl_HttpReq *reqp)
2032{
2033 Curl_HttpReq httpreq = data->state.httpreq;
2034 const char *request;
2035 if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) &&
2036 data->set.upload)
2037 httpreq = HTTPREQ_PUT;
2038
2039 /* Now set the 'request' pointer to the proper request string */
2040 if(data->set.str[STRING_CUSTOMREQUEST])
2041 request = data->set.str[STRING_CUSTOMREQUEST];
2042 else {
2043 if(data->set.opt_no_body)
2044 request = "HEAD";
2045 else {
2046 DEBUGASSERT((httpreq >= HTTPREQ_GET) && (httpreq <= HTTPREQ_HEAD));
2047 switch(httpreq) {
2048 case HTTPREQ_POST:
2049 case HTTPREQ_POST_FORM:
2050 case HTTPREQ_POST_MIME:
2051 request = "POST";
2052 break;
2053 case HTTPREQ_PUT:
2054 request = "PUT";
2055 break;
2056 default: /* this should never happen */
2057 case HTTPREQ_GET:
2058 request = "GET";
2059 break;
2060 case HTTPREQ_HEAD:
2061 request = "HEAD";
2062 break;
2063 }
2064 }
2065 }
2066 *method = request;
2067 *reqp = httpreq;
2068}
2069
2070CURLcode Curl_http_useragent(struct Curl_easy *data)
2071{
2072 /* The User-Agent string might have been allocated in url.c already, because
2073 it might have been used in the proxy connect, but if we have got a header
2074 with the user-agent string specified, we erase the previously made string
2075 here. */
2076 if(Curl_checkheaders(data, STRCONST("User-Agent"))) {
2077 free(data->state.aptr.uagent);
2078 data->state.aptr.uagent = NULL;
2079 }
2080 return CURLE_OK;
2081}
2082
2083
2084CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
2085{
2086 const char *ptr;
2087 if(!data->state.this_is_a_follow) {
2088 /* Free to avoid leaking memory on multiple requests*/
2089 free(data->state.first_host);
2090
2091 data->state.first_host = strdup(conn->host.name);
2092 if(!data->state.first_host)
2093 return CURLE_OUT_OF_MEMORY;
2094
2095 data->state.first_remote_port = conn->remote_port;
2096 data->state.first_remote_protocol = conn->handler->protocol;
2097 }
2098 Curl_safefree(data->state.aptr.host);
2099
2100 ptr = Curl_checkheaders(data, STRCONST("Host"));
2101 if(ptr && (!data->state.this_is_a_follow ||
2102 strcasecompare(data->state.first_host, conn->host.name))) {
2103#if !defined(CURL_DISABLE_COOKIES)
2104 /* If we have a given custom Host: header, we extract the host name in
2105 order to possibly use it for cookie reasons later on. We only allow the
2106 custom Host: header if this is NOT a redirect, as setting Host: in the
2107 redirected request is being out on thin ice. Except if the host name
2108 is the same as the first one! */
2109 char *cookiehost = Curl_copy_header_value(ptr);
2110 if(!cookiehost)
2111 return CURLE_OUT_OF_MEMORY;
2112 if(!*cookiehost)
2113 /* ignore empty data */
2114 free(cookiehost);
2115 else {
2116 /* If the host begins with '[', we start searching for the port after
2117 the bracket has been closed */
2118 if(*cookiehost == '[') {
2119 char *closingbracket;
2120 /* since the 'cookiehost' is an allocated memory area that will be
2121 freed later we cannot simply increment the pointer */
2122 memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1);
2123 closingbracket = strchr(cookiehost, ']');
2124 if(closingbracket)
2125 *closingbracket = 0;
2126 }
2127 else {
2128 int startsearch = 0;
2129 char *colon = strchr(cookiehost + startsearch, ':');
2130 if(colon)
2131 *colon = 0; /* The host must not include an embedded port number */
2132 }
2133 Curl_safefree(data->state.aptr.cookiehost);
2134 data->state.aptr.cookiehost = cookiehost;
2135 }
2136#endif
2137
2138 if(strcmp("Host:", ptr)) {
2139 data->state.aptr.host = aprintf("Host:%s\r\n", &ptr[5]);
2140 if(!data->state.aptr.host)
2141 return CURLE_OUT_OF_MEMORY;
2142 }
2143 else
2144 /* when clearing the header */
2145 data->state.aptr.host = NULL;
2146 }
2147 else {
2148 /* When building Host: headers, we must put the host name within
2149 [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
2150 const char *host = conn->host.name;
2151
2152 if(((conn->given->protocol&CURLPROTO_HTTPS) &&
2153 (conn->remote_port == PORT_HTTPS)) ||
2154 ((conn->given->protocol&CURLPROTO_HTTP) &&
2155 (conn->remote_port == PORT_HTTP)) )
2156 /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
2157 the port number in the host string */
2158 data->state.aptr.host = aprintf("Host: %s%s%s\r\n",
2159 conn->bits.ipv6_ip?"[":"",
2160 host,
2161 conn->bits.ipv6_ip?"]":"");
2162 else
2163 data->state.aptr.host = aprintf("Host: %s%s%s:%d\r\n",
2164 conn->bits.ipv6_ip?"[":"",
2165 host,
2166 conn->bits.ipv6_ip?"]":"",
2167 conn->remote_port);
2168
2169 if(!data->state.aptr.host)
2170 /* without Host: we can't make a nice request */
2171 return CURLE_OUT_OF_MEMORY;
2172 }
2173 return CURLE_OK;
2174}
2175
2176/*
2177 * Append the request-target to the HTTP request
2178 */
2179CURLcode Curl_http_target(struct Curl_easy *data,
2180 struct connectdata *conn,
2181 struct dynbuf *r)
2182{
2183 CURLcode result = CURLE_OK;
2184 const char *path = data->state.up.path;
2185 const char *query = data->state.up.query;
2186
2187 if(data->set.str[STRING_TARGET]) {
2188 path = data->set.str[STRING_TARGET];
2189 query = NULL;
2190 }
2191
2192#ifndef CURL_DISABLE_PROXY
2193 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
2194 /* Using a proxy but does not tunnel through it */
2195
2196 /* The path sent to the proxy is in fact the entire URL. But if the remote
2197 host is a IDN-name, we must make sure that the request we produce only
2198 uses the encoded host name! */
2199
2200 /* and no fragment part */
2201 CURLUcode uc;
2202 char *url;
2203 CURLU *h = curl_url_dup(data->state.uh);
2204 if(!h)
2205 return CURLE_OUT_OF_MEMORY;
2206
2207 if(conn->host.dispname != conn->host.name) {
2208 uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
2209 if(uc) {
2210 curl_url_cleanup(h);
2211 return CURLE_OUT_OF_MEMORY;
2212 }
2213 }
2214 uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
2215 if(uc) {
2216 curl_url_cleanup(h);
2217 return CURLE_OUT_OF_MEMORY;
2218 }
2219
2220 if(strcasecompare("http", data->state.up.scheme)) {
2221 /* when getting HTTP, we don't want the userinfo the URL */
2222 uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
2223 if(uc) {
2224 curl_url_cleanup(h);
2225 return CURLE_OUT_OF_MEMORY;
2226 }
2227 uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
2228 if(uc) {
2229 curl_url_cleanup(h);
2230 return CURLE_OUT_OF_MEMORY;
2231 }
2232 }
2233 /* Extract the URL to use in the request. Store in STRING_TEMP_URL for
2234 clean-up reasons if the function returns before the free() further
2235 down. */
2236 uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
2237 if(uc) {
2238 curl_url_cleanup(h);
2239 return CURLE_OUT_OF_MEMORY;
2240 }
2241
2242 curl_url_cleanup(h);
2243
2244 /* target or url */
2245 result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
2246 data->set.str[STRING_TARGET]:url);
2247 free(url);
2248 if(result)
2249 return (result);
2250
2251 if(strcasecompare("ftp", data->state.up.scheme)) {
2252 if(data->set.proxy_transfer_mode) {
2253 /* when doing ftp, append ;type=<a|i> if not present */
2254 char *type = strstr(path, ";type=");
2255 if(type && type[6] && type[7] == 0) {
2256 switch(Curl_raw_toupper(type[6])) {
2257 case 'A':
2258 case 'D':
2259 case 'I':
2260 break;
2261 default:
2262 type = NULL;
2263 }
2264 }
2265 if(!type) {
2266 result = Curl_dyn_addf(r, ";type=%c",
2267 data->state.prefer_ascii ? 'a' : 'i');
2268 if(result)
2269 return result;
2270 }
2271 }
2272 }
2273 }
2274
2275 else
2276#else
2277 (void)conn; /* not used in disabled-proxy builds */
2278#endif
2279 {
2280 result = Curl_dyn_add(r, path);
2281 if(result)
2282 return result;
2283 if(query)
2284 result = Curl_dyn_addf(r, "?%s", query);
2285 }
2286
2287 return result;
2288}
2289
2290CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
2291 Curl_HttpReq httpreq, const char **tep)
2292{
2293 CURLcode result = CURLE_OK;
2294 const char *ptr;
2295 struct HTTP *http = data->req.p.http;
2296 http->postsize = 0;
2297
2298 switch(httpreq) {
2299 case HTTPREQ_POST_MIME:
2300 http->sendit = &data->set.mimepost;
2301 break;
2302 case HTTPREQ_POST_FORM:
2303 /* Convert the form structure into a mime structure. */
2304 Curl_mime_cleanpart(&http->form);
2305 result = Curl_getformdata(data, &http->form, data->set.httppost,
2306 data->state.fread_func);
2307 if(result)
2308 return result;
2309 http->sendit = &http->form;
2310 break;
2311 default:
2312 http->sendit = NULL;
2313 }
2314
2315#ifndef CURL_DISABLE_MIME
2316 if(http->sendit) {
2317 const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
2318
2319 /* Read and seek body only. */
2320 http->sendit->flags |= MIME_BODY_ONLY;
2321
2322 /* Prepare the mime structure headers & set content type. */
2323
2324 if(cthdr)
2325 for(cthdr += 13; *cthdr == ' '; cthdr++)
2326 ;
2327 else if(http->sendit->kind == MIMEKIND_MULTIPART)
2328 cthdr = "multipart/form-data";
2329
2330 curl_mime_headers(http->sendit, data->set.headers, 0);
2331 result = Curl_mime_prepare_headers(http->sendit, cthdr,
2332 NULL, MIMESTRATEGY_FORM);
2333 curl_mime_headers(http->sendit, NULL, 0);
2334 if(!result)
2335 result = Curl_mime_rewind(http->sendit);
2336 if(result)
2337 return result;
2338 http->postsize = Curl_mime_size(http->sendit);
2339 }
2340#endif
2341
2342 ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
2343 if(ptr) {
2344 /* Some kind of TE is requested, check if 'chunked' is chosen */
2345 data->req.upload_chunky =
2346 Curl_compareheader(ptr,
2347 STRCONST("Transfer-Encoding:"), STRCONST("chunked"));
2348 }
2349 else {
2350 if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
2351 (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) &&
2352 http->postsize < 0) ||
2353 ((data->set.upload || httpreq == HTTPREQ_POST) &&
2354 data->state.infilesize == -1))) {
2355 if(conn->bits.authneg)
2356 /* don't enable chunked during auth neg */
2357 ;
2358 else if(Curl_use_http_1_1plus(data, conn)) {
2359 if(conn->httpversion < 20)
2360 /* HTTP, upload, unknown file size and not HTTP 1.0 */
2361 data->req.upload_chunky = TRUE;
2362 }
2363 else {
2364 failf(data, "Chunky upload is not supported by HTTP 1.0");
2365 return CURLE_UPLOAD_FAILED;
2366 }
2367 }
2368 else {
2369 /* else, no chunky upload */
2370 data->req.upload_chunky = FALSE;
2371 }
2372
2373 if(data->req.upload_chunky)
2374 *tep = "Transfer-Encoding: chunked\r\n";
2375 }
2376 return result;
2377}
2378
2379CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
2380 struct dynbuf *r, Curl_HttpReq httpreq)
2381{
2382#ifndef USE_HYPER
2383 /* Hyper always handles the body separately */
2384 curl_off_t included_body = 0;
2385#else
2386 /* from this point down, this function should not be used */
2387#define Curl_buffer_send(a,b,c,d,e) CURLE_OK
2388#endif
2389 CURLcode result = CURLE_OK;
2390 struct HTTP *http = data->req.p.http;
2391 const char *ptr;
2392
2393 /* If 'authdone' is FALSE, we must not set the write socket index to the
2394 Curl_transfer() call below, as we're not ready to actually upload any
2395 data yet. */
2396
2397 switch(httpreq) {
2398
2399 case HTTPREQ_PUT: /* Let's PUT the data to the server! */
2400
2401 if(conn->bits.authneg)
2402 http->postsize = 0;
2403 else
2404 http->postsize = data->state.infilesize;
2405
2406 if((http->postsize != -1) && !data->req.upload_chunky &&
2407 (conn->bits.authneg ||
2408 !Curl_checkheaders(data, STRCONST("Content-Length")))) {
2409 /* only add Content-Length if not uploading chunked */
2410 result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
2411 "\r\n", http->postsize);
2412 if(result)
2413 return result;
2414 }
2415
2416 if(http->postsize) {
2417 result = expect100(data, conn, r);
2418 if(result)
2419 return result;
2420 }
2421
2422 /* end of headers */
2423 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2424 if(result)
2425 return result;
2426
2427 /* set the upload size to the progress meter */
2428 Curl_pgrsSetUploadSize(data, http->postsize);
2429
2430 /* this sends the buffer and frees all the buffer resources */
2431 result = Curl_buffer_send(r, data, &data->info.request_size, 0,
2432 FIRSTSOCKET);
2433 if(result)
2434 failf(data, "Failed sending PUT request");
2435 else
2436 /* prepare for transfer */
2437 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
2438 http->postsize?FIRSTSOCKET:-1);
2439 if(result)
2440 return result;
2441 break;
2442
2443 case HTTPREQ_POST_FORM:
2444 case HTTPREQ_POST_MIME:
2445 /* This is form posting using mime data. */
2446 if(conn->bits.authneg) {
2447 /* nothing to post! */
2448 result = Curl_dyn_addn(r, STRCONST("Content-Length: 0\r\n\r\n"));
2449 if(result)
2450 return result;
2451
2452 result = Curl_buffer_send(r, data, &data->info.request_size, 0,
2453 FIRSTSOCKET);
2454 if(result)
2455 failf(data, "Failed sending POST request");
2456 else
2457 /* setup variables for the upcoming transfer */
2458 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
2459 break;
2460 }
2461
2462 data->state.infilesize = http->postsize;
2463
2464 /* We only set Content-Length and allow a custom Content-Length if
2465 we don't upload data chunked, as RFC2616 forbids us to set both
2466 kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2467 if(http->postsize != -1 && !data->req.upload_chunky &&
2468 (conn->bits.authneg ||
2469 !Curl_checkheaders(data, STRCONST("Content-Length")))) {
2470 /* we allow replacing this header if not during auth negotiation,
2471 although it isn't very wise to actually set your own */
2472 result = Curl_dyn_addf(r,
2473 "Content-Length: %" CURL_FORMAT_CURL_OFF_T
2474 "\r\n", http->postsize);
2475 if(result)
2476 return result;
2477 }
2478
2479#ifndef CURL_DISABLE_MIME
2480 /* Output mime-generated headers. */
2481 {
2482 struct curl_slist *hdr;
2483
2484 for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
2485 result = Curl_dyn_addf(r, "%s\r\n", hdr->data);
2486 if(result)
2487 return result;
2488 }
2489 }
2490#endif
2491
2492 /* For really small posts we don't use Expect: headers at all, and for
2493 the somewhat bigger ones we allow the app to disable it. Just make
2494 sure that the expect100header is always set to the preferred value
2495 here. */
2496 ptr = Curl_checkheaders(data, STRCONST("Expect"));
2497 if(ptr) {
2498 data->state.expect100header =
2499 Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
2500 }
2501 else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
2502 result = expect100(data, conn, r);
2503 if(result)
2504 return result;
2505 }
2506 else
2507 data->state.expect100header = FALSE;
2508
2509 /* make the request end in a true CRLF */
2510 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2511 if(result)
2512 return result;
2513
2514 /* set the upload size to the progress meter */
2515 Curl_pgrsSetUploadSize(data, http->postsize);
2516
2517 /* Read from mime structure. */
2518 data->state.fread_func = (curl_read_callback) Curl_mime_read;
2519 data->state.in = (void *) http->sendit;
2520 http->sending = HTTPSEND_BODY;
2521
2522 /* this sends the buffer and frees all the buffer resources */
2523 result = Curl_buffer_send(r, data, &data->info.request_size, 0,
2524 FIRSTSOCKET);
2525 if(result)
2526 failf(data, "Failed sending POST request");
2527 else
2528 /* prepare for transfer */
2529 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
2530 http->postsize?FIRSTSOCKET:-1);
2531 if(result)
2532 return result;
2533
2534 break;
2535
2536 case HTTPREQ_POST:
2537 /* this is the simple POST, using x-www-form-urlencoded style */
2538
2539 if(conn->bits.authneg)
2540 http->postsize = 0;
2541 else
2542 /* the size of the post body */
2543 http->postsize = data->state.infilesize;
2544
2545 /* We only set Content-Length and allow a custom Content-Length if
2546 we don't upload data chunked, as RFC2616 forbids us to set both
2547 kinds of headers (Transfer-Encoding: chunked and Content-Length) */
2548 if((http->postsize != -1) && !data->req.upload_chunky &&
2549 (conn->bits.authneg ||
2550 !Curl_checkheaders(data, STRCONST("Content-Length")))) {
2551 /* we allow replacing this header if not during auth negotiation,
2552 although it isn't very wise to actually set your own */
2553 result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
2554 "\r\n", http->postsize);
2555 if(result)
2556 return result;
2557 }
2558
2559 if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
2560 result = Curl_dyn_addn(r, STRCONST("Content-Type: application/"
2561 "x-www-form-urlencoded\r\n"));
2562 if(result)
2563 return result;
2564 }
2565
2566 /* For really small posts we don't use Expect: headers at all, and for
2567 the somewhat bigger ones we allow the app to disable it. Just make
2568 sure that the expect100header is always set to the preferred value
2569 here. */
2570 ptr = Curl_checkheaders(data, STRCONST("Expect"));
2571 if(ptr) {
2572 data->state.expect100header =
2573 Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
2574 }
2575 else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
2576 result = expect100(data, conn, r);
2577 if(result)
2578 return result;
2579 }
2580 else
2581 data->state.expect100header = FALSE;
2582
2583#ifndef USE_HYPER
2584 /* With Hyper the body is always passed on separately */
2585 if(data->set.postfields) {
2586
2587 /* In HTTP2, we send request body in DATA frame regardless of
2588 its size. */
2589 if(conn->httpversion != 20 &&
2590 !data->state.expect100header &&
2591 (http->postsize < MAX_INITIAL_POST_SIZE)) {
2592 /* if we don't use expect: 100 AND
2593 postsize is less than MAX_INITIAL_POST_SIZE
2594
2595 then append the post data to the HTTP request header. This limit
2596 is no magic limit but only set to prevent really huge POSTs to
2597 get the data duplicated with malloc() and family. */
2598
2599 /* end of headers! */
2600 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2601 if(result)
2602 return result;
2603
2604 if(!data->req.upload_chunky) {
2605 /* We're not sending it 'chunked', append it to the request
2606 already now to reduce the number if send() calls */
2607 result = Curl_dyn_addn(r, data->set.postfields,
2608 (size_t)http->postsize);
2609 included_body = http->postsize;
2610 }
2611 else {
2612 if(http->postsize) {
2613 char chunk[16];
2614 /* Append the POST data chunky-style */
2615 msnprintf(chunk, sizeof(chunk), "%x\r\n", (int)http->postsize);
2616 result = Curl_dyn_add(r, chunk);
2617 if(!result) {
2618 included_body = http->postsize + strlen(chunk);
2619 result = Curl_dyn_addn(r, data->set.postfields,
2620 (size_t)http->postsize);
2621 if(!result)
2622 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2623 included_body += 2;
2624 }
2625 }
2626 if(!result) {
2627 result = Curl_dyn_addn(r, STRCONST("\x30\x0d\x0a\x0d\x0a"));
2628 /* 0 CR LF CR LF */
2629 included_body += 5;
2630 }
2631 }
2632 if(result)
2633 return result;
2634 /* Make sure the progress information is accurate */
2635 Curl_pgrsSetUploadSize(data, http->postsize);
2636 }
2637 else {
2638 /* A huge POST coming up, do data separate from the request */
2639 http->postdata = data->set.postfields;
2640
2641 http->sending = HTTPSEND_BODY;
2642
2643 data->state.fread_func = (curl_read_callback)readmoredata;
2644 data->state.in = (void *)data;
2645
2646 /* set the upload size to the progress meter */
2647 Curl_pgrsSetUploadSize(data, http->postsize);
2648
2649 /* end of headers! */
2650 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2651 if(result)
2652 return result;
2653 }
2654 }
2655 else
2656#endif
2657 {
2658 /* end of headers! */
2659 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2660 if(result)
2661 return result;
2662
2663 if(data->req.upload_chunky && conn->bits.authneg) {
2664 /* Chunky upload is selected and we're negotiating auth still, send
2665 end-of-data only */
2666 result = Curl_dyn_addn(r, (char *)STRCONST("\x30\x0d\x0a\x0d\x0a"));
2667 /* 0 CR LF CR LF */
2668 if(result)
2669 return result;
2670 }
2671
2672 else if(data->state.infilesize) {
2673 /* set the upload size to the progress meter */
2674 Curl_pgrsSetUploadSize(data, http->postsize?http->postsize:-1);
2675
2676 /* set the pointer to mark that we will send the post body using the
2677 read callback, but only if we're not in authenticate negotiation */
2678 if(!conn->bits.authneg)
2679 http->postdata = (char *)&http->postdata;
2680 }
2681 }
2682 /* issue the request */
2683 result = Curl_buffer_send(r, data, &data->info.request_size, included_body,
2684 FIRSTSOCKET);
2685
2686 if(result)
2687 failf(data, "Failed sending HTTP POST request");
2688 else
2689 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
2690 http->postdata?FIRSTSOCKET:-1);
2691 break;
2692
2693 default:
2694 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2695 if(result)
2696 return result;
2697
2698 /* issue the request */
2699 result = Curl_buffer_send(r, data, &data->info.request_size, 0,
2700 FIRSTSOCKET);
2701 if(result)
2702 failf(data, "Failed sending HTTP request");
2703 else
2704 /* HTTP GET/HEAD download: */
2705 Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
2706 }
2707
2708 return result;
2709}
2710
2711#if !defined(CURL_DISABLE_COOKIES)
2712CURLcode Curl_http_cookies(struct Curl_easy *data,
2713 struct connectdata *conn,
2714 struct dynbuf *r)
2715{
2716 CURLcode result = CURLE_OK;
2717 char *addcookies = NULL;
2718 if(data->set.str[STRING_COOKIE] &&
2719 !Curl_checkheaders(data, STRCONST("Cookie")))
2720 addcookies = data->set.str[STRING_COOKIE];
2721
2722 if(data->cookies || addcookies) {
2723 struct Cookie *co = NULL; /* no cookies from start */
2724 int count = 0;
2725
2726 if(data->cookies && data->state.cookie_engine) {
2727 const char *host = data->state.aptr.cookiehost ?
2728 data->state.aptr.cookiehost : conn->host.name;
2729 const bool secure_context =
2730 conn->handler->protocol&CURLPROTO_HTTPS ||
2731 strcasecompare("localhost", host) ||
2732 !strcmp(host, "127.0.0.1") ||
2733 !strcmp(host, "[::1]") ? TRUE : FALSE;
2734 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
2735 co = Curl_cookie_getlist(data->cookies, host, data->state.up.path,
2736 secure_context);
2737 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
2738 }
2739 if(co) {
2740 struct Cookie *store = co;
2741 /* now loop through all cookies that matched */
2742 while(co) {
2743 if(co->value) {
2744 if(0 == count) {
2745 result = Curl_dyn_addn(r, STRCONST("Cookie: "));
2746 if(result)
2747 break;
2748 }
2749 result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"",
2750 co->name, co->value);
2751 if(result)
2752 break;
2753 count++;
2754 }
2755 co = co->next; /* next cookie please */
2756 }
2757 Curl_cookie_freelist(store);
2758 }
2759 if(addcookies && !result) {
2760 if(!count)
2761 result = Curl_dyn_addn(r, STRCONST("Cookie: "));
2762 if(!result) {
2763 result = Curl_dyn_addf(r, "%s%s", count?"; ":"", addcookies);
2764 count++;
2765 }
2766 }
2767 if(count && !result)
2768 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2769
2770 if(result)
2771 return result;
2772 }
2773 return result;
2774}
2775#endif
2776
2777CURLcode Curl_http_range(struct Curl_easy *data,
2778 Curl_HttpReq httpreq)
2779{
2780 if(data->state.use_range) {
2781 /*
2782 * A range is selected. We use different headers whether we're downloading
2783 * or uploading and we always let customized headers override our internal
2784 * ones if any such are specified.
2785 */
2786 if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
2787 !Curl_checkheaders(data, STRCONST("Range"))) {
2788 /* if a line like this was already allocated, free the previous one */
2789 free(data->state.aptr.rangeline);
2790 data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
2791 data->state.range);
2792 }
2793 else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
2794 !Curl_checkheaders(data, STRCONST("Content-Range"))) {
2795
2796 /* if a line like this was already allocated, free the previous one */
2797 free(data->state.aptr.rangeline);
2798
2799 if(data->set.set_resume_from < 0) {
2800 /* Upload resume was asked for, but we don't know the size of the
2801 remote part so we tell the server (and act accordingly) that we
2802 upload the whole file (again) */
2803 data->state.aptr.rangeline =
2804 aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
2805 "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
2806 data->state.infilesize - 1, data->state.infilesize);
2807
2808 }
2809 else if(data->state.resume_from) {
2810 /* This is because "resume" was selected */
2811 curl_off_t total_expected_size =
2812 data->state.resume_from + data->state.infilesize;
2813 data->state.aptr.rangeline =
2814 aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
2815 "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
2816 data->state.range, total_expected_size-1,
2817 total_expected_size);
2818 }
2819 else {
2820 /* Range was selected and then we just pass the incoming range and
2821 append total size */
2822 data->state.aptr.rangeline =
2823 aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n",
2824 data->state.range, data->state.infilesize);
2825 }
2826 if(!data->state.aptr.rangeline)
2827 return CURLE_OUT_OF_MEMORY;
2828 }
2829 }
2830 return CURLE_OK;
2831}
2832
2833CURLcode Curl_http_resume(struct Curl_easy *data,
2834 struct connectdata *conn,
2835 Curl_HttpReq httpreq)
2836{
2837 if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
2838 data->state.resume_from) {
2839 /**********************************************************************
2840 * Resuming upload in HTTP means that we PUT or POST and that we have
2841 * got a resume_from value set. The resume value has already created
2842 * a Range: header that will be passed along. We need to "fast forward"
2843 * the file the given number of bytes and decrease the assume upload
2844 * file size before we continue this venture in the dark lands of HTTP.
2845 * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
2846 *********************************************************************/
2847
2848 if(data->state.resume_from < 0) {
2849 /*
2850 * This is meant to get the size of the present remote-file by itself.
2851 * We don't support this now. Bail out!
2852 */
2853 data->state.resume_from = 0;
2854 }
2855
2856 if(data->state.resume_from && !data->state.this_is_a_follow) {
2857 /* do we still game? */
2858
2859 /* Now, let's read off the proper amount of bytes from the
2860 input. */
2861 int seekerr = CURL_SEEKFUNC_CANTSEEK;
2862 if(conn->seek_func) {
2863 Curl_set_in_callback(data, true);
2864 seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
2865 SEEK_SET);
2866 Curl_set_in_callback(data, false);
2867 }
2868
2869 if(seekerr != CURL_SEEKFUNC_OK) {
2870 curl_off_t passed = 0;
2871
2872 if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
2873 failf(data, "Could not seek stream");
2874 return CURLE_READ_ERROR;
2875 }
2876 /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
2877 do {
2878 size_t readthisamountnow =
2879 (data->state.resume_from - passed > data->set.buffer_size) ?
2880 (size_t)data->set.buffer_size :
2881 curlx_sotouz(data->state.resume_from - passed);
2882
2883 size_t actuallyread =
2884 data->state.fread_func(data->state.buffer, 1, readthisamountnow,
2885 data->state.in);
2886
2887 passed += actuallyread;
2888 if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
2889 /* this checks for greater-than only to make sure that the
2890 CURL_READFUNC_ABORT return code still aborts */
2891 failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
2892 " bytes from the input", passed);
2893 return CURLE_READ_ERROR;
2894 }
2895 } while(passed < data->state.resume_from);
2896 }
2897
2898 /* now, decrease the size of the read */
2899 if(data->state.infilesize>0) {
2900 data->state.infilesize -= data->state.resume_from;
2901
2902 if(data->state.infilesize <= 0) {
2903 failf(data, "File already completely uploaded");
2904 return CURLE_PARTIAL_FILE;
2905 }
2906 }
2907 /* we've passed, proceed as normal */
2908 }
2909 }
2910 return CURLE_OK;
2911}
2912
2913CURLcode Curl_http_firstwrite(struct Curl_easy *data,
2914 struct connectdata *conn,
2915 bool *done)
2916{
2917 struct SingleRequest *k = &data->req;
2918
2919 if(data->req.newurl) {
2920 if(conn->bits.close) {
2921 /* Abort after the headers if "follow Location" is set
2922 and we're set to close anyway. */
2923 k->keepon &= ~KEEP_RECV;
2924 *done = TRUE;
2925 return CURLE_OK;
2926 }
2927 /* We have a new url to load, but since we want to be able to re-use this
2928 connection properly, we read the full response in "ignore more" */
2929 k->ignorebody = TRUE;
2930 infof(data, "Ignoring the response-body");
2931 }
2932 if(data->state.resume_from && !k->content_range &&
2933 (data->state.httpreq == HTTPREQ_GET) &&
2934 !k->ignorebody) {
2935
2936 if(k->size == data->state.resume_from) {
2937 /* The resume point is at the end of file, consider this fine even if it
2938 doesn't allow resume from here. */
2939 infof(data, "The entire document is already downloaded");
2940 streamclose(conn, "already downloaded");
2941 /* Abort download */
2942 k->keepon &= ~KEEP_RECV;
2943 *done = TRUE;
2944 return CURLE_OK;
2945 }
2946
2947 /* we wanted to resume a download, although the server doesn't seem to
2948 * support this and we did this with a GET (if it wasn't a GET we did a
2949 * POST or PUT resume) */
2950 failf(data, "HTTP server doesn't seem to support "
2951 "byte ranges. Cannot resume.");
2952 return CURLE_RANGE_ERROR;
2953 }
2954
2955 if(data->set.timecondition && !data->state.range) {
2956 /* A time condition has been set AND no ranges have been requested. This
2957 seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct
2958 action for a HTTP/1.1 client */
2959
2960 if(!Curl_meets_timecondition(data, k->timeofdoc)) {
2961 *done = TRUE;
2962 /* We're simulating a http 304 from server so we return
2963 what should have been returned from the server */
2964 data->info.httpcode = 304;
2965 infof(data, "Simulate a HTTP 304 response");
2966 /* we abort the transfer before it is completed == we ruin the
2967 re-use ability. Close the connection */
2968 streamclose(conn, "Simulated 304 handling");
2969 return CURLE_OK;
2970 }
2971 } /* we have a time condition */
2972
2973 return CURLE_OK;
2974}
2975
2976#ifdef HAVE_LIBZ
2977CURLcode Curl_transferencode(struct Curl_easy *data)
2978{
2979 if(!Curl_checkheaders(data, STRCONST("TE")) &&
2980 data->set.http_transfer_encoding) {
2981 /* When we are to insert a TE: header in the request, we must also insert
2982 TE in a Connection: header, so we need to merge the custom provided
2983 Connection: header and prevent the original to get sent. Note that if
2984 the user has inserted his/her own TE: header we don't do this magic
2985 but then assume that the user will handle it all! */
2986 char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
2987#define TE_HEADER "TE: gzip\r\n"
2988
2989 Curl_safefree(data->state.aptr.te);
2990
2991 if(cptr) {
2992 cptr = Curl_copy_header_value(cptr);
2993 if(!cptr)
2994 return CURLE_OUT_OF_MEMORY;
2995 }
2996
2997 /* Create the (updated) Connection: header */
2998 data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
2999 cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
3000
3001 free(cptr);
3002 if(!data->state.aptr.te)
3003 return CURLE_OUT_OF_MEMORY;
3004 }
3005 return CURLE_OK;
3006}
3007#endif
3008
3009#ifndef USE_HYPER
3010/*
3011 * Curl_http() gets called from the generic multi_do() function when a HTTP
3012 * request is to be performed. This creates and sends a properly constructed
3013 * HTTP request.
3014 */
3015CURLcode Curl_http(struct Curl_easy *data, bool *done)
3016{
3017 struct connectdata *conn = data->conn;
3018 CURLcode result = CURLE_OK;
3019 struct HTTP *http;
3020 Curl_HttpReq httpreq;
3021 const char *te = ""; /* transfer-encoding */
3022 const char *request;
3023 const char *httpstring;
3024 struct dynbuf req;
3025 char *altused = NULL;
3026 const char *p_accept; /* Accept: string */
3027
3028 /* Always consider the DO phase done after this function call, even if there
3029 may be parts of the request that are not yet sent, since we can deal with
3030 the rest of the request in the PERFORM phase. */
3031 *done = TRUE;
3032
3033 if(conn->transport != TRNSPRT_QUIC) {
3034 if(conn->httpversion < 20) { /* unless the connection is re-used and
3035 already http2 */
3036 switch(conn->negnpn) {
3037 case CURL_HTTP_VERSION_2:
3038 conn->httpversion = 20; /* we know we're on HTTP/2 now */
3039
3040 result = Curl_http2_switched(data, NULL, 0);
3041 if(result)
3042 return result;
3043 break;
3044 case CURL_HTTP_VERSION_1_1:
3045 /* continue with HTTP/1.1 when explicitly requested */
3046 break;
3047 default:
3048 /* Check if user wants to use HTTP/2 with clear TCP*/
3049#ifdef USE_NGHTTP2
3050 if(data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
3051#ifndef CURL_DISABLE_PROXY
3052 if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
3053 /* We don't support HTTP/2 proxies yet. Also it's debatable
3054 whether or not this setting should apply to HTTP/2 proxies. */
3055 infof(data, "Ignoring HTTP/2 prior knowledge due to proxy");
3056 break;
3057 }
3058#endif
3059 DEBUGF(infof(data, "HTTP/2 over clean TCP"));
3060 conn->httpversion = 20;
3061
3062 result = Curl_http2_switched(data, NULL, 0);
3063 if(result)
3064 return result;
3065 }
3066#endif
3067 break;
3068 }
3069 }
3070 else {
3071 /* prepare for a http2 request */
3072 result = Curl_http2_setup(data, conn);
3073 if(result)
3074 return result;
3075 }
3076 }
3077 http = data->req.p.http;
3078 DEBUGASSERT(http);
3079
3080 result = Curl_http_host(data, conn);
3081 if(result)
3082 return result;
3083
3084 result = Curl_http_useragent(data);
3085 if(result)
3086 return result;
3087
3088 Curl_http_method(data, conn, &request, &httpreq);
3089
3090 /* setup the authentication headers */
3091 {
3092 char *pq = NULL;
3093 if(data->state.up.query) {
3094 pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
3095 if(!pq)
3096 return CURLE_OUT_OF_MEMORY;
3097 }
3098 result = Curl_http_output_auth(data, conn, request, httpreq,
3099 (pq ? pq : data->state.up.path), FALSE);
3100 free(pq);
3101 if(result)
3102 return result;
3103 }
3104
3105 Curl_safefree(data->state.aptr.ref);
3106 if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) {
3107 data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
3108 if(!data->state.aptr.ref)
3109 return CURLE_OUT_OF_MEMORY;
3110 }
3111
3112 if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
3113 data->set.str[STRING_ENCODING]) {
3114 Curl_safefree(data->state.aptr.accept_encoding);
3115 data->state.aptr.accept_encoding =
3116 aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
3117 if(!data->state.aptr.accept_encoding)
3118 return CURLE_OUT_OF_MEMORY;
3119 }
3120 else
3121 Curl_safefree(data->state.aptr.accept_encoding);
3122
3123#ifdef HAVE_LIBZ
3124 /* we only consider transfer-encoding magic if libz support is built-in */
3125 result = Curl_transferencode(data);
3126 if(result)
3127 return result;
3128#endif
3129
3130 result = Curl_http_body(data, conn, httpreq, &te);
3131 if(result)
3132 return result;
3133
3134 p_accept = Curl_checkheaders(data,
3135 STRCONST("Accept"))?NULL:"Accept: */*\r\n";
3136
3137 result = Curl_http_resume(data, conn, httpreq);
3138 if(result)
3139 return result;
3140
3141 result = Curl_http_range(data, httpreq);
3142 if(result)
3143 return result;
3144
3145 httpstring = get_http_string(data, conn);
3146
3147 /* initialize a dynamic send-buffer */
3148 Curl_dyn_init(&req, DYN_HTTP_REQUEST);
3149
3150 /* make sure the header buffer is reset - if there are leftovers from a
3151 previous transfer */
3152 Curl_dyn_reset(&data->state.headerb);
3153
3154 /* add the main request stuff */
3155 /* GET/HEAD/POST/PUT */
3156 result = Curl_dyn_addf(&req, "%s ", request);
3157 if(!result)
3158 result = Curl_http_target(data, conn, &req);
3159 if(result) {
3160 Curl_dyn_free(&req);
3161 return result;
3162 }
3163
3164#ifndef CURL_DISABLE_ALTSVC
3165 if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) {
3166 altused = aprintf("Alt-Used: %s:%d\r\n",
3167 conn->conn_to_host.name, conn->conn_to_port);
3168 if(!altused) {
3169 Curl_dyn_free(&req);
3170 return CURLE_OUT_OF_MEMORY;
3171 }
3172 }
3173#endif
3174 result =
3175 Curl_dyn_addf(&req,
3176 " HTTP/%s\r\n" /* HTTP version */
3177 "%s" /* host */
3178 "%s" /* proxyuserpwd */
3179 "%s" /* userpwd */
3180 "%s" /* range */
3181 "%s" /* user agent */
3182 "%s" /* accept */
3183 "%s" /* TE: */
3184 "%s" /* accept-encoding */
3185 "%s" /* referer */
3186 "%s" /* Proxy-Connection */
3187 "%s" /* transfer-encoding */
3188 "%s",/* Alt-Used */
3189
3190 httpstring,
3191 (data->state.aptr.host?data->state.aptr.host:""),
3192 data->state.aptr.proxyuserpwd?
3193 data->state.aptr.proxyuserpwd:"",
3194 data->state.aptr.userpwd?data->state.aptr.userpwd:"",
3195 (data->state.use_range && data->state.aptr.rangeline)?
3196 data->state.aptr.rangeline:"",
3197 (data->set.str[STRING_USERAGENT] &&
3198 *data->set.str[STRING_USERAGENT] &&
3199 data->state.aptr.uagent)?
3200 data->state.aptr.uagent:"",
3201 p_accept?p_accept:"",
3202 data->state.aptr.te?data->state.aptr.te:"",
3203 (data->set.str[STRING_ENCODING] &&
3204 *data->set.str[STRING_ENCODING] &&
3205 data->state.aptr.accept_encoding)?
3206 data->state.aptr.accept_encoding:"",
3207 (data->state.referer && data->state.aptr.ref)?
3208 data->state.aptr.ref:"" /* Referer: <data> */,
3209#ifndef CURL_DISABLE_PROXY
3210 (conn->bits.httpproxy &&
3211 !conn->bits.tunnel_proxy &&
3212 !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
3213 !Curl_checkProxyheaders(data,
3214 conn,
3215 STRCONST("Proxy-Connection")))?
3216 "Proxy-Connection: Keep-Alive\r\n":"",
3217#else
3218 "",
3219#endif
3220 te,
3221 altused ? altused : ""
3222 );
3223
3224 /* clear userpwd and proxyuserpwd to avoid re-using old credentials
3225 * from re-used connections */
3226 Curl_safefree(data->state.aptr.userpwd);
3227 Curl_safefree(data->state.aptr.proxyuserpwd);
3228 free(altused);
3229
3230 if(result) {
3231 Curl_dyn_free(&req);
3232 return result;
3233 }
3234
3235 if(!(conn->handler->flags&PROTOPT_SSL) &&
3236 conn->httpversion != 20 &&
3237 (data->state.httpwant == CURL_HTTP_VERSION_2)) {
3238 /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
3239 over SSL */
3240 result = Curl_http2_request_upgrade(&req, data);
3241 if(result) {
3242 Curl_dyn_free(&req);
3243 return result;
3244 }
3245 }
3246
3247 result = Curl_http_cookies(data, conn, &req);
3248 if(!result)
3249 result = Curl_add_timecondition(data, &req);
3250 if(!result)
3251 result = Curl_add_custom_headers(data, FALSE, &req);
3252
3253 if(!result) {
3254 http->postdata = NULL; /* nothing to post at this point */
3255 if((httpreq == HTTPREQ_GET) ||
3256 (httpreq == HTTPREQ_HEAD))
3257 Curl_pgrsSetUploadSize(data, 0); /* nothing */
3258
3259 /* bodysend takes ownership of the 'req' memory on success */
3260 result = Curl_http_bodysend(data, conn, &req, httpreq);
3261 }
3262 if(result) {
3263 Curl_dyn_free(&req);
3264 return result;
3265 }
3266
3267 if((http->postsize > -1) &&
3268 (http->postsize <= data->req.writebytecount) &&
3269 (http->sending != HTTPSEND_REQUEST))
3270 data->req.upload_done = TRUE;
3271
3272 if(data->req.writebytecount) {
3273 /* if a request-body has been sent off, we make sure this progress is noted
3274 properly */
3275 Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
3276 if(Curl_pgrsUpdate(data))
3277 result = CURLE_ABORTED_BY_CALLBACK;
3278
3279 if(!http->postsize) {
3280 /* already sent the entire request body, mark the "upload" as
3281 complete */
3282 infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
3283 " out of %" CURL_FORMAT_CURL_OFF_T " bytes",
3284 data->req.writebytecount, http->postsize);
3285 data->req.upload_done = TRUE;
3286 data->req.keepon &= ~KEEP_SEND; /* we're done writing */
3287 data->req.exp100 = EXP100_SEND_DATA; /* already sent */
3288 Curl_expire_done(data, EXPIRE_100_TIMEOUT);
3289 }
3290 }
3291
3292 if((conn->httpversion == 20) && data->req.upload_chunky)
3293 /* upload_chunky was set above to set up the request in a chunky fashion,
3294 but is disabled here again to avoid that the chunked encoded version is
3295 actually used when sending the request body over h2 */
3296 data->req.upload_chunky = FALSE;
3297 return result;
3298}
3299
3300#endif /* USE_HYPER */
3301
3302typedef enum {
3303 STATUS_UNKNOWN, /* not enough data to tell yet */
3304 STATUS_DONE, /* a status line was read */
3305 STATUS_BAD /* not a status line */
3306} statusline;
3307
3308
3309/* Check a string for a prefix. Check no more than 'len' bytes */
3310static bool checkprefixmax(const char *prefix, const char *buffer, size_t len)
3311{
3312 size_t ch = CURLMIN(strlen(prefix), len);
3313 return curl_strnequal(prefix, buffer, ch);
3314}
3315
3316/*
3317 * checkhttpprefix()
3318 *
3319 * Returns TRUE if member of the list matches prefix of string
3320 */
3321static statusline
3322checkhttpprefix(struct Curl_easy *data,
3323 const char *s, size_t len)
3324{
3325 struct curl_slist *head = data->set.http200aliases;
3326 statusline rc = STATUS_BAD;
3327 statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
3328
3329 while(head) {
3330 if(checkprefixmax(head->data, s, len)) {
3331 rc = onmatch;
3332 break;
3333 }
3334 head = head->next;
3335 }
3336
3337 if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len)))
3338 rc = onmatch;
3339
3340 return rc;
3341}
3342
3343#ifndef CURL_DISABLE_RTSP
3344static statusline
3345checkrtspprefix(struct Curl_easy *data,
3346 const char *s, size_t len)
3347{
3348 statusline result = STATUS_BAD;
3349 statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
3350 (void)data; /* unused */
3351 if(checkprefixmax("RTSP/", s, len))
3352 result = onmatch;
3353
3354 return result;
3355}
3356#endif /* CURL_DISABLE_RTSP */
3357
3358static statusline
3359checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
3360 const char *s, size_t len)
3361{
3362#ifndef CURL_DISABLE_RTSP
3363 if(conn->handler->protocol & CURLPROTO_RTSP)
3364 return checkrtspprefix(data, s, len);
3365#else
3366 (void)conn;
3367#endif /* CURL_DISABLE_RTSP */
3368
3369 return checkhttpprefix(data, s, len);
3370}
3371
3372/*
3373 * Curl_http_header() parses a single response header.
3374 */
3375CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
3376 char *headp)
3377{
3378 CURLcode result;
3379 struct SingleRequest *k = &data->req;
3380 /* Check for Content-Length: header lines to get size */
3381 if(!k->http_bodyless &&
3382 !data->set.ignorecl && checkprefix("Content-Length:", headp)) {
3383 curl_off_t contentlength;
3384 CURLofft offt = curlx_strtoofft(headp + strlen("Content-Length:"),
3385 NULL, 10, &contentlength);
3386
3387 if(offt == CURL_OFFT_OK) {
3388 k->size = contentlength;
3389 k->maxdownload = k->size;
3390 }
3391 else if(offt == CURL_OFFT_FLOW) {
3392 /* out of range */
3393 if(data->set.max_filesize) {
3394 failf(data, "Maximum file size exceeded");
3395 return CURLE_FILESIZE_EXCEEDED;
3396 }
3397 streamclose(conn, "overflow content-length");
3398 infof(data, "Overflow Content-Length: value");
3399 }
3400 else {
3401 /* negative or just rubbish - bad HTTP */
3402 failf(data, "Invalid Content-Length: value");
3403 return CURLE_WEIRD_SERVER_REPLY;
3404 }
3405 }
3406 /* check for Content-Type: header lines to get the MIME-type */
3407 else if(checkprefix("Content-Type:", headp)) {
3408 char *contenttype = Curl_copy_header_value(headp);
3409 if(!contenttype)
3410 return CURLE_OUT_OF_MEMORY;
3411 if(!*contenttype)
3412 /* ignore empty data */
3413 free(contenttype);
3414 else {
3415 Curl_safefree(data->info.contenttype);
3416 data->info.contenttype = contenttype;
3417 }
3418 }
3419#ifndef CURL_DISABLE_PROXY
3420 else if((conn->httpversion == 10) &&
3421 conn->bits.httpproxy &&
3422 Curl_compareheader(headp,
3423 STRCONST("Proxy-Connection:"),
3424 STRCONST("keep-alive"))) {
3425 /*
3426 * When a HTTP/1.0 reply comes when using a proxy, the
3427 * 'Proxy-Connection: keep-alive' line tells us the
3428 * connection will be kept alive for our pleasure.
3429 * Default action for 1.0 is to close.
3430 */
3431 connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
3432 infof(data, "HTTP/1.0 proxy connection set to keep alive");
3433 }
3434 else if((conn->httpversion == 11) &&
3435 conn->bits.httpproxy &&
3436 Curl_compareheader(headp,
3437 STRCONST("Proxy-Connection:"),
3438 STRCONST("close"))) {
3439 /*
3440 * We get a HTTP/1.1 response from a proxy and it says it'll
3441 * close down after this transfer.
3442 */
3443 connclose(conn, "Proxy-Connection: asked to close after done");
3444 infof(data, "HTTP/1.1 proxy connection set close");
3445 }
3446#endif
3447 else if((conn->httpversion == 10) &&
3448 Curl_compareheader(headp,
3449 STRCONST("Connection:"),
3450 STRCONST("keep-alive"))) {
3451 /*
3452 * A HTTP/1.0 reply with the 'Connection: keep-alive' line
3453 * tells us the connection will be kept alive for our
3454 * pleasure. Default action for 1.0 is to close.
3455 *
3456 * [RFC2068, section 19.7.1] */
3457 connkeep(conn, "Connection keep-alive");
3458 infof(data, "HTTP/1.0 connection set to keep alive");
3459 }
3460 else if(Curl_compareheader(headp,
3461 STRCONST("Connection:"), STRCONST("close"))) {
3462 /*
3463 * [RFC 2616, section 8.1.2.1]
3464 * "Connection: close" is HTTP/1.1 language and means that
3465 * the connection will close when this request has been
3466 * served.
3467 */
3468 streamclose(conn, "Connection: close used");
3469 }
3470 else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) {
3471 /* One or more encodings. We check for chunked and/or a compression
3472 algorithm. */
3473 /*
3474 * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
3475 * means that the server will send a series of "chunks". Each
3476 * chunk starts with line with info (including size of the
3477 * coming block) (terminated with CRLF), then a block of data
3478 * with the previously mentioned size. There can be any amount
3479 * of chunks, and a chunk-data set to zero signals the
3480 * end-of-chunks. */
3481
3482 result = Curl_build_unencoding_stack(data,
3483 headp + strlen("Transfer-Encoding:"),
3484 TRUE);
3485 if(result)
3486 return result;
3487 if(!k->chunk) {
3488 /* if this isn't chunked, only close can signal the end of this transfer
3489 as Content-Length is said not to be trusted for transfer-encoding! */
3490 connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
3491 k->ignore_cl = TRUE;
3492 }
3493 }
3494 else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) &&
3495 data->set.str[STRING_ENCODING]) {
3496 /*
3497 * Process Content-Encoding. Look for the values: identity,
3498 * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
3499 * x-compress are the same as gzip and compress. (Sec 3.5 RFC
3500 * 2616). zlib cannot handle compress. However, errors are
3501 * handled further down when the response body is processed
3502 */
3503 result = Curl_build_unencoding_stack(data,
3504 headp + strlen("Content-Encoding:"),
3505 FALSE);
3506 if(result)
3507 return result;
3508 }
3509 else if(checkprefix("Retry-After:", headp)) {
3510 /* Retry-After = HTTP-date / delay-seconds */
3511 curl_off_t retry_after = 0; /* zero for unknown or "now" */
3512 time_t date = Curl_getdate_capped(headp + strlen("Retry-After:"));
3513 if(-1 == date) {
3514 /* not a date, try it as a decimal number */
3515 (void)curlx_strtoofft(headp + strlen("Retry-After:"),
3516 NULL, 10, &retry_after);
3517 }
3518 else
3519 /* convert date to number of seconds into the future */
3520 retry_after = date - time(NULL);
3521 data->info.retry_after = retry_after; /* store it */
3522 }
3523 else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) {
3524 /* Content-Range: bytes [num]-
3525 Content-Range: bytes: [num]-
3526 Content-Range: [num]-
3527 Content-Range: [asterisk]/[total]
3528
3529 The second format was added since Sun's webserver
3530 JavaWebServer/1.1.1 obviously sends the header this way!
3531 The third added since some servers use that!
3532 The forth means the requested range was unsatisfied.
3533 */
3534
3535 char *ptr = headp + strlen("Content-Range:");
3536
3537 /* Move forward until first digit or asterisk */
3538 while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
3539 ptr++;
3540
3541 /* if it truly stopped on a digit */
3542 if(ISDIGIT(*ptr)) {
3543 if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
3544 if(data->state.resume_from == k->offset)
3545 /* we asked for a resume and we got it */
3546 k->content_range = TRUE;
3547 }
3548 }
3549 else
3550 data->state.resume_from = 0; /* get everything */
3551 }
3552#if !defined(CURL_DISABLE_COOKIES)
3553 else if(data->cookies && data->state.cookie_engine &&
3554 checkprefix("Set-Cookie:", headp)) {
3555 /* If there is a custom-set Host: name, use it here, or else use real peer
3556 host name. */
3557 const char *host = data->state.aptr.cookiehost?
3558 data->state.aptr.cookiehost:conn->host.name;
3559 const bool secure_context =
3560 conn->handler->protocol&CURLPROTO_HTTPS ||
3561 strcasecompare("localhost", host) ||
3562 !strcmp(host, "127.0.0.1") ||
3563 !strcmp(host, "[::1]") ? TRUE : FALSE;
3564
3565 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
3566 CURL_LOCK_ACCESS_SINGLE);
3567 Curl_cookie_add(data, data->cookies, TRUE, FALSE,
3568 headp + strlen("Set-Cookie:"), host,
3569 data->state.up.path, secure_context);
3570 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
3571 }
3572#endif
3573 else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) &&
3574 (data->set.timecondition || data->set.get_filetime) ) {
3575 k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:"));
3576 if(data->set.get_filetime)
3577 data->info.filetime = k->timeofdoc;
3578 }
3579 else if((checkprefix("WWW-Authenticate:", headp) &&
3580 (401 == k->httpcode)) ||
3581 (checkprefix("Proxy-authenticate:", headp) &&
3582 (407 == k->httpcode))) {
3583
3584 bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
3585 char *auth = Curl_copy_header_value(headp);
3586 if(!auth)
3587 return CURLE_OUT_OF_MEMORY;
3588
3589 result = Curl_http_input_auth(data, proxy, auth);
3590
3591 free(auth);
3592
3593 if(result)
3594 return result;
3595 }
3596#ifdef USE_SPNEGO
3597 else if(checkprefix("Persistent-Auth:", headp)) {
3598 struct negotiatedata *negdata = &conn->negotiate;
3599 struct auth *authp = &data->state.authhost;
3600 if(authp->picked == CURLAUTH_NEGOTIATE) {
3601 char *persistentauth = Curl_copy_header_value(headp);
3602 if(!persistentauth)
3603 return CURLE_OUT_OF_MEMORY;
3604 negdata->noauthpersist = checkprefix("false", persistentauth)?
3605 TRUE:FALSE;
3606 negdata->havenoauthpersist = TRUE;
3607 infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
3608 negdata->noauthpersist, persistentauth);
3609 free(persistentauth);
3610 }
3611 }
3612#endif
3613 else if((k->httpcode >= 300 && k->httpcode < 400) &&
3614 checkprefix("Location:", headp) &&
3615 !data->req.location) {
3616 /* this is the URL that the server advises us to use instead */
3617 char *location = Curl_copy_header_value(headp);
3618 if(!location)
3619 return CURLE_OUT_OF_MEMORY;
3620 if(!*location)
3621 /* ignore empty data */
3622 free(location);
3623 else {
3624 data->req.location = location;
3625
3626 if(data->set.http_follow_location) {
3627 DEBUGASSERT(!data->req.newurl);
3628 data->req.newurl = strdup(data->req.location); /* clone */
3629 if(!data->req.newurl)
3630 return CURLE_OUT_OF_MEMORY;
3631
3632 /* some cases of POST and PUT etc needs to rewind the data
3633 stream at this point */
3634 result = http_perhapsrewind(data, conn);
3635 if(result)
3636 return result;
3637 }
3638 }
3639 }
3640
3641#ifndef CURL_DISABLE_HSTS
3642 /* If enabled, the header is incoming and this is over HTTPS */
3643 else if(data->hsts && checkprefix("Strict-Transport-Security:", headp) &&
3644 (conn->handler->flags & PROTOPT_SSL)) {
3645 CURLcode check =
3646 Curl_hsts_parse(data->hsts, data->state.up.hostname,
3647 headp + strlen("Strict-Transport-Security:"));
3648 if(check)
3649 infof(data, "Illegal STS header skipped");
3650#ifdef DEBUGBUILD
3651 else
3652 infof(data, "Parsed STS header fine (%zu entries)",
3653 data->hsts->list.size);
3654#endif
3655 }
3656#endif
3657#ifndef CURL_DISABLE_ALTSVC
3658 /* If enabled, the header is incoming and this is over HTTPS */
3659 else if(data->asi && checkprefix("Alt-Svc:", headp) &&
3660 ((conn->handler->flags & PROTOPT_SSL) ||
3661#ifdef CURLDEBUG
3662 /* allow debug builds to circumvent the HTTPS restriction */
3663 getenv("CURL_ALTSVC_HTTP")
3664#else
3665 0
3666#endif
3667 )) {
3668 /* the ALPN of the current request */
3669 enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
3670 result = Curl_altsvc_parse(data, data->asi,
3671 headp + strlen("Alt-Svc:"),
3672 id, conn->host.name,
3673 curlx_uitous(conn->remote_port));
3674 if(result)
3675 return result;
3676 }
3677#endif
3678 else if(conn->handler->protocol & CURLPROTO_RTSP) {
3679 result = Curl_rtsp_parseheader(data, headp);
3680 if(result)
3681 return result;
3682 }
3683 return CURLE_OK;
3684}
3685
3686/*
3687 * Called after the first HTTP response line (the status line) has been
3688 * received and parsed.
3689 */
3690
3691CURLcode Curl_http_statusline(struct Curl_easy *data,
3692 struct connectdata *conn)
3693{
3694 struct SingleRequest *k = &data->req;
3695 data->info.httpcode = k->httpcode;
3696
3697 data->info.httpversion = conn->httpversion;
3698 if(!data->state.httpversion ||
3699 data->state.httpversion > conn->httpversion)
3700 /* store the lowest server version we encounter */
3701 data->state.httpversion = conn->httpversion;
3702
3703 /*
3704 * This code executes as part of processing the header. As a
3705 * result, it's not totally clear how to interpret the
3706 * response code yet as that depends on what other headers may
3707 * be present. 401 and 407 may be errors, but may be OK
3708 * depending on how authentication is working. Other codes
3709 * are definitely errors, so give up here.
3710 */
3711 if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
3712 k->httpcode == 416) {
3713 /* "Requested Range Not Satisfiable", just proceed and
3714 pretend this is no error */
3715 k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
3716 }
3717
3718 if(conn->httpversion == 10) {
3719 /* Default action for HTTP/1.0 must be to close, unless
3720 we get one of those fancy headers that tell us the
3721 server keeps it open for us! */
3722 infof(data, "HTTP 1.0, assume close after body");
3723 connclose(conn, "HTTP/1.0 close after body");
3724 }
3725 else if(conn->httpversion == 20 ||
3726 (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) {
3727 DEBUGF(infof(data, "HTTP/2 found, allow multiplexing"));
3728 /* HTTP/2 cannot avoid multiplexing since it is a core functionality
3729 of the protocol */
3730 conn->bundle->multiuse = BUNDLE_MULTIPLEX;
3731 }
3732 else if(conn->httpversion >= 11 &&
3733 !conn->bits.close) {
3734 /* If HTTP version is >= 1.1 and connection is persistent */
3735 DEBUGF(infof(data,
3736 "HTTP 1.1 or later with persistent connection"));
3737 }
3738
3739 k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
3740 switch(k->httpcode) {
3741 case 304:
3742 /* (quote from RFC2616, section 10.3.5): The 304 response
3743 * MUST NOT contain a message-body, and thus is always
3744 * terminated by the first empty line after the header
3745 * fields. */
3746 if(data->set.timecondition)
3747 data->info.timecond = TRUE;
3748 /* FALLTHROUGH */
3749 case 204:
3750 /* (quote from RFC2616, section 10.2.5): The server has
3751 * fulfilled the request but does not need to return an
3752 * entity-body ... The 204 response MUST NOT include a
3753 * message-body, and thus is always terminated by the first
3754 * empty line after the header fields. */
3755 k->size = 0;
3756 k->maxdownload = 0;
3757 k->http_bodyless = TRUE;
3758 break;
3759 default:
3760 break;
3761 }
3762 return CURLE_OK;
3763}
3764
3765/* Content-Length must be ignored if any Transfer-Encoding is present in the
3766 response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is
3767 figured out here after all headers have been received but before the final
3768 call to the user's header callback, so that a valid content length can be
3769 retrieved by the user in the final call. */
3770CURLcode Curl_http_size(struct Curl_easy *data)
3771{
3772 struct SingleRequest *k = &data->req;
3773 if(data->req.ignore_cl || k->chunk) {
3774 k->size = k->maxdownload = -1;
3775 }
3776 else if(k->size != -1) {
3777 if(data->set.max_filesize &&
3778 k->size > data->set.max_filesize) {
3779 failf(data, "Maximum file size exceeded");
3780 return CURLE_FILESIZE_EXCEEDED;
3781 }
3782 Curl_pgrsSetDownloadSize(data, k->size);
3783 k->maxdownload = k->size;
3784 }
3785 return CURLE_OK;
3786}
3787
3788static CURLcode verify_header(struct Curl_easy *data)
3789{
3790 struct SingleRequest *k = &data->req;
3791 const char *header = Curl_dyn_ptr(&data->state.headerb);
3792 size_t hlen = Curl_dyn_len(&data->state.headerb);
3793 char *ptr = memchr(header, 0x00, hlen);
3794 if(ptr) {
3795 /* this is bad, bail out */
3796 failf(data, "Nul byte in header");
3797 return CURLE_WEIRD_SERVER_REPLY;
3798 }
3799 if(k->headerline < 2)
3800 /* the first "header" is the status-line and it has no colon */
3801 return CURLE_OK;
3802 ptr = memchr(header, ':', hlen);
3803 if(!ptr) {
3804 /* this is bad, bail out */
3805 failf(data, "Header without colon");
3806 return CURLE_WEIRD_SERVER_REPLY;
3807 }
3808 return CURLE_OK;
3809}
3810
3811/*
3812 * Read any HTTP header lines from the server and pass them to the client app.
3813 */
3814CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
3815 struct connectdata *conn,
3816 ssize_t *nread,
3817 bool *stop_reading)
3818{
3819 CURLcode result;
3820 struct SingleRequest *k = &data->req;
3821 ssize_t onread = *nread;
3822 char *ostr = k->str;
3823 char *headp;
3824 char *str_start;
3825 char *end_ptr;
3826
3827 /* header line within buffer loop */
3828 do {
3829 size_t rest_length;
3830 size_t full_length;
3831 int writetype;
3832
3833 /* str_start is start of line within buf */
3834 str_start = k->str;
3835
3836 /* data is in network encoding so use 0x0a instead of '\n' */
3837 end_ptr = memchr(str_start, 0x0a, *nread);
3838
3839 if(!end_ptr) {
3840 /* Not a complete header line within buffer, append the data to
3841 the end of the headerbuff. */
3842 result = Curl_dyn_addn(&data->state.headerb, str_start, *nread);
3843 if(result)
3844 return result;
3845
3846 if(!k->headerline) {
3847 /* check if this looks like a protocol header */
3848 statusline st =
3849 checkprotoprefix(data, conn,
3850 Curl_dyn_ptr(&data->state.headerb),
3851 Curl_dyn_len(&data->state.headerb));
3852
3853 if(st == STATUS_BAD) {
3854 /* this is not the beginning of a protocol first header line */
3855 k->header = FALSE;
3856 k->badheader = HEADER_ALLBAD;
3857 streamclose(conn, "bad HTTP: No end-of-message indicator");
3858 if(!data->set.http09_allowed) {
3859 failf(data, "Received HTTP/0.9 when not allowed");
3860 return CURLE_UNSUPPORTED_PROTOCOL;
3861 }
3862 break;
3863 }
3864 }
3865
3866 break; /* read more and try again */
3867 }
3868
3869 /* decrease the size of the remaining (supposed) header line */
3870 rest_length = (end_ptr - k->str) + 1;
3871 *nread -= (ssize_t)rest_length;
3872
3873 k->str = end_ptr + 1; /* move past new line */
3874
3875 full_length = k->str - str_start;
3876
3877 result = Curl_dyn_addn(&data->state.headerb, str_start, full_length);
3878 if(result)
3879 return result;
3880
3881 /****
3882 * We now have a FULL header line in 'headerb'.
3883 *****/
3884
3885 if(!k->headerline) {
3886 /* the first read header */
3887 statusline st = checkprotoprefix(data, conn,
3888 Curl_dyn_ptr(&data->state.headerb),
3889 Curl_dyn_len(&data->state.headerb));
3890 if(st == STATUS_BAD) {
3891 streamclose(conn, "bad HTTP: No end-of-message indicator");
3892 /* this is not the beginning of a protocol first header line */
3893 if(!data->set.http09_allowed) {
3894 failf(data, "Received HTTP/0.9 when not allowed");
3895 return CURLE_UNSUPPORTED_PROTOCOL;
3896 }
3897 k->header = FALSE;
3898 if(*nread)
3899 /* since there's more, this is a partial bad header */
3900 k->badheader = HEADER_PARTHEADER;
3901 else {
3902 /* this was all we read so it's all a bad header */
3903 k->badheader = HEADER_ALLBAD;
3904 *nread = onread;
3905 k->str = ostr;
3906 return CURLE_OK;
3907 }
3908 break;
3909 }
3910 }
3911
3912 /* headers are in network encoding so use 0x0a and 0x0d instead of '\n'
3913 and '\r' */
3914 headp = Curl_dyn_ptr(&data->state.headerb);
3915 if((0x0a == *headp) || (0x0d == *headp)) {
3916 size_t headerlen;
3917 /* Zero-length header line means end of headers! */
3918
3919 if('\r' == *headp)
3920 headp++; /* pass the \r byte */
3921 if('\n' == *headp)
3922 headp++; /* pass the \n byte */
3923
3924 if(100 <= k->httpcode && 199 >= k->httpcode) {
3925 /* "A user agent MAY ignore unexpected 1xx status responses." */
3926 switch(k->httpcode) {
3927 case 100:
3928 /*
3929 * We have made a HTTP PUT or POST and this is 1.1-lingo
3930 * that tells us that the server is OK with this and ready
3931 * to receive the data.
3932 * However, we'll get more headers now so we must get
3933 * back into the header-parsing state!
3934 */
3935 k->header = TRUE;
3936 k->headerline = 0; /* restart the header line counter */
3937
3938 /* if we did wait for this do enable write now! */
3939 if(k->exp100 > EXP100_SEND_DATA) {
3940 k->exp100 = EXP100_SEND_DATA;
3941 k->keepon |= KEEP_SEND;
3942 Curl_expire_done(data, EXPIRE_100_TIMEOUT);
3943 }
3944 break;
3945 case 101:
3946 /* Switching Protocols */
3947 if(k->upgr101 == UPGR101_REQUESTED) {
3948 /* Switching to HTTP/2 */
3949 infof(data, "Received 101");
3950 k->upgr101 = UPGR101_RECEIVED;
3951
3952 /* we'll get more headers (HTTP/2 response) */
3953 k->header = TRUE;
3954 k->headerline = 0; /* restart the header line counter */
3955
3956 /* switch to http2 now. The bytes after response headers
3957 are also processed here, otherwise they are lost. */
3958 result = Curl_http2_switched(data, k->str, *nread);
3959 if(result)
3960 return result;
3961 *nread = 0;
3962 }
3963 else {
3964 /* Switching to another protocol (e.g. WebSocket) */
3965 k->header = FALSE; /* no more header to parse! */
3966 }
3967 break;
3968 default:
3969 /* the status code 1xx indicates a provisional response, so
3970 we'll get another set of headers */
3971 k->header = TRUE;
3972 k->headerline = 0; /* restart the header line counter */
3973 break;
3974 }
3975 }
3976 else {
3977 k->header = FALSE; /* no more header to parse! */
3978
3979 if((k->size == -1) && !k->chunk && !conn->bits.close &&
3980 (conn->httpversion == 11) &&
3981 !(conn->handler->protocol & CURLPROTO_RTSP) &&
3982 data->state.httpreq != HTTPREQ_HEAD) {
3983 /* On HTTP 1.1, when connection is not to get closed, but no
3984 Content-Length nor Transfer-Encoding chunked have been
3985 received, according to RFC2616 section 4.4 point 5, we
3986 assume that the server will close the connection to
3987 signal the end of the document. */
3988 infof(data, "no chunk, no close, no size. Assume close to "
3989 "signal end");
3990 streamclose(conn, "HTTP: No end-of-message indicator");
3991 }
3992 }
3993
3994 if(!k->header) {
3995 result = Curl_http_size(data);
3996 if(result)
3997 return result;
3998 }
3999
4000 /* At this point we have some idea about the fate of the connection.
4001 If we are closing the connection it may result auth failure. */
4002#if defined(USE_NTLM)
4003 if(conn->bits.close &&
4004 (((data->req.httpcode == 401) &&
4005 (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
4006 ((data->req.httpcode == 407) &&
4007 (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
4008 infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
4009 data->state.authproblem = TRUE;
4010 }
4011#endif
4012#if defined(USE_SPNEGO)
4013 if(conn->bits.close &&
4014 (((data->req.httpcode == 401) &&
4015 (conn->http_negotiate_state == GSS_AUTHRECV)) ||
4016 ((data->req.httpcode == 407) &&
4017 (conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
4018 infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
4019 data->state.authproblem = TRUE;
4020 }
4021 if((conn->http_negotiate_state == GSS_AUTHDONE) &&
4022 (data->req.httpcode != 401)) {
4023 conn->http_negotiate_state = GSS_AUTHSUCC;
4024 }
4025 if((conn->proxy_negotiate_state == GSS_AUTHDONE) &&
4026 (data->req.httpcode != 407)) {
4027 conn->proxy_negotiate_state = GSS_AUTHSUCC;
4028 }
4029#endif
4030
4031 /* now, only output this if the header AND body are requested:
4032 */
4033 writetype = CLIENTWRITE_HEADER |
4034 (data->set.include_header ? CLIENTWRITE_BODY : 0) |
4035 ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
4036
4037 headerlen = Curl_dyn_len(&data->state.headerb);
4038 result = Curl_client_write(data, writetype,
4039 Curl_dyn_ptr(&data->state.headerb),
4040 headerlen);
4041 if(result)
4042 return result;
4043
4044 data->info.header_size += (long)headerlen;
4045 data->req.headerbytecount += (long)headerlen;
4046
4047 /*
4048 * When all the headers have been parsed, see if we should give
4049 * up and return an error.
4050 */
4051 if(http_should_fail(data)) {
4052 failf(data, "The requested URL returned error: %d",
4053 k->httpcode);
4054 return CURLE_HTTP_RETURNED_ERROR;
4055 }
4056
4057 data->req.deductheadercount =
4058 (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
4059
4060 /* Curl_http_auth_act() checks what authentication methods
4061 * that are available and decides which one (if any) to
4062 * use. It will set 'newurl' if an auth method was picked. */
4063 result = Curl_http_auth_act(data);
4064
4065 if(result)
4066 return result;
4067
4068 if(k->httpcode >= 300) {
4069 if((!conn->bits.authneg) && !conn->bits.close &&
4070 !conn->bits.rewindaftersend) {
4071 /*
4072 * General treatment of errors when about to send data. Including :
4073 * "417 Expectation Failed", while waiting for 100-continue.
4074 *
4075 * The check for close above is done simply because of something
4076 * else has already deemed the connection to get closed then
4077 * something else should've considered the big picture and we
4078 * avoid this check.
4079 *
4080 * rewindaftersend indicates that something has told libcurl to
4081 * continue sending even if it gets discarded
4082 */
4083
4084 switch(data->state.httpreq) {
4085 case HTTPREQ_PUT:
4086 case HTTPREQ_POST:
4087 case HTTPREQ_POST_FORM:
4088 case HTTPREQ_POST_MIME:
4089 /* We got an error response. If this happened before the whole
4090 * request body has been sent we stop sending and mark the
4091 * connection for closure after we've read the entire response.
4092 */
4093 Curl_expire_done(data, EXPIRE_100_TIMEOUT);
4094 if(!k->upload_done) {
4095 if((k->httpcode == 417) && data->state.expect100header) {
4096 /* 417 Expectation Failed - try again without the Expect
4097 header */
4098 infof(data, "Got 417 while waiting for a 100");
4099 data->state.disableexpect = TRUE;
4100 DEBUGASSERT(!data->req.newurl);
4101 data->req.newurl = strdup(data->state.url);
4102 Curl_done_sending(data, k);
4103 }
4104 else if(data->set.http_keep_sending_on_error) {
4105 infof(data, "HTTP error before end of send, keep sending");
4106 if(k->exp100 > EXP100_SEND_DATA) {
4107 k->exp100 = EXP100_SEND_DATA;
4108 k->keepon |= KEEP_SEND;
4109 }
4110 }
4111 else {
4112 infof(data, "HTTP error before end of send, stop sending");
4113 streamclose(conn, "Stop sending data before everything sent");
4114 result = Curl_done_sending(data, k);
4115 if(result)
4116 return result;
4117 k->upload_done = TRUE;
4118 if(data->state.expect100header)
4119 k->exp100 = EXP100_FAILED;
4120 }
4121 }
4122 break;
4123
4124 default: /* default label present to avoid compiler warnings */
4125 break;
4126 }
4127 }
4128
4129 if(conn->bits.rewindaftersend) {
4130 /* We rewind after a complete send, so thus we continue
4131 sending now */
4132 infof(data, "Keep sending data to get tossed away");
4133 k->keepon |= KEEP_SEND;
4134 }
4135 }
4136
4137 if(!k->header) {
4138 /*
4139 * really end-of-headers.
4140 *
4141 * If we requested a "no body", this is a good time to get
4142 * out and return home.
4143 */
4144 if(data->set.opt_no_body)
4145 *stop_reading = TRUE;
4146#ifndef CURL_DISABLE_RTSP
4147 else if((conn->handler->protocol & CURLPROTO_RTSP) &&
4148 (data->set.rtspreq == RTSPREQ_DESCRIBE) &&
4149 (k->size <= -1))
4150 /* Respect section 4.4 of rfc2326: If the Content-Length header is
4151 absent, a length 0 must be assumed. It will prevent libcurl from
4152 hanging on DESCRIBE request that got refused for whatever
4153 reason */
4154 *stop_reading = TRUE;
4155#endif
4156
4157 /* If max download size is *zero* (nothing) we already have
4158 nothing and can safely return ok now! But for HTTP/2, we'd
4159 like to call http2_handle_stream_close to properly close a
4160 stream. In order to do this, we keep reading until we
4161 close the stream. */
4162 if(0 == k->maxdownload
4163#if defined(USE_NGHTTP2)
4164 && !((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
4165 conn->httpversion == 20)
4166#endif
4167 )
4168 *stop_reading = TRUE;
4169
4170 if(*stop_reading) {
4171 /* we make sure that this socket isn't read more now */
4172 k->keepon &= ~KEEP_RECV;
4173 }
4174
4175 Curl_debug(data, CURLINFO_HEADER_IN, str_start, headerlen);
4176 break; /* exit header line loop */
4177 }
4178
4179 /* We continue reading headers, reset the line-based header */
4180 Curl_dyn_reset(&data->state.headerb);
4181 continue;
4182 }
4183
4184 /*
4185 * Checks for special headers coming up.
4186 */
4187
4188 writetype = CLIENTWRITE_HEADER;
4189 if(!k->headerline++) {
4190 /* This is the first header, it MUST be the error code line
4191 or else we consider this to be the body right away! */
4192 int httpversion_major;
4193 int rtspversion_major;
4194 int nc = 0;
4195#define HEADER1 headp /* no conversion needed, just use headp */
4196
4197 if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
4198 /*
4199 * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
4200 *
4201 * The response code is always a three-digit number in HTTP as the spec
4202 * says. We allow any three-digit number here, but we cannot make
4203 * guarantees on future behaviors since it isn't within the protocol.
4204 */
4205 char separator;
4206 char twoorthree[2];
4207 int httpversion = 0;
4208 char digit4 = 0;
4209 nc = sscanf(HEADER1,
4210 " HTTP/%1d.%1d%c%3d%c",
4211 &httpversion_major,
4212 &httpversion,
4213 &separator,
4214 &k->httpcode,
4215 &digit4);
4216
4217 if(nc == 1 && httpversion_major >= 2 &&
4218 2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) {
4219 conn->httpversion = 0;
4220 nc = 4;
4221 separator = ' ';
4222 }
4223
4224 /* There can only be a 4th response code digit stored in 'digit4' if
4225 all the other fields were parsed and stored first, so nc is 5 when
4226 digit4 a digit.
4227
4228 The sscanf() line above will also allow zero-prefixed and negative
4229 numbers, so we check for that too here.
4230 */
4231 else if(ISDIGIT(digit4) || (nc >= 4 && k->httpcode < 100)) {
4232 failf(data, "Unsupported response code in HTTP response");
4233 return CURLE_UNSUPPORTED_PROTOCOL;
4234 }
4235
4236 if((nc >= 4) && (' ' == separator)) {
4237 httpversion += 10 * httpversion_major;
4238 switch(httpversion) {
4239 case 10:
4240 case 11:
4241#ifdef USE_HTTP2
4242 case 20:
4243#endif
4244#ifdef ENABLE_QUIC
4245 case 30:
4246#endif
4247 conn->httpversion = (unsigned char)httpversion;
4248 break;
4249 default:
4250 failf(data, "Unsupported HTTP version (%u.%d) in response",
4251 httpversion/10, httpversion%10);
4252 return CURLE_UNSUPPORTED_PROTOCOL;
4253 }
4254
4255 if(k->upgr101 == UPGR101_RECEIVED) {
4256 /* supposedly upgraded to http2 now */
4257 if(conn->httpversion != 20)
4258 infof(data, "Lying server, not serving HTTP/2");
4259 }
4260 if(conn->httpversion < 20) {
4261 conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
4262 infof(data, "Mark bundle as not supporting multiuse");
4263 }
4264 }
4265 else if(!nc) {
4266 /* this is the real world, not a Nirvana
4267 NCSA 1.5.x returns this crap when asked for HTTP/1.1
4268 */
4269 nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode);
4270 conn->httpversion = 10;
4271
4272 /* If user has set option HTTP200ALIASES,
4273 compare header line against list of aliases
4274 */
4275 if(!nc) {
4276 statusline check =
4277 checkhttpprefix(data,
4278 Curl_dyn_ptr(&data->state.headerb),
4279 Curl_dyn_len(&data->state.headerb));
4280 if(check == STATUS_DONE) {
4281 nc = 1;
4282 k->httpcode = 200;
4283 conn->httpversion = 10;
4284 }
4285 }
4286 }
4287 else {
4288 failf(data, "Unsupported HTTP version in response");
4289 return CURLE_UNSUPPORTED_PROTOCOL;
4290 }
4291 }
4292 else if(conn->handler->protocol & CURLPROTO_RTSP) {
4293 char separator;
4294 int rtspversion;
4295 nc = sscanf(HEADER1,
4296 " RTSP/%1d.%1d%c%3d",
4297 &rtspversion_major,
4298 &rtspversion,
4299 &separator,
4300 &k->httpcode);
4301 if((nc == 4) && (' ' == separator)) {
4302 conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
4303 }
4304 else {
4305 nc = 0;
4306 }
4307 }
4308
4309 if(nc) {
4310 result = Curl_http_statusline(data, conn);
4311 if(result)
4312 return result;
4313 writetype |= CLIENTWRITE_STATUS;
4314 }
4315 else {
4316 k->header = FALSE; /* this is not a header line */
4317 break;
4318 }
4319 }
4320
4321 result = verify_header(data);
4322 if(result)
4323 return result;
4324
4325 result = Curl_http_header(data, conn, headp);
4326 if(result)
4327 return result;
4328
4329 /*
4330 * End of header-checks. Write them to the client.
4331 */
4332 if(data->set.include_header)
4333 writetype |= CLIENTWRITE_BODY;
4334 if(k->httpcode/100 == 1)
4335 writetype |= CLIENTWRITE_1XX;
4336
4337 Curl_debug(data, CURLINFO_HEADER_IN, headp,
4338 Curl_dyn_len(&data->state.headerb));
4339
4340 result = Curl_client_write(data, writetype, headp,
4341 Curl_dyn_len(&data->state.headerb));
4342 if(result)
4343 return result;
4344
4345 data->info.header_size += Curl_dyn_len(&data->state.headerb);
4346 data->req.headerbytecount += Curl_dyn_len(&data->state.headerb);
4347
4348 Curl_dyn_reset(&data->state.headerb);
4349 }
4350 while(*k->str); /* header line within buffer */
4351
4352 /* We might have reached the end of the header part here, but
4353 there might be a non-header part left in the end of the read
4354 buffer. */
4355
4356 return CURLE_OK;
4357}
4358
4359#endif /* CURL_DISABLE_HTTP */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette