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