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