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