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