Coverage Report

Created: 2026-10-15 06:20

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