VirtualBox

source: vbox/trunk/src/libs/curl-8.0.1/lib/http.c@ 100347

Last change on this file since 100347 was 99344, checked in by vboxsync, 2 years ago

curl-8.0.1: Applied and adjusted our curl changes to 7.87.0 bugref:10417

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette