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