• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     if(data->set.mms_reserved_default_port != 1L)
1846       uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
1847     else
1848       uc = curl_url_get(h, CURLUPART_URL, &url, 0);
1849 
1850     if(uc) {
1851       curl_url_cleanup(h);
1852       return CURLE_OUT_OF_MEMORY;
1853     }
1854 
1855     curl_url_cleanup(h);
1856 
1857     /* target or url */
1858     result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
1859       data->set.str[STRING_TARGET]:url);
1860     free(url);
1861     if(result)
1862       return (result);
1863 
1864     if(strcasecompare("ftp", data->state.up.scheme)) {
1865       if(data->set.proxy_transfer_mode) {
1866         /* when doing ftp, append ;type=<a|i> if not present */
1867         char *type = strstr(path, ";type=");
1868         if(type && type[6] && type[7] == 0) {
1869           switch(Curl_raw_toupper(type[6])) {
1870           case 'A':
1871           case 'D':
1872           case 'I':
1873             break;
1874           default:
1875             type = NULL;
1876           }
1877         }
1878         if(!type) {
1879           result = Curl_dyn_addf(r, ";type=%c",
1880                                  data->state.prefer_ascii ? 'a' : 'i');
1881           if(result)
1882             return result;
1883         }
1884       }
1885     }
1886   }
1887 
1888   else
1889 #else
1890     (void)conn; /* not used in disabled-proxy builds */
1891 #endif
1892   {
1893     result = Curl_dyn_add(r, path);
1894     if(result)
1895       return result;
1896     if(query)
1897       result = Curl_dyn_addf(r, "?%s", query);
1898   }
1899 
1900   return result;
1901 }
1902 
1903 #if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
set_post_reader(struct Curl_easy * data,Curl_HttpReq httpreq)1904 static CURLcode set_post_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
1905 {
1906   CURLcode result;
1907 
1908   switch(httpreq) {
1909 #ifndef CURL_DISABLE_MIME
1910   case HTTPREQ_POST_MIME:
1911     data->state.mimepost = &data->set.mimepost;
1912     break;
1913 #endif
1914 #ifndef CURL_DISABLE_FORM_API
1915   case HTTPREQ_POST_FORM:
1916     /* Convert the form structure into a mime structure, then keep
1917        the conversion */
1918     if(!data->state.formp) {
1919       data->state.formp = calloc(1, sizeof(curl_mimepart));
1920       if(!data->state.formp)
1921         return CURLE_OUT_OF_MEMORY;
1922       Curl_mime_cleanpart(data->state.formp);
1923       result = Curl_getformdata(data, data->state.formp, data->set.httppost,
1924                                 data->state.fread_func);
1925       if(result) {
1926         Curl_safefree(data->state.formp);
1927         return result;
1928       }
1929       data->state.mimepost = data->state.formp;
1930     }
1931     break;
1932 #endif
1933   default:
1934     data->state.mimepost = NULL;
1935     break;
1936   }
1937 
1938   switch(httpreq) {
1939   case HTTPREQ_POST_FORM:
1940   case HTTPREQ_POST_MIME:
1941     /* This is form posting using mime data. */
1942 #ifndef CURL_DISABLE_MIME
1943     if(data->state.mimepost) {
1944       const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
1945 
1946       /* Read and seek body only. */
1947       data->state.mimepost->flags |= MIME_BODY_ONLY;
1948 
1949       /* Prepare the mime structure headers & set content type. */
1950 
1951       if(cthdr)
1952         for(cthdr += 13; *cthdr == ' '; cthdr++)
1953           ;
1954       else if(data->state.mimepost->kind == MIMEKIND_MULTIPART)
1955         cthdr = "multipart/form-data";
1956 
1957       curl_mime_headers(data->state.mimepost, data->set.headers, 0);
1958       result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr,
1959                                          NULL, MIMESTRATEGY_FORM);
1960       if(result)
1961         return result;
1962       curl_mime_headers(data->state.mimepost, NULL, 0);
1963       result = Curl_creader_set_mime(data, data->state.mimepost);
1964       if(result)
1965         return result;
1966     }
1967     else
1968 #endif
1969     {
1970       result = Curl_creader_set_null(data);
1971     }
1972     data->state.infilesize = Curl_creader_total_length(data);
1973     return result;
1974 
1975   default:
1976     return Curl_creader_set_null(data);
1977   }
1978   /* never reached */
1979 }
1980 #endif
1981 
set_reader(struct Curl_easy * data,Curl_HttpReq httpreq)1982 static CURLcode set_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
1983 {
1984   CURLcode result = CURLE_OK;
1985   curl_off_t postsize = data->state.infilesize;
1986 
1987   DEBUGASSERT(data->conn);
1988 
1989   if(data->req.authneg) {
1990     return Curl_creader_set_null(data);
1991   }
1992 
1993   switch(httpreq) {
1994   case HTTPREQ_PUT: /* Let's PUT the data to the server! */
1995     if(!postsize)
1996       result = Curl_creader_set_null(data);
1997     else
1998       result = Curl_creader_set_fread(data, postsize);
1999     return result;
2000 
2001 #if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
2002   case HTTPREQ_POST_FORM:
2003   case HTTPREQ_POST_MIME:
2004     return set_post_reader(data, httpreq);
2005 #endif
2006 
2007   case HTTPREQ_POST:
2008     /* this is the simple POST, using x-www-form-urlencoded style */
2009     /* the size of the post body */
2010     if(!postsize) {
2011       result = Curl_creader_set_null(data);
2012     }
2013     else if(data->set.postfields) {
2014       if(postsize > 0)
2015         result = Curl_creader_set_buf(data, data->set.postfields,
2016                                       (size_t)postsize);
2017       else
2018         result = Curl_creader_set_null(data);
2019     }
2020     else {
2021       /* we read the bytes from the callback. In case "chunked" encoding
2022        * is forced by the application, we disregard `postsize`. This is
2023        * a backward compatibility decision to earlier versions where
2024        * chunking disregarded this. See issue #13229. */
2025       bool chunked = FALSE;
2026       char *ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
2027       if(ptr) {
2028         /* Some kind of TE is requested, check if 'chunked' is chosen */
2029         chunked = Curl_compareheader(ptr, STRCONST("Transfer-Encoding:"),
2030                                      STRCONST("chunked"));
2031       }
2032       result = Curl_creader_set_fread(data, chunked? -1 : postsize);
2033     }
2034     return result;
2035 
2036   default:
2037     /* HTTP GET/HEAD download, has no body, needs no Content-Length */
2038     data->state.infilesize = 0;
2039     return Curl_creader_set_null(data);
2040   }
2041   /* not reached */
2042 }
2043 
http_resume(struct Curl_easy * data,Curl_HttpReq httpreq)2044 static CURLcode http_resume(struct Curl_easy *data, Curl_HttpReq httpreq)
2045 {
2046   if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
2047      data->state.resume_from) {
2048     /**********************************************************************
2049      * Resuming upload in HTTP means that we PUT or POST and that we have
2050      * got a resume_from value set. The resume value has already created
2051      * a Range: header that will be passed along. We need to "fast forward"
2052      * the file the given number of bytes and decrease the assume upload
2053      * file size before we continue this venture in the dark lands of HTTP.
2054      * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
2055      *********************************************************************/
2056 
2057     if(data->state.resume_from < 0) {
2058       /*
2059        * This is meant to get the size of the present remote-file by itself.
2060        * We don't support this now. Bail out!
2061        */
2062       data->state.resume_from = 0;
2063     }
2064 
2065     if(data->state.resume_from && !data->req.authneg) {
2066       /* only act on the first request */
2067       CURLcode result;
2068       result = Curl_creader_resume_from(data, data->state.resume_from);
2069       if(result) {
2070         failf(data, "Unable to resume from offset %" CURL_FORMAT_CURL_OFF_T,
2071               data->state.resume_from);
2072         return result;
2073       }
2074     }
2075   }
2076   return CURLE_OK;
2077 }
2078 
Curl_http_req_set_reader(struct Curl_easy * data,Curl_HttpReq httpreq,const char ** tep)2079 CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
2080                                   Curl_HttpReq httpreq,
2081                                   const char **tep)
2082 {
2083   CURLcode result = CURLE_OK;
2084   const char *ptr;
2085 
2086   result = set_reader(data, httpreq);
2087   if(result)
2088     return result;
2089 
2090   result = http_resume(data, httpreq);
2091   if(result)
2092     return result;
2093 
2094   ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
2095   if(ptr) {
2096     /* Some kind of TE is requested, check if 'chunked' is chosen */
2097     data->req.upload_chunky =
2098       Curl_compareheader(ptr,
2099                          STRCONST("Transfer-Encoding:"), STRCONST("chunked"));
2100     if(data->req.upload_chunky &&
2101        Curl_use_http_1_1plus(data, data->conn) &&
2102        (data->conn->httpversion >= 20)) {
2103        infof(data, "suppressing chunked transfer encoding on connection "
2104              "using HTTP version 2 or higher");
2105        data->req.upload_chunky = FALSE;
2106     }
2107   }
2108   else {
2109     curl_off_t req_clen = Curl_creader_total_length(data);
2110 
2111     if(req_clen < 0) {
2112       /* indeterminate request content length */
2113       if(Curl_use_http_1_1plus(data, data->conn)) {
2114         /* On HTTP/1.1, enable chunked, on HTTP/2 and later we do not
2115          * need it */
2116         data->req.upload_chunky = (data->conn->httpversion < 20);
2117       }
2118       else {
2119         failf(data, "Chunky upload is not supported by HTTP 1.0");
2120         return CURLE_UPLOAD_FAILED;
2121       }
2122     }
2123     else {
2124       /* else, no chunky upload */
2125       data->req.upload_chunky = FALSE;
2126     }
2127 
2128     if(data->req.upload_chunky)
2129       *tep = "Transfer-Encoding: chunked\r\n";
2130   }
2131   return result;
2132 }
2133 
addexpect(struct Curl_easy * data,struct dynbuf * r,bool * announced_exp100)2134 static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r,
2135                           bool *announced_exp100)
2136 {
2137   CURLcode result;
2138   char *ptr;
2139 
2140   *announced_exp100 = FALSE;
2141   /* Avoid Expect: 100-continue if Upgrade: is used */
2142   if(data->req.upgr101 != UPGR101_INIT)
2143     return CURLE_OK;
2144 
2145   /* For really small puts we don't use Expect: headers at all, and for
2146      the somewhat bigger ones we allow the app to disable it. Just make
2147      sure that the expect100header is always set to the preferred value
2148      here. */
2149   ptr = Curl_checkheaders(data, STRCONST("Expect"));
2150   if(ptr) {
2151     *announced_exp100 =
2152       Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
2153   }
2154   else if(!data->state.disableexpect &&
2155           Curl_use_http_1_1plus(data, data->conn) &&
2156           (data->conn->httpversion < 20)) {
2157     /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
2158        Expect: 100-continue to the headers which actually speeds up post
2159        operations (as there is one packet coming back from the web server) */
2160     curl_off_t client_len = Curl_creader_client_length(data);
2161     if(client_len > EXPECT_100_THRESHOLD || client_len < 0) {
2162       result = Curl_dyn_addn(r, STRCONST("Expect: 100-continue\r\n"));
2163       if(result)
2164         return result;
2165       *announced_exp100 = TRUE;
2166     }
2167   }
2168   return CURLE_OK;
2169 }
2170 
Curl_http_req_complete(struct Curl_easy * data,struct dynbuf * r,Curl_HttpReq httpreq)2171 CURLcode Curl_http_req_complete(struct Curl_easy *data,
2172                                 struct dynbuf *r, Curl_HttpReq httpreq)
2173 {
2174   CURLcode result = CURLE_OK;
2175   curl_off_t req_clen;
2176   bool announced_exp100 = FALSE;
2177 
2178   DEBUGASSERT(data->conn);
2179 #ifndef USE_HYPER
2180   if(data->req.upload_chunky) {
2181     result = Curl_httpchunk_add_reader(data);
2182     if(result)
2183       return result;
2184   }
2185 #endif
2186 
2187   /* Get the request body length that has been set up */
2188   req_clen = Curl_creader_total_length(data);
2189   switch(httpreq) {
2190   case HTTPREQ_PUT:
2191   case HTTPREQ_POST:
2192 #if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
2193   case HTTPREQ_POST_FORM:
2194   case HTTPREQ_POST_MIME:
2195 #endif
2196     /* We only set Content-Length and allow a custom Content-Length if
2197        we don't upload data chunked, as RFC2616 forbids us to set both
2198        kinds of headers (Transfer-Encoding: chunked and Content-Length).
2199        We do not override a custom "Content-Length" header, but during
2200        authentication negotiation that header is suppressed.
2201      */
2202     if(req_clen >= 0 && !data->req.upload_chunky &&
2203        (data->req.authneg ||
2204         !Curl_checkheaders(data, STRCONST("Content-Length")))) {
2205       /* we allow replacing this header if not during auth negotiation,
2206          although it isn't very wise to actually set your own */
2207       result = Curl_dyn_addf(r,
2208                              "Content-Length: %" CURL_FORMAT_CURL_OFF_T
2209                              "\r\n", req_clen);
2210     }
2211     if(result)
2212       goto out;
2213 
2214 #ifndef CURL_DISABLE_MIME
2215     /* Output mime-generated headers. */
2216     if(data->state.mimepost &&
2217        ((httpreq == HTTPREQ_POST_FORM) || (httpreq == HTTPREQ_POST_MIME))) {
2218       struct curl_slist *hdr;
2219 
2220       for(hdr = data->state.mimepost->curlheaders; hdr; hdr = hdr->next) {
2221         result = Curl_dyn_addf(r, "%s\r\n", hdr->data);
2222         if(result)
2223           goto out;
2224       }
2225     }
2226 #endif
2227     if(httpreq == HTTPREQ_POST) {
2228       if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
2229         result = Curl_dyn_addn(r, STRCONST("Content-Type: application/"
2230                                            "x-www-form-urlencoded\r\n"));
2231         if(result)
2232           goto out;
2233       }
2234     }
2235     result = addexpect(data, r, &announced_exp100);
2236     if(result)
2237       goto out;
2238     break;
2239   default:
2240     break;
2241   }
2242 
2243   /* end of headers */
2244   result = Curl_dyn_addn(r, STRCONST("\r\n"));
2245   if(!result) {
2246     Curl_pgrsSetUploadSize(data, req_clen);
2247     if(announced_exp100)
2248       result = http_exp100_add_reader(data);
2249   }
2250 
2251 out:
2252   if(!result) {
2253     /* setup variables for the upcoming transfer */
2254     Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
2255   }
2256   return result;
2257 }
2258 
2259 #if !defined(CURL_DISABLE_COOKIES)
2260 
Curl_http_cookies(struct Curl_easy * data,struct connectdata * conn,struct dynbuf * r)2261 CURLcode Curl_http_cookies(struct Curl_easy *data,
2262                            struct connectdata *conn,
2263                            struct dynbuf *r)
2264 {
2265   CURLcode result = CURLE_OK;
2266   char *addcookies = NULL;
2267   bool linecap = FALSE;
2268   if(data->set.str[STRING_COOKIE] &&
2269      !Curl_checkheaders(data, STRCONST("Cookie")))
2270     addcookies = data->set.str[STRING_COOKIE];
2271 
2272   if(data->cookies || addcookies) {
2273     struct Cookie *co = NULL; /* no cookies from start */
2274     int count = 0;
2275 
2276     if(data->cookies && data->state.cookie_engine) {
2277       const char *host = data->state.aptr.cookiehost ?
2278         data->state.aptr.cookiehost : conn->host.name;
2279       const bool secure_context =
2280         conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
2281         strcasecompare("localhost", host) ||
2282         !strcmp(host, "127.0.0.1") ||
2283         !strcmp(host, "::1") ? TRUE : FALSE;
2284       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
2285       co = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path,
2286                                secure_context);
2287       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
2288     }
2289     if(co) {
2290       struct Cookie *store = co;
2291       size_t clen = 8; /* hold the size of the generated Cookie: header */
2292       /* now loop through all cookies that matched */
2293       while(co) {
2294         if(co->value) {
2295           size_t add;
2296           if(!count) {
2297             result = Curl_dyn_addn(r, STRCONST("Cookie: "));
2298             if(result)
2299               break;
2300           }
2301           add = strlen(co->name) + strlen(co->value) + 1;
2302           if(clen + add >= MAX_COOKIE_HEADER_LEN) {
2303             infof(data, "Restricted outgoing cookies due to header size, "
2304                   "'%s' not sent", co->name);
2305             linecap = TRUE;
2306             break;
2307           }
2308           result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"",
2309                                  co->name, co->value);
2310           if(result)
2311             break;
2312           clen += add + (count ? 2 : 0);
2313           count++;
2314         }
2315         co = co->next; /* next cookie please */
2316       }
2317       Curl_cookie_freelist(store);
2318     }
2319     if(addcookies && !result && !linecap) {
2320       if(!count)
2321         result = Curl_dyn_addn(r, STRCONST("Cookie: "));
2322       if(!result) {
2323         result = Curl_dyn_addf(r, "%s%s", count?"; ":"", addcookies);
2324         count++;
2325       }
2326     }
2327     if(count && !result)
2328       result = Curl_dyn_addn(r, STRCONST("\r\n"));
2329 
2330     if(result)
2331       return result;
2332   }
2333   return result;
2334 }
2335 #endif
2336 
Curl_http_range(struct Curl_easy * data,Curl_HttpReq httpreq)2337 CURLcode Curl_http_range(struct Curl_easy *data,
2338                          Curl_HttpReq httpreq)
2339 {
2340   if(data->state.use_range) {
2341     /*
2342      * A range is selected. We use different headers whether we're downloading
2343      * or uploading and we always let customized headers override our internal
2344      * ones if any such are specified.
2345      */
2346     if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
2347        !Curl_checkheaders(data, STRCONST("Range"))) {
2348       /* if a line like this was already allocated, free the previous one */
2349       free(data->state.aptr.rangeline);
2350       data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
2351                                            data->state.range);
2352     }
2353     else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
2354             !Curl_checkheaders(data, STRCONST("Content-Range"))) {
2355       curl_off_t req_clen = Curl_creader_total_length(data);
2356       /* if a line like this was already allocated, free the previous one */
2357       free(data->state.aptr.rangeline);
2358 
2359       if(data->set.set_resume_from < 0) {
2360         /* Upload resume was asked for, but we don't know the size of the
2361            remote part so we tell the server (and act accordingly) that we
2362            upload the whole file (again) */
2363         data->state.aptr.rangeline =
2364           aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
2365                   "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
2366                   req_clen - 1, req_clen);
2367 
2368       }
2369       else if(data->state.resume_from) {
2370         /* This is because "resume" was selected */
2371         /* TODO: not sure if we want to send this header during authentication
2372          * negotiation, but test1084 checks for it. In which case we have a
2373          * "null" client reader installed that gives an unexpected length. */
2374         curl_off_t total_len = data->req.authneg?
2375                                data->state.infilesize :
2376                                (data->state.resume_from + req_clen);
2377         data->state.aptr.rangeline =
2378           aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
2379                   "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
2380                   data->state.range, total_len-1, total_len);
2381       }
2382       else {
2383         /* Range was selected and then we just pass the incoming range and
2384            append total size */
2385         data->state.aptr.rangeline =
2386           aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n",
2387                   data->state.range, req_clen);
2388       }
2389       if(!data->state.aptr.rangeline)
2390         return CURLE_OUT_OF_MEMORY;
2391     }
2392   }
2393   return CURLE_OK;
2394 }
2395 
Curl_http_firstwrite(struct Curl_easy * data)2396 CURLcode Curl_http_firstwrite(struct Curl_easy *data)
2397 {
2398   struct connectdata *conn = data->conn;
2399   struct SingleRequest *k = &data->req;
2400 
2401   if(data->req.newurl) {
2402     if(conn->bits.close) {
2403       /* Abort after the headers if "follow Location" is set
2404          and we're set to close anyway. */
2405       k->keepon &= ~KEEP_RECV;
2406       k->done = TRUE;
2407       return CURLE_OK;
2408     }
2409     /* We have a new url to load, but since we want to be able to reuse this
2410        connection properly, we read the full response in "ignore more" */
2411     k->ignorebody = TRUE;
2412     infof(data, "Ignoring the response-body");
2413   }
2414   if(data->state.resume_from && !k->content_range &&
2415      (data->state.httpreq == HTTPREQ_GET) &&
2416      !k->ignorebody) {
2417 
2418     if(k->size == data->state.resume_from) {
2419       /* The resume point is at the end of file, consider this fine even if it
2420          doesn't allow resume from here. */
2421       infof(data, "The entire document is already downloaded");
2422       streamclose(conn, "already downloaded");
2423       /* Abort download */
2424       k->keepon &= ~KEEP_RECV;
2425       k->done = TRUE;
2426       return CURLE_OK;
2427     }
2428 
2429     /* we wanted to resume a download, although the server doesn't seem to
2430      * support this and we did this with a GET (if it wasn't a GET we did a
2431      * POST or PUT resume) */
2432     failf(data, "HTTP server doesn't seem to support "
2433           "byte ranges. Cannot resume.");
2434     return CURLE_RANGE_ERROR;
2435   }
2436 
2437   if(data->set.timecondition && !data->state.range) {
2438     /* A time condition has been set AND no ranges have been requested. This
2439        seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct
2440        action for an HTTP/1.1 client */
2441 
2442     if(!Curl_meets_timecondition(data, k->timeofdoc)) {
2443       k->done = TRUE;
2444       /* We're simulating an HTTP 304 from server so we return
2445          what should have been returned from the server */
2446       data->info.httpcode = 304;
2447       infof(data, "Simulate an HTTP 304 response");
2448       /* we abort the transfer before it is completed == we ruin the
2449          reuse ability. Close the connection */
2450       streamclose(conn, "Simulated 304 handling");
2451       return CURLE_OK;
2452     }
2453   } /* we have a time condition */
2454 
2455   return CURLE_OK;
2456 }
2457 
2458 #ifdef HAVE_LIBZ
Curl_transferencode(struct Curl_easy * data)2459 CURLcode Curl_transferencode(struct Curl_easy *data)
2460 {
2461   if(!Curl_checkheaders(data, STRCONST("TE")) &&
2462      data->set.http_transfer_encoding) {
2463     /* When we are to insert a TE: header in the request, we must also insert
2464        TE in a Connection: header, so we need to merge the custom provided
2465        Connection: header and prevent the original to get sent. Note that if
2466        the user has inserted his/her own TE: header we don't do this magic
2467        but then assume that the user will handle it all! */
2468     char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
2469 #define TE_HEADER "TE: gzip\r\n"
2470 
2471     Curl_safefree(data->state.aptr.te);
2472 
2473     if(cptr) {
2474       cptr = Curl_copy_header_value(cptr);
2475       if(!cptr)
2476         return CURLE_OUT_OF_MEMORY;
2477     }
2478 
2479     /* Create the (updated) Connection: header */
2480     data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
2481                                 cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
2482 
2483     free(cptr);
2484     if(!data->state.aptr.te)
2485       return CURLE_OUT_OF_MEMORY;
2486   }
2487   return CURLE_OK;
2488 }
2489 #endif
2490 
2491 #ifndef USE_HYPER
2492 /*
2493  * Curl_http() gets called from the generic multi_do() function when an HTTP
2494  * request is to be performed. This creates and sends a properly constructed
2495  * HTTP request.
2496  */
Curl_http(struct Curl_easy * data,bool * done)2497 CURLcode Curl_http(struct Curl_easy *data, bool *done)
2498 {
2499   struct connectdata *conn = data->conn;
2500   CURLcode result = CURLE_OK;
2501   Curl_HttpReq httpreq;
2502   const char *te = ""; /* transfer-encoding */
2503   const char *request;
2504   const char *httpstring;
2505   struct dynbuf req;
2506   char *altused = NULL;
2507   const char *p_accept;      /* Accept: string */
2508 
2509   /* Always consider the DO phase done after this function call, even if there
2510      may be parts of the request that are not yet sent, since we can deal with
2511      the rest of the request in the PERFORM phase. */
2512   *done = TRUE;
2513 
2514   switch(conn->alpn) {
2515   case CURL_HTTP_VERSION_3:
2516     DEBUGASSERT(Curl_conn_is_http3(data, conn, FIRSTSOCKET));
2517     break;
2518   case CURL_HTTP_VERSION_2:
2519 #ifndef CURL_DISABLE_PROXY
2520     if(!Curl_conn_is_http2(data, conn, FIRSTSOCKET) &&
2521        conn->bits.proxy && !conn->bits.tunnel_proxy
2522       ) {
2523       result = Curl_http2_switch(data, conn, FIRSTSOCKET);
2524       if(result)
2525         goto fail;
2526     }
2527     else
2528 #endif
2529       DEBUGASSERT(Curl_conn_is_http2(data, conn, FIRSTSOCKET));
2530     break;
2531   case CURL_HTTP_VERSION_1_1:
2532     /* continue with HTTP/1.x when explicitly requested */
2533     break;
2534   default:
2535     /* Check if user wants to use HTTP/2 with clear TCP */
2536     if(Curl_http2_may_switch(data, conn, FIRSTSOCKET)) {
2537       DEBUGF(infof(data, "HTTP/2 over clean TCP"));
2538       result = Curl_http2_switch(data, conn, FIRSTSOCKET);
2539       if(result)
2540         goto fail;
2541     }
2542     break;
2543   }
2544 
2545   /* Add collecting of headers written to client. For a new connection,
2546    * we might have done that already, but reuse
2547    * or multiplex needs it here as well. */
2548   result = Curl_headers_init(data);
2549   if(result)
2550     goto fail;
2551 
2552   result = Curl_http_host(data, conn);
2553   if(result)
2554     goto fail;
2555 
2556   result = Curl_http_useragent(data);
2557   if(result)
2558     goto fail;
2559 
2560   Curl_http_method(data, conn, &request, &httpreq);
2561 
2562   /* setup the authentication headers */
2563   {
2564     char *pq = NULL;
2565     if(data->state.up.query) {
2566       pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
2567       if(!pq)
2568         return CURLE_OUT_OF_MEMORY;
2569     }
2570     result = Curl_http_output_auth(data, conn, request, httpreq,
2571                                    (pq ? pq : data->state.up.path), FALSE);
2572     free(pq);
2573     if(result)
2574       goto fail;
2575   }
2576 
2577   Curl_safefree(data->state.aptr.ref);
2578   if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) {
2579     data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
2580     if(!data->state.aptr.ref)
2581       return CURLE_OUT_OF_MEMORY;
2582   }
2583 
2584   if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
2585      data->set.str[STRING_ENCODING]) {
2586     Curl_safefree(data->state.aptr.accept_encoding);
2587     data->state.aptr.accept_encoding =
2588       aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
2589     if(!data->state.aptr.accept_encoding)
2590       return CURLE_OUT_OF_MEMORY;
2591   }
2592   else
2593     Curl_safefree(data->state.aptr.accept_encoding);
2594 
2595 #ifdef HAVE_LIBZ
2596   /* we only consider transfer-encoding magic if libz support is built-in */
2597   result = Curl_transferencode(data);
2598   if(result)
2599     goto fail;
2600 #endif
2601 
2602   result = Curl_http_req_set_reader(data, httpreq, &te);
2603   if(result)
2604     goto fail;
2605 
2606   p_accept = Curl_checkheaders(data,
2607                                STRCONST("Accept"))?NULL:"Accept: */*\r\n";
2608 
2609   result = Curl_http_range(data, httpreq);
2610   if(result)
2611     goto fail;
2612 
2613   httpstring = get_http_string(data, conn);
2614 
2615   /* initialize a dynamic send-buffer */
2616   Curl_dyn_init(&req, DYN_HTTP_REQUEST);
2617 
2618   /* make sure the header buffer is reset - if there are leftovers from a
2619      previous transfer */
2620   Curl_dyn_reset(&data->state.headerb);
2621 
2622   /* add the main request stuff */
2623   /* GET/HEAD/POST/PUT */
2624   result = Curl_dyn_addf(&req, "%s ", request);
2625   if(!result)
2626     result = Curl_http_target(data, conn, &req);
2627   if(result) {
2628     Curl_dyn_free(&req);
2629     goto fail;
2630   }
2631 
2632 #ifndef CURL_DISABLE_ALTSVC
2633   if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) {
2634     altused = aprintf("Alt-Used: %s:%d\r\n",
2635                       conn->conn_to_host.name, conn->conn_to_port);
2636     if(!altused) {
2637       Curl_dyn_free(&req);
2638       return CURLE_OUT_OF_MEMORY;
2639     }
2640   }
2641 #endif
2642   result =
2643     Curl_dyn_addf(&req,
2644                   " HTTP/%s\r\n" /* HTTP version */
2645                   "%s" /* host */
2646                   "%s" /* proxyuserpwd */
2647                   "%s" /* userpwd */
2648                   "%s" /* range */
2649                   "%s" /* user agent */
2650                   "%s" /* accept */
2651                   "%s" /* TE: */
2652                   "%s" /* accept-encoding */
2653                   "%s" /* referer */
2654                   "%s" /* Proxy-Connection */
2655                   "%s" /* transfer-encoding */
2656                   "%s",/* Alt-Used */
2657 
2658                   httpstring,
2659                   (data->state.aptr.host?data->state.aptr.host:""),
2660 #ifndef CURL_DISABLE_PROXY
2661                   data->state.aptr.proxyuserpwd?
2662                   data->state.aptr.proxyuserpwd:"",
2663 #else
2664                   "",
2665 #endif
2666                   data->state.aptr.userpwd?data->state.aptr.userpwd:"",
2667                   (data->state.use_range && data->state.aptr.rangeline)?
2668                   data->state.aptr.rangeline:"",
2669                   (data->set.str[STRING_USERAGENT] &&
2670                    *data->set.str[STRING_USERAGENT] &&
2671                    data->state.aptr.uagent)?
2672                   data->state.aptr.uagent:"",
2673                   p_accept?p_accept:"",
2674                   data->state.aptr.te?data->state.aptr.te:"",
2675                   (data->set.str[STRING_ENCODING] &&
2676                    *data->set.str[STRING_ENCODING] &&
2677                    data->state.aptr.accept_encoding)?
2678                   data->state.aptr.accept_encoding:"",
2679                   (data->state.referer && data->state.aptr.ref)?
2680                   data->state.aptr.ref:"" /* Referer: <data> */,
2681 #ifndef CURL_DISABLE_PROXY
2682                   (conn->bits.httpproxy &&
2683                    !conn->bits.tunnel_proxy &&
2684                    !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
2685                    !Curl_checkProxyheaders(data,
2686                                            conn,
2687                                            STRCONST("Proxy-Connection")))?
2688                   "Proxy-Connection: Keep-Alive\r\n":"",
2689 #else
2690                   "",
2691 #endif
2692                   te,
2693                   altused ? altused : ""
2694       );
2695 
2696   /* clear userpwd and proxyuserpwd to avoid reusing old credentials
2697    * from reused connections */
2698   Curl_safefree(data->state.aptr.userpwd);
2699 #ifndef CURL_DISABLE_PROXY
2700   Curl_safefree(data->state.aptr.proxyuserpwd);
2701 #endif
2702   free(altused);
2703 
2704   if(result) {
2705     Curl_dyn_free(&req);
2706     goto fail;
2707   }
2708 
2709   if(!(conn->handler->flags&PROTOPT_SSL) &&
2710      conn->httpversion < 20 &&
2711      (data->state.httpwant == CURL_HTTP_VERSION_2)) {
2712     /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
2713        over SSL */
2714     result = Curl_http2_request_upgrade(&req, data);
2715     if(result) {
2716       Curl_dyn_free(&req);
2717       return result;
2718     }
2719   }
2720 
2721   result = Curl_http_cookies(data, conn, &req);
2722 #ifdef USE_WEBSOCKETS
2723   if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
2724     result = Curl_ws_request(data, &req);
2725 #endif
2726   if(!result)
2727     result = Curl_add_timecondition(data, &req);
2728   if(!result)
2729     result = Curl_add_custom_headers(data, FALSE, &req);
2730 
2731   if(!result) {
2732     /* req_send takes ownership of the 'req' memory on success */
2733     result = Curl_http_req_complete(data, &req, httpreq);
2734     if(!result)
2735       result = Curl_req_send(data, &req);
2736   }
2737   Curl_dyn_free(&req);
2738   if(result)
2739     goto fail;
2740 
2741   if((conn->httpversion >= 20) && data->req.upload_chunky)
2742     /* upload_chunky was set above to set up the request in a chunky fashion,
2743        but is disabled here again to avoid that the chunked encoded version is
2744        actually used when sending the request body over h2 */
2745     data->req.upload_chunky = FALSE;
2746 fail:
2747   if(CURLE_TOO_LARGE == result)
2748     failf(data, "HTTP request too large");
2749   return result;
2750 }
2751 
2752 #endif /* USE_HYPER */
2753 
2754 typedef enum {
2755   STATUS_UNKNOWN, /* not enough data to tell yet */
2756   STATUS_DONE, /* a status line was read */
2757   STATUS_BAD /* not a status line */
2758 } statusline;
2759 
2760 
2761 /* Check a string for a prefix. Check no more than 'len' bytes */
checkprefixmax(const char * prefix,const char * buffer,size_t len)2762 static bool checkprefixmax(const char *prefix, const char *buffer, size_t len)
2763 {
2764   size_t ch = CURLMIN(strlen(prefix), len);
2765   return curl_strnequal(prefix, buffer, ch);
2766 }
2767 
2768 /*
2769  * checkhttpprefix()
2770  *
2771  * Returns TRUE if member of the list matches prefix of string
2772  */
2773 static statusline
checkhttpprefix(struct Curl_easy * data,const char * s,size_t len)2774 checkhttpprefix(struct Curl_easy *data,
2775                 const char *s, size_t len)
2776 {
2777   struct curl_slist *head = data->set.http200aliases;
2778   statusline rc = STATUS_BAD;
2779   statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
2780 
2781   while(head) {
2782     if(checkprefixmax(head->data, s, len)) {
2783       rc = onmatch;
2784       break;
2785     }
2786     head = head->next;
2787   }
2788 
2789   if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len)))
2790     rc = onmatch;
2791 
2792   return rc;
2793 }
2794 
2795 #ifndef CURL_DISABLE_RTSP
2796 static statusline
checkrtspprefix(struct Curl_easy * data,const char * s,size_t len)2797 checkrtspprefix(struct Curl_easy *data,
2798                 const char *s, size_t len)
2799 {
2800   statusline result = STATUS_BAD;
2801   statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
2802   (void)data; /* unused */
2803   if(checkprefixmax("RTSP/", s, len))
2804     result = onmatch;
2805 
2806   return result;
2807 }
2808 #endif /* CURL_DISABLE_RTSP */
2809 
2810 static statusline
checkprotoprefix(struct Curl_easy * data,struct connectdata * conn,const char * s,size_t len)2811 checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
2812                  const char *s, size_t len)
2813 {
2814 #ifndef CURL_DISABLE_RTSP
2815   if(conn->handler->protocol & CURLPROTO_RTSP)
2816     return checkrtspprefix(data, s, len);
2817 #else
2818   (void)conn;
2819 #endif /* CURL_DISABLE_RTSP */
2820 
2821   return checkhttpprefix(data, s, len);
2822 }
2823 
2824 /* HTTP header has field name `n` (a string constant) */
2825 #define HD_IS(hd, hdlen, n) \
2826   (((hdlen) >= (sizeof(n)-1)) && curl_strnequal((n), (hd), (sizeof(n)-1)))
2827 
2828 #define HD_VAL(hd, hdlen, n) \
2829   ((((hdlen) >= (sizeof(n)-1)) && \
2830     curl_strnequal((n), (hd), (sizeof(n)-1)))? (hd + (sizeof(n)-1)) : NULL)
2831 
2832 /* HTTP header has field name `n` (a string constant) and contains `v`
2833  * (a string constant) in its value(s) */
2834 #define HD_IS_AND_SAYS(hd, hdlen, n, v) \
2835   (HD_IS(hd, hdlen, n) && \
2836    ((hdlen) > ((sizeof(n)-1) + (sizeof(v)-1))) && \
2837    Curl_compareheader(hd, STRCONST(n), STRCONST(v)))
2838 
2839 /*
2840  * Curl_http_header() parses a single response header.
2841  */
Curl_http_header(struct Curl_easy * data,const char * hd,size_t hdlen)2842 CURLcode Curl_http_header(struct Curl_easy *data,
2843                           const char *hd, size_t hdlen)
2844 {
2845   struct connectdata *conn = data->conn;
2846   CURLcode result;
2847   struct SingleRequest *k = &data->req;
2848   const char *v;
2849 
2850   switch(hd[0]) {
2851   case 'a':
2852   case 'A':
2853 #ifndef CURL_DISABLE_ALTSVC
2854     v = (data->asi &&
2855          ((data->conn->handler->flags & PROTOPT_SSL) ||
2856 #ifdef CURLDEBUG
2857           /* allow debug builds to circumvent the HTTPS restriction */
2858           getenv("CURL_ALTSVC_HTTP")
2859 #else
2860           0
2861 #endif
2862         ))? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
2863     if(v) {
2864       /* the ALPN of the current request */
2865       enum alpnid id = (conn->httpversion == 30)? ALPN_h3 :
2866                          (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
2867       return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
2868                                curlx_uitous((unsigned int)conn->remote_port));
2869     }
2870 #endif
2871     break;
2872   case 'c':
2873   case 'C':
2874     /* Check for Content-Length: header lines to get size */
2875     v = (!k->http_bodyless && !data->set.ignorecl)?
2876         HD_VAL(hd, hdlen, "Content-Length:") : NULL;
2877     if(v) {
2878       curl_off_t contentlength;
2879       CURLofft offt = curlx_strtoofft(v, NULL, 10, &contentlength);
2880 
2881       if(offt == CURL_OFFT_OK) {
2882         k->size = contentlength;
2883         k->maxdownload = k->size;
2884       }
2885       else if(offt == CURL_OFFT_FLOW) {
2886         /* out of range */
2887         if(data->set.max_filesize) {
2888           failf(data, "Maximum file size exceeded");
2889           return CURLE_FILESIZE_EXCEEDED;
2890         }
2891         streamclose(conn, "overflow content-length");
2892         infof(data, "Overflow Content-Length: value");
2893       }
2894       else {
2895         /* negative or just rubbish - bad HTTP */
2896         failf(data, "Invalid Content-Length: value");
2897         return CURLE_WEIRD_SERVER_REPLY;
2898       }
2899       return CURLE_OK;
2900     }
2901     v = (!k->http_bodyless && data->set.str[STRING_ENCODING])?
2902         HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
2903     if(v) {
2904       /*
2905        * Process Content-Encoding. Look for the values: identity,
2906        * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
2907        * x-compress are the same as gzip and compress. (Sec 3.5 RFC
2908        * 2616). zlib cannot handle compress.  However, errors are
2909        * handled further down when the response body is processed
2910        */
2911       return Curl_build_unencoding_stack(data, v, FALSE);
2912     }
2913     /* check for Content-Type: header lines to get the MIME-type */
2914     v = HD_VAL(hd, hdlen, "Content-Type:");
2915     if(v) {
2916       char *contenttype = Curl_copy_header_value(hd);
2917       if(!contenttype)
2918         return CURLE_OUT_OF_MEMORY;
2919       if(!*contenttype)
2920         /* ignore empty data */
2921         free(contenttype);
2922       else {
2923         Curl_safefree(data->info.contenttype);
2924         data->info.contenttype = contenttype;
2925       }
2926       return CURLE_OK;
2927     }
2928     if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
2929       /*
2930        * [RFC 2616, section 8.1.2.1]
2931        * "Connection: close" is HTTP/1.1 language and means that
2932        * the connection will close when this request has been
2933        * served.
2934        */
2935       streamclose(conn, "Connection: close used");
2936       return CURLE_OK;
2937     }
2938     if((conn->httpversion == 10) &&
2939        HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
2940       /*
2941        * An HTTP/1.0 reply with the 'Connection: keep-alive' line
2942        * tells us the connection will be kept alive for our
2943        * pleasure.  Default action for 1.0 is to close.
2944        *
2945        * [RFC2068, section 19.7.1] */
2946       connkeep(conn, "Connection keep-alive");
2947       infof(data, "HTTP/1.0 connection set to keep alive");
2948       return CURLE_OK;
2949     }
2950     v = !k->http_bodyless? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
2951     if(v) {
2952       /* Content-Range: bytes [num]-
2953          Content-Range: bytes: [num]-
2954          Content-Range: [num]-
2955          Content-Range: [asterisk]/[total]
2956 
2957          The second format was added since Sun's webserver
2958          JavaWebServer/1.1.1 obviously sends the header this way!
2959          The third added since some servers use that!
2960          The fourth means the requested range was unsatisfied.
2961       */
2962 
2963       const char *ptr = v;
2964 
2965       /* Move forward until first digit or asterisk */
2966       while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
2967         ptr++;
2968 
2969       /* if it truly stopped on a digit */
2970       if(ISDIGIT(*ptr)) {
2971         if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
2972           if(data->state.resume_from == k->offset)
2973             /* we asked for a resume and we got it */
2974             k->content_range = TRUE;
2975         }
2976       }
2977       else if(k->httpcode < 300)
2978         data->state.resume_from = 0; /* get everything */
2979     }
2980     break;
2981   case 'l':
2982   case 'L':
2983     v = (!k->http_bodyless &&
2984          (data->set.timecondition || data->set.get_filetime))?
2985         HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
2986     if(v) {
2987       k->timeofdoc = Curl_getdate_capped(v);
2988       if(data->set.get_filetime)
2989         data->info.filetime = k->timeofdoc;
2990       return CURLE_OK;
2991     }
2992     if((k->httpcode >= 300 && k->httpcode < 400) &&
2993             HD_IS(hd, hdlen, "Location:") &&
2994             !data->req.location) {
2995       /* this is the URL that the server advises us to use instead */
2996       char *location = Curl_copy_header_value(hd);
2997       if(!location)
2998         return CURLE_OUT_OF_MEMORY;
2999       if(!*location)
3000         /* ignore empty data */
3001         free(location);
3002       else {
3003         data->req.location = location;
3004 
3005         if(data->set.http_follow_location) {
3006           DEBUGASSERT(!data->req.newurl);
3007           data->req.newurl = strdup(data->req.location); /* clone */
3008           if(!data->req.newurl)
3009             return CURLE_OUT_OF_MEMORY;
3010 
3011           /* some cases of POST and PUT etc needs to rewind the data
3012              stream at this point */
3013           result = http_perhapsrewind(data, conn);
3014           if(result)
3015             return result;
3016 
3017           /* mark the next request as a followed location: */
3018           data->state.this_is_a_follow = TRUE;
3019         }
3020       }
3021     }
3022     break;
3023   case 'p':
3024   case 'P':
3025 #ifndef CURL_DISABLE_PROXY
3026     v = HD_VAL(hd, hdlen, "Proxy-Connection:");
3027     if(v) {
3028       if((conn->httpversion == 10) && conn->bits.httpproxy &&
3029          HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
3030         /*
3031          * When an HTTP/1.0 reply comes when using a proxy, the
3032          * 'Proxy-Connection: keep-alive' line tells us the
3033          * connection will be kept alive for our pleasure.
3034          * Default action for 1.0 is to close.
3035          */
3036         connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
3037         infof(data, "HTTP/1.0 proxy connection set to keep alive");
3038       }
3039       else if((conn->httpversion == 11) && conn->bits.httpproxy &&
3040               HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
3041         /*
3042          * We get an HTTP/1.1 response from a proxy and it says it'll
3043          * close down after this transfer.
3044          */
3045         connclose(conn, "Proxy-Connection: asked to close after done");
3046         infof(data, "HTTP/1.1 proxy connection set close");
3047       }
3048       return CURLE_OK;
3049     }
3050 #endif
3051     if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) {
3052       char *auth = Curl_copy_header_value(hd);
3053       if(!auth)
3054         return CURLE_OUT_OF_MEMORY;
3055       result = Curl_http_input_auth(data, TRUE, auth);
3056       free(auth);
3057       return result;
3058     }
3059 #ifdef USE_SPNEGO
3060     if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
3061       struct negotiatedata *negdata = &conn->negotiate;
3062       struct auth *authp = &data->state.authhost;
3063       if(authp->picked == CURLAUTH_NEGOTIATE) {
3064         char *persistentauth = Curl_copy_header_value(hd);
3065         if(!persistentauth)
3066           return CURLE_OUT_OF_MEMORY;
3067         negdata->noauthpersist = checkprefix("false", persistentauth)?
3068           TRUE:FALSE;
3069         negdata->havenoauthpersist = TRUE;
3070         infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
3071               negdata->noauthpersist, persistentauth);
3072         free(persistentauth);
3073       }
3074     }
3075 #endif
3076     break;
3077   case 'r':
3078   case 'R':
3079     v = HD_VAL(hd, hdlen, "Retry-After:");
3080     if(v) {
3081       /* Retry-After = HTTP-date / delay-seconds */
3082       curl_off_t retry_after = 0; /* zero for unknown or "now" */
3083       /* Try it as a decimal number, if it works it is not a date */
3084       (void)curlx_strtoofft(v, NULL, 10, &retry_after);
3085       if(!retry_after) {
3086         time_t date = Curl_getdate_capped(v);
3087         if(-1 != date)
3088           /* convert date to number of seconds into the future */
3089           retry_after = date - time(NULL);
3090       }
3091       data->info.retry_after = retry_after; /* store it */
3092       return CURLE_OK;
3093     }
3094     break;
3095   case 's':
3096   case 'S':
3097 #if !defined(CURL_DISABLE_COOKIES)
3098     v = (data->cookies && data->state.cookie_engine)?
3099         HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
3100     if(v) {
3101       /* If there is a custom-set Host: name, use it here, or else use
3102        * real peer host name. */
3103       const char *host = data->state.aptr.cookiehost?
3104         data->state.aptr.cookiehost:conn->host.name;
3105       const bool secure_context =
3106         conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
3107         strcasecompare("localhost", host) ||
3108         !strcmp(host, "127.0.0.1") ||
3109         !strcmp(host, "::1") ? TRUE : FALSE;
3110 
3111       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
3112                       CURL_LOCK_ACCESS_SINGLE);
3113       Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
3114                       data->state.up.path, secure_context);
3115       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
3116       return CURLE_OK;
3117     }
3118 #endif
3119 #ifndef CURL_DISABLE_HSTS
3120     /* If enabled, the header is incoming and this is over HTTPS */
3121     v = (data->hsts &&
3122          ((conn->handler->flags & PROTOPT_SSL) ||
3123 #ifdef CURLDEBUG
3124            /* allow debug builds to circumvent the HTTPS restriction */
3125            getenv("CURL_HSTS_HTTP")
3126 #else
3127            0
3128 #endif
3129             )
3130         )? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
3131     if(v) {
3132       CURLcode check =
3133         Curl_hsts_parse(data->hsts, conn->host.name, v);
3134       if(check)
3135         infof(data, "Illegal STS header skipped");
3136 #ifdef DEBUGBUILD
3137       else
3138         infof(data, "Parsed STS header fine (%zu entries)",
3139               data->hsts->list.size);
3140 #endif
3141     }
3142 #endif
3143     break;
3144   case 't':
3145   case 'T':
3146     /* RFC 9112, ch. 6.1
3147      * "Transfer-Encoding MAY be sent in a response to a HEAD request or
3148      *  in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a
3149      *  GET request, neither of which includes a message body, to indicate
3150      *  that the origin server would have applied a transfer coding to the
3151      *  message body if the request had been an unconditional GET."
3152      *
3153      * Read: in these cases the 'Transfer-Encoding' does not apply
3154      * to any data following the response headers. Do not add any decoders.
3155      */
3156     v = (!k->http_bodyless &&
3157          (data->state.httpreq != HTTPREQ_HEAD) &&
3158          (k->httpcode != 304))?
3159         HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
3160     if(v) {
3161       /* One or more encodings. We check for chunked and/or a compression
3162          algorithm. */
3163       result = Curl_build_unencoding_stack(data, v, TRUE);
3164       if(result)
3165         return result;
3166       if(!k->chunk && data->set.http_transfer_encoding) {
3167         /* if this isn't chunked, only close can signal the end of this
3168          * transfer as Content-Length is said not to be trusted for
3169          * transfer-encoding! */
3170         connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
3171         k->ignore_cl = TRUE;
3172       }
3173       return CURLE_OK;
3174     }
3175     break;
3176   case 'w':
3177   case 'W':
3178     if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) {
3179       char *auth = Curl_copy_header_value(hd);
3180       if(!auth)
3181         return CURLE_OUT_OF_MEMORY;
3182       result = Curl_http_input_auth(data, FALSE, auth);
3183       free(auth);
3184       return result;
3185     }
3186     break;
3187   }
3188 
3189   if(conn->handler->protocol & CURLPROTO_RTSP) {
3190     result = Curl_rtsp_parseheader(data, hd);
3191     if(result)
3192       return result;
3193   }
3194   return CURLE_OK;
3195 }
3196 
3197 /*
3198  * Called after the first HTTP response line (the status line) has been
3199  * received and parsed.
3200  */
Curl_http_statusline(struct Curl_easy * data,struct connectdata * conn)3201 CURLcode Curl_http_statusline(struct Curl_easy *data,
3202                               struct connectdata *conn)
3203 {
3204   struct SingleRequest *k = &data->req;
3205 
3206   switch(k->httpversion) {
3207   case 10:
3208   case 11:
3209 #ifdef USE_HTTP2
3210   case 20:
3211 #endif
3212 #ifdef USE_HTTP3
3213   case 30:
3214 #endif
3215     /* no major version switch mid-connection */
3216     if(conn->httpversion &&
3217        (k->httpversion/10 != conn->httpversion/10)) {
3218       failf(data, "Version mismatch (from HTTP/%u to HTTP/%u)",
3219             conn->httpversion/10, k->httpversion/10);
3220       return CURLE_UNSUPPORTED_PROTOCOL;
3221     }
3222     break;
3223   default:
3224     failf(data, "Unsupported HTTP version (%u.%d) in response",
3225           k->httpversion/10, k->httpversion%10);
3226     return CURLE_UNSUPPORTED_PROTOCOL;
3227   }
3228 
3229   data->info.httpcode = k->httpcode;
3230   data->info.httpversion = k->httpversion;
3231   conn->httpversion = (unsigned char)k->httpversion;
3232 
3233   if(!data->state.httpversion || data->state.httpversion > k->httpversion)
3234     /* store the lowest server version we encounter */
3235     data->state.httpversion = (unsigned char)k->httpversion;
3236 
3237   /*
3238    * This code executes as part of processing the header.  As a
3239    * result, it's not totally clear how to interpret the
3240    * response code yet as that depends on what other headers may
3241    * be present.  401 and 407 may be errors, but may be OK
3242    * depending on how authentication is working.  Other codes
3243    * are definitely errors, so give up here.
3244    */
3245   if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
3246      k->httpcode == 416) {
3247     /* "Requested Range Not Satisfiable", just proceed and
3248        pretend this is no error */
3249     k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
3250   }
3251 
3252   if(k->httpversion == 10) {
3253     /* Default action for HTTP/1.0 must be to close, unless
3254        we get one of those fancy headers that tell us the
3255        server keeps it open for us! */
3256     infof(data, "HTTP 1.0, assume close after body");
3257     connclose(conn, "HTTP/1.0 close after body");
3258   }
3259   else if(k->httpversion == 20 ||
3260           (k->upgr101 == UPGR101_H2 && k->httpcode == 101)) {
3261     DEBUGF(infof(data, "HTTP/2 found, allow multiplexing"));
3262     /* HTTP/2 cannot avoid multiplexing since it is a core functionality
3263        of the protocol */
3264     conn->bundle->multiuse = BUNDLE_MULTIPLEX;
3265   }
3266 
3267   k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
3268   switch(k->httpcode) {
3269   case 304:
3270     /* (quote from RFC2616, section 10.3.5): The 304 response
3271      * MUST NOT contain a message-body, and thus is always
3272      * terminated by the first empty line after the header
3273      * fields.  */
3274     if(data->set.timecondition)
3275       data->info.timecond = TRUE;
3276     FALLTHROUGH();
3277   case 204:
3278     /* (quote from RFC2616, section 10.2.5): The server has
3279      * fulfilled the request but does not need to return an
3280      * entity-body ... The 204 response MUST NOT include a
3281      * message-body, and thus is always terminated by the first
3282      * empty line after the header fields. */
3283     k->size = 0;
3284     k->maxdownload = 0;
3285     k->http_bodyless = TRUE;
3286     break;
3287   default:
3288     break;
3289   }
3290   return CURLE_OK;
3291 }
3292 
3293 /* Content-Length must be ignored if any Transfer-Encoding is present in the
3294    response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4.  This is
3295    figured out here after all headers have been received but before the final
3296    call to the user's header callback, so that a valid content length can be
3297    retrieved by the user in the final call. */
Curl_http_size(struct Curl_easy * data)3298 CURLcode Curl_http_size(struct Curl_easy *data)
3299 {
3300   struct SingleRequest *k = &data->req;
3301   if(data->req.ignore_cl || k->chunk) {
3302     k->size = k->maxdownload = -1;
3303   }
3304   else if(k->size != -1) {
3305     if(data->set.max_filesize &&
3306        k->size > data->set.max_filesize) {
3307       failf(data, "Maximum file size exceeded");
3308       return CURLE_FILESIZE_EXCEEDED;
3309     }
3310     Curl_pgrsSetDownloadSize(data, k->size);
3311     k->maxdownload = k->size;
3312   }
3313   return CURLE_OK;
3314 }
3315 
verify_header(struct Curl_easy * data,const char * hd,size_t hdlen)3316 static CURLcode verify_header(struct Curl_easy *data,
3317                               const char *hd, size_t hdlen)
3318 {
3319   struct SingleRequest *k = &data->req;
3320   char *ptr = memchr(hd, 0x00, hdlen);
3321   if(ptr) {
3322     /* this is bad, bail out */
3323     failf(data, "Nul byte in header");
3324     return CURLE_WEIRD_SERVER_REPLY;
3325   }
3326   if(k->headerline < 2)
3327     /* the first "header" is the status-line and it has no colon */
3328     return CURLE_OK;
3329   if(((hd[0] == ' ') || (hd[0] == '\t')) && k->headerline > 2)
3330     /* line folding, can't happen on line 2 */
3331     ;
3332   else {
3333     ptr = memchr(hd, ':', hdlen);
3334     if(!ptr) {
3335       /* this is bad, bail out */
3336       failf(data, "Header without colon");
3337       return CURLE_WEIRD_SERVER_REPLY;
3338     }
3339   }
3340   return CURLE_OK;
3341 }
3342 
Curl_bump_headersize(struct Curl_easy * data,size_t delta,bool connect_only)3343 CURLcode Curl_bump_headersize(struct Curl_easy *data,
3344                               size_t delta,
3345                               bool connect_only)
3346 {
3347   size_t bad = 0;
3348   unsigned int max = MAX_HTTP_RESP_HEADER_SIZE;
3349   if(delta < MAX_HTTP_RESP_HEADER_SIZE) {
3350     data->info.header_size += (unsigned int)delta;
3351     data->req.allheadercount += (unsigned int)delta;
3352     if(!connect_only)
3353       data->req.headerbytecount += (unsigned int)delta;
3354     if(data->req.allheadercount > max)
3355       bad = data->req.allheadercount;
3356     else if(data->info.header_size > (max * 20)) {
3357       bad = data->info.header_size;
3358       max *= 20;
3359     }
3360   }
3361   else
3362     bad = data->req.allheadercount + delta;
3363   if(bad) {
3364     failf(data, "Too large response headers: %zu > %u", bad, max);
3365     return CURLE_RECV_ERROR;
3366   }
3367   return CURLE_OK;
3368 }
3369 
3370 
http_on_response(struct Curl_easy * data,const char * buf,size_t blen,size_t * pconsumed)3371 static CURLcode http_on_response(struct Curl_easy *data,
3372                                  const char *buf, size_t blen,
3373                                  size_t *pconsumed)
3374 {
3375   struct connectdata *conn = data->conn;
3376   CURLcode result = CURLE_OK;
3377   struct SingleRequest *k = &data->req;
3378 
3379   (void)buf; /* not used without HTTP2 enabled */
3380   *pconsumed = 0;
3381 
3382   if(k->upgr101 == UPGR101_RECEIVED) {
3383     /* supposedly upgraded to http2 now */
3384     if(conn->httpversion != 20)
3385       infof(data, "Lying server, not serving HTTP/2");
3386   }
3387   if(conn->httpversion < 20) {
3388     conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
3389   }
3390 
3391   if(k->httpcode < 100) {
3392     failf(data, "Unsupported response code in HTTP response");
3393     return CURLE_UNSUPPORTED_PROTOCOL;
3394   }
3395   else if(k->httpcode < 200) {
3396     /* "A user agent MAY ignore unexpected 1xx status responses."
3397      * By default, we expect to get more responses after this one. */
3398     k->header = TRUE;
3399     k->headerline = 0; /* restart the header line counter */
3400 
3401     switch(k->httpcode) {
3402     case 100:
3403       /*
3404        * We have made an HTTP PUT or POST and this is 1.1-lingo
3405        * that tells us that the server is OK with this and ready
3406        * to receive the data.
3407        */
3408       Curl_http_exp100_got100(data);
3409       break;
3410     case 101:
3411       /* Switching Protocols only allowed from HTTP/1.1 */
3412       if(conn->httpversion != 11) {
3413         /* invalid for other HTTP versions */
3414         failf(data, "unexpected 101 response code");
3415         return CURLE_WEIRD_SERVER_REPLY;
3416       }
3417       if(k->upgr101 == UPGR101_H2) {
3418         /* Switching to HTTP/2, where we will get more responses */
3419         infof(data, "Received 101, Switching to HTTP/2");
3420         k->upgr101 = UPGR101_RECEIVED;
3421         /* We expect more response from HTTP/2 later */
3422         k->header = TRUE;
3423         k->headerline = 0; /* restart the header line counter */
3424         /* Any remaining `buf` bytes are already HTTP/2 and passed to
3425          * be processed. */
3426         result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
3427         if(result)
3428           return result;
3429         *pconsumed += blen;
3430       }
3431 #ifdef USE_WEBSOCKETS
3432       else if(k->upgr101 == UPGR101_WS) {
3433         /* verify the response. Any passed `buf` bytes are already in
3434          * WebSockets format and taken in by the protocol handler. */
3435         result = Curl_ws_accept(data, buf, blen);
3436         if(result)
3437           return result;
3438         *pconsumed += blen; /* ws accept handled the data */
3439         k->header = FALSE; /* we will not get more responses */
3440         if(data->set.connect_only)
3441           k->keepon &= ~KEEP_RECV; /* read no more content */
3442       }
3443 #endif
3444       else {
3445         /* We silently accept this as the final response.
3446          * TODO: this looks, uhm, wrong. What are we switching to if we
3447          * did not ask for an Upgrade? Maybe the application provided an
3448          * `Upgrade: xxx` header? */
3449         k->header = FALSE;
3450       }
3451       break;
3452     default:
3453       /* The server may send us other 1xx responses, like informative
3454        * 103. This have no influence on request processing and we expect
3455        * to receive a final response eventually. */
3456       break;
3457     }
3458     return result;
3459   }
3460 
3461   /* k->httpcode >= 200, final response */
3462   k->header = FALSE;
3463 
3464   if(k->upgr101 == UPGR101_H2) {
3465     /* A requested upgrade was denied, poke the multi handle to possibly
3466        allow a pending pipewait to continue */
3467     Curl_multi_connchanged(data->multi);
3468   }
3469 
3470   if((k->size == -1) && !k->chunk && !conn->bits.close &&
3471      (conn->httpversion == 11) &&
3472      !(conn->handler->protocol & CURLPROTO_RTSP) &&
3473      data->state.httpreq != HTTPREQ_HEAD) {
3474     /* On HTTP 1.1, when connection is not to get closed, but no
3475        Content-Length nor Transfer-Encoding chunked have been
3476        received, according to RFC2616 section 4.4 point 5, we
3477        assume that the server will close the connection to
3478        signal the end of the document. */
3479     infof(data, "no chunk, no close, no size. Assume close to "
3480           "signal end");
3481     streamclose(conn, "HTTP: No end-of-message indicator");
3482   }
3483 
3484   /* At this point we have some idea about the fate of the connection.
3485      If we are closing the connection it may result auth failure. */
3486 #if defined(USE_NTLM)
3487   if(conn->bits.close &&
3488      (((data->req.httpcode == 401) &&
3489        (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
3490       ((data->req.httpcode == 407) &&
3491        (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
3492     infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
3493     data->state.authproblem = TRUE;
3494   }
3495 #endif
3496 #if defined(USE_SPNEGO)
3497   if(conn->bits.close &&
3498     (((data->req.httpcode == 401) &&
3499       (conn->http_negotiate_state == GSS_AUTHRECV)) ||
3500      ((data->req.httpcode == 407) &&
3501       (conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
3502     infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
3503     data->state.authproblem = TRUE;
3504   }
3505   if((conn->http_negotiate_state == GSS_AUTHDONE) &&
3506      (data->req.httpcode != 401)) {
3507     conn->http_negotiate_state = GSS_AUTHSUCC;
3508   }
3509   if((conn->proxy_negotiate_state == GSS_AUTHDONE) &&
3510      (data->req.httpcode != 407)) {
3511     conn->proxy_negotiate_state = GSS_AUTHSUCC;
3512   }
3513 #endif
3514 
3515 #ifdef USE_WEBSOCKETS
3516   /* All >=200 HTTP status codes are errors when wanting websockets */
3517   if(data->req.upgr101 == UPGR101_WS) {
3518     failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
3519     return CURLE_HTTP_RETURNED_ERROR;
3520   }
3521 #endif
3522 
3523   /* Check if this response means the transfer errored. */
3524   if(http_should_fail(data, data->req.httpcode)) {
3525     failf(data, "The requested URL returned error: %d",
3526           k->httpcode);
3527     return CURLE_HTTP_RETURNED_ERROR;
3528   }
3529 
3530   /* Curl_http_auth_act() checks what authentication methods
3531    * that are available and decides which one (if any) to
3532    * use. It will set 'newurl' if an auth method was picked. */
3533   result = Curl_http_auth_act(data);
3534   if(result)
3535     return result;
3536 
3537   if(k->httpcode >= 300) {
3538     if((!data->req.authneg) && !conn->bits.close &&
3539        !Curl_creader_will_rewind(data)) {
3540       /*
3541        * General treatment of errors when about to send data. Including :
3542        * "417 Expectation Failed", while waiting for 100-continue.
3543        *
3544        * The check for close above is done simply because of something
3545        * else has already deemed the connection to get closed then
3546        * something else should've considered the big picture and we
3547        * avoid this check.
3548        *
3549        */
3550 
3551       switch(data->state.httpreq) {
3552       case HTTPREQ_PUT:
3553       case HTTPREQ_POST:
3554       case HTTPREQ_POST_FORM:
3555       case HTTPREQ_POST_MIME:
3556         /* We got an error response. If this happened before the whole
3557          * request body has been sent we stop sending and mark the
3558          * connection for closure after we've read the entire response.
3559          */
3560         if(!Curl_req_done_sending(data)) {
3561           if((k->httpcode == 417) && Curl_http_exp100_is_selected(data)) {
3562             /* 417 Expectation Failed - try again without the Expect
3563                header */
3564             if(!k->writebytecount && http_exp100_is_waiting(data)) {
3565               infof(data, "Got HTTP failure 417 while waiting for a 100");
3566             }
3567             else {
3568               infof(data, "Got HTTP failure 417 while sending data");
3569               streamclose(conn,
3570                           "Stop sending data before everything sent");
3571               result = http_perhapsrewind(data, conn);
3572               if(result)
3573                 return result;
3574             }
3575             data->state.disableexpect = TRUE;
3576             DEBUGASSERT(!data->req.newurl);
3577             data->req.newurl = strdup(data->state.url);
3578             Curl_req_abort_sending(data);
3579           }
3580           else if(data->set.http_keep_sending_on_error) {
3581             infof(data, "HTTP error before end of send, keep sending");
3582             http_exp100_send_anyway(data);
3583           }
3584           else {
3585             infof(data, "HTTP error before end of send, stop sending");
3586             streamclose(conn, "Stop sending data before everything sent");
3587             result = Curl_req_abort_sending(data);
3588             if(result)
3589               return result;
3590           }
3591         }
3592         break;
3593 
3594       default: /* default label present to avoid compiler warnings */
3595         break;
3596       }
3597     }
3598 
3599     if(Curl_creader_will_rewind(data) && !Curl_req_done_sending(data)) {
3600       /* We rewind before next send, continue sending now */
3601       infof(data, "Keep sending data to get tossed away");
3602       k->keepon |= KEEP_SEND;
3603     }
3604 
3605   }
3606 
3607   /* This is the last response that we will got for the current request.
3608    * Check on the body size and determine if the response is complete.
3609    */
3610   result = Curl_http_size(data);
3611   if(result)
3612     return result;
3613 
3614   /* If we requested a "no body", this is a good time to get
3615    * out and return home.
3616    */
3617   if(data->req.no_body)
3618     k->download_done = TRUE;
3619 
3620   /* If max download size is *zero* (nothing) we already have
3621      nothing and can safely return ok now!  But for HTTP/2, we'd
3622      like to call http2_handle_stream_close to properly close a
3623      stream.  In order to do this, we keep reading until we
3624      close the stream. */
3625   if(0 == k->maxdownload
3626      && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
3627      && !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
3628     k->download_done = TRUE;
3629 
3630   /* final response without error, prepare to receive the body */
3631   return Curl_http_firstwrite(data);
3632 }
3633 
http_rw_hd(struct Curl_easy * data,const char * hd,size_t hdlen,const char * buf_remain,size_t blen,size_t * pconsumed)3634 static CURLcode http_rw_hd(struct Curl_easy *data,
3635                            const char *hd, size_t hdlen,
3636                            const char *buf_remain, size_t blen,
3637                            size_t *pconsumed)
3638 {
3639   CURLcode result = CURLE_OK;
3640   struct SingleRequest *k = &data->req;
3641   int writetype;
3642 
3643   *pconsumed = 0;
3644   if((0x0a == *hd) || (0x0d == *hd)) {
3645     /* Empty header line means end of headers! */
3646     size_t consumed;
3647 
3648     /* now, only output this if the header AND body are requested:
3649      */
3650     Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
3651 
3652     writetype = CLIENTWRITE_HEADER |
3653       ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
3654 
3655     result = Curl_client_write(data, writetype, hd, hdlen);
3656     if(result)
3657       return result;
3658 
3659     result = Curl_bump_headersize(data, hdlen, FALSE);
3660     if(result)
3661       return result;
3662 
3663     data->req.deductheadercount =
3664       (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
3665 
3666     /* analyze the response to find out what to do. */
3667     /* Caveat: we clear anything in the header brigade, because a
3668      * response might switch HTTP version which may call use recursively.
3669      * Not nice, but that is currently the way of things. */
3670     Curl_dyn_reset(&data->state.headerb);
3671     result = http_on_response(data, buf_remain, blen, &consumed);
3672     if(result)
3673       return result;
3674     *pconsumed += consumed;
3675     return CURLE_OK;
3676   }
3677 
3678   /*
3679    * Checks for special headers coming up.
3680    */
3681 
3682   writetype = CLIENTWRITE_HEADER;
3683   if(!k->headerline++) {
3684     /* This is the first header, it MUST be the error code line
3685        or else we consider this to be the body right away! */
3686     bool fine_statusline = FALSE;
3687 
3688     k->httpversion = 0; /* Don't know yet */
3689     if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
3690       /*
3691        * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
3692        *
3693        * The response code is always a three-digit number in HTTP as the spec
3694        * says. We allow any three-digit number here, but we cannot make
3695        * guarantees on future behaviors since it isn't within the protocol.
3696        */
3697       const char *p = hd;
3698 
3699       while(*p && ISBLANK(*p))
3700         p++;
3701       if(!strncmp(p, "HTTP/", 5)) {
3702         p += 5;
3703         switch(*p) {
3704         case '1':
3705           p++;
3706           if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
3707             if(ISBLANK(p[2])) {
3708               k->httpversion = 10 + (p[1] - '0');
3709               p += 3;
3710               if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
3711                 k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
3712                   (p[2] - '0');
3713                 p += 3;
3714                 if(ISSPACE(*p))
3715                   fine_statusline = TRUE;
3716               }
3717             }
3718           }
3719           if(!fine_statusline) {
3720             failf(data, "Unsupported HTTP/1 subversion in response");
3721             return CURLE_UNSUPPORTED_PROTOCOL;
3722           }
3723           break;
3724         case '2':
3725         case '3':
3726           if(!ISBLANK(p[1]))
3727             break;
3728           k->httpversion = (*p - '0') * 10;
3729           p += 2;
3730           if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
3731             k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
3732               (p[2] - '0');
3733             p += 3;
3734             if(!ISSPACE(*p))
3735               break;
3736             fine_statusline = TRUE;
3737           }
3738           break;
3739         default: /* unsupported */
3740           failf(data, "Unsupported HTTP version in response");
3741           return CURLE_UNSUPPORTED_PROTOCOL;
3742         }
3743       }
3744 
3745       if(!fine_statusline) {
3746         /* If user has set option HTTP200ALIASES,
3747            compare header line against list of aliases
3748         */
3749         statusline check = checkhttpprefix(data, hd, hdlen);
3750         if(check == STATUS_DONE) {
3751           fine_statusline = TRUE;
3752           k->httpcode = 200;
3753           k->httpversion = 10;
3754         }
3755       }
3756     }
3757     else if(data->conn->handler->protocol & CURLPROTO_RTSP) {
3758       const char *p = hd;
3759       while(*p && ISBLANK(*p))
3760         p++;
3761       if(!strncmp(p, "RTSP/", 5)) {
3762         p += 5;
3763         if(ISDIGIT(*p)) {
3764           p++;
3765           if((p[0] == '.') && ISDIGIT(p[1])) {
3766             if(ISBLANK(p[2])) {
3767               p += 3;
3768               if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
3769                 k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
3770                   (p[2] - '0');
3771                 p += 3;
3772                 if(ISSPACE(*p)) {
3773                   fine_statusline = TRUE;
3774                   k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
3775                 }
3776               }
3777             }
3778           }
3779         }
3780         if(!fine_statusline)
3781           return CURLE_WEIRD_SERVER_REPLY;
3782       }
3783     }
3784 
3785     if(fine_statusline) {
3786       result = Curl_http_statusline(data, data->conn);
3787       if(result)
3788         return result;
3789       writetype |= CLIENTWRITE_STATUS;
3790     }
3791     else {
3792       k->header = FALSE;   /* this is not a header line */
3793       return CURLE_WEIRD_SERVER_REPLY;
3794     }
3795   }
3796 
3797   result = verify_header(data, hd, hdlen);
3798   if(result)
3799     return result;
3800 
3801   result = Curl_http_header(data, hd, hdlen);
3802   if(result)
3803     return result;
3804 
3805   /*
3806    * Taken in one (more) header. Write it to the client.
3807    */
3808   Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
3809 
3810   if(k->httpcode/100 == 1)
3811     writetype |= CLIENTWRITE_1XX;
3812   result = Curl_client_write(data, writetype, hd, hdlen);
3813   if(result)
3814     return result;
3815 
3816   result = Curl_bump_headersize(data, hdlen, FALSE);
3817   if(result)
3818     return result;
3819 
3820   return CURLE_OK;
3821 }
3822 
3823 /*
3824  * Read any HTTP header lines from the server and pass them to the client app.
3825  */
http_parse_headers(struct Curl_easy * data,const char * buf,size_t blen,size_t * pconsumed)3826 static CURLcode http_parse_headers(struct Curl_easy *data,
3827                                    const char *buf, size_t blen,
3828                                    size_t *pconsumed)
3829 {
3830   struct connectdata *conn = data->conn;
3831   CURLcode result = CURLE_OK;
3832   struct SingleRequest *k = &data->req;
3833   char *end_ptr;
3834   bool leftover_body = FALSE;
3835 
3836   /* header line within buffer loop */
3837   *pconsumed = 0;
3838   while(blen && k->header) {
3839     size_t consumed;
3840 
3841     end_ptr = memchr(buf, '\n', blen);
3842     if(!end_ptr) {
3843       /* Not a complete header line within buffer, append the data to
3844          the end of the headerbuff. */
3845       result = Curl_dyn_addn(&data->state.headerb, buf, blen);
3846       if(result)
3847         return result;
3848       *pconsumed += blen;
3849 
3850       if(!k->headerline) {
3851         /* check if this looks like a protocol header */
3852         statusline st =
3853           checkprotoprefix(data, conn,
3854                            Curl_dyn_ptr(&data->state.headerb),
3855                            Curl_dyn_len(&data->state.headerb));
3856 
3857         if(st == STATUS_BAD) {
3858           /* this is not the beginning of a protocol first header line */
3859           k->header = FALSE;
3860           streamclose(conn, "bad HTTP: No end-of-message indicator");
3861           if(conn->httpversion >= 10) {
3862             failf(data, "Invalid status line");
3863             return CURLE_WEIRD_SERVER_REPLY;
3864           }
3865           if(!data->set.http09_allowed) {
3866             failf(data, "Received HTTP/0.9 when not allowed");
3867             return CURLE_UNSUPPORTED_PROTOCOL;
3868           }
3869           leftover_body = TRUE;
3870           goto out;
3871         }
3872       }
3873       goto out; /* read more and try again */
3874     }
3875 
3876     /* decrease the size of the remaining (supposed) header line */
3877     consumed = (end_ptr - buf) + 1;
3878     result = Curl_dyn_addn(&data->state.headerb, buf, consumed);
3879     if(result)
3880       return result;
3881     blen -= consumed;
3882     buf += consumed;
3883     *pconsumed += consumed;
3884 
3885     /****
3886      * We now have a FULL header line in 'headerb'.
3887      *****/
3888 
3889     if(!k->headerline) {
3890       /* the first read header */
3891       statusline st = checkprotoprefix(data, conn,
3892                                        Curl_dyn_ptr(&data->state.headerb),
3893                                        Curl_dyn_len(&data->state.headerb));
3894       if(st == STATUS_BAD) {
3895         streamclose(conn, "bad HTTP: No end-of-message indicator");
3896         /* this is not the beginning of a protocol first header line */
3897         if(conn->httpversion >= 10) {
3898           failf(data, "Invalid status line");
3899           return CURLE_WEIRD_SERVER_REPLY;
3900         }
3901         if(!data->set.http09_allowed) {
3902           failf(data, "Received HTTP/0.9 when not allowed");
3903           return CURLE_UNSUPPORTED_PROTOCOL;
3904         }
3905         k->header = FALSE;
3906         leftover_body = TRUE;
3907         goto out;
3908       }
3909     }
3910 
3911     result = http_rw_hd(data, Curl_dyn_ptr(&data->state.headerb),
3912                         Curl_dyn_len(&data->state.headerb),
3913                         buf, blen, &consumed);
3914     /* We are done with this line. We reset because response
3915      * processing might switch to HTTP/2 and that might call us
3916      * directly again. */
3917     Curl_dyn_reset(&data->state.headerb);
3918     if(consumed) {
3919       blen -= consumed;
3920       buf += consumed;
3921       *pconsumed += consumed;
3922     }
3923     if(result)
3924       return result;
3925   }
3926 
3927   /* We might have reached the end of the header part here, but
3928      there might be a non-header part left in the end of the read
3929      buffer. */
3930 out:
3931   if(!k->header && !leftover_body) {
3932     Curl_dyn_free(&data->state.headerb);
3933   }
3934   return CURLE_OK;
3935 }
3936 
Curl_http_write_resp_hd(struct Curl_easy * data,const char * hd,size_t hdlen,bool is_eos)3937 CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
3938                                  const char *hd, size_t hdlen,
3939                                  bool is_eos)
3940 {
3941   CURLcode result;
3942   size_t consumed;
3943   char tmp = 0;
3944 
3945   result = http_rw_hd(data, hd, hdlen, &tmp, 0, &consumed);
3946   if(!result && is_eos) {
3947     result = Curl_client_write(data, (CLIENTWRITE_BODY|CLIENTWRITE_EOS),
3948                                &tmp, 0);
3949   }
3950   return result;
3951 }
3952 
3953 /*
3954  * HTTP protocol `write_resp` implementation. Will parse headers
3955  * when not done yet and otherwise return without consuming data.
3956  */
Curl_http_write_resp_hds(struct Curl_easy * data,const char * buf,size_t blen,size_t * pconsumed)3957 CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
3958                                   const char *buf, size_t blen,
3959                                   size_t *pconsumed)
3960 {
3961   if(!data->req.header) {
3962     *pconsumed = 0;
3963     return CURLE_OK;
3964   }
3965   else {
3966     CURLcode result;
3967 
3968     result = http_parse_headers(data, buf, blen, pconsumed);
3969     if(!result && !data->req.header) {
3970       if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) {
3971         /* leftover from parsing something that turned out not
3972          * to be a header, only happens if we allow for
3973          * HTTP/0.9 like responses */
3974         result = Curl_client_write(data, CLIENTWRITE_BODY,
3975                                    Curl_dyn_ptr(&data->state.headerb),
3976                                    Curl_dyn_len(&data->state.headerb));
3977       }
3978       Curl_dyn_free(&data->state.headerb);
3979     }
3980     return result;
3981   }
3982 }
3983 
Curl_http_write_resp(struct Curl_easy * data,const char * buf,size_t blen,bool is_eos)3984 CURLcode Curl_http_write_resp(struct Curl_easy *data,
3985                               const char *buf, size_t blen,
3986                               bool is_eos)
3987 {
3988   CURLcode result;
3989   size_t consumed;
3990   int flags;
3991 
3992   result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
3993   if(result || data->req.done)
3994     goto out;
3995 
3996   DEBUGASSERT(consumed <= blen);
3997   blen -= consumed;
3998   buf += consumed;
3999   /* either all was consumed in header parsing, or we have data left
4000    * and are done with headers, e.g. it is BODY data */
4001   DEBUGASSERT(!blen || !data->req.header);
4002   if(!data->req.header && (blen || is_eos)) {
4003     /* BODY data after header been parsed, write and consume */
4004     flags = CLIENTWRITE_BODY;
4005     if(is_eos)
4006       flags |= CLIENTWRITE_EOS;
4007     result = Curl_client_write(data, flags, (char *)buf, blen);
4008   }
4009 out:
4010   return result;
4011 }
4012 
4013 /* Decode HTTP status code string. */
Curl_http_decode_status(int * pstatus,const char * s,size_t len)4014 CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len)
4015 {
4016   CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
4017   int status = 0;
4018   int i;
4019 
4020   if(len != 3)
4021     goto out;
4022 
4023   for(i = 0; i < 3; ++i) {
4024     char c = s[i];
4025 
4026     if(c < '0' || c > '9')
4027       goto out;
4028 
4029     status *= 10;
4030     status += c - '0';
4031   }
4032   result = CURLE_OK;
4033 out:
4034   *pstatus = result? -1 : status;
4035   return result;
4036 }
4037 
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)4038 CURLcode Curl_http_req_make(struct httpreq **preq,
4039                             const char *method, size_t m_len,
4040                             const char *scheme, size_t s_len,
4041                             const char *authority, size_t a_len,
4042                             const char *path, size_t p_len)
4043 {
4044   struct httpreq *req;
4045   CURLcode result = CURLE_OUT_OF_MEMORY;
4046 
4047   DEBUGASSERT(method);
4048   if(m_len + 1 > sizeof(req->method))
4049     return CURLE_BAD_FUNCTION_ARGUMENT;
4050 
4051   req = calloc(1, sizeof(*req));
4052   if(!req)
4053     goto out;
4054   memcpy(req->method, method, m_len);
4055   if(scheme) {
4056     req->scheme = Curl_memdup0(scheme, s_len);
4057     if(!req->scheme)
4058       goto out;
4059   }
4060   if(authority) {
4061     req->authority = Curl_memdup0(authority, a_len);
4062     if(!req->authority)
4063       goto out;
4064   }
4065   if(path) {
4066     req->path = Curl_memdup0(path, p_len);
4067     if(!req->path)
4068       goto out;
4069   }
4070   Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
4071   Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
4072   result = CURLE_OK;
4073 
4074 out:
4075   if(result && req)
4076     Curl_http_req_free(req);
4077   *preq = result? NULL : req;
4078   return result;
4079 }
4080 
req_assign_url_authority(struct httpreq * req,CURLU * url)4081 static CURLcode req_assign_url_authority(struct httpreq *req, CURLU *url)
4082 {
4083   char *user, *pass, *host, *port;
4084   struct dynbuf buf;
4085   CURLUcode uc;
4086   CURLcode result = CURLE_URL_MALFORMAT;
4087 
4088   user = pass = host = port = NULL;
4089   Curl_dyn_init(&buf, DYN_HTTP_REQUEST);
4090 
4091   uc = curl_url_get(url, CURLUPART_HOST, &host, 0);
4092   if(uc && uc != CURLUE_NO_HOST)
4093     goto out;
4094   if(!host) {
4095     req->authority = NULL;
4096     result = CURLE_OK;
4097     goto out;
4098   }
4099 
4100   uc = curl_url_get(url, CURLUPART_PORT, &port, CURLU_NO_DEFAULT_PORT);
4101   if(uc && uc != CURLUE_NO_PORT)
4102     goto out;
4103   uc = curl_url_get(url, CURLUPART_USER, &user, 0);
4104   if(uc && uc != CURLUE_NO_USER)
4105     goto out;
4106   if(user) {
4107     uc = curl_url_get(url, CURLUPART_PASSWORD, &pass, 0);
4108     if(uc && uc != CURLUE_NO_PASSWORD)
4109       goto out;
4110   }
4111 
4112   if(user) {
4113     result = Curl_dyn_add(&buf, user);
4114     if(result)
4115       goto out;
4116     if(pass) {
4117       result = Curl_dyn_addf(&buf, ":%s", pass);
4118       if(result)
4119         goto out;
4120     }
4121     result = Curl_dyn_add(&buf, "@");
4122     if(result)
4123       goto out;
4124   }
4125   result = Curl_dyn_add(&buf, host);
4126   if(result)
4127     goto out;
4128   if(port) {
4129     result = Curl_dyn_addf(&buf, ":%s", port);
4130     if(result)
4131       goto out;
4132   }
4133   req->authority = strdup(Curl_dyn_ptr(&buf));
4134   if(!req->authority)
4135     goto out;
4136   result = CURLE_OK;
4137 
4138 out:
4139   free(user);
4140   free(pass);
4141   free(host);
4142   free(port);
4143   Curl_dyn_free(&buf);
4144   return result;
4145 }
4146 
req_assign_url_path(struct httpreq * req,CURLU * url)4147 static CURLcode req_assign_url_path(struct httpreq *req, CURLU *url)
4148 {
4149   char *path, *query;
4150   struct dynbuf buf;
4151   CURLUcode uc;
4152   CURLcode result = CURLE_URL_MALFORMAT;
4153 
4154   path = query = NULL;
4155   Curl_dyn_init(&buf, DYN_HTTP_REQUEST);
4156 
4157   uc = curl_url_get(url, CURLUPART_PATH, &path, CURLU_PATH_AS_IS);
4158   if(uc)
4159     goto out;
4160   uc = curl_url_get(url, CURLUPART_QUERY, &query, 0);
4161   if(uc && uc != CURLUE_NO_QUERY)
4162     goto out;
4163 
4164   if(!path && !query) {
4165     req->path = NULL;
4166   }
4167   else if(path && !query) {
4168     req->path = path;
4169     path = NULL;
4170   }
4171   else {
4172     if(path) {
4173       result = Curl_dyn_add(&buf, path);
4174       if(result)
4175         goto out;
4176     }
4177     if(query) {
4178       result = Curl_dyn_addf(&buf, "?%s", query);
4179       if(result)
4180         goto out;
4181     }
4182     req->path = strdup(Curl_dyn_ptr(&buf));
4183     if(!req->path)
4184       goto out;
4185   }
4186   result = CURLE_OK;
4187 
4188 out:
4189   free(path);
4190   free(query);
4191   Curl_dyn_free(&buf);
4192   return result;
4193 }
4194 
Curl_http_req_make2(struct httpreq ** preq,const char * method,size_t m_len,CURLU * url,const char * scheme_default)4195 CURLcode Curl_http_req_make2(struct httpreq **preq,
4196                              const char *method, size_t m_len,
4197                              CURLU *url, const char *scheme_default)
4198 {
4199   struct httpreq *req;
4200   CURLcode result = CURLE_OUT_OF_MEMORY;
4201   CURLUcode uc;
4202 
4203   DEBUGASSERT(method);
4204   if(m_len + 1 > sizeof(req->method))
4205     return CURLE_BAD_FUNCTION_ARGUMENT;
4206 
4207   req = calloc(1, sizeof(*req));
4208   if(!req)
4209     goto out;
4210   memcpy(req->method, method, m_len);
4211 
4212   uc = curl_url_get(url, CURLUPART_SCHEME, &req->scheme, 0);
4213   if(uc && uc != CURLUE_NO_SCHEME)
4214     goto out;
4215   if(!req->scheme && scheme_default) {
4216     req->scheme = strdup(scheme_default);
4217     if(!req->scheme)
4218       goto out;
4219   }
4220 
4221   result = req_assign_url_authority(req, url);
4222   if(result)
4223     goto out;
4224   result = req_assign_url_path(req, url);
4225   if(result)
4226     goto out;
4227 
4228   Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
4229   Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
4230   result = CURLE_OK;
4231 
4232 out:
4233   if(result && req)
4234     Curl_http_req_free(req);
4235   *preq = result? NULL : req;
4236   return result;
4237 }
4238 
Curl_http_req_free(struct httpreq * req)4239 void Curl_http_req_free(struct httpreq *req)
4240 {
4241   if(req) {
4242     free(req->scheme);
4243     free(req->authority);
4244     free(req->path);
4245     Curl_dynhds_free(&req->headers);
4246     Curl_dynhds_free(&req->trailers);
4247     free(req);
4248   }
4249 }
4250 
4251 struct name_const {
4252   const char *name;
4253   size_t namelen;
4254 };
4255 
4256 static struct name_const H2_NON_FIELD[] = {
4257   { STRCONST("Host") },
4258   { STRCONST("Upgrade") },
4259   { STRCONST("Connection") },
4260   { STRCONST("Keep-Alive") },
4261   { STRCONST("Proxy-Connection") },
4262   { STRCONST("Transfer-Encoding") },
4263 };
4264 
h2_non_field(const char * name,size_t namelen)4265 static bool h2_non_field(const char *name, size_t namelen)
4266 {
4267   size_t i;
4268   for(i = 0; i < sizeof(H2_NON_FIELD)/sizeof(H2_NON_FIELD[0]); ++i) {
4269     if(namelen < H2_NON_FIELD[i].namelen)
4270       return FALSE;
4271     if(namelen == H2_NON_FIELD[i].namelen &&
4272        strcasecompare(H2_NON_FIELD[i].name, name))
4273       return TRUE;
4274   }
4275   return FALSE;
4276 }
4277 
Curl_http_req_to_h2(struct dynhds * h2_headers,struct httpreq * req,struct Curl_easy * data)4278 CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
4279                              struct httpreq *req, struct Curl_easy *data)
4280 {
4281   const char *scheme = NULL, *authority = NULL;
4282   struct dynhds_entry *e;
4283   size_t i;
4284   CURLcode result;
4285 
4286   DEBUGASSERT(req);
4287   DEBUGASSERT(h2_headers);
4288 
4289   if(req->scheme) {
4290     scheme = req->scheme;
4291   }
4292   else if(strcmp("CONNECT", req->method)) {
4293     scheme = Curl_checkheaders(data, STRCONST(HTTP_PSEUDO_SCHEME));
4294     if(scheme) {
4295       scheme += sizeof(HTTP_PSEUDO_SCHEME);
4296       while(*scheme && ISBLANK(*scheme))
4297         scheme++;
4298       infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme);
4299     }
4300     else {
4301       scheme = (data->conn && data->conn->handler->flags & PROTOPT_SSL)?
4302                 "https" : "http";
4303     }
4304   }
4305 
4306   if(req->authority) {
4307     authority = req->authority;
4308   }
4309   else {
4310     e = Curl_dynhds_get(&req->headers, STRCONST("Host"));
4311     if(e)
4312       authority = e->value;
4313   }
4314 
4315   Curl_dynhds_reset(h2_headers);
4316   Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE);
4317   result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD),
4318                            req->method, strlen(req->method));
4319   if(!result && scheme) {
4320     result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME),
4321                              scheme, strlen(scheme));
4322   }
4323   if(!result && authority) {
4324     result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY),
4325                              authority, strlen(authority));
4326   }
4327   if(!result && req->path) {
4328     result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH),
4329                              req->path, strlen(req->path));
4330   }
4331   for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) {
4332     e = Curl_dynhds_getn(&req->headers, i);
4333     if(!h2_non_field(e->name, e->namelen)) {
4334       result = Curl_dynhds_add(h2_headers, e->name, e->namelen,
4335                                e->value, e->valuelen);
4336     }
4337   }
4338 
4339   return result;
4340 }
4341 
Curl_http_resp_make(struct http_resp ** presp,int status,const char * description)4342 CURLcode Curl_http_resp_make(struct http_resp **presp,
4343                              int status,
4344                              const char *description)
4345 {
4346   struct http_resp *resp;
4347   CURLcode result = CURLE_OUT_OF_MEMORY;
4348 
4349   resp = calloc(1, sizeof(*resp));
4350   if(!resp)
4351     goto out;
4352 
4353   resp->status = status;
4354   if(description) {
4355     resp->description = strdup(description);
4356     if(!resp->description)
4357       goto out;
4358   }
4359   Curl_dynhds_init(&resp->headers, 0, DYN_HTTP_REQUEST);
4360   Curl_dynhds_init(&resp->trailers, 0, DYN_HTTP_REQUEST);
4361   result = CURLE_OK;
4362 
4363 out:
4364   if(result && resp)
4365     Curl_http_resp_free(resp);
4366   *presp = result? NULL : resp;
4367   return result;
4368 }
4369 
Curl_http_resp_free(struct http_resp * resp)4370 void Curl_http_resp_free(struct http_resp *resp)
4371 {
4372   if(resp) {
4373     free(resp->description);
4374     Curl_dynhds_free(&resp->headers);
4375     Curl_dynhds_free(&resp->trailers);
4376     if(resp->prev)
4377       Curl_http_resp_free(resp->prev);
4378     free(resp);
4379   }
4380 }
4381 
4382 struct cr_exp100_ctx {
4383   struct Curl_creader super;
4384   struct curltime start; /* time started waiting */
4385   enum expect100 state;
4386 };
4387 
4388 /* Expect: 100-continue client reader, blocking uploads */
4389 
http_exp100_continue(struct Curl_easy * data,struct Curl_creader * reader)4390 static void http_exp100_continue(struct Curl_easy *data,
4391                                  struct Curl_creader *reader)
4392 {
4393   struct cr_exp100_ctx *ctx = reader->ctx;
4394   if(ctx->state > EXP100_SEND_DATA) {
4395     ctx->state = EXP100_SEND_DATA;
4396     data->req.keepon |= KEEP_SEND;
4397     data->req.keepon &= ~KEEP_SEND_TIMED;
4398     Curl_expire_done(data, EXPIRE_100_TIMEOUT);
4399   }
4400 }
4401 
cr_exp100_read(struct Curl_easy * data,struct Curl_creader * reader,char * buf,size_t blen,size_t * nread,bool * eos)4402 static CURLcode cr_exp100_read(struct Curl_easy *data,
4403                                struct Curl_creader *reader,
4404                                char *buf, size_t blen,
4405                                size_t *nread, bool *eos)
4406 {
4407   struct cr_exp100_ctx *ctx = reader->ctx;
4408   timediff_t ms;
4409 
4410   switch(ctx->state) {
4411   case EXP100_SENDING_REQUEST:
4412     /* We are now waiting for a reply from the server or
4413      * a timeout on our side */
4414     DEBUGF(infof(data, "cr_exp100_read, start AWAITING_CONTINUE"));
4415     ctx->state = EXP100_AWAITING_CONTINUE;
4416     ctx->start = Curl_now();
4417     Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
4418     data->req.keepon &= ~KEEP_SEND;
4419     data->req.keepon |= KEEP_SEND_TIMED;
4420     *nread = 0;
4421     *eos = FALSE;
4422     return CURLE_OK;
4423   case EXP100_FAILED:
4424     DEBUGF(infof(data, "cr_exp100_read, expectation failed, error"));
4425     *nread = 0;
4426     *eos = FALSE;
4427     return CURLE_READ_ERROR;
4428   case EXP100_AWAITING_CONTINUE:
4429     ms = Curl_timediff(Curl_now(), ctx->start);
4430     if(ms < data->set.expect_100_timeout) {
4431       DEBUGF(infof(data, "cr_exp100_read, AWAITING_CONTINUE, not expired"));
4432       data->req.keepon &= ~KEEP_SEND;
4433       data->req.keepon |= KEEP_SEND_TIMED;
4434       *nread = 0;
4435       *eos = FALSE;
4436       return CURLE_OK;
4437     }
4438     /* we've waited long enough, continue anyway */
4439     http_exp100_continue(data, reader);
4440     infof(data, "Done waiting for 100-continue");
4441     FALLTHROUGH();
4442   default:
4443     DEBUGF(infof(data, "cr_exp100_read, pass through"));
4444     return Curl_creader_read(data, reader->next, buf, blen, nread, eos);
4445   }
4446 }
4447 
cr_exp100_done(struct Curl_easy * data,struct Curl_creader * reader,int premature)4448 static void cr_exp100_done(struct Curl_easy *data,
4449                            struct Curl_creader *reader, int premature)
4450 {
4451   struct cr_exp100_ctx *ctx = reader->ctx;
4452   ctx->state = premature? EXP100_FAILED : EXP100_SEND_DATA;
4453   data->req.keepon &= ~KEEP_SEND_TIMED;
4454   Curl_expire_done(data, EXPIRE_100_TIMEOUT);
4455 }
4456 
4457 static const struct Curl_crtype cr_exp100 = {
4458   "cr-exp100",
4459   Curl_creader_def_init,
4460   cr_exp100_read,
4461   Curl_creader_def_close,
4462   Curl_creader_def_needs_rewind,
4463   Curl_creader_def_total_length,
4464   Curl_creader_def_resume_from,
4465   Curl_creader_def_rewind,
4466   Curl_creader_def_unpause,
4467   cr_exp100_done,
4468   sizeof(struct cr_exp100_ctx)
4469 };
4470 
http_exp100_add_reader(struct Curl_easy * data)4471 static CURLcode http_exp100_add_reader(struct Curl_easy *data)
4472 {
4473   struct Curl_creader *reader = NULL;
4474   CURLcode result;
4475 
4476   result = Curl_creader_create(&reader, data, &cr_exp100,
4477                                CURL_CR_PROTOCOL);
4478   if(!result)
4479     result = Curl_creader_add(data, reader);
4480   if(!result) {
4481     struct cr_exp100_ctx *ctx = reader->ctx;
4482     ctx->state = EXP100_SENDING_REQUEST;
4483   }
4484 
4485   if(result && reader)
4486     Curl_creader_free(data, reader);
4487   return result;
4488 }
4489 
Curl_http_exp100_got100(struct Curl_easy * data)4490 void Curl_http_exp100_got100(struct Curl_easy *data)
4491 {
4492   struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
4493   if(r)
4494     http_exp100_continue(data, r);
4495 }
4496 
http_exp100_is_waiting(struct Curl_easy * data)4497 static bool http_exp100_is_waiting(struct Curl_easy *data)
4498 {
4499   struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
4500   if(r) {
4501     struct cr_exp100_ctx *ctx = r->ctx;
4502     return (ctx->state == EXP100_AWAITING_CONTINUE);
4503   }
4504   return FALSE;
4505 }
4506 
http_exp100_send_anyway(struct Curl_easy * data)4507 static void http_exp100_send_anyway(struct Curl_easy *data)
4508 {
4509   struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
4510   if(r)
4511     http_exp100_continue(data, r);
4512 }
4513 
Curl_http_exp100_is_selected(struct Curl_easy * data)4514 bool Curl_http_exp100_is_selected(struct Curl_easy *data)
4515 {
4516   struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
4517   return r? TRUE : FALSE;
4518 }
4519 
4520 #endif /* CURL_DISABLE_HTTP */
4521