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