Coverage Report

Created: 2026-06-15 07:03

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