Coverage Report

Created: 2026-09-14 07:04

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