Coverage Report

Created: 2026-09-14 07:06

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