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