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