VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/http.c@ 106165

最後變更 在這個檔案從106165是 104083,由 vboxsync 提交於 8 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

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

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