Coverage Report

Created: 2026-04-12 06:59

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