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