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