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