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