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