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