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 uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
1846 if(uc) {
1847 curl_url_cleanup(h);
1848 return CURLE_OUT_OF_MEMORY;
1849 }
1850
1851 curl_url_cleanup(h);
1852
1853 /* target or url */
1854 result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
1855 data->set.str[STRING_TARGET]:url);
1856 free(url);
1857 if(result)
1858 return (result);
1859
1860 if(strcasecompare("ftp", data->state.up.scheme)) {
1861 if(data->set.proxy_transfer_mode) {
1862 /* when doing ftp, append ;type=<a|i> if not present */
1863 char *type = strstr(path, ";type=");
1864 if(type && type[6] && type[7] == 0) {
1865 switch(Curl_raw_toupper(type[6])) {
1866 case 'A':
1867 case 'D':
1868 case 'I':
1869 break;
1870 default:
1871 type = NULL;
1872 }
1873 }
1874 if(!type) {
1875 result = Curl_dyn_addf(r, ";type=%c",
1876 data->state.prefer_ascii ? 'a' : 'i');
1877 if(result)
1878 return result;
1879 }
1880 }
1881 }
1882 }
1883
1884 else
1885 #else
1886 (void)conn; /* not used in disabled-proxy builds */
1887 #endif
1888 {
1889 result = Curl_dyn_add(r, path);
1890 if(result)
1891 return result;
1892 if(query)
1893 result = Curl_dyn_addf(r, "?%s", query);
1894 }
1895
1896 return result;
1897 }
1898
1899 #if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
set_post_reader(struct Curl_easy * data,Curl_HttpReq httpreq)1900 static CURLcode set_post_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
1901 {
1902 CURLcode result;
1903
1904 switch(httpreq) {
1905 #ifndef CURL_DISABLE_MIME
1906 case HTTPREQ_POST_MIME:
1907 data->state.mimepost = &data->set.mimepost;
1908 break;
1909 #endif
1910 #ifndef CURL_DISABLE_FORM_API
1911 case HTTPREQ_POST_FORM:
1912 /* Convert the form structure into a mime structure, then keep
1913 the conversion */
1914 if(!data->state.formp) {
1915 data->state.formp = calloc(1, sizeof(curl_mimepart));
1916 if(!data->state.formp)
1917 return CURLE_OUT_OF_MEMORY;
1918 Curl_mime_cleanpart(data->state.formp);
1919 result = Curl_getformdata(data, data->state.formp, data->set.httppost,
1920 data->state.fread_func);
1921 if(result) {
1922 Curl_safefree(data->state.formp);
1923 return result;
1924 }
1925 data->state.mimepost = data->state.formp;
1926 }
1927 break;
1928 #endif
1929 default:
1930 data->state.mimepost = NULL;
1931 break;
1932 }
1933
1934 switch(httpreq) {
1935 case HTTPREQ_POST_FORM:
1936 case HTTPREQ_POST_MIME:
1937 /* This is form posting using mime data. */
1938 #ifndef CURL_DISABLE_MIME
1939 if(data->state.mimepost) {
1940 const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
1941
1942 /* Read and seek body only. */
1943 data->state.mimepost->flags |= MIME_BODY_ONLY;
1944
1945 /* Prepare the mime structure headers & set content type. */
1946
1947 if(cthdr)
1948 for(cthdr += 13; *cthdr == ' '; cthdr++)
1949 ;
1950 else if(data->state.mimepost->kind == MIMEKIND_MULTIPART)
1951 cthdr = "multipart/form-data";
1952
1953 curl_mime_headers(data->state.mimepost, data->set.headers, 0);
1954 result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr,
1955 NULL, MIMESTRATEGY_FORM);
1956 if(result)
1957 return result;
1958 curl_mime_headers(data->state.mimepost, NULL, 0);
1959 result = Curl_creader_set_mime(data, data->state.mimepost);
1960 if(result)
1961 return result;
1962 }
1963 else
1964 #endif
1965 {
1966 result = Curl_creader_set_null(data);
1967 }
1968 data->state.infilesize = Curl_creader_total_length(data);
1969 return result;
1970
1971 default:
1972 return Curl_creader_set_null(data);
1973 }
1974 /* never reached */
1975 }
1976 #endif
1977
set_reader(struct Curl_easy * data,Curl_HttpReq httpreq)1978 static CURLcode set_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
1979 {
1980 CURLcode result = CURLE_OK;
1981 curl_off_t postsize = data->state.infilesize;
1982
1983 DEBUGASSERT(data->conn);
1984
1985 if(data->req.authneg) {
1986 return Curl_creader_set_null(data);
1987 }
1988
1989 switch(httpreq) {
1990 case HTTPREQ_PUT: /* Let's PUT the data to the server! */
1991 if(!postsize)
1992 result = Curl_creader_set_null(data);
1993 else
1994 result = Curl_creader_set_fread(data, postsize);
1995 return result;
1996
1997 #if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
1998 case HTTPREQ_POST_FORM:
1999 case HTTPREQ_POST_MIME:
2000 return set_post_reader(data, httpreq);
2001 #endif
2002
2003 case HTTPREQ_POST:
2004 /* this is the simple POST, using x-www-form-urlencoded style */
2005 /* the size of the post body */
2006 if(!postsize) {
2007 result = Curl_creader_set_null(data);
2008 }
2009 else if(data->set.postfields) {
2010 if(postsize > 0)
2011 result = Curl_creader_set_buf(data, data->set.postfields,
2012 (size_t)postsize);
2013 else
2014 result = Curl_creader_set_null(data);
2015 }
2016 else {
2017 /* we read the bytes from the callback. In case "chunked" encoding
2018 * is forced by the application, we disregard `postsize`. This is
2019 * a backward compatibility decision to earlier versions where
2020 * chunking disregarded this. See issue #13229. */
2021 bool chunked = FALSE;
2022 char *ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
2023 if(ptr) {
2024 /* Some kind of TE is requested, check if 'chunked' is chosen */
2025 chunked = Curl_compareheader(ptr, STRCONST("Transfer-Encoding:"),
2026 STRCONST("chunked"));
2027 }
2028 result = Curl_creader_set_fread(data, chunked? -1 : postsize);
2029 }
2030 return result;
2031
2032 default:
2033 /* HTTP GET/HEAD download, has no body, needs no Content-Length */
2034 data->state.infilesize = 0;
2035 return Curl_creader_set_null(data);
2036 }
2037 /* not reached */
2038 }
2039
http_resume(struct Curl_easy * data,Curl_HttpReq httpreq)2040 static CURLcode http_resume(struct Curl_easy *data, Curl_HttpReq httpreq)
2041 {
2042 if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
2043 data->state.resume_from) {
2044 /**********************************************************************
2045 * Resuming upload in HTTP means that we PUT or POST and that we have
2046 * got a resume_from value set. The resume value has already created
2047 * a Range: header that will be passed along. We need to "fast forward"
2048 * the file the given number of bytes and decrease the assume upload
2049 * file size before we continue this venture in the dark lands of HTTP.
2050 * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
2051 *********************************************************************/
2052
2053 if(data->state.resume_from < 0) {
2054 /*
2055 * This is meant to get the size of the present remote-file by itself.
2056 * We don't support this now. Bail out!
2057 */
2058 data->state.resume_from = 0;
2059 }
2060
2061 if(data->state.resume_from && !data->req.authneg) {
2062 /* only act on the first request */
2063 CURLcode result;
2064 result = Curl_creader_resume_from(data, data->state.resume_from);
2065 if(result) {
2066 failf(data, "Unable to resume from offset %" CURL_FORMAT_CURL_OFF_T,
2067 data->state.resume_from);
2068 return result;
2069 }
2070 }
2071 }
2072 return CURLE_OK;
2073 }
2074
Curl_http_req_set_reader(struct Curl_easy * data,Curl_HttpReq httpreq,const char ** tep)2075 CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
2076 Curl_HttpReq httpreq,
2077 const char **tep)
2078 {
2079 CURLcode result = CURLE_OK;
2080 const char *ptr;
2081
2082 result = set_reader(data, httpreq);
2083 if(result)
2084 return result;
2085
2086 result = http_resume(data, httpreq);
2087 if(result)
2088 return result;
2089
2090 ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
2091 if(ptr) {
2092 /* Some kind of TE is requested, check if 'chunked' is chosen */
2093 data->req.upload_chunky =
2094 Curl_compareheader(ptr,
2095 STRCONST("Transfer-Encoding:"), STRCONST("chunked"));
2096 if(data->req.upload_chunky &&
2097 Curl_use_http_1_1plus(data, data->conn) &&
2098 (data->conn->httpversion >= 20)) {
2099 infof(data, "suppressing chunked transfer encoding on connection "
2100 "using HTTP version 2 or higher");
2101 data->req.upload_chunky = FALSE;
2102 }
2103 }
2104 else {
2105 curl_off_t req_clen = Curl_creader_total_length(data);
2106
2107 if(req_clen < 0) {
2108 /* indeterminate request content length */
2109 if(Curl_use_http_1_1plus(data, data->conn)) {
2110 /* On HTTP/1.1, enable chunked, on HTTP/2 and later we do not
2111 * need it */
2112 data->req.upload_chunky = (data->conn->httpversion < 20);
2113 }
2114 else {
2115 failf(data, "Chunky upload is not supported by HTTP 1.0");
2116 return CURLE_UPLOAD_FAILED;
2117 }
2118 }
2119 else {
2120 /* else, no chunky upload */
2121 data->req.upload_chunky = FALSE;
2122 }
2123
2124 if(data->req.upload_chunky)
2125 *tep = "Transfer-Encoding: chunked\r\n";
2126 }
2127 return result;
2128 }
2129
addexpect(struct Curl_easy * data,struct dynbuf * r,bool * announced_exp100)2130 static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r,
2131 bool *announced_exp100)
2132 {
2133 CURLcode result;
2134 char *ptr;
2135
2136 *announced_exp100 = FALSE;
2137 /* Avoid Expect: 100-continue if Upgrade: is used */
2138 if(data->req.upgr101 != UPGR101_INIT)
2139 return CURLE_OK;
2140
2141 /* For really small puts we don't use Expect: headers at all, and for
2142 the somewhat bigger ones we allow the app to disable it. Just make
2143 sure that the expect100header is always set to the preferred value
2144 here. */
2145 ptr = Curl_checkheaders(data, STRCONST("Expect"));
2146 if(ptr) {
2147 *announced_exp100 =
2148 Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
2149 }
2150 else if(!data->state.disableexpect &&
2151 Curl_use_http_1_1plus(data, data->conn) &&
2152 (data->conn->httpversion < 20)) {
2153 /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
2154 Expect: 100-continue to the headers which actually speeds up post
2155 operations (as there is one packet coming back from the web server) */
2156 curl_off_t client_len = Curl_creader_client_length(data);
2157 if(client_len > EXPECT_100_THRESHOLD || client_len < 0) {
2158 result = Curl_dyn_addn(r, STRCONST("Expect: 100-continue\r\n"));
2159 if(result)
2160 return result;
2161 *announced_exp100 = TRUE;
2162 }
2163 }
2164 return CURLE_OK;
2165 }
2166
Curl_http_req_complete(struct Curl_easy * data,struct dynbuf * r,Curl_HttpReq httpreq)2167 CURLcode Curl_http_req_complete(struct Curl_easy *data,
2168 struct dynbuf *r, Curl_HttpReq httpreq)
2169 {
2170 CURLcode result = CURLE_OK;
2171 curl_off_t req_clen;
2172 bool announced_exp100 = FALSE;
2173
2174 DEBUGASSERT(data->conn);
2175 #ifndef USE_HYPER
2176 if(data->req.upload_chunky) {
2177 result = Curl_httpchunk_add_reader(data);
2178 if(result)
2179 return result;
2180 }
2181 #endif
2182
2183 /* Get the request body length that has been set up */
2184 req_clen = Curl_creader_total_length(data);
2185 switch(httpreq) {
2186 case HTTPREQ_PUT:
2187 case HTTPREQ_POST:
2188 #if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
2189 case HTTPREQ_POST_FORM:
2190 case HTTPREQ_POST_MIME:
2191 #endif
2192 /* We only set Content-Length and allow a custom Content-Length if
2193 we don't upload data chunked, as RFC2616 forbids us to set both
2194 kinds of headers (Transfer-Encoding: chunked and Content-Length).
2195 We do not override a custom "Content-Length" header, but during
2196 authentication negotiation that header is suppressed.
2197 */
2198 if(req_clen >= 0 && !data->req.upload_chunky &&
2199 (data->req.authneg ||
2200 !Curl_checkheaders(data, STRCONST("Content-Length")))) {
2201 /* we allow replacing this header if not during auth negotiation,
2202 although it isn't very wise to actually set your own */
2203 result = Curl_dyn_addf(r,
2204 "Content-Length: %" CURL_FORMAT_CURL_OFF_T
2205 "\r\n", req_clen);
2206 }
2207 if(result)
2208 goto out;
2209
2210 #ifndef CURL_DISABLE_MIME
2211 /* Output mime-generated headers. */
2212 if(data->state.mimepost &&
2213 ((httpreq == HTTPREQ_POST_FORM) || (httpreq == HTTPREQ_POST_MIME))) {
2214 struct curl_slist *hdr;
2215
2216 for(hdr = data->state.mimepost->curlheaders; hdr; hdr = hdr->next) {
2217 result = Curl_dyn_addf(r, "%s\r\n", hdr->data);
2218 if(result)
2219 goto out;
2220 }
2221 }
2222 #endif
2223 if(httpreq == HTTPREQ_POST) {
2224 if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
2225 result = Curl_dyn_addn(r, STRCONST("Content-Type: application/"
2226 "x-www-form-urlencoded\r\n"));
2227 if(result)
2228 goto out;
2229 }
2230 }
2231 result = addexpect(data, r, &announced_exp100);
2232 if(result)
2233 goto out;
2234 break;
2235 default:
2236 break;
2237 }
2238
2239 /* end of headers */
2240 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2241 if(!result) {
2242 Curl_pgrsSetUploadSize(data, req_clen);
2243 if(announced_exp100)
2244 result = http_exp100_add_reader(data);
2245 }
2246
2247 out:
2248 if(!result) {
2249 /* setup variables for the upcoming transfer */
2250 Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
2251 }
2252 return result;
2253 }
2254
2255 #if !defined(CURL_DISABLE_COOKIES)
2256
Curl_http_cookies(struct Curl_easy * data,struct connectdata * conn,struct dynbuf * r)2257 CURLcode Curl_http_cookies(struct Curl_easy *data,
2258 struct connectdata *conn,
2259 struct dynbuf *r)
2260 {
2261 CURLcode result = CURLE_OK;
2262 char *addcookies = NULL;
2263 bool linecap = FALSE;
2264 if(data->set.str[STRING_COOKIE] &&
2265 !Curl_checkheaders(data, STRCONST("Cookie")))
2266 addcookies = data->set.str[STRING_COOKIE];
2267
2268 if(data->cookies || addcookies) {
2269 struct Cookie *co = NULL; /* no cookies from start */
2270 int count = 0;
2271
2272 if(data->cookies && data->state.cookie_engine) {
2273 const char *host = data->state.aptr.cookiehost ?
2274 data->state.aptr.cookiehost : conn->host.name;
2275 const bool secure_context =
2276 conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
2277 strcasecompare("localhost", host) ||
2278 !strcmp(host, "127.0.0.1") ||
2279 !strcmp(host, "::1") ? TRUE : FALSE;
2280 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
2281 co = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path,
2282 secure_context);
2283 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
2284 }
2285 if(co) {
2286 struct Cookie *store = co;
2287 size_t clen = 8; /* hold the size of the generated Cookie: header */
2288 /* now loop through all cookies that matched */
2289 while(co) {
2290 if(co->value) {
2291 size_t add;
2292 if(!count) {
2293 result = Curl_dyn_addn(r, STRCONST("Cookie: "));
2294 if(result)
2295 break;
2296 }
2297 add = strlen(co->name) + strlen(co->value) + 1;
2298 if(clen + add >= MAX_COOKIE_HEADER_LEN) {
2299 infof(data, "Restricted outgoing cookies due to header size, "
2300 "'%s' not sent", co->name);
2301 linecap = TRUE;
2302 break;
2303 }
2304 result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"",
2305 co->name, co->value);
2306 if(result)
2307 break;
2308 clen += add + (count ? 2 : 0);
2309 count++;
2310 }
2311 co = co->next; /* next cookie please */
2312 }
2313 Curl_cookie_freelist(store);
2314 }
2315 if(addcookies && !result && !linecap) {
2316 if(!count)
2317 result = Curl_dyn_addn(r, STRCONST("Cookie: "));
2318 if(!result) {
2319 result = Curl_dyn_addf(r, "%s%s", count?"; ":"", addcookies);
2320 count++;
2321 }
2322 }
2323 if(count && !result)
2324 result = Curl_dyn_addn(r, STRCONST("\r\n"));
2325
2326 if(result)
2327 return result;
2328 }
2329 return result;
2330 }
2331 #endif
2332
Curl_http_range(struct Curl_easy * data,Curl_HttpReq httpreq)2333 CURLcode Curl_http_range(struct Curl_easy *data,
2334 Curl_HttpReq httpreq)
2335 {
2336 if(data->state.use_range) {
2337 /*
2338 * A range is selected. We use different headers whether we're downloading
2339 * or uploading and we always let customized headers override our internal
2340 * ones if any such are specified.
2341 */
2342 if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
2343 !Curl_checkheaders(data, STRCONST("Range"))) {
2344 /* if a line like this was already allocated, free the previous one */
2345 free(data->state.aptr.rangeline);
2346 data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
2347 data->state.range);
2348 }
2349 else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
2350 !Curl_checkheaders(data, STRCONST("Content-Range"))) {
2351 curl_off_t req_clen = Curl_creader_total_length(data);
2352 /* if a line like this was already allocated, free the previous one */
2353 free(data->state.aptr.rangeline);
2354
2355 if(data->set.set_resume_from < 0) {
2356 /* Upload resume was asked for, but we don't know the size of the
2357 remote part so we tell the server (and act accordingly) that we
2358 upload the whole file (again) */
2359 data->state.aptr.rangeline =
2360 aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
2361 "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
2362 req_clen - 1, req_clen);
2363
2364 }
2365 else if(data->state.resume_from) {
2366 /* This is because "resume" was selected */
2367 /* TODO: not sure if we want to send this header during authentication
2368 * negotiation, but test1084 checks for it. In which case we have a
2369 * "null" client reader installed that gives an unexpected length. */
2370 curl_off_t total_len = data->req.authneg?
2371 data->state.infilesize :
2372 (data->state.resume_from + req_clen);
2373 data->state.aptr.rangeline =
2374 aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
2375 "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
2376 data->state.range, total_len-1, total_len);
2377 }
2378 else {
2379 /* Range was selected and then we just pass the incoming range and
2380 append total size */
2381 data->state.aptr.rangeline =
2382 aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n",
2383 data->state.range, req_clen);
2384 }
2385 if(!data->state.aptr.rangeline)
2386 return CURLE_OUT_OF_MEMORY;
2387 }
2388 }
2389 return CURLE_OK;
2390 }
2391
Curl_http_firstwrite(struct Curl_easy * data)2392 CURLcode Curl_http_firstwrite(struct Curl_easy *data)
2393 {
2394 struct connectdata *conn = data->conn;
2395 struct SingleRequest *k = &data->req;
2396
2397 if(data->req.newurl) {
2398 if(conn->bits.close) {
2399 /* Abort after the headers if "follow Location" is set
2400 and we're set to close anyway. */
2401 k->keepon &= ~KEEP_RECV;
2402 k->done = TRUE;
2403 return CURLE_OK;
2404 }
2405 /* We have a new url to load, but since we want to be able to reuse this
2406 connection properly, we read the full response in "ignore more" */
2407 k->ignorebody = TRUE;
2408 infof(data, "Ignoring the response-body");
2409 }
2410 if(data->state.resume_from && !k->content_range &&
2411 (data->state.httpreq == HTTPREQ_GET) &&
2412 !k->ignorebody) {
2413
2414 if(k->size == data->state.resume_from) {
2415 /* The resume point is at the end of file, consider this fine even if it
2416 doesn't allow resume from here. */
2417 infof(data, "The entire document is already downloaded");
2418 streamclose(conn, "already downloaded");
2419 /* Abort download */
2420 k->keepon &= ~KEEP_RECV;
2421 k->done = TRUE;
2422 return CURLE_OK;
2423 }
2424
2425 /* we wanted to resume a download, although the server doesn't seem to
2426 * support this and we did this with a GET (if it wasn't a GET we did a
2427 * POST or PUT resume) */
2428 failf(data, "HTTP server doesn't seem to support "
2429 "byte ranges. Cannot resume.");
2430 return CURLE_RANGE_ERROR;
2431 }
2432
2433 if(data->set.timecondition && !data->state.range) {
2434 /* A time condition has been set AND no ranges have been requested. This
2435 seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct
2436 action for an HTTP/1.1 client */
2437
2438 if(!Curl_meets_timecondition(data, k->timeofdoc)) {
2439 k->done = TRUE;
2440 /* We're simulating an HTTP 304 from server so we return
2441 what should have been returned from the server */
2442 data->info.httpcode = 304;
2443 infof(data, "Simulate an HTTP 304 response");
2444 /* we abort the transfer before it is completed == we ruin the
2445 reuse ability. Close the connection */
2446 streamclose(conn, "Simulated 304 handling");
2447 return CURLE_OK;
2448 }
2449 } /* we have a time condition */
2450
2451 return CURLE_OK;
2452 }
2453
2454 #ifdef HAVE_LIBZ
Curl_transferencode(struct Curl_easy * data)2455 CURLcode Curl_transferencode(struct Curl_easy *data)
2456 {
2457 if(!Curl_checkheaders(data, STRCONST("TE")) &&
2458 data->set.http_transfer_encoding) {
2459 /* When we are to insert a TE: header in the request, we must also insert
2460 TE in a Connection: header, so we need to merge the custom provided
2461 Connection: header and prevent the original to get sent. Note that if
2462 the user has inserted his/her own TE: header we don't do this magic
2463 but then assume that the user will handle it all! */
2464 char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
2465 #define TE_HEADER "TE: gzip\r\n"
2466
2467 Curl_safefree(data->state.aptr.te);
2468
2469 if(cptr) {
2470 cptr = Curl_copy_header_value(cptr);
2471 if(!cptr)
2472 return CURLE_OUT_OF_MEMORY;
2473 }
2474
2475 /* Create the (updated) Connection: header */
2476 data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
2477 cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
2478
2479 free(cptr);
2480 if(!data->state.aptr.te)
2481 return CURLE_OUT_OF_MEMORY;
2482 }
2483 return CURLE_OK;
2484 }
2485 #endif
2486
2487 #ifndef USE_HYPER
2488 /*
2489 * Curl_http() gets called from the generic multi_do() function when an HTTP
2490 * request is to be performed. This creates and sends a properly constructed
2491 * HTTP request.
2492 */
Curl_http(struct Curl_easy * data,bool * done)2493 CURLcode Curl_http(struct Curl_easy *data, bool *done)
2494 {
2495 struct connectdata *conn = data->conn;
2496 CURLcode result = CURLE_OK;
2497 Curl_HttpReq httpreq;
2498 const char *te = ""; /* transfer-encoding */
2499 const char *request;
2500 const char *httpstring;
2501 struct dynbuf req;
2502 char *altused = NULL;
2503 const char *p_accept; /* Accept: string */
2504
2505 /* Always consider the DO phase done after this function call, even if there
2506 may be parts of the request that are not yet sent, since we can deal with
2507 the rest of the request in the PERFORM phase. */
2508 *done = TRUE;
2509
2510 switch(conn->alpn) {
2511 case CURL_HTTP_VERSION_3:
2512 DEBUGASSERT(Curl_conn_is_http3(data, conn, FIRSTSOCKET));
2513 break;
2514 case CURL_HTTP_VERSION_2:
2515 #ifndef CURL_DISABLE_PROXY
2516 if(!Curl_conn_is_http2(data, conn, FIRSTSOCKET) &&
2517 conn->bits.proxy && !conn->bits.tunnel_proxy
2518 ) {
2519 result = Curl_http2_switch(data, conn, FIRSTSOCKET);
2520 if(result)
2521 goto fail;
2522 }
2523 else
2524 #endif
2525 DEBUGASSERT(Curl_conn_is_http2(data, conn, FIRSTSOCKET));
2526 break;
2527 case CURL_HTTP_VERSION_1_1:
2528 /* continue with HTTP/1.x when explicitly requested */
2529 break;
2530 default:
2531 /* Check if user wants to use HTTP/2 with clear TCP */
2532 if(Curl_http2_may_switch(data, conn, FIRSTSOCKET)) {
2533 DEBUGF(infof(data, "HTTP/2 over clean TCP"));
2534 result = Curl_http2_switch(data, conn, FIRSTSOCKET);
2535 if(result)
2536 goto fail;
2537 }
2538 break;
2539 }
2540
2541 /* Add collecting of headers written to client. For a new connection,
2542 * we might have done that already, but reuse
2543 * or multiplex needs it here as well. */
2544 result = Curl_headers_init(data);
2545 if(result)
2546 goto fail;
2547
2548 result = Curl_http_host(data, conn);
2549 if(result)
2550 goto fail;
2551
2552 result = Curl_http_useragent(data);
2553 if(result)
2554 goto fail;
2555
2556 Curl_http_method(data, conn, &request, &httpreq);
2557
2558 /* setup the authentication headers */
2559 {
2560 char *pq = NULL;
2561 if(data->state.up.query) {
2562 pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
2563 if(!pq)
2564 return CURLE_OUT_OF_MEMORY;
2565 }
2566 result = Curl_http_output_auth(data, conn, request, httpreq,
2567 (pq ? pq : data->state.up.path), FALSE);
2568 free(pq);
2569 if(result)
2570 goto fail;
2571 }
2572
2573 Curl_safefree(data->state.aptr.ref);
2574 if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) {
2575 data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
2576 if(!data->state.aptr.ref)
2577 return CURLE_OUT_OF_MEMORY;
2578 }
2579
2580 if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
2581 data->set.str[STRING_ENCODING]) {
2582 Curl_safefree(data->state.aptr.accept_encoding);
2583 data->state.aptr.accept_encoding =
2584 aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
2585 if(!data->state.aptr.accept_encoding)
2586 return CURLE_OUT_OF_MEMORY;
2587 }
2588 else
2589 Curl_safefree(data->state.aptr.accept_encoding);
2590
2591 #ifdef HAVE_LIBZ
2592 /* we only consider transfer-encoding magic if libz support is built-in */
2593 result = Curl_transferencode(data);
2594 if(result)
2595 goto fail;
2596 #endif
2597
2598 result = Curl_http_req_set_reader(data, httpreq, &te);
2599 if(result)
2600 goto fail;
2601
2602 p_accept = Curl_checkheaders(data,
2603 STRCONST("Accept"))?NULL:"Accept: */*\r\n";
2604
2605 result = Curl_http_range(data, httpreq);
2606 if(result)
2607 goto fail;
2608
2609 httpstring = get_http_string(data, conn);
2610
2611 /* initialize a dynamic send-buffer */
2612 Curl_dyn_init(&req, DYN_HTTP_REQUEST);
2613
2614 /* make sure the header buffer is reset - if there are leftovers from a
2615 previous transfer */
2616 Curl_dyn_reset(&data->state.headerb);
2617
2618 /* add the main request stuff */
2619 /* GET/HEAD/POST/PUT */
2620 result = Curl_dyn_addf(&req, "%s ", request);
2621 if(!result)
2622 result = Curl_http_target(data, conn, &req);
2623 if(result) {
2624 Curl_dyn_free(&req);
2625 goto fail;
2626 }
2627
2628 #ifndef CURL_DISABLE_ALTSVC
2629 if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) {
2630 altused = aprintf("Alt-Used: %s:%d\r\n",
2631 conn->conn_to_host.name, conn->conn_to_port);
2632 if(!altused) {
2633 Curl_dyn_free(&req);
2634 return CURLE_OUT_OF_MEMORY;
2635 }
2636 }
2637 #endif
2638 result =
2639 Curl_dyn_addf(&req,
2640 " HTTP/%s\r\n" /* HTTP version */
2641 "%s" /* host */
2642 "%s" /* proxyuserpwd */
2643 "%s" /* userpwd */
2644 "%s" /* range */
2645 "%s" /* user agent */
2646 "%s" /* accept */
2647 "%s" /* TE: */
2648 "%s" /* accept-encoding */
2649 "%s" /* referer */
2650 "%s" /* Proxy-Connection */
2651 "%s" /* transfer-encoding */
2652 "%s",/* Alt-Used */
2653
2654 httpstring,
2655 (data->state.aptr.host?data->state.aptr.host:""),
2656 #ifndef CURL_DISABLE_PROXY
2657 data->state.aptr.proxyuserpwd?
2658 data->state.aptr.proxyuserpwd:"",
2659 #else
2660 "",
2661 #endif
2662 data->state.aptr.userpwd?data->state.aptr.userpwd:"",
2663 (data->state.use_range && data->state.aptr.rangeline)?
2664 data->state.aptr.rangeline:"",
2665 (data->set.str[STRING_USERAGENT] &&
2666 *data->set.str[STRING_USERAGENT] &&
2667 data->state.aptr.uagent)?
2668 data->state.aptr.uagent:"",
2669 p_accept?p_accept:"",
2670 data->state.aptr.te?data->state.aptr.te:"",
2671 (data->set.str[STRING_ENCODING] &&
2672 *data->set.str[STRING_ENCODING] &&
2673 data->state.aptr.accept_encoding)?
2674 data->state.aptr.accept_encoding:"",
2675 (data->state.referer && data->state.aptr.ref)?
2676 data->state.aptr.ref:"" /* Referer: <data> */,
2677 #ifndef CURL_DISABLE_PROXY
2678 (conn->bits.httpproxy &&
2679 !conn->bits.tunnel_proxy &&
2680 !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
2681 !Curl_checkProxyheaders(data,
2682 conn,
2683 STRCONST("Proxy-Connection")))?
2684 "Proxy-Connection: Keep-Alive\r\n":"",
2685 #else
2686 "",
2687 #endif
2688 te,
2689 altused ? altused : ""
2690 );
2691
2692 /* clear userpwd and proxyuserpwd to avoid reusing old credentials
2693 * from reused connections */
2694 Curl_safefree(data->state.aptr.userpwd);
2695 #ifndef CURL_DISABLE_PROXY
2696 Curl_safefree(data->state.aptr.proxyuserpwd);
2697 #endif
2698 free(altused);
2699
2700 if(result) {
2701 Curl_dyn_free(&req);
2702 goto fail;
2703 }
2704
2705 if(!(conn->handler->flags&PROTOPT_SSL) &&
2706 conn->httpversion < 20 &&
2707 (data->state.httpwant == CURL_HTTP_VERSION_2)) {
2708 /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
2709 over SSL */
2710 result = Curl_http2_request_upgrade(&req, data);
2711 if(result) {
2712 Curl_dyn_free(&req);
2713 return result;
2714 }
2715 }
2716
2717 result = Curl_http_cookies(data, conn, &req);
2718 #ifdef USE_WEBSOCKETS
2719 if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
2720 result = Curl_ws_request(data, &req);
2721 #endif
2722 if(!result)
2723 result = Curl_add_timecondition(data, &req);
2724 if(!result)
2725 result = Curl_add_custom_headers(data, FALSE, &req);
2726
2727 if(!result) {
2728 /* req_send takes ownership of the 'req' memory on success */
2729 result = Curl_http_req_complete(data, &req, httpreq);
2730 if(!result)
2731 result = Curl_req_send(data, &req);
2732 }
2733 Curl_dyn_free(&req);
2734 if(result)
2735 goto fail;
2736
2737 if((conn->httpversion >= 20) && data->req.upload_chunky)
2738 /* upload_chunky was set above to set up the request in a chunky fashion,
2739 but is disabled here again to avoid that the chunked encoded version is
2740 actually used when sending the request body over h2 */
2741 data->req.upload_chunky = FALSE;
2742 fail:
2743 if(CURLE_TOO_LARGE == result)
2744 failf(data, "HTTP request too large");
2745 return result;
2746 }
2747
2748 #endif /* USE_HYPER */
2749
2750 typedef enum {
2751 STATUS_UNKNOWN, /* not enough data to tell yet */
2752 STATUS_DONE, /* a status line was read */
2753 STATUS_BAD /* not a status line */
2754 } statusline;
2755
2756
2757 /* Check a string for a prefix. Check no more than 'len' bytes */
checkprefixmax(const char * prefix,const char * buffer,size_t len)2758 static bool checkprefixmax(const char *prefix, const char *buffer, size_t len)
2759 {
2760 size_t ch = CURLMIN(strlen(prefix), len);
2761 return curl_strnequal(prefix, buffer, ch);
2762 }
2763
2764 /*
2765 * checkhttpprefix()
2766 *
2767 * Returns TRUE if member of the list matches prefix of string
2768 */
2769 static statusline
checkhttpprefix(struct Curl_easy * data,const char * s,size_t len)2770 checkhttpprefix(struct Curl_easy *data,
2771 const char *s, size_t len)
2772 {
2773 struct curl_slist *head = data->set.http200aliases;
2774 statusline rc = STATUS_BAD;
2775 statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
2776
2777 while(head) {
2778 if(checkprefixmax(head->data, s, len)) {
2779 rc = onmatch;
2780 break;
2781 }
2782 head = head->next;
2783 }
2784
2785 if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len)))
2786 rc = onmatch;
2787
2788 return rc;
2789 }
2790
2791 #ifndef CURL_DISABLE_RTSP
2792 static statusline
checkrtspprefix(struct Curl_easy * data,const char * s,size_t len)2793 checkrtspprefix(struct Curl_easy *data,
2794 const char *s, size_t len)
2795 {
2796 statusline result = STATUS_BAD;
2797 statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
2798 (void)data; /* unused */
2799 if(checkprefixmax("RTSP/", s, len))
2800 result = onmatch;
2801
2802 return result;
2803 }
2804 #endif /* CURL_DISABLE_RTSP */
2805
2806 static statusline
checkprotoprefix(struct Curl_easy * data,struct connectdata * conn,const char * s,size_t len)2807 checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
2808 const char *s, size_t len)
2809 {
2810 #ifndef CURL_DISABLE_RTSP
2811 if(conn->handler->protocol & CURLPROTO_RTSP)
2812 return checkrtspprefix(data, s, len);
2813 #else
2814 (void)conn;
2815 #endif /* CURL_DISABLE_RTSP */
2816
2817 return checkhttpprefix(data, s, len);
2818 }
2819
2820 /* HTTP header has field name `n` (a string constant) */
2821 #define HD_IS(hd, hdlen, n) \
2822 (((hdlen) >= (sizeof(n)-1)) && curl_strnequal((n), (hd), (sizeof(n)-1)))
2823
2824 #define HD_VAL(hd, hdlen, n) \
2825 ((((hdlen) >= (sizeof(n)-1)) && \
2826 curl_strnequal((n), (hd), (sizeof(n)-1)))? (hd + (sizeof(n)-1)) : NULL)
2827
2828 /* HTTP header has field name `n` (a string constant) and contains `v`
2829 * (a string constant) in its value(s) */
2830 #define HD_IS_AND_SAYS(hd, hdlen, n, v) \
2831 (HD_IS(hd, hdlen, n) && \
2832 ((hdlen) > ((sizeof(n)-1) + (sizeof(v)-1))) && \
2833 Curl_compareheader(hd, STRCONST(n), STRCONST(v)))
2834
2835 /*
2836 * Curl_http_header() parses a single response header.
2837 */
Curl_http_header(struct Curl_easy * data,const char * hd,size_t hdlen)2838 CURLcode Curl_http_header(struct Curl_easy *data,
2839 const char *hd, size_t hdlen)
2840 {
2841 struct connectdata *conn = data->conn;
2842 CURLcode result;
2843 struct SingleRequest *k = &data->req;
2844 const char *v;
2845
2846 switch(hd[0]) {
2847 case 'a':
2848 case 'A':
2849 #ifndef CURL_DISABLE_ALTSVC
2850 v = (data->asi &&
2851 ((data->conn->handler->flags & PROTOPT_SSL) ||
2852 #ifdef CURLDEBUG
2853 /* allow debug builds to circumvent the HTTPS restriction */
2854 getenv("CURL_ALTSVC_HTTP")
2855 #else
2856 0
2857 #endif
2858 ))? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
2859 if(v) {
2860 /* the ALPN of the current request */
2861 enum alpnid id = (conn->httpversion == 30)? ALPN_h3 :
2862 (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
2863 return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
2864 curlx_uitous((unsigned int)conn->remote_port));
2865 }
2866 #endif
2867 break;
2868 case 'c':
2869 case 'C':
2870 /* Check for Content-Length: header lines to get size */
2871 v = (!k->http_bodyless && !data->set.ignorecl)?
2872 HD_VAL(hd, hdlen, "Content-Length:") : NULL;
2873 if(v) {
2874 curl_off_t contentlength;
2875 CURLofft offt = curlx_strtoofft(v, NULL, 10, &contentlength);
2876
2877 if(offt == CURL_OFFT_OK) {
2878 k->size = contentlength;
2879 k->maxdownload = k->size;
2880 }
2881 else if(offt == CURL_OFFT_FLOW) {
2882 /* out of range */
2883 if(data->set.max_filesize) {
2884 failf(data, "Maximum file size exceeded");
2885 return CURLE_FILESIZE_EXCEEDED;
2886 }
2887 streamclose(conn, "overflow content-length");
2888 infof(data, "Overflow Content-Length: value");
2889 }
2890 else {
2891 /* negative or just rubbish - bad HTTP */
2892 failf(data, "Invalid Content-Length: value");
2893 return CURLE_WEIRD_SERVER_REPLY;
2894 }
2895 return CURLE_OK;
2896 }
2897 v = (!k->http_bodyless && data->set.str[STRING_ENCODING])?
2898 HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
2899 if(v) {
2900 /*
2901 * Process Content-Encoding. Look for the values: identity,
2902 * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
2903 * x-compress are the same as gzip and compress. (Sec 3.5 RFC
2904 * 2616). zlib cannot handle compress. However, errors are
2905 * handled further down when the response body is processed
2906 */
2907 return Curl_build_unencoding_stack(data, v, FALSE);
2908 }
2909 /* check for Content-Type: header lines to get the MIME-type */
2910 v = HD_VAL(hd, hdlen, "Content-Type:");
2911 if(v) {
2912 char *contenttype = Curl_copy_header_value(hd);
2913 if(!contenttype)
2914 return CURLE_OUT_OF_MEMORY;
2915 if(!*contenttype)
2916 /* ignore empty data */
2917 free(contenttype);
2918 else {
2919 Curl_safefree(data->info.contenttype);
2920 data->info.contenttype = contenttype;
2921 }
2922 return CURLE_OK;
2923 }
2924 if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
2925 /*
2926 * [RFC 2616, section 8.1.2.1]
2927 * "Connection: close" is HTTP/1.1 language and means that
2928 * the connection will close when this request has been
2929 * served.
2930 */
2931 streamclose(conn, "Connection: close used");
2932 return CURLE_OK;
2933 }
2934 if((conn->httpversion == 10) &&
2935 HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
2936 /*
2937 * An HTTP/1.0 reply with the 'Connection: keep-alive' line
2938 * tells us the connection will be kept alive for our
2939 * pleasure. Default action for 1.0 is to close.
2940 *
2941 * [RFC2068, section 19.7.1] */
2942 connkeep(conn, "Connection keep-alive");
2943 infof(data, "HTTP/1.0 connection set to keep alive");
2944 return CURLE_OK;
2945 }
2946 v = !k->http_bodyless? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
2947 if(v) {
2948 /* Content-Range: bytes [num]-
2949 Content-Range: bytes: [num]-
2950 Content-Range: [num]-
2951 Content-Range: [asterisk]/[total]
2952
2953 The second format was added since Sun's webserver
2954 JavaWebServer/1.1.1 obviously sends the header this way!
2955 The third added since some servers use that!
2956 The fourth means the requested range was unsatisfied.
2957 */
2958
2959 const char *ptr = v;
2960
2961 /* Move forward until first digit or asterisk */
2962 while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
2963 ptr++;
2964
2965 /* if it truly stopped on a digit */
2966 if(ISDIGIT(*ptr)) {
2967 if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
2968 if(data->state.resume_from == k->offset)
2969 /* we asked for a resume and we got it */
2970 k->content_range = TRUE;
2971 }
2972 }
2973 else if(k->httpcode < 300)
2974 data->state.resume_from = 0; /* get everything */
2975 }
2976 break;
2977 case 'l':
2978 case 'L':
2979 v = (!k->http_bodyless &&
2980 (data->set.timecondition || data->set.get_filetime))?
2981 HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
2982 if(v) {
2983 k->timeofdoc = Curl_getdate_capped(v);
2984 if(data->set.get_filetime)
2985 data->info.filetime = k->timeofdoc;
2986 return CURLE_OK;
2987 }
2988 if((k->httpcode >= 300 && k->httpcode < 400) &&
2989 HD_IS(hd, hdlen, "Location:") &&
2990 !data->req.location) {
2991 /* this is the URL that the server advises us to use instead */
2992 char *location = Curl_copy_header_value(hd);
2993 if(!location)
2994 return CURLE_OUT_OF_MEMORY;
2995 if(!*location)
2996 /* ignore empty data */
2997 free(location);
2998 else {
2999 data->req.location = location;
3000
3001 if(data->set.http_follow_location) {
3002 DEBUGASSERT(!data->req.newurl);
3003 data->req.newurl = strdup(data->req.location); /* clone */
3004 if(!data->req.newurl)
3005 return CURLE_OUT_OF_MEMORY;
3006
3007 /* some cases of POST and PUT etc needs to rewind the data
3008 stream at this point */
3009 result = http_perhapsrewind(data, conn);
3010 if(result)
3011 return result;
3012
3013 /* mark the next request as a followed location: */
3014 data->state.this_is_a_follow = TRUE;
3015 }
3016 }
3017 }
3018 break;
3019 case 'p':
3020 case 'P':
3021 #ifndef CURL_DISABLE_PROXY
3022 v = HD_VAL(hd, hdlen, "Proxy-Connection:");
3023 if(v) {
3024 if((conn->httpversion == 10) && conn->bits.httpproxy &&
3025 HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
3026 /*
3027 * When an HTTP/1.0 reply comes when using a proxy, the
3028 * 'Proxy-Connection: keep-alive' line tells us the
3029 * connection will be kept alive for our pleasure.
3030 * Default action for 1.0 is to close.
3031 */
3032 connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
3033 infof(data, "HTTP/1.0 proxy connection set to keep alive");
3034 }
3035 else if((conn->httpversion == 11) && conn->bits.httpproxy &&
3036 HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
3037 /*
3038 * We get an HTTP/1.1 response from a proxy and it says it'll
3039 * close down after this transfer.
3040 */
3041 connclose(conn, "Proxy-Connection: asked to close after done");
3042 infof(data, "HTTP/1.1 proxy connection set close");
3043 }
3044 return CURLE_OK;
3045 }
3046 #endif
3047 if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) {
3048 char *auth = Curl_copy_header_value(hd);
3049 if(!auth)
3050 return CURLE_OUT_OF_MEMORY;
3051 result = Curl_http_input_auth(data, TRUE, auth);
3052 free(auth);
3053 return result;
3054 }
3055 #ifdef USE_SPNEGO
3056 if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
3057 struct negotiatedata *negdata = &conn->negotiate;
3058 struct auth *authp = &data->state.authhost;
3059 if(authp->picked == CURLAUTH_NEGOTIATE) {
3060 char *persistentauth = Curl_copy_header_value(hd);
3061 if(!persistentauth)
3062 return CURLE_OUT_OF_MEMORY;
3063 negdata->noauthpersist = checkprefix("false", persistentauth)?
3064 TRUE:FALSE;
3065 negdata->havenoauthpersist = TRUE;
3066 infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
3067 negdata->noauthpersist, persistentauth);
3068 free(persistentauth);
3069 }
3070 }
3071 #endif
3072 break;
3073 case 'r':
3074 case 'R':
3075 v = HD_VAL(hd, hdlen, "Retry-After:");
3076 if(v) {
3077 /* Retry-After = HTTP-date / delay-seconds */
3078 curl_off_t retry_after = 0; /* zero for unknown or "now" */
3079 /* Try it as a decimal number, if it works it is not a date */
3080 (void)curlx_strtoofft(v, NULL, 10, &retry_after);
3081 if(!retry_after) {
3082 time_t date = Curl_getdate_capped(v);
3083 if(-1 != date)
3084 /* convert date to number of seconds into the future */
3085 retry_after = date - time(NULL);
3086 }
3087 data->info.retry_after = retry_after; /* store it */
3088 return CURLE_OK;
3089 }
3090 break;
3091 case 's':
3092 case 'S':
3093 #if !defined(CURL_DISABLE_COOKIES)
3094 v = (data->cookies && data->state.cookie_engine)?
3095 HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
3096 if(v) {
3097 /* If there is a custom-set Host: name, use it here, or else use
3098 * real peer host name. */
3099 const char *host = data->state.aptr.cookiehost?
3100 data->state.aptr.cookiehost:conn->host.name;
3101 const bool secure_context =
3102 conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
3103 strcasecompare("localhost", host) ||
3104 !strcmp(host, "127.0.0.1") ||
3105 !strcmp(host, "::1") ? TRUE : FALSE;
3106
3107 Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
3108 CURL_LOCK_ACCESS_SINGLE);
3109 Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
3110 data->state.up.path, secure_context);
3111 Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
3112 return CURLE_OK;
3113 }
3114 #endif
3115 #ifndef CURL_DISABLE_HSTS
3116 /* If enabled, the header is incoming and this is over HTTPS */
3117 v = (data->hsts &&
3118 ((conn->handler->flags & PROTOPT_SSL) ||
3119 #ifdef CURLDEBUG
3120 /* allow debug builds to circumvent the HTTPS restriction */
3121 getenv("CURL_HSTS_HTTP")
3122 #else
3123 0
3124 #endif
3125 )
3126 )? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
3127 if(v) {
3128 CURLcode check =
3129 Curl_hsts_parse(data->hsts, conn->host.name, v);
3130 if(check)
3131 infof(data, "Illegal STS header skipped");
3132 #ifdef DEBUGBUILD
3133 else
3134 infof(data, "Parsed STS header fine (%zu entries)",
3135 data->hsts->list.size);
3136 #endif
3137 }
3138 #endif
3139 break;
3140 case 't':
3141 case 'T':
3142 v = !k->http_bodyless? HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
3143 if(v) {
3144 /* One or more encodings. We check for chunked and/or a compression
3145 algorithm. */
3146 /*
3147 * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
3148 * means that the server will send a series of "chunks". Each
3149 * chunk starts with line with info (including size of the
3150 * coming block) (terminated with CRLF), then a block of data
3151 * with the previously mentioned size. There can be any amount
3152 * of chunks, and a chunk-data set to zero signals the
3153 * end-of-chunks. */
3154
3155 result = Curl_build_unencoding_stack(data, v, TRUE);
3156 if(result)
3157 return result;
3158 if(!k->chunk && data->set.http_transfer_encoding) {
3159 /* if this isn't chunked, only close can signal the end of this
3160 * transfer as Content-Length is said not to be trusted for
3161 * transfer-encoding! */
3162 connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
3163 k->ignore_cl = TRUE;
3164 }
3165 return CURLE_OK;
3166 }
3167 break;
3168 case 'w':
3169 case 'W':
3170 if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) {
3171 char *auth = Curl_copy_header_value(hd);
3172 if(!auth)
3173 return CURLE_OUT_OF_MEMORY;
3174 result = Curl_http_input_auth(data, FALSE, auth);
3175 free(auth);
3176 return result;
3177 }
3178 break;
3179 }
3180
3181 if(conn->handler->protocol & CURLPROTO_RTSP) {
3182 result = Curl_rtsp_parseheader(data, hd);
3183 if(result)
3184 return result;
3185 }
3186 return CURLE_OK;
3187 }
3188
3189 /*
3190 * Called after the first HTTP response line (the status line) has been
3191 * received and parsed.
3192 */
Curl_http_statusline(struct Curl_easy * data,struct connectdata * conn)3193 CURLcode Curl_http_statusline(struct Curl_easy *data,
3194 struct connectdata *conn)
3195 {
3196 struct SingleRequest *k = &data->req;
3197
3198 switch(k->httpversion) {
3199 case 10:
3200 case 11:
3201 #ifdef USE_HTTP2
3202 case 20:
3203 #endif
3204 #ifdef USE_HTTP3
3205 case 30:
3206 #endif
3207 /* no major version switch mid-connection */
3208 if(conn->httpversion &&
3209 (k->httpversion/10 != conn->httpversion/10)) {
3210 failf(data, "Version mismatch (from HTTP/%u to HTTP/%u)",
3211 conn->httpversion/10, k->httpversion/10);
3212 return CURLE_UNSUPPORTED_PROTOCOL;
3213 }
3214 break;
3215 default:
3216 failf(data, "Unsupported HTTP version (%u.%d) in response",
3217 k->httpversion/10, k->httpversion%10);
3218 return CURLE_UNSUPPORTED_PROTOCOL;
3219 }
3220
3221 data->info.httpcode = k->httpcode;
3222 data->info.httpversion = k->httpversion;
3223 conn->httpversion = (unsigned char)k->httpversion;
3224
3225 if(!data->state.httpversion || data->state.httpversion > k->httpversion)
3226 /* store the lowest server version we encounter */
3227 data->state.httpversion = (unsigned char)k->httpversion;
3228
3229 /*
3230 * This code executes as part of processing the header. As a
3231 * result, it's not totally clear how to interpret the
3232 * response code yet as that depends on what other headers may
3233 * be present. 401 and 407 may be errors, but may be OK
3234 * depending on how authentication is working. Other codes
3235 * are definitely errors, so give up here.
3236 */
3237 if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
3238 k->httpcode == 416) {
3239 /* "Requested Range Not Satisfiable", just proceed and
3240 pretend this is no error */
3241 k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
3242 }
3243
3244 if(k->httpversion == 10) {
3245 /* Default action for HTTP/1.0 must be to close, unless
3246 we get one of those fancy headers that tell us the
3247 server keeps it open for us! */
3248 infof(data, "HTTP 1.0, assume close after body");
3249 connclose(conn, "HTTP/1.0 close after body");
3250 }
3251 else if(k->httpversion == 20 ||
3252 (k->upgr101 == UPGR101_H2 && k->httpcode == 101)) {
3253 DEBUGF(infof(data, "HTTP/2 found, allow multiplexing"));
3254 /* HTTP/2 cannot avoid multiplexing since it is a core functionality
3255 of the protocol */
3256 conn->bundle->multiuse = BUNDLE_MULTIPLEX;
3257 }
3258 else if(k->httpversion >= 11 && !conn->bits.close) {
3259 /* If HTTP version is >= 1.1 and connection is persistent */
3260 DEBUGF(infof(data, "HTTP 1.1 or later with persistent connection"));
3261 }
3262
3263 k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
3264 switch(k->httpcode) {
3265 case 304:
3266 /* (quote from RFC2616, section 10.3.5): The 304 response
3267 * MUST NOT contain a message-body, and thus is always
3268 * terminated by the first empty line after the header
3269 * fields. */
3270 if(data->set.timecondition)
3271 data->info.timecond = TRUE;
3272 FALLTHROUGH();
3273 case 204:
3274 /* (quote from RFC2616, section 10.2.5): The server has
3275 * fulfilled the request but does not need to return an
3276 * entity-body ... The 204 response MUST NOT include a
3277 * message-body, and thus is always terminated by the first
3278 * empty line after the header fields. */
3279 k->size = 0;
3280 k->maxdownload = 0;
3281 k->http_bodyless = TRUE;
3282 break;
3283 default:
3284 break;
3285 }
3286 return CURLE_OK;
3287 }
3288
3289 /* Content-Length must be ignored if any Transfer-Encoding is present in the
3290 response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is
3291 figured out here after all headers have been received but before the final
3292 call to the user's header callback, so that a valid content length can be
3293 retrieved by the user in the final call. */
Curl_http_size(struct Curl_easy * data)3294 CURLcode Curl_http_size(struct Curl_easy *data)
3295 {
3296 struct SingleRequest *k = &data->req;
3297 if(data->req.ignore_cl || k->chunk) {
3298 k->size = k->maxdownload = -1;
3299 }
3300 else if(k->size != -1) {
3301 if(data->set.max_filesize &&
3302 k->size > data->set.max_filesize) {
3303 failf(data, "Maximum file size exceeded");
3304 return CURLE_FILESIZE_EXCEEDED;
3305 }
3306 Curl_pgrsSetDownloadSize(data, k->size);
3307 k->maxdownload = k->size;
3308 }
3309 return CURLE_OK;
3310 }
3311
verify_header(struct Curl_easy * data,const char * hd,size_t hdlen)3312 static CURLcode verify_header(struct Curl_easy *data,
3313 const char *hd, size_t hdlen)
3314 {
3315 struct SingleRequest *k = &data->req;
3316 char *ptr = memchr(hd, 0x00, hdlen);
3317 if(ptr) {
3318 /* this is bad, bail out */
3319 failf(data, "Nul byte in header");
3320 return CURLE_WEIRD_SERVER_REPLY;
3321 }
3322 if(k->headerline < 2)
3323 /* the first "header" is the status-line and it has no colon */
3324 return CURLE_OK;
3325 if(((hd[0] == ' ') || (hd[0] == '\t')) && k->headerline > 2)
3326 /* line folding, can't happen on line 2 */
3327 ;
3328 else {
3329 ptr = memchr(hd, ':', hdlen);
3330 if(!ptr) {
3331 /* this is bad, bail out */
3332 failf(data, "Header without colon");
3333 return CURLE_WEIRD_SERVER_REPLY;
3334 }
3335 }
3336 return CURLE_OK;
3337 }
3338
Curl_bump_headersize(struct Curl_easy * data,size_t delta,bool connect_only)3339 CURLcode Curl_bump_headersize(struct Curl_easy *data,
3340 size_t delta,
3341 bool connect_only)
3342 {
3343 size_t bad = 0;
3344 unsigned int max = MAX_HTTP_RESP_HEADER_SIZE;
3345 if(delta < MAX_HTTP_RESP_HEADER_SIZE) {
3346 data->info.header_size += (unsigned int)delta;
3347 data->req.allheadercount += (unsigned int)delta;
3348 if(!connect_only)
3349 data->req.headerbytecount += (unsigned int)delta;
3350 if(data->req.allheadercount > max)
3351 bad = data->req.allheadercount;
3352 else if(data->info.header_size > (max * 20)) {
3353 bad = data->info.header_size;
3354 max *= 20;
3355 }
3356 }
3357 else
3358 bad = data->req.allheadercount + delta;
3359 if(bad) {
3360 failf(data, "Too large response headers: %zu > %u", bad, max);
3361 return CURLE_RECV_ERROR;
3362 }
3363 return CURLE_OK;
3364 }
3365
3366
http_on_response(struct Curl_easy * data,const char * buf,size_t blen,size_t * pconsumed)3367 static CURLcode http_on_response(struct Curl_easy *data,
3368 const char *buf, size_t blen,
3369 size_t *pconsumed)
3370 {
3371 struct connectdata *conn = data->conn;
3372 CURLcode result = CURLE_OK;
3373 struct SingleRequest *k = &data->req;
3374
3375 (void)buf; /* not used without HTTP2 enabled */
3376 *pconsumed = 0;
3377
3378 if(k->upgr101 == UPGR101_RECEIVED) {
3379 /* supposedly upgraded to http2 now */
3380 if(conn->httpversion != 20)
3381 infof(data, "Lying server, not serving HTTP/2");
3382 }
3383 if(conn->httpversion < 20) {
3384 conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
3385 }
3386
3387 if(k->httpcode < 100) {
3388 failf(data, "Unsupported response code in HTTP response");
3389 return CURLE_UNSUPPORTED_PROTOCOL;
3390 }
3391 else if(k->httpcode < 200) {
3392 /* "A user agent MAY ignore unexpected 1xx status responses."
3393 * By default, we expect to get more responses after this one. */
3394 k->header = TRUE;
3395 k->headerline = 0; /* restart the header line counter */
3396
3397 switch(k->httpcode) {
3398 case 100:
3399 /*
3400 * We have made an HTTP PUT or POST and this is 1.1-lingo
3401 * that tells us that the server is OK with this and ready
3402 * to receive the data.
3403 */
3404 Curl_http_exp100_got100(data);
3405 break;
3406 case 101:
3407 /* Switching Protocols only allowed from HTTP/1.1 */
3408 if(conn->httpversion != 11) {
3409 /* invalid for other HTTP versions */
3410 failf(data, "unexpected 101 response code");
3411 return CURLE_WEIRD_SERVER_REPLY;
3412 }
3413 if(k->upgr101 == UPGR101_H2) {
3414 /* Switching to HTTP/2, where we will get more responses */
3415 infof(data, "Received 101, Switching to HTTP/2");
3416 k->upgr101 = UPGR101_RECEIVED;
3417 /* We expect more response from HTTP/2 later */
3418 k->header = TRUE;
3419 k->headerline = 0; /* restart the header line counter */
3420 /* Any remaining `buf` bytes are already HTTP/2 and passed to
3421 * be processed. */
3422 result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
3423 if(result)
3424 return result;
3425 *pconsumed += blen;
3426 }
3427 #ifdef USE_WEBSOCKETS
3428 else if(k->upgr101 == UPGR101_WS) {
3429 /* verify the response. Any passed `buf` bytes are already in
3430 * WebSockets format and taken in by the protocol handler. */
3431 result = Curl_ws_accept(data, buf, blen);
3432 if(result)
3433 return result;
3434 *pconsumed += blen; /* ws accept handled the data */
3435 k->header = FALSE; /* we will not get more responses */
3436 if(data->set.connect_only)
3437 k->keepon &= ~KEEP_RECV; /* read no more content */
3438 }
3439 #endif
3440 else {
3441 /* We silently accept this as the final response.
3442 * TODO: this looks, uhm, wrong. What are we switching to if we
3443 * did not ask for an Upgrade? Maybe the application provided an
3444 * `Upgrade: xxx` header? */
3445 k->header = FALSE;
3446 }
3447 break;
3448 default:
3449 /* The server may send us other 1xx responses, like informative
3450 * 103. This have no influence on request processing and we expect
3451 * to receive a final response eventually. */
3452 break;
3453 }
3454 return result;
3455 }
3456
3457 /* k->httpcode >= 200, final response */
3458 k->header = FALSE;
3459
3460 if(k->upgr101 == UPGR101_H2) {
3461 /* A requested upgrade was denied, poke the multi handle to possibly
3462 allow a pending pipewait to continue */
3463 Curl_multi_connchanged(data->multi);
3464 }
3465
3466 if((k->size == -1) && !k->chunk && !conn->bits.close &&
3467 (conn->httpversion == 11) &&
3468 !(conn->handler->protocol & CURLPROTO_RTSP) &&
3469 data->state.httpreq != HTTPREQ_HEAD) {
3470 /* On HTTP 1.1, when connection is not to get closed, but no
3471 Content-Length nor Transfer-Encoding chunked have been
3472 received, according to RFC2616 section 4.4 point 5, we
3473 assume that the server will close the connection to
3474 signal the end of the document. */
3475 infof(data, "no chunk, no close, no size. Assume close to "
3476 "signal end");
3477 streamclose(conn, "HTTP: No end-of-message indicator");
3478 }
3479
3480 /* At this point we have some idea about the fate of the connection.
3481 If we are closing the connection it may result auth failure. */
3482 #if defined(USE_NTLM)
3483 if(conn->bits.close &&
3484 (((data->req.httpcode == 401) &&
3485 (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
3486 ((data->req.httpcode == 407) &&
3487 (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
3488 infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
3489 data->state.authproblem = TRUE;
3490 }
3491 #endif
3492 #if defined(USE_SPNEGO)
3493 if(conn->bits.close &&
3494 (((data->req.httpcode == 401) &&
3495 (conn->http_negotiate_state == GSS_AUTHRECV)) ||
3496 ((data->req.httpcode == 407) &&
3497 (conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
3498 infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
3499 data->state.authproblem = TRUE;
3500 }
3501 if((conn->http_negotiate_state == GSS_AUTHDONE) &&
3502 (data->req.httpcode != 401)) {
3503 conn->http_negotiate_state = GSS_AUTHSUCC;
3504 }
3505 if((conn->proxy_negotiate_state == GSS_AUTHDONE) &&
3506 (data->req.httpcode != 407)) {
3507 conn->proxy_negotiate_state = GSS_AUTHSUCC;
3508 }
3509 #endif
3510
3511 #ifdef USE_WEBSOCKETS
3512 /* All >=200 HTTP status codes are errors when wanting websockets */
3513 if(data->req.upgr101 == UPGR101_WS) {
3514 failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
3515 return CURLE_HTTP_RETURNED_ERROR;
3516 }
3517 #endif
3518
3519 /* Check if this response means the transfer errored. */
3520 if(http_should_fail(data, data->req.httpcode)) {
3521 failf(data, "The requested URL returned error: %d",
3522 k->httpcode);
3523 return CURLE_HTTP_RETURNED_ERROR;
3524 }
3525
3526 /* Curl_http_auth_act() checks what authentication methods
3527 * that are available and decides which one (if any) to
3528 * use. It will set 'newurl' if an auth method was picked. */
3529 result = Curl_http_auth_act(data);
3530 if(result)
3531 return result;
3532
3533 if(k->httpcode >= 300) {
3534 if((!data->req.authneg) && !conn->bits.close &&
3535 !Curl_creader_will_rewind(data)) {
3536 /*
3537 * General treatment of errors when about to send data. Including :
3538 * "417 Expectation Failed", while waiting for 100-continue.
3539 *
3540 * The check for close above is done simply because of something
3541 * else has already deemed the connection to get closed then
3542 * something else should've considered the big picture and we
3543 * avoid this check.
3544 *
3545 */
3546
3547 switch(data->state.httpreq) {
3548 case HTTPREQ_PUT:
3549 case HTTPREQ_POST:
3550 case HTTPREQ_POST_FORM:
3551 case HTTPREQ_POST_MIME:
3552 /* We got an error response. If this happened before the whole
3553 * request body has been sent we stop sending and mark the
3554 * connection for closure after we've read the entire response.
3555 */
3556 if(!Curl_req_done_sending(data)) {
3557 if((k->httpcode == 417) && Curl_http_exp100_is_selected(data)) {
3558 /* 417 Expectation Failed - try again without the Expect
3559 header */
3560 if(!k->writebytecount && http_exp100_is_waiting(data)) {
3561 infof(data, "Got HTTP failure 417 while waiting for a 100");
3562 }
3563 else {
3564 infof(data, "Got HTTP failure 417 while sending data");
3565 streamclose(conn,
3566 "Stop sending data before everything sent");
3567 result = http_perhapsrewind(data, conn);
3568 if(result)
3569 return result;
3570 }
3571 data->state.disableexpect = TRUE;
3572 DEBUGASSERT(!data->req.newurl);
3573 data->req.newurl = strdup(data->state.url);
3574 Curl_req_abort_sending(data);
3575 }
3576 else if(data->set.http_keep_sending_on_error) {
3577 infof(data, "HTTP error before end of send, keep sending");
3578 http_exp100_send_anyway(data);
3579 }
3580 else {
3581 infof(data, "HTTP error before end of send, stop sending");
3582 streamclose(conn, "Stop sending data before everything sent");
3583 result = Curl_req_abort_sending(data);
3584 if(result)
3585 return result;
3586 }
3587 }
3588 break;
3589
3590 default: /* default label present to avoid compiler warnings */
3591 break;
3592 }
3593 }
3594
3595 if(Curl_creader_will_rewind(data) && !Curl_req_done_sending(data)) {
3596 /* We rewind before next send, continue sending now */
3597 infof(data, "Keep sending data to get tossed away");
3598 k->keepon |= KEEP_SEND;
3599 }
3600
3601 }
3602
3603 /* This is the last response that we will got for the current request.
3604 * Check on the body size and determine if the response is complete.
3605 */
3606 result = Curl_http_size(data);
3607 if(result)
3608 return result;
3609
3610 /* If we requested a "no body", this is a good time to get
3611 * out and return home.
3612 */
3613 if(data->req.no_body)
3614 k->download_done = TRUE;
3615
3616 /* If max download size is *zero* (nothing) we already have
3617 nothing and can safely return ok now! But for HTTP/2, we'd
3618 like to call http2_handle_stream_close to properly close a
3619 stream. In order to do this, we keep reading until we
3620 close the stream. */
3621 if(0 == k->maxdownload
3622 && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
3623 && !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
3624 k->download_done = TRUE;
3625
3626 /* final response without error, prepare to receive the body */
3627 return Curl_http_firstwrite(data);
3628 }
3629
http_rw_hd(struct Curl_easy * data,const char * hd,size_t hdlen,const char * buf_remain,size_t blen,size_t * pconsumed)3630 static CURLcode http_rw_hd(struct Curl_easy *data,
3631 const char *hd, size_t hdlen,
3632 const char *buf_remain, size_t blen,
3633 size_t *pconsumed)
3634 {
3635 CURLcode result = CURLE_OK;
3636 struct SingleRequest *k = &data->req;
3637 int writetype;
3638
3639 *pconsumed = 0;
3640 if((0x0a == *hd) || (0x0d == *hd)) {
3641 /* Empty header line means end of headers! */
3642 size_t consumed;
3643
3644 /* now, only output this if the header AND body are requested:
3645 */
3646 Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
3647
3648 writetype = CLIENTWRITE_HEADER |
3649 ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
3650
3651 result = Curl_client_write(data, writetype, hd, hdlen);
3652 if(result)
3653 return result;
3654
3655 result = Curl_bump_headersize(data, hdlen, FALSE);
3656 if(result)
3657 return result;
3658
3659 data->req.deductheadercount =
3660 (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
3661
3662 /* analyze the response to find out what to do. */
3663 /* Caveat: we clear anything in the header brigade, because a
3664 * response might switch HTTP version which may call use recursively.
3665 * Not nice, but that is currently the way of things. */
3666 Curl_dyn_reset(&data->state.headerb);
3667 result = http_on_response(data, buf_remain, blen, &consumed);
3668 if(result)
3669 return result;
3670 *pconsumed += consumed;
3671 return CURLE_OK;
3672 }
3673
3674 /*
3675 * Checks for special headers coming up.
3676 */
3677
3678 writetype = CLIENTWRITE_HEADER;
3679 if(!k->headerline++) {
3680 /* This is the first header, it MUST be the error code line
3681 or else we consider this to be the body right away! */
3682 bool fine_statusline = FALSE;
3683
3684 k->httpversion = 0; /* Don't know yet */
3685 if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
3686 /*
3687 * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
3688 *
3689 * The response code is always a three-digit number in HTTP as the spec
3690 * says. We allow any three-digit number here, but we cannot make
3691 * guarantees on future behaviors since it isn't within the protocol.
3692 */
3693 const char *p = hd;
3694
3695 while(*p && ISBLANK(*p))
3696 p++;
3697 if(!strncmp(p, "HTTP/", 5)) {
3698 p += 5;
3699 switch(*p) {
3700 case '1':
3701 p++;
3702 if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
3703 if(ISBLANK(p[2])) {
3704 k->httpversion = 10 + (p[1] - '0');
3705 p += 3;
3706 if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
3707 k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
3708 (p[2] - '0');
3709 p += 3;
3710 if(ISSPACE(*p))
3711 fine_statusline = TRUE;
3712 }
3713 }
3714 }
3715 if(!fine_statusline) {
3716 failf(data, "Unsupported HTTP/1 subversion in response");
3717 return CURLE_UNSUPPORTED_PROTOCOL;
3718 }
3719 break;
3720 case '2':
3721 case '3':
3722 if(!ISBLANK(p[1]))
3723 break;
3724 k->httpversion = (*p - '0') * 10;
3725 p += 2;
3726 if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
3727 k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
3728 (p[2] - '0');
3729 p += 3;
3730 if(!ISSPACE(*p))
3731 break;
3732 fine_statusline = TRUE;
3733 }
3734 break;
3735 default: /* unsupported */
3736 failf(data, "Unsupported HTTP version in response");
3737 return CURLE_UNSUPPORTED_PROTOCOL;
3738 }
3739 }
3740
3741 if(!fine_statusline) {
3742 /* If user has set option HTTP200ALIASES,
3743 compare header line against list of aliases
3744 */
3745 statusline check = checkhttpprefix(data, hd, hdlen);
3746 if(check == STATUS_DONE) {
3747 fine_statusline = TRUE;
3748 k->httpcode = 200;
3749 k->httpversion = 10;
3750 }
3751 }
3752 }
3753 else if(data->conn->handler->protocol & CURLPROTO_RTSP) {
3754 const char *p = hd;
3755 while(*p && ISBLANK(*p))
3756 p++;
3757 if(!strncmp(p, "RTSP/", 5)) {
3758 p += 5;
3759 if(ISDIGIT(*p)) {
3760 p++;
3761 if((p[0] == '.') && ISDIGIT(p[1])) {
3762 if(ISBLANK(p[2])) {
3763 p += 3;
3764 if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
3765 k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
3766 (p[2] - '0');
3767 p += 3;
3768 if(ISSPACE(*p)) {
3769 fine_statusline = TRUE;
3770 k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
3771 }
3772 }
3773 }
3774 }
3775 }
3776 if(!fine_statusline)
3777 return CURLE_WEIRD_SERVER_REPLY;
3778 }
3779 }
3780
3781 if(fine_statusline) {
3782 result = Curl_http_statusline(data, data->conn);
3783 if(result)
3784 return result;
3785 writetype |= CLIENTWRITE_STATUS;
3786 }
3787 else {
3788 k->header = FALSE; /* this is not a header line */
3789 return CURLE_WEIRD_SERVER_REPLY;
3790 }
3791 }
3792
3793 result = verify_header(data, hd, hdlen);
3794 if(result)
3795 return result;
3796
3797 result = Curl_http_header(data, hd, hdlen);
3798 if(result)
3799 return result;
3800
3801 /*
3802 * Taken in one (more) header. Write it to the client.
3803 */
3804 Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
3805
3806 if(k->httpcode/100 == 1)
3807 writetype |= CLIENTWRITE_1XX;
3808 result = Curl_client_write(data, writetype, hd, hdlen);
3809 if(result)
3810 return result;
3811
3812 result = Curl_bump_headersize(data, hdlen, FALSE);
3813 if(result)
3814 return result;
3815
3816 return CURLE_OK;
3817 }
3818
3819 /*
3820 * Read any HTTP header lines from the server and pass them to the client app.
3821 */
http_parse_headers(struct Curl_easy * data,const char * buf,size_t blen,size_t * pconsumed)3822 static CURLcode http_parse_headers(struct Curl_easy *data,
3823 const char *buf, size_t blen,
3824 size_t *pconsumed)
3825 {
3826 struct connectdata *conn = data->conn;
3827 CURLcode result = CURLE_OK;
3828 struct SingleRequest *k = &data->req;
3829 char *end_ptr;
3830 bool leftover_body = FALSE;
3831
3832 /* header line within buffer loop */
3833 *pconsumed = 0;
3834 while(blen && k->header) {
3835 size_t consumed;
3836
3837 end_ptr = memchr(buf, '\n', blen);
3838 if(!end_ptr) {
3839 /* Not a complete header line within buffer, append the data to
3840 the end of the headerbuff. */
3841 result = Curl_dyn_addn(&data->state.headerb, buf, blen);
3842 if(result)
3843 return result;
3844 *pconsumed += blen;
3845
3846 if(!k->headerline) {
3847 /* check if this looks like a protocol header */
3848 statusline st =
3849 checkprotoprefix(data, conn,
3850 Curl_dyn_ptr(&data->state.headerb),
3851 Curl_dyn_len(&data->state.headerb));
3852
3853 if(st == STATUS_BAD) {
3854 /* this is not the beginning of a protocol first header line */
3855 k->header = FALSE;
3856 streamclose(conn, "bad HTTP: No end-of-message indicator");
3857 if(conn->httpversion >= 10) {
3858 failf(data, "Invalid status line");
3859 return CURLE_WEIRD_SERVER_REPLY;
3860 }
3861 if(!data->set.http09_allowed) {
3862 failf(data, "Received HTTP/0.9 when not allowed");
3863 return CURLE_UNSUPPORTED_PROTOCOL;
3864 }
3865 leftover_body = TRUE;
3866 goto out;
3867 }
3868 }
3869 goto out; /* read more and try again */
3870 }
3871
3872 /* decrease the size of the remaining (supposed) header line */
3873 consumed = (end_ptr - buf) + 1;
3874 result = Curl_dyn_addn(&data->state.headerb, buf, consumed);
3875 if(result)
3876 return result;
3877 blen -= consumed;
3878 buf += consumed;
3879 *pconsumed += consumed;
3880
3881 /****
3882 * We now have a FULL header line in 'headerb'.
3883 *****/
3884
3885 if(!k->headerline) {
3886 /* the first read header */
3887 statusline st = checkprotoprefix(data, conn,
3888 Curl_dyn_ptr(&data->state.headerb),
3889 Curl_dyn_len(&data->state.headerb));
3890 if(st == STATUS_BAD) {
3891 streamclose(conn, "bad HTTP: No end-of-message indicator");
3892 /* this is not the beginning of a protocol first header line */
3893 if(conn->httpversion >= 10) {
3894 failf(data, "Invalid status line");
3895 return CURLE_WEIRD_SERVER_REPLY;
3896 }
3897 if(!data->set.http09_allowed) {
3898 failf(data, "Received HTTP/0.9 when not allowed");
3899 return CURLE_UNSUPPORTED_PROTOCOL;
3900 }
3901 k->header = FALSE;
3902 leftover_body = TRUE;
3903 goto out;
3904 }
3905 }
3906
3907 result = http_rw_hd(data, Curl_dyn_ptr(&data->state.headerb),
3908 Curl_dyn_len(&data->state.headerb),
3909 buf, blen, &consumed);
3910 /* We are done with this line. We reset because response
3911 * processing might switch to HTTP/2 and that might call us
3912 * directly again. */
3913 Curl_dyn_reset(&data->state.headerb);
3914 if(consumed) {
3915 blen -= consumed;
3916 buf += consumed;
3917 *pconsumed += consumed;
3918 }
3919 if(result)
3920 return result;
3921 }
3922
3923 /* We might have reached the end of the header part here, but
3924 there might be a non-header part left in the end of the read
3925 buffer. */
3926 out:
3927 if(!k->header && !leftover_body) {
3928 Curl_dyn_free(&data->state.headerb);
3929 }
3930 return CURLE_OK;
3931 }
3932
Curl_http_write_resp_hd(struct Curl_easy * data,const char * hd,size_t hdlen,bool is_eos)3933 CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
3934 const char *hd, size_t hdlen,
3935 bool is_eos)
3936 {
3937 CURLcode result;
3938 size_t consumed;
3939 char tmp = 0;
3940
3941 result = http_rw_hd(data, hd, hdlen, &tmp, 0, &consumed);
3942 if(!result && is_eos) {
3943 result = Curl_client_write(data, (CLIENTWRITE_BODY|CLIENTWRITE_EOS),
3944 &tmp, 0);
3945 }
3946 return result;
3947 }
3948
3949 /*
3950 * HTTP protocol `write_resp` implementation. Will parse headers
3951 * when not done yet and otherwise return without consuming data.
3952 */
Curl_http_write_resp_hds(struct Curl_easy * data,const char * buf,size_t blen,size_t * pconsumed)3953 CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
3954 const char *buf, size_t blen,
3955 size_t *pconsumed)
3956 {
3957 if(!data->req.header) {
3958 *pconsumed = 0;
3959 return CURLE_OK;
3960 }
3961 else {
3962 CURLcode result;
3963
3964 result = http_parse_headers(data, buf, blen, pconsumed);
3965 if(!result && !data->req.header) {
3966 if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) {
3967 /* leftover from parsing something that turned out not
3968 * to be a header, only happens if we allow for
3969 * HTTP/0.9 like responses */
3970 result = Curl_client_write(data, CLIENTWRITE_BODY,
3971 Curl_dyn_ptr(&data->state.headerb),
3972 Curl_dyn_len(&data->state.headerb));
3973 }
3974 Curl_dyn_free(&data->state.headerb);
3975 }
3976 return result;
3977 }
3978 }
3979
Curl_http_write_resp(struct Curl_easy * data,const char * buf,size_t blen,bool is_eos)3980 CURLcode Curl_http_write_resp(struct Curl_easy *data,
3981 const char *buf, size_t blen,
3982 bool is_eos)
3983 {
3984 CURLcode result;
3985 size_t consumed;
3986 int flags;
3987
3988 result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
3989 if(result || data->req.done)
3990 goto out;
3991
3992 DEBUGASSERT(consumed <= blen);
3993 blen -= consumed;
3994 buf += consumed;
3995 /* either all was consumed in header parsing, or we have data left
3996 * and are done with headers, e.g. it is BODY data */
3997 DEBUGASSERT(!blen || !data->req.header);
3998 if(!data->req.header && (blen || is_eos)) {
3999 /* BODY data after header been parsed, write and consume */
4000 flags = CLIENTWRITE_BODY;
4001 if(is_eos)
4002 flags |= CLIENTWRITE_EOS;
4003 result = Curl_client_write(data, flags, (char *)buf, blen);
4004 }
4005 out:
4006 return result;
4007 }
4008
4009 /* Decode HTTP status code string. */
Curl_http_decode_status(int * pstatus,const char * s,size_t len)4010 CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len)
4011 {
4012 CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
4013 int status = 0;
4014 int i;
4015
4016 if(len != 3)
4017 goto out;
4018
4019 for(i = 0; i < 3; ++i) {
4020 char c = s[i];
4021
4022 if(c < '0' || c > '9')
4023 goto out;
4024
4025 status *= 10;
4026 status += c - '0';
4027 }
4028 result = CURLE_OK;
4029 out:
4030 *pstatus = result? -1 : status;
4031 return result;
4032 }
4033
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)4034 CURLcode Curl_http_req_make(struct httpreq **preq,
4035 const char *method, size_t m_len,
4036 const char *scheme, size_t s_len,
4037 const char *authority, size_t a_len,
4038 const char *path, size_t p_len)
4039 {
4040 struct httpreq *req;
4041 CURLcode result = CURLE_OUT_OF_MEMORY;
4042
4043 DEBUGASSERT(method);
4044 if(m_len + 1 > sizeof(req->method))
4045 return CURLE_BAD_FUNCTION_ARGUMENT;
4046
4047 req = calloc(1, sizeof(*req));
4048 if(!req)
4049 goto out;
4050 memcpy(req->method, method, m_len);
4051 if(scheme) {
4052 req->scheme = Curl_memdup0(scheme, s_len);
4053 if(!req->scheme)
4054 goto out;
4055 }
4056 if(authority) {
4057 req->authority = Curl_memdup0(authority, a_len);
4058 if(!req->authority)
4059 goto out;
4060 }
4061 if(path) {
4062 req->path = Curl_memdup0(path, p_len);
4063 if(!req->path)
4064 goto out;
4065 }
4066 Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
4067 Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
4068 result = CURLE_OK;
4069
4070 out:
4071 if(result && req)
4072 Curl_http_req_free(req);
4073 *preq = result? NULL : req;
4074 return result;
4075 }
4076
req_assign_url_authority(struct httpreq * req,CURLU * url)4077 static CURLcode req_assign_url_authority(struct httpreq *req, CURLU *url)
4078 {
4079 char *user, *pass, *host, *port;
4080 struct dynbuf buf;
4081 CURLUcode uc;
4082 CURLcode result = CURLE_URL_MALFORMAT;
4083
4084 user = pass = host = port = NULL;
4085 Curl_dyn_init(&buf, DYN_HTTP_REQUEST);
4086
4087 uc = curl_url_get(url, CURLUPART_HOST, &host, 0);
4088 if(uc && uc != CURLUE_NO_HOST)
4089 goto out;
4090 if(!host) {
4091 req->authority = NULL;
4092 result = CURLE_OK;
4093 goto out;
4094 }
4095
4096 uc = curl_url_get(url, CURLUPART_PORT, &port, CURLU_NO_DEFAULT_PORT);
4097 if(uc && uc != CURLUE_NO_PORT)
4098 goto out;
4099 uc = curl_url_get(url, CURLUPART_USER, &user, 0);
4100 if(uc && uc != CURLUE_NO_USER)
4101 goto out;
4102 if(user) {
4103 uc = curl_url_get(url, CURLUPART_PASSWORD, &pass, 0);
4104 if(uc && uc != CURLUE_NO_PASSWORD)
4105 goto out;
4106 }
4107
4108 if(user) {
4109 result = Curl_dyn_add(&buf, user);
4110 if(result)
4111 goto out;
4112 if(pass) {
4113 result = Curl_dyn_addf(&buf, ":%s", pass);
4114 if(result)
4115 goto out;
4116 }
4117 result = Curl_dyn_add(&buf, "@");
4118 if(result)
4119 goto out;
4120 }
4121 result = Curl_dyn_add(&buf, host);
4122 if(result)
4123 goto out;
4124 if(port) {
4125 result = Curl_dyn_addf(&buf, ":%s", port);
4126 if(result)
4127 goto out;
4128 }
4129 req->authority = strdup(Curl_dyn_ptr(&buf));
4130 if(!req->authority)
4131 goto out;
4132 result = CURLE_OK;
4133
4134 out:
4135 free(user);
4136 free(pass);
4137 free(host);
4138 free(port);
4139 Curl_dyn_free(&buf);
4140 return result;
4141 }
4142
req_assign_url_path(struct httpreq * req,CURLU * url)4143 static CURLcode req_assign_url_path(struct httpreq *req, CURLU *url)
4144 {
4145 char *path, *query;
4146 struct dynbuf buf;
4147 CURLUcode uc;
4148 CURLcode result = CURLE_URL_MALFORMAT;
4149
4150 path = query = NULL;
4151 Curl_dyn_init(&buf, DYN_HTTP_REQUEST);
4152
4153 uc = curl_url_get(url, CURLUPART_PATH, &path, CURLU_PATH_AS_IS);
4154 if(uc)
4155 goto out;
4156 uc = curl_url_get(url, CURLUPART_QUERY, &query, 0);
4157 if(uc && uc != CURLUE_NO_QUERY)
4158 goto out;
4159
4160 if(!path && !query) {
4161 req->path = NULL;
4162 }
4163 else if(path && !query) {
4164 req->path = path;
4165 path = NULL;
4166 }
4167 else {
4168 if(path) {
4169 result = Curl_dyn_add(&buf, path);
4170 if(result)
4171 goto out;
4172 }
4173 if(query) {
4174 result = Curl_dyn_addf(&buf, "?%s", query);
4175 if(result)
4176 goto out;
4177 }
4178 req->path = strdup(Curl_dyn_ptr(&buf));
4179 if(!req->path)
4180 goto out;
4181 }
4182 result = CURLE_OK;
4183
4184 out:
4185 free(path);
4186 free(query);
4187 Curl_dyn_free(&buf);
4188 return result;
4189 }
4190
Curl_http_req_make2(struct httpreq ** preq,const char * method,size_t m_len,CURLU * url,const char * scheme_default)4191 CURLcode Curl_http_req_make2(struct httpreq **preq,
4192 const char *method, size_t m_len,
4193 CURLU *url, const char *scheme_default)
4194 {
4195 struct httpreq *req;
4196 CURLcode result = CURLE_OUT_OF_MEMORY;
4197 CURLUcode uc;
4198
4199 DEBUGASSERT(method);
4200 if(m_len + 1 > sizeof(req->method))
4201 return CURLE_BAD_FUNCTION_ARGUMENT;
4202
4203 req = calloc(1, sizeof(*req));
4204 if(!req)
4205 goto out;
4206 memcpy(req->method, method, m_len);
4207
4208 uc = curl_url_get(url, CURLUPART_SCHEME, &req->scheme, 0);
4209 if(uc && uc != CURLUE_NO_SCHEME)
4210 goto out;
4211 if(!req->scheme && scheme_default) {
4212 req->scheme = strdup(scheme_default);
4213 if(!req->scheme)
4214 goto out;
4215 }
4216
4217 result = req_assign_url_authority(req, url);
4218 if(result)
4219 goto out;
4220 result = req_assign_url_path(req, url);
4221 if(result)
4222 goto out;
4223
4224 Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
4225 Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
4226 result = CURLE_OK;
4227
4228 out:
4229 if(result && req)
4230 Curl_http_req_free(req);
4231 *preq = result? NULL : req;
4232 return result;
4233 }
4234
Curl_http_req_free(struct httpreq * req)4235 void Curl_http_req_free(struct httpreq *req)
4236 {
4237 if(req) {
4238 free(req->scheme);
4239 free(req->authority);
4240 free(req->path);
4241 Curl_dynhds_free(&req->headers);
4242 Curl_dynhds_free(&req->trailers);
4243 free(req);
4244 }
4245 }
4246
4247 struct name_const {
4248 const char *name;
4249 size_t namelen;
4250 };
4251
4252 static struct name_const H2_NON_FIELD[] = {
4253 { STRCONST("Host") },
4254 { STRCONST("Upgrade") },
4255 { STRCONST("Connection") },
4256 { STRCONST("Keep-Alive") },
4257 { STRCONST("Proxy-Connection") },
4258 { STRCONST("Transfer-Encoding") },
4259 };
4260
h2_non_field(const char * name,size_t namelen)4261 static bool h2_non_field(const char *name, size_t namelen)
4262 {
4263 size_t i;
4264 for(i = 0; i < sizeof(H2_NON_FIELD)/sizeof(H2_NON_FIELD[0]); ++i) {
4265 if(namelen < H2_NON_FIELD[i].namelen)
4266 return FALSE;
4267 if(namelen == H2_NON_FIELD[i].namelen &&
4268 strcasecompare(H2_NON_FIELD[i].name, name))
4269 return TRUE;
4270 }
4271 return FALSE;
4272 }
4273
Curl_http_req_to_h2(struct dynhds * h2_headers,struct httpreq * req,struct Curl_easy * data)4274 CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
4275 struct httpreq *req, struct Curl_easy *data)
4276 {
4277 const char *scheme = NULL, *authority = NULL;
4278 struct dynhds_entry *e;
4279 size_t i;
4280 CURLcode result;
4281
4282 DEBUGASSERT(req);
4283 DEBUGASSERT(h2_headers);
4284
4285 if(req->scheme) {
4286 scheme = req->scheme;
4287 }
4288 else if(strcmp("CONNECT", req->method)) {
4289 scheme = Curl_checkheaders(data, STRCONST(HTTP_PSEUDO_SCHEME));
4290 if(scheme) {
4291 scheme += sizeof(HTTP_PSEUDO_SCHEME);
4292 while(*scheme && ISBLANK(*scheme))
4293 scheme++;
4294 infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme);
4295 }
4296 else {
4297 scheme = (data->conn && data->conn->handler->flags & PROTOPT_SSL)?
4298 "https" : "http";
4299 }
4300 }
4301
4302 if(req->authority) {
4303 authority = req->authority;
4304 }
4305 else {
4306 e = Curl_dynhds_get(&req->headers, STRCONST("Host"));
4307 if(e)
4308 authority = e->value;
4309 }
4310
4311 Curl_dynhds_reset(h2_headers);
4312 Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE);
4313 result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD),
4314 req->method, strlen(req->method));
4315 if(!result && scheme) {
4316 result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME),
4317 scheme, strlen(scheme));
4318 }
4319 if(!result && authority) {
4320 result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY),
4321 authority, strlen(authority));
4322 }
4323 if(!result && req->path) {
4324 result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH),
4325 req->path, strlen(req->path));
4326 }
4327 for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) {
4328 e = Curl_dynhds_getn(&req->headers, i);
4329 if(!h2_non_field(e->name, e->namelen)) {
4330 result = Curl_dynhds_add(h2_headers, e->name, e->namelen,
4331 e->value, e->valuelen);
4332 }
4333 }
4334
4335 return result;
4336 }
4337
Curl_http_resp_make(struct http_resp ** presp,int status,const char * description)4338 CURLcode Curl_http_resp_make(struct http_resp **presp,
4339 int status,
4340 const char *description)
4341 {
4342 struct http_resp *resp;
4343 CURLcode result = CURLE_OUT_OF_MEMORY;
4344
4345 resp = calloc(1, sizeof(*resp));
4346 if(!resp)
4347 goto out;
4348
4349 resp->status = status;
4350 if(description) {
4351 resp->description = strdup(description);
4352 if(!resp->description)
4353 goto out;
4354 }
4355 Curl_dynhds_init(&resp->headers, 0, DYN_HTTP_REQUEST);
4356 Curl_dynhds_init(&resp->trailers, 0, DYN_HTTP_REQUEST);
4357 result = CURLE_OK;
4358
4359 out:
4360 if(result && resp)
4361 Curl_http_resp_free(resp);
4362 *presp = result? NULL : resp;
4363 return result;
4364 }
4365
Curl_http_resp_free(struct http_resp * resp)4366 void Curl_http_resp_free(struct http_resp *resp)
4367 {
4368 if(resp) {
4369 free(resp->description);
4370 Curl_dynhds_free(&resp->headers);
4371 Curl_dynhds_free(&resp->trailers);
4372 if(resp->prev)
4373 Curl_http_resp_free(resp->prev);
4374 free(resp);
4375 }
4376 }
4377
4378 struct cr_exp100_ctx {
4379 struct Curl_creader super;
4380 struct curltime start; /* time started waiting */
4381 enum expect100 state;
4382 };
4383
4384 /* Expect: 100-continue client reader, blocking uploads */
4385
http_exp100_continue(struct Curl_easy * data,struct Curl_creader * reader)4386 static void http_exp100_continue(struct Curl_easy *data,
4387 struct Curl_creader *reader)
4388 {
4389 struct cr_exp100_ctx *ctx = reader->ctx;
4390 if(ctx->state > EXP100_SEND_DATA) {
4391 ctx->state = EXP100_SEND_DATA;
4392 data->req.keepon |= KEEP_SEND;
4393 data->req.keepon &= ~KEEP_SEND_TIMED;
4394 Curl_expire_done(data, EXPIRE_100_TIMEOUT);
4395 }
4396 }
4397
cr_exp100_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * nread,bool * eos)4398 static CURLcode cr_exp100_read(struct Curl_easy *data,
4399 struct Curl_creader *reader,
4400 char *buf, size_t blen,
4401 size_t *nread, bool *eos)
4402 {
4403 struct cr_exp100_ctx *ctx = reader->ctx;
4404 timediff_t ms;
4405
4406 switch(ctx->state) {
4407 case EXP100_SENDING_REQUEST:
4408 /* We are now waiting for a reply from the server or
4409 * a timeout on our side */
4410 DEBUGF(infof(data, "cr_exp100_read, start AWAITING_CONTINUE"));
4411 ctx->state = EXP100_AWAITING_CONTINUE;
4412 ctx->start = Curl_now();
4413 Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
4414 data->req.keepon &= ~KEEP_SEND;
4415 data->req.keepon |= KEEP_SEND_TIMED;
4416 *nread = 0;
4417 *eos = FALSE;
4418 return CURLE_OK;
4419 case EXP100_FAILED:
4420 DEBUGF(infof(data, "cr_exp100_read, expectation failed, error"));
4421 *nread = 0;
4422 *eos = FALSE;
4423 return CURLE_READ_ERROR;
4424 case EXP100_AWAITING_CONTINUE:
4425 ms = Curl_timediff(Curl_now(), ctx->start);
4426 if(ms < data->set.expect_100_timeout) {
4427 DEBUGF(infof(data, "cr_exp100_read, AWAITING_CONTINUE, not expired"));
4428 data->req.keepon &= ~KEEP_SEND;
4429 data->req.keepon |= KEEP_SEND_TIMED;
4430 *nread = 0;
4431 *eos = FALSE;
4432 return CURLE_OK;
4433 }
4434 /* we've waited long enough, continue anyway */
4435 http_exp100_continue(data, reader);
4436 infof(data, "Done waiting for 100-continue");
4437 FALLTHROUGH();
4438 default:
4439 DEBUGF(infof(data, "cr_exp100_read, pass through"));
4440 return Curl_creader_read(data, reader->next, buf, blen, nread, eos);
4441 }
4442 }
4443
cr_exp100_done(struct Curl_easy * data,struct Curl_creader * reader,int premature)4444 static void cr_exp100_done(struct Curl_easy *data,
4445 struct Curl_creader *reader, int premature)
4446 {
4447 struct cr_exp100_ctx *ctx = reader->ctx;
4448 ctx->state = premature? EXP100_FAILED : EXP100_SEND_DATA;
4449 data->req.keepon &= ~KEEP_SEND_TIMED;
4450 Curl_expire_done(data, EXPIRE_100_TIMEOUT);
4451 }
4452
4453 static const struct Curl_crtype cr_exp100 = {
4454 "cr-exp100",
4455 Curl_creader_def_init,
4456 cr_exp100_read,
4457 Curl_creader_def_close,
4458 Curl_creader_def_needs_rewind,
4459 Curl_creader_def_total_length,
4460 Curl_creader_def_resume_from,
4461 Curl_creader_def_rewind,
4462 Curl_creader_def_unpause,
4463 cr_exp100_done,
4464 sizeof(struct cr_exp100_ctx)
4465 };
4466
http_exp100_add_reader(struct Curl_easy * data)4467 static CURLcode http_exp100_add_reader(struct Curl_easy *data)
4468 {
4469 struct Curl_creader *reader = NULL;
4470 CURLcode result;
4471
4472 result = Curl_creader_create(&reader, data, &cr_exp100,
4473 CURL_CR_PROTOCOL);
4474 if(!result)
4475 result = Curl_creader_add(data, reader);
4476 if(!result) {
4477 struct cr_exp100_ctx *ctx = reader->ctx;
4478 ctx->state = EXP100_SENDING_REQUEST;
4479 }
4480
4481 if(result && reader)
4482 Curl_creader_free(data, reader);
4483 return result;
4484 }
4485
Curl_http_exp100_got100(struct Curl_easy * data)4486 void Curl_http_exp100_got100(struct Curl_easy *data)
4487 {
4488 struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
4489 if(r)
4490 http_exp100_continue(data, r);
4491 }
4492
http_exp100_is_waiting(struct Curl_easy * data)4493 static bool http_exp100_is_waiting(struct Curl_easy *data)
4494 {
4495 struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
4496 if(r) {
4497 struct cr_exp100_ctx *ctx = r->ctx;
4498 return (ctx->state == EXP100_AWAITING_CONTINUE);
4499 }
4500 return FALSE;
4501 }
4502
http_exp100_send_anyway(struct Curl_easy * data)4503 static void http_exp100_send_anyway(struct Curl_easy *data)
4504 {
4505 struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
4506 if(r)
4507 http_exp100_continue(data, r);
4508 }
4509
Curl_http_exp100_is_selected(struct Curl_easy * data)4510 bool Curl_http_exp100_is_selected(struct Curl_easy *data)
4511 {
4512 struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
4513 return r? TRUE : FALSE;
4514 }
4515
4516 #endif /* CURL_DISABLE_HTTP */
4517