VirtualBox

source: vbox/trunk/src/libs/curl-8.11.1/lib/http.c@ 108333

最後變更 在這個檔案從108333是 108048,由 vboxsync 提交於 7 週 前

curl-8.11.1: Applied and adjusted our curl changes to 8.7.1. jiraref:VBP-1535

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

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