Coverage Report

Created: 2026-10-15 06:18

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