Coverage Report

Created: 2026-09-04 07:16

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