Coverage Report

Created: 2026-09-14 06:43

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