Coverage Report

Created: 2026-09-01 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/http.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
#include "urldata.h"
26
27
#ifndef CURL_DISABLE_HTTP
28
29
#ifdef HAVE_NETINET_IN_H
30
#include <netinet/in.h>
31
#endif
32
33
#ifdef HAVE_NETDB_H
34
#include <netdb.h>
35
#endif
36
#ifdef HAVE_ARPA_INET_H
37
#include <arpa/inet.h>
38
#endif
39
#ifdef HAVE_NET_IF_H
40
#include <net/if.h>
41
#endif
42
#ifdef HAVE_SYS_IOCTL_H
43
#include <sys/ioctl.h>
44
#endif
45
46
#ifdef HAVE_SYS_PARAM_H
47
#include <sys/param.h>
48
#endif
49
50
#include "transfer.h"
51
#include "sendf.h"
52
#include "curl_trc.h"
53
#include "formdata.h"
54
#include "mime.h"
55
#include "progress.h"
56
#include "curlx/base64.h"
57
#include "cookie.h"
58
#include "vauth/vauth.h"
59
#include "vquic/vquic.h"
60
#include "http_digest.h"
61
#include "http_ntlm.h"
62
#include "http_negotiate.h"
63
#include "http_aws_sigv4.h"
64
#include "http_httpsig.h"
65
#include "url.h"
66
#include "urlapi-int.h"
67
#include "curl_share.h"
68
#include "dynhds.h"
69
#include "http.h"
70
#include "headers.h"
71
#include "select.h"
72
#include "parsedate.h" /* for the week day and month names */
73
#include "multiif.h"
74
#include "strcase.h"
75
#include "content_encoding.h"
76
#include "http_proxy.h"
77
#include "http2.h"
78
#include "cfilters.h"
79
#include "connect.h"
80
#include "curlx/strdup.h"
81
#include "altsvc.h"
82
#include "hsts.h"
83
#include "rtsp.h"
84
#include "ws.h"
85
#include "bufref.h"
86
#include "curlx/strparse.h"
87
88
void Curl_http_neg_init(struct Curl_easy *data, struct http_negotiation *neg)
89
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(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
1527
0
    *nread = 0;
1528
0
    *eos = FALSE;
1529
0
    return CURLE_OK;
1530
0
  case EXP100_FAILED:
1531
0
    DEBUGF(infof(data, "cr_exp100_read, expectation failed, error"));
1532
0
    *nread = 0;
1533
0
    *eos = FALSE;
1534
0
    return CURLE_READ_ERROR;
1535
0
  case EXP100_AWAITING_CONTINUE:
1536
0
    ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &ctx->start);
1537
0
    if(ms < data->set.expect_100_timeout) {
1538
0
      DEBUGF(infof(data, "cr_exp100_read, AWAITING_CONTINUE, not expired"));
1539
0
      *nread = 0;
1540
0
      *eos = FALSE;
1541
0
      return CURLE_OK;
1542
0
    }
1543
    /* we have waited long enough, continue anyway */
1544
0
    http_exp100_continue(data, reader);
1545
0
    infof(data, "Done waiting for 100-continue");
1546
0
    FALLTHROUGH();
1547
0
  default:
1548
0
    DEBUGF(infof(data, "cr_exp100_read, pass through"));
1549
0
    return Curl_creader_read(data, reader->next, buf, blen, nread, eos);
1550
0
  }
1551
0
}
1552
1553
static void cr_exp100_done(struct Curl_easy *data,
1554
                           struct Curl_creader *reader, int premature)
1555
0
{
1556
0
  struct cr_exp100_ctx *ctx = reader->ctx;
1557
0
  ctx->state = premature ? EXP100_FAILED : EXP100_SEND_DATA;
1558
0
  Curl_expire_clear(data, EXPIRE_100_TIMEOUT);
1559
0
}
1560
1561
static const struct Curl_crtype cr_exp100 = {
1562
  "cr-exp100",
1563
  Curl_creader_def_init,
1564
  cr_exp100_read,
1565
  Curl_creader_def_close,
1566
  Curl_creader_def_needs_rewind,
1567
  Curl_creader_def_total_length,
1568
  Curl_creader_def_resume_from,
1569
  Curl_creader_def_cntrl,
1570
  Curl_creader_def_is_paused,
1571
  cr_exp100_done,
1572
  sizeof(struct cr_exp100_ctx)
1573
};
1574
1575
static CURLcode http_exp100_add_reader(struct Curl_easy *data)
1576
0
{
1577
0
  struct Curl_creader *reader = NULL;
1578
0
  CURLcode result;
1579
1580
0
  result = Curl_creader_create(&reader, data, &cr_exp100, CURL_CR_PROTOCOL);
1581
0
  if(!result)
1582
0
    result = Curl_creader_add(data, reader);
1583
0
  if(!result) {
1584
0
    struct cr_exp100_ctx *ctx = reader->ctx;
1585
0
    ctx->state = EXP100_SENDING_REQUEST;
1586
0
  }
1587
1588
0
  if(result && reader)
1589
0
    Curl_creader_free(data, reader);
1590
0
  return result;
1591
0
}
1592
1593
static void http_exp100_got100(struct Curl_easy *data)
1594
0
{
1595
0
  struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
1596
0
  if(r)
1597
0
    http_exp100_continue(data, r);
1598
0
}
1599
1600
static bool http_exp100_is_waiting(struct Curl_easy *data)
1601
0
{
1602
0
  struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
1603
0
  if(r) {
1604
0
    struct cr_exp100_ctx *ctx = r->ctx;
1605
0
    return ctx->state == EXP100_AWAITING_CONTINUE;
1606
0
  }
1607
0
  return FALSE;
1608
0
}
1609
1610
static void http_exp100_send_anyway(struct Curl_easy *data)
1611
0
{
1612
0
  struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
1613
0
  if(r)
1614
0
    http_exp100_continue(data, r);
1615
0
}
1616
1617
static bool http_exp100_is_selected(struct Curl_easy *data)
1618
0
{
1619
0
  struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
1620
0
  return !!r;
1621
0
}
1622
1623
/* this returns the socket to wait for in the DO and DOING state for the multi
1624
   interface and then we are always _sending_ a request and thus we wait for
1625
   the single socket to become writable only */
1626
CURLcode Curl_http_doing_pollset(struct Curl_easy *data,
1627
                                 struct easy_pollset *ps)
1628
0
{
1629
  /* write mode */
1630
0
  return Curl_pollset_add_out(data, ps, data->conn->sock[FIRSTSOCKET]);
1631
0
}
1632
1633
CURLcode Curl_http_perform_pollset(struct Curl_easy *data,
1634
                                   struct easy_pollset *ps)
1635
0
{
1636
0
  struct connectdata *conn = data->conn;
1637
0
  CURLcode result = CURLE_OK;
1638
1639
0
  if(CURL_REQ_WANT_RECV(data)) {
1640
0
    result = Curl_pollset_add_in(data, ps, conn->sock[FIRSTSOCKET]);
1641
0
  }
1642
1643
  /* on a "Expect: 100-continue" timed wait, do not poll for outgoing */
1644
0
  if(!result && Curl_req_want_send(data) && !http_exp100_is_waiting(data)) {
1645
0
    result = Curl_pollset_add_out(data, ps, conn->sock[FIRSTSOCKET]);
1646
0
  }
1647
0
  return result;
1648
0
}
1649
1650
static CURLcode http_write_header(struct Curl_easy *data,
1651
                                  const char *hd, size_t hdlen)
1652
0
{
1653
0
  CURLcode result;
1654
0
  int writetype;
1655
1656
  /* now, only output this if the header AND body are requested:
1657
   */
1658
0
  Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
1659
1660
0
  writetype = CLIENTWRITE_HEADER |
1661
0
    ((data->req.httpcode / 100 == 1) ? CLIENTWRITE_1XX : 0);
1662
1663
0
  result = Curl_client_write(data, writetype, hd, hdlen);
1664
0
  if(result)
1665
0
    return result;
1666
1667
0
  result = Curl_bump_headersize(data, hdlen, FALSE);
1668
0
  if(result)
1669
0
    return result;
1670
1671
0
  data->req.deductheadercount = (100 <= data->req.httpcode &&
1672
0
                                 199 >= data->req.httpcode) ?
1673
0
    data->req.headerbytecount : 0;
1674
0
  return result;
1675
0
}
1676
1677
/*
1678
 * Curl_http_done() gets called after a single HTTP request has been
1679
 * performed.
1680
 */
1681
1682
CURLcode Curl_http_done(struct Curl_easy *data,
1683
                        CURLcode status, bool premature)
1684
0
{
1685
0
  struct connectdata *conn = data->conn;
1686
1687
  /* Clear multipass flag. If authentication is not done yet, then it will get
1688
   * a chance to be set back to true when we output the next auth header */
1689
0
  data->state.authhost.multipass = FALSE;
1690
0
  data->state.authproxy.multipass = FALSE;
1691
1692
0
  if(curlx_dyn_len(&data->state.headerb)) {
1693
0
    (void)http_write_header(data, curlx_dyn_ptr(&data->state.headerb),
1694
0
                            curlx_dyn_len(&data->state.headerb));
1695
0
  }
1696
0
  curlx_dyn_reset(&data->state.headerb);
1697
1698
0
  if(status)
1699
0
    return status;
1700
1701
0
  if(!premature && /* this check is pointless when DONE is called before the
1702
                      entire operation is complete */
1703
0
     !conn->bits.retry &&
1704
0
     !data->set.connect_only &&
1705
0
     (data->req.bytecount +
1706
0
      data->req.headerbytecount -
1707
0
      data->req.deductheadercount) <= 0) {
1708
    /* If this connection is not closed to be retried, AND nothing was
1709
       read from the HTTP server (that counts), this cannot be right so we
1710
       return an error here */
1711
0
    failf(data, "Empty reply from server");
1712
    /* Mark it as closed to avoid the "left intact" message */
1713
0
    streamclose(conn);
1714
0
    return CURLE_GOT_NOTHING;
1715
0
  }
1716
1717
0
  return CURLE_OK;
1718
0
}
1719
1720
/* Determine if we may use HTTP 1.1 for this request. */
1721
static bool http_may_use_1_1(const struct Curl_easy *data)
1722
0
{
1723
0
  const struct connectdata *conn = data->conn;
1724
  /* We have seen a previous response for *this* transfer with 1.0,
1725
   * on another connection or the same one. */
1726
0
  if(data->state.http_neg.rcvd_min == 10)
1727
0
    return FALSE;
1728
  /* We have seen a previous response on *this* connection with 1.0. */
1729
0
  if(conn && conn->httpversion_seen == 10)
1730
0
    return FALSE;
1731
  /* We want 1.0 and have seen no previous response on *this* connection
1732
     with a higher version (maybe no response at all yet). */
1733
0
  if(data->state.http_neg.only_10 &&
1734
0
     (!conn || conn->httpversion_seen <= 10))
1735
0
    return FALSE;
1736
  /* We are not restricted to use 1.0 only. */
1737
0
  return !data->state.http_neg.only_10;
1738
0
}
1739
1740
static unsigned char http_request_version(struct Curl_easy *data)
1741
0
{
1742
0
  unsigned char v = Curl_conn_http_version(data, data->conn);
1743
0
  if(!v) {
1744
    /* No specific HTTP connection filter installed. */
1745
0
    v = http_may_use_1_1(data) ? 11 : 10;
1746
0
  }
1747
0
  return v;
1748
0
}
1749
1750
static const char *get_http_string(int httpversion)
1751
0
{
1752
0
  switch(httpversion) {
1753
0
  case 30:
1754
0
    return "3";
1755
0
  case 20:
1756
0
    return "2";
1757
0
  case 11:
1758
0
    return "1.1";
1759
0
  default:
1760
0
    return "1.0";
1761
0
  }
1762
0
}
1763
1764
CURLcode Curl_add_custom_headers(struct Curl_easy *data,
1765
                                 bool is_connect, int httpversion,
1766
                                 struct dynbuf *req)
1767
0
{
1768
0
  struct curl_slist *h[2];
1769
0
  struct curl_slist *headers;
1770
0
  int numlists = 1; /* by default */
1771
0
  int i;
1772
1773
0
#ifndef CURL_DISABLE_PROXY
1774
0
  enum Curl_proxy_use proxy;
1775
1776
0
  if(is_connect)
1777
0
    proxy = HEADER_CONNECT;
1778
0
  else
1779
0
    proxy = data->conn->bits.origin_is_proxy ? HEADER_PROXY : HEADER_SERVER;
1780
1781
0
  switch(proxy) {
1782
0
  case HEADER_SERVER:
1783
0
    h[0] = data->set.headers;
1784
0
    break;
1785
0
  case HEADER_PROXY:
1786
0
    h[0] = data->set.headers;
1787
0
    if(data->set.sep_headers) {
1788
0
      h[1] = data->set.proxyheaders;
1789
0
      numlists++;
1790
0
    }
1791
0
    break;
1792
0
  case HEADER_CONNECT:
1793
0
    if(data->set.sep_headers)
1794
0
      h[0] = data->set.proxyheaders;
1795
0
    else
1796
0
      h[0] = data->set.headers;
1797
0
    break;
1798
0
  case HEADER_CONNECT_UDP:
1799
0
    if(data->set.sep_headers)
1800
0
      h[0] = data->set.proxyheaders;
1801
0
    else
1802
0
      h[0] = data->set.headers;
1803
0
    break;
1804
0
  }
1805
#else
1806
  (void)is_connect;
1807
  h[0] = data->set.headers;
1808
#endif
1809
1810
  /* loop through one or two lists */
1811
0
  for(i = 0; i < numlists; i++) {
1812
0
    for(headers = h[i]; headers; headers = headers->next) {
1813
0
      CURLcode result = CURLE_OK;
1814
0
      bool blankheader = FALSE;
1815
0
      struct Curl_str name;
1816
0
      const char *p = headers->data;
1817
0
      const char *origp = p;
1818
0
      size_t hlen = strlen(origp);
1819
1820
      /* explicitly asked to send header without content is done by a header
1821
         that ends with a semicolon, but there must be no colon present in the
1822
         name */
1823
0
      if(!curlx_str_until(&p, &name, hlen, ';') &&
1824
0
         !curlx_str_single(&p, ';') &&
1825
0
         !curlx_str_single(&p, '\0') &&
1826
0
         !memchr(curlx_str(&name), ':', curlx_strlen(&name)))
1827
0
        blankheader = TRUE;
1828
0
      else {
1829
0
        p = origp;
1830
0
        if(!curlx_str_until(&p, &name, hlen, ':') &&
1831
0
           !curlx_str_single(&p, ':')) {
1832
0
          struct Curl_str val;
1833
0
          curlx_str_untilnl(&p, &val, hlen);
1834
0
          curlx_str_trimblanks(&val);
1835
0
          if(!curlx_strlen(&val))
1836
            /* no content, do not send this */
1837
0
            continue;
1838
0
        }
1839
0
        else
1840
          /* no colon */
1841
0
          continue;
1842
0
      }
1843
1844
      /* a field name is a token and carries no surrounding whitespace, so
1845
         trim the parsed name before matching. Otherwise `Authorization :`
1846
         (space before the colon) slips past the Authorization/Cookie check
1847
         below and gets forwarded to another host on a redirect. */
1848
0
      curlx_str_trimblanks(&name);
1849
1850
      /* only send this if the contents was non-blank or done special */
1851
1852
0
      if(data->state.http_host &&
1853
         /* a Host: header was sent already, do not pass on any custom
1854
            Host: header as that will produce *two* in the same
1855
            request! */
1856
0
         curlx_str_casecompare(&name, "Host"))
1857
0
        ;
1858
0
      else if(data->state.httpreq == HTTPREQ_POST_FORM &&
1859
              /* this header (extended by formdata.c) is sent later */
1860
0
              curlx_str_casecompare(&name, "Content-Type"))
1861
0
        ;
1862
0
      else if(data->state.httpreq == HTTPREQ_POST_MIME &&
1863
              /* this header is sent later */
1864
0
              curlx_str_casecompare(&name, "Content-Type"))
1865
0
        ;
1866
0
      else if(data->req.authneg &&
1867
              /* while doing auth neg, do not allow the custom length since
1868
                 we will force length zero then */
1869
0
              curlx_str_casecompare(&name, "Content-Length"))
1870
0
        ;
1871
0
      else if(curlx_str_casecompare(&name, "Connection"))
1872
        /* Connection headers are handled specially */
1873
0
        ;
1874
0
      else if((httpversion >= 20) &&
1875
0
              curlx_str_casecompare(&name, "Transfer-Encoding"))
1876
        /* HTTP/2 does not support chunked requests */
1877
0
        ;
1878
0
      else if((curlx_str_casecompare(&name, "Authorization") ||
1879
0
               curlx_str_casecompare(&name, "Cookie")) &&
1880
              /* be careful of sending this potentially sensitive header to
1881
                 other hosts */
1882
0
              !Curl_auth_allowed_to_host(data))
1883
0
        ;
1884
0
      else if(blankheader) {
1885
0
        result = curlx_dyn_addn(req, curlx_str(&name), curlx_strlen(&name));
1886
0
        if(!result)
1887
0
          result = curlx_dyn_addn(req, STRCONST(":\r\n"));
1888
0
      }
1889
0
      else
1890
0
        result = curlx_dyn_addf(req, "%s\r\n", origp);
1891
1892
0
      if(result)
1893
0
        return result;
1894
0
    }
1895
0
  }
1896
1897
0
  return CURLE_OK;
1898
0
}
1899
1900
#ifndef CURL_DISABLE_PARSEDATE
1901
CURLcode Curl_add_timecondition(struct Curl_easy *data,
1902
                                struct dynbuf *req)
1903
0
{
1904
0
  const struct tm *tm;
1905
0
  struct tm keeptime;
1906
0
  CURLcode result;
1907
0
  char datestr[80];
1908
0
  const char *condp;
1909
0
  size_t len;
1910
1911
0
  if(data->set.timecondition == CURL_TIMECOND_NONE)
1912
    /* no condition was asked for */
1913
0
    return CURLE_OK;
1914
1915
0
  result = curlx_gmtime(data->set.timevalue, &keeptime);
1916
0
  if(result) {
1917
0
    failf(data, "Invalid TIMEVALUE");
1918
0
    return result;
1919
0
  }
1920
0
  tm = &keeptime;
1921
1922
0
  switch(data->set.timecondition) {
1923
0
  default:
1924
0
    DEBUGF(infof(data, "invalid time condition"));
1925
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1926
1927
0
  case CURL_TIMECOND_IFMODSINCE:
1928
0
    condp = "If-Modified-Since";
1929
0
    len = 17;
1930
0
    break;
1931
0
  case CURL_TIMECOND_IFUNMODSINCE:
1932
0
    condp = "If-Unmodified-Since";
1933
0
    len = 19;
1934
0
    break;
1935
0
  case CURL_TIMECOND_LASTMOD:
1936
0
    condp = "Last-Modified";
1937
0
    len = 13;
1938
0
    break;
1939
0
  }
1940
1941
0
  if(Curl_checkheaders(data, condp, len)) {
1942
    /* A custom header was specified; it will be sent instead. */
1943
0
    return CURLE_OK;
1944
0
  }
1945
1946
  /* The If-Modified-Since header family should have their times set in
1947
   * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
1948
   * represented in Greenwich Mean Time (GMT), without exception. For the
1949
   * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
1950
   * Time)." (see page 20 of RFC2616).
1951
   */
1952
1953
  /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
1954
0
  curl_msnprintf(datestr, sizeof(datestr),
1955
0
                 "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
1956
0
                 condp,
1957
0
                 Curl_wkday[tm->tm_wday ? tm->tm_wday - 1 : 6],
1958
0
                 tm->tm_mday,
1959
0
                 Curl_month[tm->tm_mon],
1960
0
                 tm->tm_year + 1900,
1961
0
                 tm->tm_hour,
1962
0
                 tm->tm_min,
1963
0
                 tm->tm_sec);
1964
1965
0
  result = curlx_dyn_add(req, datestr);
1966
0
  return result;
1967
0
}
1968
#else
1969
/* disabled */
1970
CURLcode Curl_add_timecondition(struct Curl_easy *data,
1971
                                struct dynbuf *req)
1972
{
1973
  (void)data;
1974
  (void)req;
1975
  return CURLE_OK;
1976
}
1977
#endif
1978
1979
void Curl_http_method(struct Curl_easy *data,
1980
                      const char **method, Curl_HttpReq *reqp)
1981
0
{
1982
0
  Curl_HttpReq httpreq = (Curl_HttpReq)data->state.httpreq;
1983
0
  const char *request;
1984
0
#ifndef CURL_DISABLE_WEBSOCKETS
1985
0
  if(data->conn->scheme->protocol & (CURLPROTO_WS | CURLPROTO_WSS))
1986
0
    httpreq = HTTPREQ_GET;
1987
0
  else
1988
0
#endif
1989
0
  if((data->conn->scheme->protocol & (PROTO_FAMILY_HTTP | CURLPROTO_FTP)) &&
1990
0
     data->state.upload)
1991
0
    httpreq = HTTPREQ_PUT;
1992
1993
  /* Now set the 'request' pointer to the proper request string */
1994
0
  if(!data->state.http_ignorecustom &&
1995
0
     CURL_EASY_STR(data, STRING_CUSTOMREQUEST)) {
1996
0
    request = CURL_EASY_STR(data, STRING_CUSTOMREQUEST);
1997
0
  }
1998
0
  else {
1999
0
    if(data->req.no_body)
2000
0
      request = "HEAD";
2001
0
    else {
2002
0
      DEBUGASSERT((httpreq >= HTTPREQ_GET) && (httpreq <= HTTPREQ_HEAD));
2003
0
      switch(httpreq) {
2004
0
      case HTTPREQ_POST:
2005
0
      case HTTPREQ_POST_FORM:
2006
0
      case HTTPREQ_POST_MIME:
2007
0
        request = "POST";
2008
0
        break;
2009
0
      case HTTPREQ_PUT:
2010
0
        request = "PUT";
2011
0
        break;
2012
0
      default: /* this should never happen */
2013
0
      case HTTPREQ_GET:
2014
0
        request = "GET";
2015
0
        break;
2016
0
      case HTTPREQ_HEAD:
2017
0
        request = "HEAD";
2018
0
        break;
2019
0
      }
2020
0
    }
2021
0
  }
2022
0
  *method = request;
2023
0
  *reqp = httpreq;
2024
0
}
2025
2026
static CURLcode http_set_aptr_host(struct Curl_easy *data)
2027
0
{
2028
0
  struct connectdata *conn = data->conn;
2029
0
  const char *ptr = NULL;
2030
2031
0
  curlx_safefree(data->state.http_host);
2032
0
#ifndef CURL_DISABLE_COOKIES
2033
0
  curlx_safefree(data->req.cookiehost);
2034
0
#endif
2035
2036
0
  if(Curl_peer_equal(data->state.initial_origin, data->state.origin))
2037
0
    ptr = Curl_checkheaders(data, STRCONST("Host"));
2038
2039
0
  if(ptr) {
2040
0
#ifndef CURL_DISABLE_COOKIES
2041
    /* If we have a given custom Host: header, we extract the hostname in
2042
       order to possibly use it for cookie reasons later on. We only allow the
2043
       custom Host: header if this is NOT a redirect, as setting Host: in the
2044
       redirected request is being out on thin ice. Except if the hostname
2045
       is the same as the first one! */
2046
0
    char *cookiehost;
2047
0
    CURLcode result = copy_custom_value(ptr, &cookiehost);
2048
0
    if(result)
2049
0
      return result;
2050
0
    if(!*cookiehost)
2051
      /* ignore empty data */
2052
0
      curlx_free(cookiehost);
2053
0
    else {
2054
      /* If the host begins with '[', we start searching for the port after
2055
         the bracket has been closed */
2056
0
      if(*cookiehost == '[') {
2057
0
        char *closingbracket;
2058
        /* since the 'cookiehost' is an allocated memory area that will be
2059
           freed later we cannot increment the pointer */
2060
0
        memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1);
2061
0
        closingbracket = strchr(cookiehost, ']');
2062
0
        if(closingbracket)
2063
0
          *closingbracket = 0;
2064
0
      }
2065
0
      else {
2066
0
        int startsearch = 0;
2067
0
        char *colon = strchr(cookiehost + startsearch, ':');
2068
0
        if(colon)
2069
0
          *colon = 0; /* The host must not include an embedded port number */
2070
0
      }
2071
0
      data->req.cookiehost = cookiehost;
2072
0
    }
2073
0
#endif
2074
2075
0
    if(!curl_strequal("Host:", ptr)) {
2076
0
      data->state.http_host = curl_maprintf("Host:%s", &ptr[5]);
2077
0
      if(!data->state.http_host)
2078
0
        return CURLE_OUT_OF_MEMORY;
2079
0
    }
2080
0
  }
2081
0
  else {
2082
    /* This is the  HTTP Host: header, so we want
2083
     * - for IPv6 origins: "[ipv6-address]" where the IPv6 address is
2084
     *  found in origin->hostname, stripped of zoneid/scopeid.
2085
     * - the (IDN converted) origin->hostname (DNS name or IPv4) otherwise.
2086
     * Note: zoneid/scopeid  only applies to local routing and has no
2087
     * meaning on the remote HTTP server (eg. would confuse it). */
2088
0
    bool ipv6 = (bool)data->state.origin->ipv6;
2089
0
    struct dynbuf tmp;
2090
0
    size_t hlen;
2091
0
    CURLcode result;
2092
2093
0
    curlx_dyn_init(&tmp, DYN_HTTP_REQUEST);
2094
0
    result = curlx_dyn_addn(&tmp, STRCONST("Host: "));
2095
0
    if(!result && ipv6)
2096
0
      result = curlx_dyn_addn(&tmp, STRCONST("["));
2097
0
    if(!result)
2098
0
      result = curlx_dyn_add(&tmp, data->state.origin->hostname);
2099
0
    if(!result && ipv6)
2100
0
      result = curlx_dyn_addn(&tmp, STRCONST("]"));
2101
0
    if(!result &&
2102
0
       ((data->state.origin->port != data->state.origin->scheme->defport) ||
2103
0
       (data->state.origin->scheme->family != conn->scheme->family))) {
2104
0
      result = curlx_dyn_addf(&tmp, ":%u", data->state.origin->port);
2105
0
    }
2106
2107
0
    data->state.http_host = result ? NULL : curlx_dyn_take(&tmp, &hlen);
2108
0
    curlx_dyn_free(&tmp);
2109
0
    return result;
2110
0
  }
2111
0
  return CURLE_OK;
2112
0
}
2113
2114
/*
2115
 * Append the request-target to the HTTP request
2116
 */
2117
static CURLcode http_target(struct Curl_easy *data,
2118
                            struct dynbuf *r)
2119
0
{
2120
0
  CURLcode result = CURLE_OK;
2121
0
  const char *path = data->state.up.path;
2122
0
  const char *query = data->state.up.query;
2123
0
#ifndef CURL_DISABLE_PROXY
2124
0
  struct connectdata *conn = data->conn;
2125
0
#endif
2126
2127
0
  if(CURL_EASY_STR(data, STRING_TARGET)) {
2128
0
    path = CURL_EASY_STR(data, STRING_TARGET);
2129
0
    query = NULL;
2130
0
  }
2131
2132
0
#ifndef CURL_DISABLE_PROXY
2133
0
  if(conn->bits.origin_is_proxy) {
2134
    /* Using a proxy but does not tunnel through it */
2135
2136
    /* The path sent to the proxy is in fact the entire URL, but if the remote
2137
       host is a IDN-name, we must make sure that the request we produce only
2138
       uses the decoded hostname! */
2139
2140
    /* and no fragment part */
2141
0
    CURLUcode uc;
2142
0
    char *url;
2143
0
    CURLU *h = curl_url_dup(data->state.uh);
2144
0
    if(!h)
2145
0
      return CURLE_OUT_OF_MEMORY;
2146
2147
0
    if(!data->state.origin->ipv6 &&
2148
0
       (data->state.origin->user_hostname != data->state.origin->hostname)) {
2149
0
      uc = curl_url_set(h, CURLUPART_HOST, data->state.origin->hostname, 0);
2150
0
      if(uc) {
2151
0
        curl_url_cleanup(h);
2152
0
        return CURLE_OUT_OF_MEMORY;
2153
0
      }
2154
0
    }
2155
0
    uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
2156
0
    if(uc) {
2157
0
      curl_url_cleanup(h);
2158
0
      return CURLE_OUT_OF_MEMORY;
2159
0
    }
2160
2161
0
    if(data->state.origin->scheme == &Curl_scheme_http) {
2162
      /* when getting HTTP, we do not want the userinfo the URL */
2163
0
      uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
2164
0
      if(uc) {
2165
0
        curl_url_cleanup(h);
2166
0
        return CURLE_OUT_OF_MEMORY;
2167
0
      }
2168
0
      uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
2169
0
      if(uc) {
2170
0
        curl_url_cleanup(h);
2171
0
        return CURLE_OUT_OF_MEMORY;
2172
0
      }
2173
0
    }
2174
0
    else if(data->state.creds && (data->state.creds->source != CREDS_URL)) {
2175
        /* credentials not from the URL need to be set */
2176
0
      uc = curl_url_set(h, CURLUPART_USER,
2177
0
                        data->state.creds->user, CURLU_URLENCODE);
2178
0
      if(!uc)
2179
0
        uc = curl_url_set(h, CURLUPART_PASSWORD,
2180
0
                          data->state.creds->passwd, CURLU_URLENCODE);
2181
0
      if(uc) {
2182
0
        curl_url_cleanup(h);
2183
0
        return Curl_uc_to_curlcode(uc);
2184
0
      }
2185
0
    }
2186
2187
    /* Extract the URL to use in the request. */
2188
0
    uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
2189
0
    if(uc) {
2190
0
      curl_url_cleanup(h);
2191
0
      return CURLE_OUT_OF_MEMORY;
2192
0
    }
2193
2194
0
    curl_url_cleanup(h);
2195
2196
    /* target or URL */
2197
0
    result = curlx_dyn_add(r, CURL_EASY_STR(data, STRING_TARGET) ?
2198
0
      CURL_EASY_STR(data, STRING_TARGET) : url);
2199
0
    curlx_free(url);
2200
0
    if(result)
2201
0
      return result;
2202
2203
0
    if((data->state.origin->scheme == &Curl_scheme_ftp) &&
2204
0
       data->set.proxy_transfer_mode) {
2205
      /* when doing ftp, append ;type=<a|i> if not present */
2206
0
      size_t len = strlen(path);
2207
0
      bool type_present = FALSE;
2208
0
      if((len >= 7) && !memcmp(&path[len - 7], ";type=", 6)) {
2209
0
        switch(Curl_raw_toupper(path[len - 1])) {
2210
0
        case 'A':
2211
0
        case 'D':
2212
0
        case 'I':
2213
0
          type_present = TRUE;
2214
0
          break;
2215
0
        }
2216
0
      }
2217
0
      if(!type_present) {
2218
0
        result = curlx_dyn_addf(r, ";type=%c",
2219
0
                                data->state.prefer_ascii ? 'a' : 'i');
2220
0
        if(result)
2221
0
          return result;
2222
0
      }
2223
0
    }
2224
0
  }
2225
2226
0
  else
2227
0
#endif
2228
0
  {
2229
0
    result = curlx_dyn_add(r, path);
2230
0
    if(result)
2231
0
      return result;
2232
0
    if(query)
2233
0
      result = curlx_dyn_addf(r, "?%s", query);
2234
0
  }
2235
2236
0
  return result;
2237
0
}
2238
2239
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
2240
static CURLcode set_post_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
2241
0
{
2242
0
  CURLcode result;
2243
2244
0
  switch(httpreq) {
2245
0
#ifndef CURL_DISABLE_MIME
2246
0
  case HTTPREQ_POST_MIME:
2247
0
    data->state.mimepost = data->set.mimepostp;
2248
0
    break;
2249
0
#endif
2250
0
#ifndef CURL_DISABLE_FORM_API
2251
0
  case HTTPREQ_POST_FORM:
2252
    /* Convert the form structure into a mime structure, then keep
2253
       the conversion */
2254
0
    if(!data->state.formp) {
2255
0
      data->state.formp = curlx_calloc(1, sizeof(curl_mimepart));
2256
0
      if(!data->state.formp)
2257
0
        return CURLE_OUT_OF_MEMORY;
2258
0
      Curl_mime_cleanpart(data->state.formp);
2259
0
      result = Curl_getformdata(data, data->state.formp, data->set.httppost,
2260
0
                                data->state.fread_func);
2261
0
      if(result) {
2262
0
        curlx_safefree(data->state.formp);
2263
0
        return result;
2264
0
      }
2265
0
      data->state.mimepost = data->state.formp;
2266
0
    }
2267
0
    break;
2268
0
#endif
2269
0
  default:
2270
0
    data->state.mimepost = NULL;
2271
0
    break;
2272
0
  }
2273
2274
0
  switch(httpreq) {
2275
0
  case HTTPREQ_POST_FORM:
2276
0
  case HTTPREQ_POST_MIME:
2277
    /* This is form posting using mime data. */
2278
0
#ifndef CURL_DISABLE_MIME
2279
0
    if(data->state.mimepost) {
2280
0
      const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
2281
2282
      /* Read and seek body only. */
2283
0
      data->state.mimepost->flags |= MIME_BODY_ONLY;
2284
2285
      /* Prepare the mime structure headers & set content type. */
2286
2287
0
      if(cthdr)
2288
0
        for(cthdr += 13; *cthdr == ' '; cthdr++)
2289
0
          ;
2290
0
      else if(data->state.mimepost->kind == MIMEKIND_MULTIPART)
2291
0
        cthdr = "multipart/form-data";
2292
2293
0
      curl_mime_headers(data->state.mimepost, data->set.headers, 0);
2294
0
      result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr,
2295
0
                                         NULL, MIMESTRATEGY_FORM);
2296
0
      if(result)
2297
0
        return result;
2298
0
      curl_mime_headers(data->state.mimepost, NULL, 0);
2299
0
      result = Curl_creader_set_mime(data, data->state.mimepost);
2300
0
      if(result)
2301
0
        return result;
2302
0
    }
2303
0
    else
2304
0
#endif
2305
0
    {
2306
0
      result = Curl_creader_set_null(data);
2307
0
    }
2308
0
    data->state.infilesize = Curl_creader_total_length(data);
2309
0
    return result;
2310
2311
0
  default:
2312
0
    return Curl_creader_set_null(data);
2313
0
  }
2314
  /* never reached */
2315
0
}
2316
#endif
2317
2318
static CURLcode set_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
2319
0
{
2320
0
  CURLcode result = CURLE_OK;
2321
0
  curl_off_t postsize = data->state.infilesize;
2322
2323
0
  DEBUGASSERT(data->conn);
2324
2325
0
  if(data->req.authneg) {
2326
0
    return Curl_creader_set_null(data);
2327
0
  }
2328
2329
0
  switch(httpreq) {
2330
0
  case HTTPREQ_PUT: /* Let's PUT the data to the server! */
2331
0
    return postsize ? Curl_creader_set_fread(data, postsize) :
2332
0
      Curl_creader_set_null(data);
2333
2334
0
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
2335
0
  case HTTPREQ_POST_FORM:
2336
0
  case HTTPREQ_POST_MIME:
2337
0
    return set_post_reader(data, httpreq);
2338
0
#endif
2339
2340
0
  case HTTPREQ_POST:
2341
    /* this is the simple POST, using x-www-form-urlencoded style */
2342
    /* the size of the post body */
2343
0
    if(!postsize) {
2344
0
      result = Curl_creader_set_null(data);
2345
0
    }
2346
0
    else if(data->set.postfields) {
2347
0
      size_t plen = curlx_sotouz_range(postsize, 0, SIZE_MAX);
2348
0
      if(plen == SIZE_MAX)
2349
0
        return CURLE_OUT_OF_MEMORY;
2350
0
      else if(plen)
2351
0
        result = Curl_creader_set_buf(data, data->set.postfields, plen);
2352
0
      else
2353
0
        result = Curl_creader_set_null(data);
2354
0
    }
2355
0
    else {
2356
      /* we read the bytes from the callback. In case "chunked" encoding
2357
       * is forced by the application, we disregard `postsize`. This is
2358
       * a backward compatibility decision to earlier versions where
2359
       * chunking disregarded this. See issue #13229. */
2360
0
      bool chunked = FALSE;
2361
0
      char *ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
2362
0
      if(ptr) {
2363
        /* Some kind of TE is requested, check if 'chunked' is chosen */
2364
0
        chunked = Curl_compareheader(ptr, STRCONST("Transfer-Encoding:"),
2365
0
                                     STRCONST("chunked"));
2366
0
      }
2367
0
      result = Curl_creader_set_fread(data, chunked ? -1 : postsize);
2368
0
    }
2369
0
    return result;
2370
2371
0
  default:
2372
    /* HTTP GET/HEAD download, has no body, needs no Content-Length */
2373
0
    data->state.infilesize = 0;
2374
0
    return Curl_creader_set_null(data);
2375
0
  }
2376
  /* not reached */
2377
0
}
2378
2379
static CURLcode http_resume(struct Curl_easy *data, Curl_HttpReq httpreq)
2380
0
{
2381
0
  if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
2382
0
     data->state.resume_from) {
2383
    /**********************************************************************
2384
     * Resuming upload in HTTP means that we PUT or POST and that we have
2385
     * got a resume_from value set. The resume value has already created
2386
     * a Range: header that will be passed along. We need to "fast forward"
2387
     * the file the given number of bytes and decrease the assume upload
2388
     * file size before we continue this venture in the dark lands of HTTP.
2389
     * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
2390
     *********************************************************************/
2391
2392
0
    if(data->state.resume_from < 0) {
2393
      /*
2394
       * This is meant to get the size of the present remote-file by itself.
2395
       * We do not support this now. Bail out!
2396
       */
2397
0
      data->state.resume_from = 0;
2398
0
    }
2399
2400
0
    if(data->state.resume_from && !data->req.authneg) {
2401
      /* only act on the first request */
2402
0
      CURLcode result;
2403
0
      result = Curl_creader_resume_from(data, data->state.resume_from);
2404
0
      if(result) {
2405
0
        failf(data, "Unable to resume from offset %" FMT_OFF_T,
2406
0
              data->state.resume_from);
2407
0
        return result;
2408
0
      }
2409
0
    }
2410
0
  }
2411
0
  return CURLE_OK;
2412
0
}
2413
2414
static CURLcode http_req_set_TE(struct Curl_easy *data,
2415
                                struct dynbuf *req,
2416
                                int httpversion)
2417
0
{
2418
0
  CURLcode result = CURLE_OK;
2419
0
  const char *ptr;
2420
2421
0
  ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
2422
0
  if(ptr) {
2423
    /* Some kind of TE is requested, check if 'chunked' is chosen */
2424
0
    data->req.upload_chunky =
2425
0
      Curl_compareheader(ptr,
2426
0
                         STRCONST("Transfer-Encoding:"), STRCONST("chunked"));
2427
0
    if(data->req.upload_chunky && (httpversion >= 20)) {
2428
0
      infof(data, "suppressing chunked transfer encoding on connection "
2429
0
            "using HTTP version 2 or higher");
2430
0
      data->req.upload_chunky = FALSE;
2431
0
    }
2432
0
  }
2433
0
  else {
2434
0
    curl_off_t req_clen = Curl_creader_total_length(data);
2435
2436
0
    if(req_clen < 0) {
2437
      /* indeterminate request content length */
2438
0
      if(httpversion > 10) {
2439
        /* On HTTP/1.1, enable chunked, on HTTP/2 and later we do not
2440
         * need it */
2441
0
        data->req.upload_chunky = (httpversion < 20);
2442
0
      }
2443
0
      else {
2444
0
        failf(data, "Chunky upload is not supported by HTTP 1.0");
2445
0
        return CURLE_UPLOAD_FAILED;
2446
0
      }
2447
0
    }
2448
0
    else {
2449
      /* else, no chunky upload */
2450
0
      data->req.upload_chunky = FALSE;
2451
0
    }
2452
2453
0
    if(data->req.upload_chunky)
2454
0
      result = curlx_dyn_add(req, "Transfer-Encoding: chunked\r\n");
2455
0
  }
2456
0
  return result;
2457
0
}
2458
2459
static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r,
2460
                          int httpversion, bool *announced_exp100)
2461
0
{
2462
0
  CURLcode result;
2463
0
  char *ptr;
2464
2465
0
  *announced_exp100 = FALSE;
2466
  /* Avoid Expect: 100-continue if Upgrade: is used */
2467
0
  if(data->req.upgr101 != UPGR101_NONE)
2468
0
    return CURLE_OK;
2469
2470
  /* For really small puts we do not use Expect: headers at all, and for
2471
     the somewhat bigger ones we allow the app to disable it. Make
2472
     sure that the expect100header is always set to the preferred value
2473
     here. */
2474
0
  ptr = Curl_checkheaders(data, STRCONST("Expect"));
2475
0
  if(ptr) {
2476
0
    *announced_exp100 =
2477
0
      Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
2478
0
  }
2479
0
  else if(!data->state.disableexpect && (httpversion == 11)) {
2480
    /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
2481
       Expect: 100-continue to the headers which actually speeds up post
2482
       operations (as there is one packet coming back from the web server) */
2483
0
    curl_off_t client_len = Curl_creader_client_length(data);
2484
0
    if(client_len > EXPECT_100_THRESHOLD || client_len < 0) {
2485
0
      result = curlx_dyn_addn(r, STRCONST("Expect: 100-continue\r\n"));
2486
0
      if(result)
2487
0
        return result;
2488
0
      *announced_exp100 = TRUE;
2489
0
    }
2490
0
  }
2491
0
  return CURLE_OK;
2492
0
}
2493
2494
static CURLcode http_add_content_hds(struct Curl_easy *data,
2495
                                     struct dynbuf *r,
2496
                                     int httpversion,
2497
                                     Curl_HttpReq httpreq)
2498
0
{
2499
0
  CURLcode result = CURLE_OK;
2500
0
  curl_off_t req_clen;
2501
0
  bool announced_exp100 = FALSE;
2502
2503
0
  DEBUGASSERT(data->conn);
2504
0
  if(data->req.upload_chunky) {
2505
0
    result = Curl_httpchunk_add_reader(data);
2506
0
    if(result)
2507
0
      return result;
2508
0
  }
2509
2510
  /* Get the request body length that has been set up */
2511
0
  req_clen = Curl_creader_total_length(data);
2512
0
  switch(httpreq) {
2513
0
  case HTTPREQ_PUT:
2514
0
  case HTTPREQ_POST:
2515
0
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
2516
0
  case HTTPREQ_POST_FORM:
2517
0
  case HTTPREQ_POST_MIME:
2518
0
#endif
2519
    /* We only set Content-Length and allow a custom Content-Length if
2520
       we do not upload data chunked, as RFC2616 forbids us to set both
2521
       kinds of headers (Transfer-Encoding: chunked and Content-Length).
2522
       We do not override a custom "Content-Length" header, but during
2523
       authentication negotiation that header is suppressed.
2524
     */
2525
0
    if(req_clen >= 0 && !data->req.upload_chunky &&
2526
0
       (data->req.authneg ||
2527
0
        !Curl_checkheaders(data, STRCONST("Content-Length")))) {
2528
      /* we allow replacing this header if not during auth negotiation,
2529
         although it is not wise to actually set your own */
2530
0
      result = curlx_dyn_addf(r, "Content-Length: %" FMT_OFF_T "\r\n",
2531
0
                              req_clen);
2532
0
    }
2533
0
    if(result)
2534
0
      goto out;
2535
2536
0
#ifndef CURL_DISABLE_MIME
2537
    /* Output mime-generated headers. */
2538
0
    if(data->state.mimepost &&
2539
0
       ((httpreq == HTTPREQ_POST_FORM) || (httpreq == HTTPREQ_POST_MIME))) {
2540
0
      struct curl_slist *hdr;
2541
2542
0
      for(hdr = data->state.mimepost->curlheaders; hdr; hdr = hdr->next) {
2543
0
        result = curlx_dyn_addf(r, "%s\r\n", hdr->data);
2544
0
        if(result)
2545
0
          goto out;
2546
0
      }
2547
0
    }
2548
0
#endif
2549
0
    if(httpreq == HTTPREQ_POST) {
2550
0
      if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
2551
0
        result = curlx_dyn_addn(r, STRCONST("Content-Type: application/"
2552
0
                                            "x-www-form-urlencoded\r\n"));
2553
0
        if(result)
2554
0
          goto out;
2555
0
      }
2556
0
    }
2557
0
    result = addexpect(data, r, httpversion, &announced_exp100);
2558
0
    if(result)
2559
0
      goto out;
2560
0
    break;
2561
0
  default:
2562
0
    break;
2563
0
  }
2564
2565
0
  Curl_pgrsSetUploadSize(data, req_clen);
2566
0
  if(announced_exp100)
2567
0
    result = http_exp100_add_reader(data);
2568
2569
0
out:
2570
0
  return result;
2571
0
}
2572
2573
#ifndef CURL_DISABLE_COOKIES
2574
2575
static CURLcode http_cookies(struct Curl_easy *data,
2576
                             struct dynbuf *r)
2577
0
{
2578
0
  CURLcode result = CURLE_OK;
2579
0
  const char *addcookies = NULL;
2580
0
  bool linecap = FALSE;
2581
0
  if(CURL_EASY_STR(data, STRING_COOKIE) &&
2582
0
     !Curl_checkheaders(data, STRCONST("Cookie")) &&
2583
0
     Curl_auth_allowed_to_host(data))
2584
0
    addcookies = CURL_EASY_STR(data, STRING_COOKIE);
2585
2586
0
  if(data->cookies || addcookies) {
2587
0
    struct Curl_llist list;
2588
0
    int count = 0;
2589
2590
0
    if(data->cookies && data->state.cookie_engine) {
2591
0
      bool okay;
2592
0
      const char *host = data->req.cookiehost ?
2593
0
        data->req.cookiehost : data->state.origin->hostname;
2594
0
      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
2595
0
      result = Curl_cookie_getlist(data, &okay, host, &list);
2596
0
      if(!result && okay) {
2597
0
        struct Curl_llist_node *n;
2598
0
        size_t clen = 8; /* hold the size of the generated Cookie: header */
2599
2600
        /* loop through all cookies that matched */
2601
0
        for(n = Curl_llist_head(&list); n; n = Curl_node_next(n)) {
2602
0
          struct Cookie *co = Curl_node_elem(n);
2603
0
          if(co->value) {
2604
0
            size_t add;
2605
0
            if(!count) {
2606
0
              result = curlx_dyn_addn(r, STRCONST("Cookie: "));
2607
0
              if(result)
2608
0
                break;
2609
0
            }
2610
0
            add = strlen(co->name) + strlen(co->value) + 1;
2611
0
            if(clen + add >= MAX_COOKIE_HEADER_LEN) {
2612
0
              infof(data, "Restricted outgoing cookies due to header size, "
2613
0
                    "'%s' not sent", co->name);
2614
0
              linecap = TRUE;
2615
0
              break;
2616
0
            }
2617
0
            result = curlx_dyn_addf(r, "%s%s=%s", count ? "; " : "",
2618
0
                                    co->name, co->value);
2619
0
            if(result)
2620
0
              break;
2621
0
            clen += add + (count ? 2 : 0);
2622
0
            count++;
2623
0
          }
2624
0
        }
2625
0
        Curl_llist_destroy(&list, NULL);
2626
0
      }
2627
0
      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
2628
0
    }
2629
0
    if(addcookies && !result && !linecap) {
2630
0
      if(!count)
2631
0
        result = curlx_dyn_addn(r, STRCONST("Cookie: "));
2632
0
      if(!result) {
2633
0
        result = curlx_dyn_addf(r, "%s%s", count ? "; " : "", addcookies);
2634
0
        count++;
2635
0
      }
2636
0
    }
2637
0
    if(count && !result)
2638
0
      result = curlx_dyn_addn(r, STRCONST("\r\n"));
2639
2640
0
    if(result)
2641
0
      return result;
2642
0
  }
2643
0
  return result;
2644
0
}
2645
#else
2646
#define http_cookies(a, b) CURLE_OK
2647
#endif
2648
2649
static CURLcode http_range(struct Curl_easy *data,
2650
                           Curl_HttpReq httpreq)
2651
0
{
2652
0
  if(data->state.use_range) {
2653
    /*
2654
     * A range is selected. We use different headers whether we are downloading
2655
     * or uploading and we always let customized headers override our internal
2656
     * ones if any such are specified.
2657
     */
2658
0
    if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
2659
0
       !Curl_checkheaders(data, STRCONST("Range"))) {
2660
      /* if a line like this was already allocated, free the previous one */
2661
0
      curlx_free(data->state.rangeline);
2662
0
      data->state.rangeline = curl_maprintf("Range: bytes=%s\r\n",
2663
0
                                                 data->state.range);
2664
0
      if(!data->state.rangeline)
2665
0
        return CURLE_OUT_OF_MEMORY;
2666
0
    }
2667
0
    else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
2668
0
            !Curl_checkheaders(data, STRCONST("Content-Range"))) {
2669
0
      curl_off_t req_clen = Curl_creader_total_length(data);
2670
      /* if a line like this was already allocated, free the previous one */
2671
0
      curlx_free(data->state.rangeline);
2672
2673
0
      if(data->set.set_resume_from < 0) {
2674
        /* Upload resume was asked for, but we do not know the size of the
2675
           remote part so we tell the server (and act accordingly) that we
2676
           upload the whole file (again) */
2677
0
        data->state.rangeline =
2678
0
          curl_maprintf("Content-Range: bytes 0-%" FMT_OFF_T "/"
2679
0
                        "%" FMT_OFF_T "\r\n", req_clen - 1, req_clen);
2680
0
      }
2681
0
      else if(data->state.resume_from) {
2682
        /* This is because "resume" was selected */
2683
        /* Not sure if we want to send this header during authentication
2684
         * negotiation, but test1084 checks for it. In which case we have a
2685
         * "null" client reader installed that gives an unexpected length. */
2686
0
        curl_off_t total_len = data->req.authneg ?
2687
0
                               data->state.infilesize :
2688
0
                               (data->state.resume_from + req_clen);
2689
0
        data->state.rangeline =
2690
0
          curl_maprintf("Content-Range: bytes %s%" FMT_OFF_T "/"
2691
0
                        "%" FMT_OFF_T "\r\n",
2692
0
                        data->state.range, total_len - 1, total_len);
2693
0
      }
2694
0
      else {
2695
        /* Range was selected and then we pass the incoming range and append
2696
           total size */
2697
0
        data->state.rangeline =
2698
0
          curl_maprintf("Content-Range: bytes %s/%" FMT_OFF_T "\r\n",
2699
0
                        data->state.range, req_clen);
2700
0
      }
2701
0
      if(!data->state.rangeline)
2702
0
        return CURLE_OUT_OF_MEMORY;
2703
0
    }
2704
0
  }
2705
0
  return CURLE_OK;
2706
0
}
2707
2708
static CURLcode http_firstwrite(struct Curl_easy *data)
2709
0
{
2710
0
  struct connectdata *conn = data->conn;
2711
0
  struct SingleRequest *k = &data->req;
2712
2713
0
  if(data->req.newurl) {
2714
0
    if(conn->bits.close) {
2715
      /* Abort after the headers if "follow Location" is set
2716
         and we are set to close anyway. */
2717
0
      CURL_REQ_CLEAR_RECV(data);
2718
0
      k->done = TRUE;
2719
0
      return CURLE_OK;
2720
0
    }
2721
    /* We have a new URL to load, but since we want to be able to reuse this
2722
       connection properly, we read the full response in "ignore more" */
2723
0
    k->ignorebody = TRUE;
2724
0
    infof(data, "Ignoring the response-body");
2725
0
  }
2726
0
  if(data->state.resume_from && !k->content_range &&
2727
0
     (data->state.httpreq == HTTPREQ_GET) &&
2728
0
     !k->ignorebody) {
2729
2730
0
    if(k->size == data->state.resume_from) {
2731
      /* The resume point is at the end of file, consider this fine even if it
2732
         does not allow resume from here. */
2733
0
      infof(data, "The entire document is already downloaded");
2734
0
      streamclose(conn);
2735
      /* Abort download */
2736
0
      CURL_REQ_CLEAR_RECV(data);
2737
0
      k->done = TRUE;
2738
0
      return CURLE_OK;
2739
0
    }
2740
2741
    /* we wanted to resume a download, although the server does not seem to
2742
     * support this and we did this with a GET (if it was not a GET we did a
2743
     * POST or PUT resume) */
2744
0
    failf(data, "HTTP server does not seem to support "
2745
0
          "byte ranges. Cannot resume.");
2746
0
    return CURLE_RANGE_ERROR;
2747
0
  }
2748
2749
0
  if(data->set.timecondition && !data->state.range) {
2750
    /* A time condition has been set AND no ranges have been requested. This
2751
       seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct
2752
       action for an HTTP/1.1 client */
2753
2754
0
    if(!Curl_meets_timecondition(data, k->timeofdoc)) {
2755
0
      k->done = TRUE;
2756
      /* We are simulating an HTTP 304 from server so we return
2757
         what should have been returned from the server */
2758
0
      data->info.httpcode = 304;
2759
0
      infof(data, "Simulate an HTTP 304 response");
2760
      /* we abort the transfer before it is completed == we ruin the
2761
         reuse ability. Close the connection */
2762
0
      streamclose(conn);
2763
0
      return CURLE_OK;
2764
0
    }
2765
0
  } /* we have a time condition */
2766
2767
0
  return CURLE_OK;
2768
0
}
2769
2770
static CURLcode http_check_new_conn(struct Curl_easy *data)
2771
0
{
2772
0
  struct connectdata *conn = data->conn;
2773
0
  const char *info_version = NULL;
2774
0
  const char *alpn;
2775
0
  CURLcode result;
2776
2777
0
  alpn = Curl_conn_get_alpn_negotiated(data, conn);
2778
0
  if(alpn && !strcmp("h3", alpn)) {
2779
0
#ifndef CURL_DISABLE_PROXY
2780
0
    if(!conn->bits.origin_is_proxy)
2781
0
#endif
2782
0
      DEBUGASSERT(Curl_conn_http_version(data, conn) == 30);
2783
0
    info_version = "HTTP/3";
2784
0
  }
2785
0
  else if(alpn && !strcmp("h2", alpn)) {
2786
0
#ifndef CURL_DISABLE_PROXY
2787
0
    if((Curl_conn_http_version(data, conn) != 20) &&
2788
0
       conn->bits.origin_is_proxy) {
2789
0
      result = Curl_http2_switch(data);
2790
0
      if(result)
2791
0
        return result;
2792
0
    }
2793
0
    else
2794
0
#endif
2795
0
    DEBUGASSERT(Curl_conn_http_version(data, conn) == 20);
2796
0
    info_version = "HTTP/2";
2797
0
  }
2798
0
  else {
2799
    /* Check if user wants to use HTTP/2 with clear TCP */
2800
0
    if(Curl_http2_may_switch(data)) {
2801
0
      DEBUGF(infof(data, "HTTP/2 over clean TCP"));
2802
0
      result = Curl_http2_switch(data);
2803
0
      if(result)
2804
0
        return result;
2805
0
      info_version = "HTTP/2";
2806
      /* There is no ALPN here, but the connection is now definitely h2 */
2807
0
      conn->httpversion_seen = 20;
2808
0
      Curl_conn_set_multiplex(conn);
2809
0
    }
2810
0
    else
2811
0
      info_version = "HTTP/1.x";
2812
0
  }
2813
2814
0
  if(info_version)
2815
0
    infof(data, "using %s", info_version);
2816
0
  return CURLE_OK;
2817
0
}
2818
2819
static CURLcode http_add_connection_hd(struct Curl_easy *data,
2820
                                       struct dynbuf *req)
2821
0
{
2822
0
  struct curl_slist *head;
2823
0
  const char *sep = "Connection: ";
2824
0
  CURLcode result = CURLE_OK;
2825
0
  size_t rlen = curlx_dyn_len(req);
2826
0
  bool skip;
2827
2828
  /* Add the 1st custom "Connection: " header, if there is one */
2829
0
  for(head = data->set.headers; head; head = head->next) {
2830
0
    if(curl_strnequal(head->data, "Connection", 10) &&
2831
0
       Curl_headersep(head->data[10]) &&
2832
0
       !http_header_is_empty(head->data)) {
2833
0
      char *value;
2834
0
      result = copy_custom_value(head->data, &value);
2835
0
      if(result)
2836
0
        return result;
2837
0
      result = curlx_dyn_addf(req, "%s%s", sep, value);
2838
0
      sep = ", ";
2839
0
      curlx_free(value);
2840
0
      break; /* leave, having added 1st one */
2841
0
    }
2842
0
  }
2843
2844
  /* add our internal Connection: header values, if we have any */
2845
0
  if(!result && data->state.http_hd_te) {
2846
0
    result = curlx_dyn_addf(req, "%s%s", sep, "TE");
2847
0
    sep = ", ";
2848
0
  }
2849
0
  if(!result && data->state.http_hd_upgrade) {
2850
0
    result = curlx_dyn_addf(req, "%s%s", sep, "Upgrade");
2851
0
    sep = ", ";
2852
0
  }
2853
0
  if(!result && data->state.http_hd_h2_settings) {
2854
0
    result = curlx_dyn_addf(req, "%s%s", sep, "HTTP2-Settings");
2855
0
  }
2856
0
  if(!result && (rlen < curlx_dyn_len(req)))
2857
0
    result = curlx_dyn_addn(req, STRCONST("\r\n"));
2858
0
  if(result)
2859
0
    return result;
2860
2861
  /* Add all user-defined Connection: headers after the first */
2862
0
  skip = TRUE;
2863
0
  for(head = data->set.headers; head; head = head->next) {
2864
0
    if(curl_strnequal(head->data, "Connection", 10) &&
2865
0
       Curl_headersep(head->data[10]) &&
2866
0
       !http_header_is_empty(head->data)) {
2867
0
      if(skip) {
2868
0
        skip = FALSE;
2869
0
        continue;
2870
0
      }
2871
0
      result = curlx_dyn_addf(req, "%s\r\n", head->data);
2872
0
      if(result)
2873
0
        return result;
2874
0
    }
2875
0
  }
2876
2877
0
  return CURLE_OK;
2878
0
}
2879
2880
/* Header identifier in order we send them by default */
2881
typedef enum {
2882
  H1_HD_REQUEST,
2883
  H1_HD_HOST,
2884
#ifndef CURL_DISABLE_PROXY
2885
  H1_HD_PROXY_AUTH,
2886
#endif
2887
  H1_HD_AUTH,
2888
  H1_HD_RANGE,
2889
  H1_HD_USER_AGENT,
2890
  H1_HD_ACCEPT,
2891
  H1_HD_TE,
2892
  H1_HD_ACCEPT_ENCODING,
2893
  H1_HD_REFERER,
2894
#ifndef CURL_DISABLE_PROXY
2895
  H1_HD_PROXY_CONNECTION,
2896
#endif
2897
  H1_HD_TRANSFER_ENCODING,
2898
#ifndef CURL_DISABLE_ALTSVC
2899
  H1_HD_ALT_USED,
2900
#endif
2901
  H1_HD_UPGRADE,
2902
  H1_HD_COOKIES,
2903
  H1_HD_CONDITIONALS,
2904
  H1_HD_CUSTOM,
2905
  H1_HD_CONTENT,
2906
  H1_HD_CONNECTION,
2907
  H1_HD_LAST  /* the last, empty header line */
2908
} http_hd_t;
2909
2910
static CURLcode http_add_hd(struct Curl_easy *data,
2911
                            struct dynbuf *req,
2912
                            http_hd_t id,
2913
                            unsigned char httpversion,
2914
                            const char *method,
2915
                            Curl_HttpReq httpreq)
2916
0
{
2917
0
  CURLcode result = CURLE_OK;
2918
0
#if !defined(CURL_DISABLE_ALTSVC) || \
2919
0
  !defined(CURL_DISABLE_PROXY) || \
2920
0
  !defined(CURL_DISABLE_WEBSOCKETS)
2921
0
  struct connectdata *conn = data->conn;
2922
0
#endif
2923
0
  switch(id) {
2924
0
  case H1_HD_REQUEST:
2925
    /* add the main request stuff */
2926
    /* GET/HEAD/POST/PUT */
2927
0
    result = curlx_dyn_addf(req, "%s ", method);
2928
0
    if(!result)
2929
0
      result = http_target(data, req);
2930
0
    if(!result)
2931
0
      result = curlx_dyn_addf(req, " HTTP/%s\r\n",
2932
0
                              get_http_string(httpversion));
2933
0
    break;
2934
2935
0
  case H1_HD_HOST:
2936
0
    if(data->state.http_host) {
2937
0
      result = curlx_dyn_add(req, data->state.http_host);
2938
0
      if(!result)
2939
0
        result = curlx_dyn_addn(req, STRCONST("\r\n"));
2940
0
    }
2941
0
    break;
2942
2943
0
#ifndef CURL_DISABLE_PROXY
2944
0
  case H1_HD_PROXY_AUTH:
2945
0
    if(data->req.hd_proxy_auth)
2946
0
      result = curlx_dyn_add(req, data->req.hd_proxy_auth);
2947
0
    break;
2948
0
#endif
2949
2950
0
  case H1_HD_AUTH:
2951
0
    if(data->req.hd_auth)
2952
0
      result = curlx_dyn_add(req, data->req.hd_auth);
2953
0
    break;
2954
2955
0
  case H1_HD_RANGE:
2956
0
    if(data->state.use_range && data->state.rangeline)
2957
0
      result = curlx_dyn_add(req, data->state.rangeline);
2958
0
    break;
2959
2960
0
  case H1_HD_USER_AGENT: {
2961
0
    const char *ua = CURL_EASY_STR(data, STRING_USERAGENT);
2962
0
    if(ua && *ua && !Curl_checkheaders(data, STRCONST("User-Agent")))
2963
0
      result = curlx_dyn_addf(req, "User-Agent: %s\r\n", ua);
2964
0
    break;
2965
0
  }
2966
2967
0
  case H1_HD_ACCEPT:
2968
0
    if(!Curl_checkheaders(data, STRCONST("Accept")))
2969
0
      result = curlx_dyn_add(req, "Accept: */*\r\n");
2970
0
    break;
2971
2972
0
  case H1_HD_TE:
2973
0
#ifdef HAVE_LIBZ
2974
0
    if(!Curl_checkheaders(data, STRCONST("TE")) &&
2975
0
       data->set.http_transfer_encoding) {
2976
0
      data->state.http_hd_te = TRUE;
2977
0
      result = curlx_dyn_add(req, "TE: gzip\r\n");
2978
0
    }
2979
0
#endif
2980
0
    break;
2981
2982
0
  case H1_HD_ACCEPT_ENCODING: {
2983
0
    const char *enc = CURL_EASY_STR(data, STRING_ENCODING);
2984
0
    if(enc && !Curl_checkheaders(data, STRCONST("Accept-Encoding")))
2985
0
      result = curlx_dyn_addf(req, "Accept-Encoding: %s\r\n", enc);
2986
0
    break;
2987
0
  }
2988
2989
0
  case H1_HD_REFERER:
2990
0
    if(Curl_bufref_ptr(&data->state.referer) &&
2991
0
       !Curl_checkheaders(data, STRCONST("Referer")))
2992
0
      result = curlx_dyn_addf(req, "Referer: %s\r\n",
2993
0
                              Curl_bufref_ptr(&data->state.referer));
2994
0
    break;
2995
2996
0
#ifndef CURL_DISABLE_PROXY
2997
0
  case H1_HD_PROXY_CONNECTION:
2998
0
    if(conn->bits.origin_is_proxy &&
2999
0
       !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
3000
0
       !Curl_checkProxyheaders(data, data->conn, STRCONST("Proxy-Connection")))
3001
0
      result = curlx_dyn_add(req, "Proxy-Connection: Keep-Alive\r\n");
3002
0
    break;
3003
0
#endif
3004
3005
0
  case H1_HD_TRANSFER_ENCODING:
3006
0
    result = http_req_set_TE(data, req, httpversion);
3007
0
    break;
3008
3009
0
#ifndef CURL_DISABLE_ALTSVC
3010
0
  case H1_HD_ALT_USED:
3011
0
    if(conn->bits.altused && conn->via_peer &&
3012
0
       !Curl_checkheaders(data, STRCONST("Alt-Used")))
3013
0
      result = curlx_dyn_addf(req, "Alt-Used: %s:%u\r\n",
3014
0
                              conn->via_peer->hostname, conn->via_peer->port);
3015
0
    break;
3016
0
#endif
3017
3018
0
  case H1_HD_UPGRADE:
3019
0
    if(!Curl_conn_is_ssl(data->conn, FIRSTSOCKET) && (httpversion < 20) &&
3020
0
       (data->state.http_neg.wanted & CURL_HTTP_V2x) &&
3021
0
       data->state.http_neg.h2_upgrade) {
3022
      /* append HTTP2 upgrade magic stuff to the HTTP request if it is not done
3023
         over SSL */
3024
0
      result = Curl_http2_request_upgrade(req, data);
3025
0
    }
3026
0
#ifndef CURL_DISABLE_WEBSOCKETS
3027
0
    if(!result && conn->scheme->protocol & (CURLPROTO_WS | CURLPROTO_WSS))
3028
0
      result = Curl_ws_request(data, req);
3029
0
#endif
3030
0
    break;
3031
3032
0
  case H1_HD_COOKIES:
3033
0
    result = http_cookies(data, req);
3034
0
    break;
3035
3036
0
  case H1_HD_CONDITIONALS:
3037
0
    result = Curl_add_timecondition(data, req);
3038
0
    break;
3039
3040
0
  case H1_HD_CUSTOM:
3041
0
    result = Curl_add_custom_headers(data, FALSE, httpversion, req);
3042
0
    break;
3043
3044
0
  case H1_HD_CONTENT:
3045
0
    result = http_add_content_hds(data, req, httpversion, httpreq);
3046
0
    break;
3047
3048
0
  case H1_HD_CONNECTION: {
3049
0
    result = http_add_connection_hd(data, req);
3050
0
    break;
3051
0
  }
3052
3053
0
  case H1_HD_LAST:
3054
0
    result = curlx_dyn_addn(req, STRCONST("\r\n"));
3055
0
    break;
3056
0
  }
3057
0
  return result;
3058
0
}
3059
3060
/*
3061
 * Curl_http() gets called from the generic multi_do() function when an HTTP
3062
 * request is to be performed. This creates and sends a properly constructed
3063
 * HTTP request.
3064
 */
3065
CURLcode Curl_http(struct Curl_easy *data, bool *done)
3066
0
{
3067
0
  CURLcode result = CURLE_OK;
3068
0
  Curl_HttpReq httpreq;
3069
0
  const char *method;
3070
0
  struct dynbuf req;
3071
0
  unsigned char httpversion;
3072
0
  size_t hd_id;
3073
3074
  /* Always consider the DO phase done after this function call, even if there
3075
     may be parts of the request that are not yet sent, since we can deal with
3076
     the rest of the request in the PERFORM phase. */
3077
0
  *done = TRUE;
3078
  /* initialize a dynamic send-buffer */
3079
0
  curlx_dyn_init(&req, DYN_HTTP_REQUEST);
3080
  /* make sure the header buffer is reset - if there are leftovers from a
3081
     previous transfer */
3082
0
  curlx_dyn_reset(&data->state.headerb);
3083
0
  data->state.maybe_folded = FALSE;
3084
3085
0
  if(!data->conn->bits.reuse) {
3086
0
    result = http_check_new_conn(data);
3087
0
    if(result)
3088
0
      goto out;
3089
0
  }
3090
3091
  /* Add collecting of headers written to client. For a new connection,
3092
   * we might have done that already, but reuse
3093
   * or multiplex needs it here as well. */
3094
0
  result = Curl_headers_init(data);
3095
0
  if(result)
3096
0
    goto out;
3097
3098
0
  data->state.http_hd_te = FALSE;
3099
0
  data->state.http_hd_upgrade = FALSE;
3100
0
  data->state.http_hd_h2_settings = FALSE;
3101
3102
  /* what kind of request do we need to send? */
3103
0
  Curl_http_method(data, &method, &httpreq);
3104
3105
  /* select host to send */
3106
0
  result = http_set_aptr_host(data);
3107
  /* setup the authentication headers, how that method and host are known */
3108
0
  if(!result)
3109
0
    result = Curl_http_output_auth(data, data->conn, method, httpreq,
3110
0
                                   data->state.up.path,
3111
0
                                   data->state.up.query, FALSE);
3112
  /* Setup input reader, resume information and ranges */
3113
0
  if(!result)
3114
0
    result = set_reader(data, httpreq);
3115
0
  if(!result)
3116
0
    result = http_resume(data, httpreq);
3117
0
  if(!result)
3118
0
    result = http_range(data, httpreq);
3119
0
  if(result)
3120
0
    goto out;
3121
3122
0
  httpversion = http_request_version(data);
3123
  /* Add request line and all headers to `req` */
3124
0
  for(hd_id = 0; hd_id <= H1_HD_LAST; ++hd_id) {
3125
0
    result = http_add_hd(data, &req, (http_hd_t)hd_id,
3126
0
                         httpversion, method, httpreq);
3127
0
    if(result)
3128
0
      goto out;
3129
0
  }
3130
3131
  /* setup variables for the upcoming transfer and send */
3132
0
  Curl_xfer_setup_sendrecv(data, FIRSTSOCKET, -1);
3133
0
  result = Curl_req_send(data, &req, httpversion);
3134
3135
0
  if((httpversion >= 20) && data->req.upload_chunky)
3136
    /* upload_chunky was set above to set up the request in a chunky fashion,
3137
       but is disabled here again to avoid that the chunked encoded version is
3138
       actually used when sending the request body over h2 */
3139
0
    data->req.upload_chunky = FALSE;
3140
3141
0
out:
3142
0
  if(result == CURLE_TOO_LARGE)
3143
0
    failf(data, "HTTP request too large");
3144
3145
0
  curlx_dyn_free(&req);
3146
0
  return result;
3147
0
}
3148
3149
typedef enum {
3150
  STATUS_UNKNOWN, /* not enough data to tell yet */
3151
  STATUS_DONE, /* a status line was read */
3152
  STATUS_BAD /* not a status line */
3153
} statusline;
3154
3155
/* Check a string for a prefix. Check no more than 'len' bytes */
3156
static bool checkprefixmax(const char *prefix, const char *buffer, size_t len)
3157
0
{
3158
0
  size_t ch = CURLMIN(strlen(prefix), len);
3159
0
  return curl_strnequal(prefix, buffer, ch);
3160
0
}
3161
3162
/*
3163
 * checkhttpprefix()
3164
 *
3165
 * Returns TRUE if member of the list matches prefix of string
3166
 */
3167
static statusline checkhttpprefix(struct Curl_easy *data,
3168
                                  const char *s, size_t len)
3169
0
{
3170
0
  struct curl_slist *head = data->set.http200aliases;
3171
0
  statusline rc = STATUS_BAD;
3172
0
  statusline onmatch = len >= 5 ? STATUS_DONE : STATUS_UNKNOWN;
3173
3174
0
  while(head) {
3175
0
    if(checkprefixmax(head->data, s, len)) {
3176
0
      rc = onmatch;
3177
0
      break;
3178
0
    }
3179
0
    head = head->next;
3180
0
  }
3181
3182
0
  if((rc != STATUS_DONE) && checkprefixmax("HTTP/", s, len))
3183
0
    rc = onmatch;
3184
3185
0
  return rc;
3186
0
}
3187
3188
#ifndef CURL_DISABLE_RTSP
3189
static statusline checkrtspprefix(struct Curl_easy *data,
3190
                                  const char *s, size_t len)
3191
0
{
3192
0
  statusline status = STATUS_BAD;
3193
0
  statusline onmatch = len >= 5 ? STATUS_DONE : STATUS_UNKNOWN;
3194
0
  (void)data;
3195
0
  if(checkprefixmax("RTSP/", s, len))
3196
0
    status = onmatch;
3197
3198
0
  return status;
3199
0
}
3200
#endif /* CURL_DISABLE_RTSP */
3201
3202
static statusline checkprotoprefix(struct Curl_easy *data,
3203
                                   struct connectdata *conn,
3204
                                   const char *s, size_t len)
3205
0
{
3206
0
#ifndef CURL_DISABLE_RTSP
3207
0
  if(conn->scheme->protocol & CURLPROTO_RTSP)
3208
0
    return checkrtspprefix(data, s, len);
3209
#else
3210
  (void)conn;
3211
#endif /* CURL_DISABLE_RTSP */
3212
3213
0
  return checkhttpprefix(data, s, len);
3214
0
}
3215
3216
/* HTTP header has field name `n` (a string constant) */
3217
#define HD_IS(hd, hdlen, n) \
3218
0
  (((hdlen) >= (sizeof(n) - 1)) && curl_strnequal(n, hd, sizeof(n) - 1))
3219
3220
#define HD_VAL(hd, hdlen, n) \
3221
0
  ((((hdlen) >= (sizeof(n) - 1)) && (hd) && \
3222
0
    curl_strnequal(n, hd, sizeof(n) - 1)) ? ((hd) + (sizeof(n) - 1)) : NULL)
3223
3224
/* HTTP header has field name `n` (a string constant) and contains `v`
3225
 * (a string constant) in its value(s) */
3226
#define HD_IS_AND_SAYS(hd, hdlen, n, v) \
3227
0
  (HD_IS(hd, hdlen, n) && \
3228
0
   ((hdlen) > ((sizeof(n) - 1) + (sizeof(v) - 1))) && \
3229
0
   Curl_compareheader(hd, STRCONST(n), STRCONST(v)))
3230
3231
/*
3232
 * http_header_a() parses a single response header starting with A.
3233
 */
3234
static CURLcode http_header_a(struct Curl_easy *data,
3235
                              const char *hd, size_t hdlen)
3236
0
{
3237
0
#ifndef CURL_DISABLE_ALTSVC
3238
0
  const char *v;
3239
0
  v = (data->asi &&
3240
0
       (Curl_xfer_is_secure(data) ||
3241
0
#ifdef DEBUGBUILD
3242
        /* allow debug builds to circumvent the HTTPS restriction */
3243
0
        getenv("CURL_ALTSVC_HTTP")
3244
#else
3245
        0
3246
#endif
3247
0
         )) ? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
3248
0
  if(v) {
3249
    /* the ALPN of the current request */
3250
0
    struct SingleRequest *k = &data->req;
3251
0
    enum alpnid id = (k->httpversion == 30) ? ALPN_h3 :
3252
0
      (k->httpversion == 20) ? ALPN_h2 : ALPN_h1;
3253
0
    return Curl_altsvc_parse(data, data->asi, v, data->state.origin, id);
3254
0
  }
3255
#else
3256
  (void)data;
3257
  (void)hd;
3258
  (void)hdlen;
3259
#endif
3260
0
  return CURLE_OK;
3261
0
}
3262
3263
/*
3264
 * http_header_c() parses a single response header starting with C.
3265
 */
3266
static CURLcode http_header_c(struct Curl_easy *data,
3267
                              const char *hd, size_t hdlen)
3268
0
{
3269
0
  struct connectdata *conn = data->conn;
3270
0
  struct SingleRequest *k = &data->req;
3271
0
  const char *v;
3272
3273
  /* Check for Content-Length: header lines to get size. Browsers insist we
3274
     should accept multiple Content-Length headers and that a comma separated
3275
     list also is fine and then we should accept them all as long as they are
3276
     the same value. Different values trigger error.
3277
   */
3278
0
  v = (!k->http_bodyless && !data->set.ignorecl) ?
3279
0
    HD_VAL(hd, hdlen, "Content-Length:") : NULL;
3280
0
  if(v) {
3281
0
    do {
3282
0
      curl_off_t contentlength;
3283
0
      int offt = curlx_str_numblanks(&v, &contentlength);
3284
3285
0
      if(offt == STRE_OVERFLOW) {
3286
        /* out of range */
3287
0
        if(data->set.max_filesize) {
3288
0
          failf(data, "Maximum file size exceeded");
3289
0
          return CURLE_FILESIZE_EXCEEDED;
3290
0
        }
3291
0
        streamclose(conn);
3292
0
        infof(data, "Overflow Content-Length: value");
3293
0
        return CURLE_OK;
3294
0
      }
3295
0
      else {
3296
0
        if((offt == STRE_OK) &&
3297
0
           ((k->size == -1) || /* not set to something before */
3298
0
            (k->size == contentlength))) { /* or the same value */
3299
3300
0
          k->size = contentlength;
3301
0
          curlx_str_passblanks(&v);
3302
3303
          /* on a comma, loop and get the next instead */
3304
0
          if(!curlx_str_single(&v, ','))
3305
0
            continue;
3306
3307
0
          if(!curlx_str_newline(&v)) {
3308
0
            k->maxdownload = k->size;
3309
0
            return CURLE_OK;
3310
0
          }
3311
0
        }
3312
        /* negative, different value or rubbish - bad HTTP */
3313
0
        failf(data, "Invalid Content-Length: value");
3314
0
        return CURLE_WEIRD_SERVER_REPLY;
3315
0
      }
3316
0
    } while(1);
3317
0
  }
3318
0
  v = (!k->http_bodyless && CURL_EASY_STR(data, STRING_ENCODING)) ?
3319
0
    HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
3320
0
  if(v) {
3321
    /*
3322
     * Process Content-Encoding. Look for the values: identity, gzip, deflate,
3323
     * compress, x-gzip and x-compress. x-gzip and x-compress are the same as
3324
     * gzip and compress. (Sec 3.5 RFC 2616). zlib cannot handle compress.
3325
     * Errors are handled further down when the response body is processed
3326
     */
3327
0
    return Curl_build_unencoding_stack(data, v, FALSE);
3328
0
  }
3329
  /* check for Content-Type: header lines to get the MIME-type */
3330
0
  v = HD_VAL(hd, hdlen, "Content-Type:");
3331
0
  if(v) {
3332
0
    char *contenttype = Curl_copy_header_value(hd);
3333
0
    if(!contenttype)
3334
0
      return CURLE_OUT_OF_MEMORY;
3335
0
    if(!*contenttype)
3336
      /* ignore empty data */
3337
0
      curlx_free(contenttype);
3338
0
    else {
3339
0
      curlx_free(data->info.contenttype);
3340
0
      data->info.contenttype = contenttype;
3341
0
    }
3342
0
    return CURLE_OK;
3343
0
  }
3344
0
  if((k->httpversion < 20) &&
3345
0
     HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
3346
    /*
3347
     * [RFC 2616, section 8.1.2.1]
3348
     * "Connection: close" is HTTP/1.1 language and means that
3349
     * the connection will close when this request has been
3350
     * served.
3351
     */
3352
0
    connclose(conn);
3353
0
    return CURLE_OK;
3354
0
  }
3355
0
  if((k->httpversion == 10) &&
3356
0
     HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
3357
    /*
3358
     * An HTTP/1.0 reply with the 'Connection: keep-alive' line
3359
     * tells us the connection will be kept alive for our
3360
     * pleasure. Default action for 1.0 is to close.
3361
     *
3362
     * [RFC2068, section 19.7.1] */
3363
0
    connkeep(conn);
3364
0
    infof(data, "HTTP/1.0 connection set to keep alive");
3365
0
    return CURLE_OK;
3366
0
  }
3367
0
  v = !k->http_bodyless ? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
3368
0
  if(v) {
3369
    /* Content-Range: bytes [num]-
3370
       Content-Range: bytes: [num]-
3371
       Content-Range: [num]-
3372
       Content-Range: [asterisk]/[total]
3373
3374
       The second format was added since Sun's webserver
3375
       JavaWebServer/1.1.1 obviously sends the header this way!
3376
       The third added since some servers use that!
3377
       The fourth means the requested range was unsatisfied.
3378
     */
3379
3380
0
    const char *ptr = v;
3381
3382
    /* Move forward until first digit or asterisk */
3383
0
    while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
3384
0
      ptr++;
3385
3386
    /* if it truly stopped on a digit */
3387
0
    if(ISDIGIT(*ptr)) {
3388
0
      if(!curlx_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) &&
3389
0
         (data->state.resume_from == k->offset))
3390
        /* we asked for a resume and we got it */
3391
0
        k->content_range = TRUE;
3392
0
    }
3393
0
    else if(k->httpcode < 300)
3394
0
      data->state.resume_from = 0; /* get everything */
3395
0
  }
3396
0
  return CURLE_OK;
3397
0
}
3398
3399
/*
3400
 * http_header_l() parses a single response header starting with L.
3401
 */
3402
static CURLcode http_header_l(struct Curl_easy *data,
3403
                              const char *hd, size_t hdlen)
3404
0
{
3405
0
  struct connectdata *conn = data->conn;
3406
0
  struct SingleRequest *k = &data->req;
3407
0
  const char *v = (!k->http_bodyless &&
3408
0
                   (data->set.timecondition || data->set.get_filetime)) ?
3409
0
    HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
3410
0
  if(v) {
3411
0
    if(Curl_getdate_capped(v, &k->timeofdoc))
3412
0
      k->timeofdoc = 0;
3413
0
    if(data->set.get_filetime)
3414
0
      data->info.filetime = k->timeofdoc;
3415
0
    return CURLE_OK;
3416
0
  }
3417
0
  if(HD_IS(hd, hdlen, "Location:")) {
3418
    /* this is the URL that the server advises us to use instead */
3419
0
    char *location = Curl_copy_header_value(hd);
3420
0
    if(!location)
3421
0
      return CURLE_OUT_OF_MEMORY;
3422
0
    if(!*location ||
3423
0
       (data->req.location && !strcmp(data->req.location, location))) {
3424
      /* ignore empty header, or exact repeat of a previous one */
3425
0
      curlx_free(location);
3426
0
      return CURLE_OK;
3427
0
    }
3428
0
    else {
3429
      /* has value and is not an exact repeat */
3430
0
      if(data->req.location) {
3431
0
        failf(data, "Multiple Location headers");
3432
0
        curlx_free(location);
3433
0
        return CURLE_WEIRD_SERVER_REPLY;
3434
0
      }
3435
0
      data->req.location = location;
3436
3437
0
      if((k->httpcode >= 300 && k->httpcode < 400) &&
3438
0
         data->set.http_follow_mode) {
3439
0
        CURLcode result;
3440
0
        DEBUGASSERT(!data->req.newurl);
3441
0
        data->req.newurl = curlx_strdup(data->req.location); /* clone */
3442
0
        if(!data->req.newurl)
3443
0
          return CURLE_OUT_OF_MEMORY;
3444
3445
        /* some cases of POST and PUT etc needs to rewind the data
3446
           stream at this point */
3447
0
        result = http_perhapsrewind(data, conn);
3448
0
        if(result)
3449
0
          return result;
3450
3451
        /* mark the next request as a followed location: */
3452
0
        data->state.this_is_a_follow = TRUE;
3453
0
      }
3454
0
    }
3455
0
  }
3456
0
  return CURLE_OK;
3457
0
}
3458
3459
/*
3460
 * http_header_p() parses a single response header starting with P.
3461
 */
3462
static CURLcode http_header_p(struct Curl_easy *data,
3463
                              const char *hd, size_t hdlen)
3464
0
{
3465
0
  struct SingleRequest *k = &data->req;
3466
3467
0
#ifndef CURL_DISABLE_PROXY
3468
0
  const char *v = HD_VAL(hd, hdlen, "Proxy-Connection:");
3469
0
  if(v) {
3470
0
    struct connectdata *conn = data->conn;
3471
0
    if((k->httpversion == 10) && conn->http_proxy.peer &&
3472
0
       HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
3473
      /*
3474
       * When an HTTP/1.0 reply comes when using a proxy, the
3475
       * 'Proxy-Connection: keep-alive' line tells us the
3476
       * connection will be kept alive for our pleasure.
3477
       * Default action for 1.0 is to close.
3478
       */
3479
0
      connkeep(conn); /* do not close */
3480
0
      infof(data, "HTTP/1.0 proxy connection set to keep alive");
3481
0
    }
3482
0
    else if((k->httpversion == 11) && conn->http_proxy.peer &&
3483
0
            HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
3484
      /*
3485
       * We get an HTTP/1.1 response from a proxy and it says it will
3486
       * close down after this transfer.
3487
       */
3488
0
      connclose(conn);
3489
0
      infof(data, "HTTP/1.1 proxy connection set close");
3490
0
    }
3491
0
    return CURLE_OK;
3492
0
  }
3493
0
#endif
3494
0
  if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) {
3495
0
    char *auth = Curl_copy_header_value(hd);
3496
0
    CURLcode result = auth ? CURLE_OK : CURLE_OUT_OF_MEMORY;
3497
0
    if(!result) {
3498
0
      result = Curl_http_input_auth(data, TRUE, auth);
3499
0
      curlx_free(auth);
3500
0
    }
3501
0
    return result;
3502
0
  }
3503
#ifdef USE_SPNEGO
3504
  if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
3505
    struct connectdata *conn = data->conn;
3506
    struct negotiatedata *negdata = Curl_auth_nego_get(conn, FALSE);
3507
    struct auth *authp = &data->state.authhost;
3508
    if(!negdata)
3509
      return CURLE_OUT_OF_MEMORY;
3510
    if(authp->picked == CURLAUTH_NEGOTIATE) {
3511
      char *persistentauth = Curl_copy_header_value(hd);
3512
      if(!persistentauth)
3513
        return CURLE_OUT_OF_MEMORY;
3514
      negdata->noauthpersist = !!checkprefix("false", persistentauth);
3515
      negdata->havenoauthpersist = TRUE;
3516
      infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
3517
            negdata->noauthpersist, persistentauth);
3518
      curlx_free(persistentauth);
3519
    }
3520
  }
3521
#endif
3522
0
  return CURLE_OK;
3523
0
}
3524
3525
/*
3526
 * http_header_r() parses a single response header starting with R.
3527
 */
3528
static CURLcode http_header_r(struct Curl_easy *data,
3529
                              const char *hd, size_t hdlen)
3530
0
{
3531
0
  const char *v = HD_VAL(hd, hdlen, "Retry-After:");
3532
0
  if(v) {
3533
    /* Retry-After = HTTP-date / delay-seconds */
3534
0
    curl_off_t retry_after = 0; /* zero for unknown or "now" */
3535
0
    time_t date = 0;
3536
0
    curlx_str_passblanks(&v);
3537
3538
    /* try it as a date first, because a date can otherwise start with and
3539
       get treated as a number */
3540
0
    if(!Curl_getdate_capped(v, &date)) {
3541
0
      time_t current = time(NULL);
3542
0
      if(date >= current)
3543
        /* convert date to number of seconds into the future */
3544
0
        retry_after = date - current;
3545
0
    }
3546
0
    else
3547
      /* Try it as a decimal number, ignore errors */
3548
0
      (void)curlx_str_number(&v, &retry_after, CURL_OFF_T_MAX);
3549
    /* limit to 6 hours max. this is not documented so that it can be changed
3550
       in the future if necessary. */
3551
0
    if(retry_after > 21600)
3552
0
      retry_after = 21600;
3553
0
    data->info.retry_after = retry_after;
3554
0
  }
3555
0
  return CURLE_OK;
3556
0
}
3557
3558
/*
3559
 * http_header_s() parses a single response header starting with S.
3560
 */
3561
static CURLcode http_header_s(struct Curl_easy *data,
3562
                              const char *hd, size_t hdlen)
3563
0
{
3564
0
#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_HSTS)
3565
0
  const char *v;
3566
#else
3567
  (void)data;
3568
  (void)hd;
3569
  (void)hdlen;
3570
#endif
3571
3572
0
#ifndef CURL_DISABLE_COOKIES
3573
0
  v = (data->cookies && data->state.cookie_engine) ?
3574
0
    HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
3575
0
  if(v) {
3576
    /* If there is a custom-set Host: name, use it here, or else use
3577
     * real peer hostname. */
3578
0
    const char *host = data->req.cookiehost ?
3579
0
      data->req.cookiehost : data->state.origin->hostname;
3580
0
    const unsigned char secure_context = Curl_secure_context(data, host) ?
3581
0
      COOKIE_SECURE : 0;
3582
0
    CURLcode result;
3583
0
    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
3584
0
    result = Curl_cookie_add(data, data->cookies, v, host,
3585
0
                             data->state.up.path,
3586
0
                             COOKIE_HTTPHEADER | secure_context);
3587
0
    Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
3588
0
    return result;
3589
0
  }
3590
0
#endif
3591
0
#ifndef CURL_DISABLE_HSTS
3592
  /* If enabled, the header is incoming and this is over HTTPS */
3593
0
  v = (data->hsts &&
3594
0
       (Curl_xfer_is_secure(data) ||
3595
0
#ifdef DEBUGBUILD
3596
        /* allow debug builds to circumvent the HTTPS restriction */
3597
0
        getenv("CURL_HSTS_HTTP")
3598
#else
3599
        0
3600
#endif
3601
0
         )
3602
0
    ) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
3603
0
  if(v) {
3604
0
    CURLcode result = Curl_hsts_parse(
3605
0
      data->hsts, data->state.origin->hostname, v);
3606
0
    if(result) {
3607
0
      if(result == CURLE_OUT_OF_MEMORY)
3608
0
        return result;
3609
0
      infof(data, "Illegal STS header skipped");
3610
0
    }
3611
0
#ifdef DEBUGBUILD
3612
0
    else
3613
0
      infof(data, "Parsed STS header fine (%zu entries)",
3614
0
            Curl_llist_count(&data->hsts->list));
3615
0
#endif
3616
0
  }
3617
0
#endif
3618
3619
0
  return CURLE_OK;
3620
0
}
3621
3622
/*
3623
 * http_header_t() parses a single response header starting with T.
3624
 */
3625
static CURLcode http_header_t(struct Curl_easy *data,
3626
                              const char *hd, size_t hdlen)
3627
0
{
3628
0
  struct connectdata *conn = data->conn;
3629
0
  struct SingleRequest *k = &data->req;
3630
3631
  /* RFC 9112, ch. 6.1
3632
   * "Transfer-Encoding MAY be sent in a response to a HEAD request or
3633
   *  in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a
3634
   *  GET request, neither of which includes a message body, to indicate
3635
   *  that the origin server would have applied a transfer coding to the
3636
   *  message body if the request had been an unconditional GET."
3637
   *
3638
   * Read: in these cases the 'Transfer-Encoding' does not apply
3639
   * to any data following the response headers. Do not add any decoders.
3640
   */
3641
0
  const char *v = (!k->http_bodyless &&
3642
0
                   (data->state.httpreq != HTTPREQ_HEAD) &&
3643
0
                   (k->httpcode != 304)) ?
3644
0
    HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
3645
0
  if(v) {
3646
    /* One or more encodings. We check for chunked and/or a compression
3647
       algorithm. */
3648
0
    CURLcode result = Curl_build_unencoding_stack(data, v, TRUE);
3649
0
    if(result)
3650
0
      return result;
3651
0
    if(!k->chunk && data->set.http_transfer_encoding) {
3652
      /* if this is not chunked, only close can signal the end of this
3653
       * transfer as Content-Length is said not to be trusted for
3654
       * transfer-encoding! */
3655
0
      CURL_TRC_M(data, "HTTP/1.1 transfer-encoding without chunks");
3656
0
      connclose(conn);
3657
0
      k->ignore_cl = TRUE;
3658
0
    }
3659
0
    return CURLE_OK;
3660
0
  }
3661
0
  v = HD_VAL(hd, hdlen, "Trailer:");
3662
0
  if(v) {
3663
0
    data->req.resp_trailer = TRUE;
3664
0
    return CURLE_OK;
3665
0
  }
3666
0
  return CURLE_OK;
3667
0
}
3668
3669
/*
3670
 * http_header_w() parses a single response header starting with W.
3671
 */
3672
static CURLcode http_header_w(struct Curl_easy *data,
3673
                              const char *hd, size_t hdlen)
3674
0
{
3675
0
  struct SingleRequest *k = &data->req;
3676
0
  CURLcode result = CURLE_OK;
3677
3678
0
  if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) {
3679
0
    char *auth = Curl_copy_header_value(hd);
3680
0
    if(!auth)
3681
0
      result = CURLE_OUT_OF_MEMORY;
3682
0
    else {
3683
0
      result = Curl_http_input_auth(data, FALSE, auth);
3684
0
      curlx_free(auth);
3685
0
    }
3686
0
  }
3687
0
  return result;
3688
0
}
3689
3690
/*
3691
 * http_header() parses a single response header.
3692
 */
3693
static CURLcode http_header(struct Curl_easy *data,
3694
                            const char *hd, size_t hdlen)
3695
0
{
3696
0
  CURLcode result = CURLE_OK;
3697
3698
0
  switch(hd[0]) {
3699
0
  case 'a':
3700
0
  case 'A':
3701
0
    result = http_header_a(data, hd, hdlen);
3702
0
    break;
3703
0
  case 'c':
3704
0
  case 'C':
3705
0
    result = http_header_c(data, hd, hdlen);
3706
0
    break;
3707
0
  case 'l':
3708
0
  case 'L':
3709
0
    result = http_header_l(data, hd, hdlen);
3710
0
    break;
3711
0
  case 'p':
3712
0
  case 'P':
3713
0
    result = http_header_p(data, hd, hdlen);
3714
0
    break;
3715
0
  case 'r':
3716
0
  case 'R':
3717
0
    result = http_header_r(data, hd, hdlen);
3718
0
    break;
3719
0
  case 's':
3720
0
  case 'S':
3721
0
    result = http_header_s(data, hd, hdlen);
3722
0
    break;
3723
0
  case 't':
3724
0
  case 'T':
3725
0
    result = http_header_t(data, hd, hdlen);
3726
0
    break;
3727
0
  case 'w':
3728
0
  case 'W':
3729
0
    result = http_header_w(data, hd, hdlen);
3730
0
    break;
3731
0
  }
3732
3733
0
  if(!result) {
3734
0
    struct connectdata *conn = data->conn;
3735
0
    if(conn->scheme->protocol & CURLPROTO_RTSP)
3736
0
      result = Curl_rtsp_parseheader(data, hd);
3737
0
  }
3738
0
  return result;
3739
0
}
3740
3741
/*
3742
 * Called after the first HTTP response line (the status line) has been
3743
 * received and parsed.
3744
 */
3745
static CURLcode http_statusline(struct Curl_easy *data,
3746
                                struct connectdata *conn)
3747
0
{
3748
0
  struct SingleRequest *k = &data->req;
3749
3750
0
  switch(k->httpversion) {
3751
0
  case 10:
3752
0
  case 11:
3753
0
#ifdef USE_HTTP2
3754
0
  case 20:
3755
0
#endif
3756
#ifdef USE_HTTP3
3757
  case 30:
3758
#endif
3759
    /* no major version switch mid-connection */
3760
0
    if(k->httpversion_sent &&
3761
0
       (k->httpversion / 10 != k->httpversion_sent / 10)) {
3762
0
      failf(data, "Version mismatch (from HTTP/%d to HTTP/%d)",
3763
0
            k->httpversion_sent / 10, k->httpversion / 10);
3764
0
      return CURLE_WEIRD_SERVER_REPLY;
3765
0
    }
3766
0
    break;
3767
0
  default:
3768
0
    failf(data, "Unsupported HTTP version (%d.%d) in response",
3769
0
          k->httpversion / 10, k->httpversion % 10);
3770
0
    return CURLE_UNSUPPORTED_PROTOCOL;
3771
0
  }
3772
3773
0
  data->info.httpcode = k->httpcode;
3774
0
  data->info.httpversion = k->httpversion;
3775
0
  conn->httpversion_seen = k->httpversion;
3776
3777
0
  if(!data->state.http_neg.rcvd_min ||
3778
0
     data->state.http_neg.rcvd_min > k->httpversion)
3779
    /* store the lowest server version we encounter */
3780
0
    data->state.http_neg.rcvd_min = k->httpversion;
3781
3782
  /*
3783
   * This code executes as part of processing the header. As a
3784
   * result, it is not totally clear how to interpret the
3785
   * response code yet as that depends on what other headers may
3786
   * be present. 401 and 407 may be errors, but may be OK
3787
   * depending on how authentication is working. Other codes
3788
   * are definitely errors, so give up here.
3789
   */
3790
0
  if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
3791
0
     k->httpcode == 416) {
3792
    /* "Requested Range Not Satisfiable", proceed and pretend this is no
3793
       error */
3794
0
    k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
3795
0
  }
3796
3797
0
  if(k->httpversion == 10) {
3798
    /* Default action for HTTP/1.0 must be to close, unless
3799
       we get one of those fancy headers that tell us the
3800
       server keeps it open for us! */
3801
0
    infof(data, "HTTP 1.0, assume close after body");
3802
0
    connclose(conn);
3803
0
  }
3804
3805
0
  k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
3806
0
  switch(k->httpcode) {
3807
0
  case 304:
3808
    /* (quote from RFC2616, section 10.3.5): The 304 response
3809
     * MUST NOT contain a message-body, and thus is always
3810
     * terminated by the first empty line after the header
3811
     * fields. */
3812
0
    if(data->set.timecondition)
3813
0
      data->info.timecond = TRUE;
3814
0
    FALLTHROUGH();
3815
0
  case 204:
3816
    /* (quote from RFC2616, section 10.2.5): The server has
3817
     * fulfilled the request but does not need to return an
3818
     * entity-body ... The 204 response MUST NOT include a
3819
     * message-body, and thus is always terminated by the first
3820
     * empty line after the header fields. */
3821
0
    k->size = 0;
3822
0
    k->maxdownload = 0;
3823
0
    k->http_bodyless = TRUE;
3824
0
    break;
3825
0
  default:
3826
0
    break;
3827
0
  }
3828
0
  return CURLE_OK;
3829
0
}
3830
3831
/* Content-Length must be ignored if any Transfer-Encoding is present in the
3832
   response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is
3833
   figured out here after all headers have been received but before the final
3834
   call to the user's header callback, so that a valid content length can be
3835
   retrieved by the user in the final call. */
3836
static CURLcode http_size(struct Curl_easy *data)
3837
0
{
3838
0
  struct SingleRequest *k = &data->req;
3839
0
  if(data->req.ignore_cl || k->chunk) {
3840
0
    k->size = k->maxdownload = -1;
3841
0
  }
3842
0
  else if(k->size != -1) {
3843
0
    if(data->set.max_filesize &&
3844
0
       !k->ignorebody &&
3845
0
       (k->size > data->set.max_filesize)) {
3846
0
      failf(data, "Maximum file size exceeded");
3847
0
      return CURLE_FILESIZE_EXCEEDED;
3848
0
    }
3849
0
    if(k->ignorebody)
3850
0
      infof(data, "setting size while ignoring");
3851
0
    Curl_pgrsSetDownloadSize(data, k->size);
3852
0
    k->maxdownload = k->size;
3853
0
  }
3854
0
  return CURLE_OK;
3855
0
}
3856
3857
CURLcode Curl_verify_header(struct Curl_easy *data,
3858
                            const char *hd, size_t hdlen)
3859
0
{
3860
0
  struct SingleRequest *k = &data->req;
3861
0
  const char *ptr = memchr(hd, 0x00, hdlen);
3862
0
  if(ptr) {
3863
    /* this is bad, bail out */
3864
0
    failf(data, "Nul byte in header");
3865
0
    return CURLE_WEIRD_SERVER_REPLY;
3866
0
  }
3867
0
  if(hdlen > 2) {
3868
0
    ptr = memchr(hd, '\r', hdlen - 2);
3869
0
    if(ptr) {
3870
      /* CR may only precede the LF, nothing else */
3871
0
      failf(data, "Carriage return found in header");
3872
0
      return CURLE_WEIRD_SERVER_REPLY;
3873
0
    }
3874
0
  }
3875
0
  if(k->headerline < 2)
3876
    /* the first "header" is the status-line and it has no colon */
3877
0
    return CURLE_OK;
3878
0
  if(((hd[0] == ' ') || (hd[0] == '\t')) && k->headerline > 2)
3879
    /* line folding, cannot happen on line 2 */
3880
0
    ;
3881
0
  else {
3882
0
    ptr = memchr(hd, ':', hdlen);
3883
0
    if(!ptr) {
3884
      /* this is bad, bail out */
3885
0
      failf(data, "Header without colon");
3886
0
      return CURLE_WEIRD_SERVER_REPLY;
3887
0
    }
3888
0
  }
3889
0
  return CURLE_OK;
3890
0
}
3891
3892
CURLcode Curl_bump_headersize(struct Curl_easy *data,
3893
                              size_t delta,
3894
                              bool connect_only)
3895
0
{
3896
0
  size_t bad = 0;
3897
0
  unsigned int max = MAX_HTTP_RESP_HEADER_SIZE;
3898
0
  if(delta < MAX_HTTP_RESP_HEADER_SIZE) {
3899
0
    data->info.header_size += (unsigned int)delta;
3900
0
    data->req.allheadercount += (unsigned int)delta;
3901
0
    if(!connect_only)
3902
0
      data->req.headerbytecount += (unsigned int)delta;
3903
0
    if(data->req.allheadercount > max)
3904
0
      bad = data->req.allheadercount;
3905
0
    else if(data->info.header_size > (max * 20)) {
3906
0
      bad = data->info.header_size;
3907
0
      max *= 20;
3908
0
    }
3909
0
  }
3910
0
  else
3911
0
    bad = data->req.allheadercount + delta;
3912
0
  if(bad) {
3913
0
    failf(data, "Too large response headers: %zu > %u", bad, max);
3914
0
    return CURLE_RECV_ERROR;
3915
0
  }
3916
0
  return CURLE_OK;
3917
0
}
3918
3919
/*
3920
 * Handle a 101 Switching Protocols response. Performs the actual protocol
3921
 * upgrade to HTTP/2 or WebSocket based on what was requested.
3922
 */
3923
static CURLcode http_on_101_upgrade(struct Curl_easy *data,
3924
                                    const char *buf, size_t blen,
3925
                                    size_t *pconsumed,
3926
                                    bool *conn_changed)
3927
0
{
3928
0
  struct connectdata *conn = data->conn;
3929
0
  struct SingleRequest *k = &data->req;
3930
3931
#if !defined(USE_NGHTTP2) && defined(CURL_DISABLE_WEBSOCKETS)
3932
  (void)buf;
3933
  (void)blen;
3934
  (void)pconsumed;
3935
#else
3936
0
  CURLcode result;
3937
0
  int upgr101_requested = k->upgr101;
3938
0
#endif
3939
3940
0
  if(k->httpversion_sent != 11) {
3941
    /* invalid for other HTTP versions */
3942
0
    failf(data, "server sent 101 response while not talking HTTP/1.1");
3943
0
    return CURLE_WEIRD_SERVER_REPLY;
3944
0
  }
3945
3946
  /* Whatever the success, upgrade was selected. */
3947
0
  k->upgr101 = UPGR101_RECEIVED;
3948
0
  conn->bits.upgrade_in_progress = FALSE;
3949
0
  *conn_changed = TRUE;
3950
3951
  /* To be fully compliant, we would check the "Upgrade:" response header to
3952
   * mention the protocol we requested. */
3953
0
#ifdef USE_NGHTTP2
3954
0
  if(upgr101_requested == UPGR101_H2) {
3955
    /* Switch to HTTP/2, where we will get more responses. blen bytes in buf
3956
     * are already h2 protocol bytes */
3957
0
    infof(data, "Received 101, Switching to HTTP/2");
3958
0
    result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
3959
0
    if(!result)
3960
0
      *pconsumed += blen;
3961
0
    return result;
3962
0
  }
3963
0
#endif
3964
0
#ifndef CURL_DISABLE_WEBSOCKETS
3965
0
  if(upgr101_requested == UPGR101_WS) {
3966
    /* Switch to WebSocket, where we now stream ws frames. blen bytes in buf
3967
     * are already ws protocol bytes */
3968
0
    infof(data, "Received 101, Switching to WebSocket");
3969
0
    result = Curl_ws_accept(data, buf, blen);
3970
0
    if(!result)
3971
0
      *pconsumed += blen; /* ws accept handled the data */
3972
0
    return result;
3973
0
  }
3974
0
#endif
3975
  /* We silently accept this as the final response. What are we switching to
3976
   * if we did not ask for an Upgrade? Maybe the application provided an
3977
   * `Upgrade: xxx` header? */
3978
0
  k->header = FALSE;
3979
0
  return CURLE_OK;
3980
0
}
3981
3982
/*
3983
 * Handle 1xx intermediate HTTP responses. Sets up state for more
3984
 * headers and processes 100-continue and 101 upgrade responses.
3985
 */
3986
static CURLcode http_on_1xx_response(struct Curl_easy *data,
3987
                                     const char *buf, size_t blen,
3988
                                     size_t *pconsumed,
3989
                                     bool *conn_changed)
3990
0
{
3991
0
  struct SingleRequest *k = &data->req;
3992
3993
  /* "A user agent MAY ignore unexpected 1xx status responses."
3994
   * By default, we expect to get more responses after this one. */
3995
0
  k->header = TRUE;
3996
0
  k->headerline = 0; /* restart the header line counter */
3997
3998
0
  switch(k->httpcode) {
3999
0
  case 100:
4000
    /* We have made an HTTP PUT or POST and this is 1.1-lingo that tells us
4001
     * that the server is OK with this and ready to receive the data. */
4002
0
    http_exp100_got100(data);
4003
0
    break;
4004
0
  case 101:
4005
0
    return http_on_101_upgrade(data, buf, blen, pconsumed, conn_changed);
4006
0
  default:
4007
    /* The server may send us other 1xx responses, like informative 103. This
4008
     * has no influence on request processing and we expect to receive a
4009
     * final response eventually. */
4010
0
    break;
4011
0
  }
4012
0
  return CURLE_OK;
4013
0
}
4014
4015
#if defined(USE_NTLM) || defined(USE_SPNEGO)
4016
/*
4017
 * Check if NTLM or SPNEGO authentication negotiation failed due to
4018
 * connection closure (typically on HTTP/1.0 servers).
4019
 */
4020
static void http_check_auth_closure(struct Curl_easy *data,
4021
                                    struct connectdata *conn)
4022
{
4023
  /* At this point we have some idea about the fate of the connection. If we
4024
     are closing the connection it may result auth failure. */
4025
#ifdef USE_NTLM
4026
  if(conn->bits.close &&
4027
     (((data->req.httpcode == 401) &&
4028
       (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
4029
      ((data->req.httpcode == 407) &&
4030
       (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
4031
    infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
4032
    data->state.authproblem = TRUE;
4033
  }
4034
#endif
4035
#ifdef USE_SPNEGO
4036
  if(conn->bits.close &&
4037
    (((data->req.httpcode == 401) &&
4038
      (conn->http_negotiate_state == GSS_AUTHRECV)) ||
4039
     ((data->req.httpcode == 407) &&
4040
      (conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
4041
    infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
4042
    data->state.authproblem = TRUE;
4043
  }
4044
  if((conn->http_negotiate_state == GSS_AUTHDONE) &&
4045
     (data->req.httpcode != 401)) {
4046
    conn->http_negotiate_state = GSS_AUTHSUCC;
4047
  }
4048
  if((conn->proxy_negotiate_state == GSS_AUTHDONE) &&
4049
     (data->req.httpcode != 407)) {
4050
    conn->proxy_negotiate_state = GSS_AUTHSUCC;
4051
  }
4052
#endif
4053
}
4054
#else
4055
#define http_check_auth_closure(x, y) /* empty */
4056
#endif
4057
4058
/*
4059
 * Handle an error response (>= 300) received while still sending the
4060
 * request body. Deals with 417 Expectation Failed retries, keep-sending
4061
 * on error, and aborting the send.
4062
 */
4063
static CURLcode http_handle_send_error(struct Curl_easy *data)
4064
0
{
4065
0
  struct connectdata *conn = data->conn;
4066
0
  struct SingleRequest *k = &data->req;
4067
0
  CURLcode result = CURLE_OK;
4068
4069
0
  if(!data->req.authneg && !conn->bits.close &&
4070
0
     !Curl_creader_will_rewind(data)) {
4071
    /*
4072
     * General treatment of errors when about to send data.
4073
     * Including: "417 Expectation Failed", while waiting for
4074
     * 100-continue.
4075
     *
4076
     * The check for close above is done because if something
4077
     * else has already deemed the connection to get closed then
4078
     * something else should have considered the big picture and
4079
     * we avoid this check.
4080
     */
4081
4082
0
    switch(data->state.httpreq) {
4083
0
    case HTTPREQ_PUT:
4084
0
    case HTTPREQ_POST:
4085
0
    case HTTPREQ_POST_FORM:
4086
0
    case HTTPREQ_POST_MIME:
4087
      /* We got an error response. If this happened before the
4088
       * whole request body has been sent we stop sending and
4089
       * mark the connection for closure after we have read the
4090
       * entire response. */
4091
0
      if(!Curl_req_done_sending(data)) {
4092
0
        if((k->httpcode == 417) && http_exp100_is_selected(data)) {
4093
          /* 417 Expectation Failed - try again without the
4094
             Expect header */
4095
0
          if(!k->writebytecount && http_exp100_is_waiting(data)) {
4096
0
            infof(data, "Got HTTP failure 417 while waiting for a 100");
4097
0
          }
4098
0
          else {
4099
0
            infof(data, "Got HTTP failure 417 while sending data");
4100
0
            streamclose(conn);
4101
0
            result = http_perhapsrewind(data, conn);
4102
0
            if(result)
4103
0
              return result;
4104
0
          }
4105
0
          data->state.disableexpect = TRUE;
4106
0
          Curl_req_abort_sending(data);
4107
0
          DEBUGASSERT(!data->req.newurl);
4108
0
          data->req.newurl = Curl_bufref_dup(&data->state.url);
4109
0
          if(!data->req.newurl)
4110
0
            return CURLE_OUT_OF_MEMORY;
4111
0
        }
4112
0
        else if(data->set.http_keep_sending_on_error) {
4113
0
          infof(data, "HTTP error before end of send, keep sending");
4114
0
          http_exp100_send_anyway(data);
4115
0
        }
4116
0
        else {
4117
0
          infof(data, "HTTP error before end of send, stop sending");
4118
0
          streamclose(conn);
4119
0
          result = Curl_req_abort_sending(data);
4120
0
          if(result)
4121
0
            return result;
4122
0
        }
4123
0
      }
4124
0
      break;
4125
4126
0
    default: /* default label present to avoid compiler warnings */
4127
0
      break;
4128
0
    }
4129
0
  }
4130
4131
0
  if(Curl_creader_will_rewind(data) && !Curl_req_done_sending(data)) {
4132
    /* We rewind before next send, continue sending now */
4133
0
    infof(data, "Keep sending data to get tossed away");
4134
0
    CURL_REQ_SET_SEND(data);
4135
0
  }
4136
0
  return result;
4137
0
}
4138
4139
static CURLcode http_on_response(struct Curl_easy *data,
4140
                                 const char *last_hd, size_t last_hd_len,
4141
                                 const char *buf, size_t blen,
4142
                                 size_t *pconsumed)
4143
0
{
4144
0
  struct connectdata *conn = data->conn;
4145
0
  CURLcode result = CURLE_OK;
4146
0
  struct SingleRequest *k = &data->req;
4147
0
  bool conn_changed = FALSE;
4148
4149
0
  (void)buf; /* not used without HTTP2 enabled */
4150
0
  *pconsumed = 0;
4151
4152
0
  if(k->upgr101 == UPGR101_RECEIVED) {
4153
    /* supposedly upgraded to http2 now */
4154
0
    if(data->req.httpversion != 20)
4155
0
      infof(data, "Lying server, not serving HTTP/2");
4156
0
  }
4157
4158
0
  if(k->httpcode < 200 && last_hd) {
4159
    /* Intermediate responses might trigger processing of more responses,
4160
     * write the last header to the client before proceeding. */
4161
0
    result = http_write_header(data, last_hd, last_hd_len);
4162
0
    last_hd = NULL; /* handled it */
4163
0
    if(result)
4164
0
      goto out;
4165
0
  }
4166
4167
0
  if(k->httpcode < 100) {
4168
0
    failf(data, "Unsupported response code in HTTP response");
4169
0
    result = CURLE_UNSUPPORTED_PROTOCOL;
4170
0
    goto out;
4171
0
  }
4172
0
  else if(k->httpcode < 200) {
4173
0
    result = http_on_1xx_response(data, buf, blen, pconsumed, &conn_changed);
4174
0
    goto out;
4175
0
  }
4176
4177
  /* k->httpcode >= 200, final response */
4178
0
  k->header = FALSE;
4179
0
  if(conn->bits.upgrade_in_progress) {
4180
    /* Asked for protocol upgrade, but it was not selected */
4181
0
    conn->bits.upgrade_in_progress = FALSE;
4182
0
    conn_changed = TRUE;
4183
0
  }
4184
4185
0
  if((k->size == -1) && !k->chunk && !conn->bits.close &&
4186
0
     (k->httpversion == 11) &&
4187
0
     !(conn->scheme->protocol & CURLPROTO_RTSP) &&
4188
0
     data->state.httpreq != HTTPREQ_HEAD) {
4189
    /* On HTTP 1.1, when connection is not to get closed, but no
4190
       Content-Length nor Transfer-Encoding chunked have been received,
4191
       according to RFC2616 section 4.4 point 5, we assume that the server
4192
       will close the connection to signal the end of the document. */
4193
0
    infof(data, "no chunk, no close, no size. Assume close to signal end");
4194
0
    streamclose(conn);
4195
0
  }
4196
4197
0
  http_check_auth_closure(data, conn);
4198
4199
0
#ifndef CURL_DISABLE_WEBSOCKETS
4200
  /* All >=200 HTTP status codes are errors when wanting ws */
4201
0
  if(data->req.upgr101 == UPGR101_WS) {
4202
0
    failf(data, "Refused WebSocket upgrade: %d", k->httpcode);
4203
0
    result = CURLE_HTTP_RETURNED_ERROR;
4204
0
    goto out;
4205
0
  }
4206
0
#endif
4207
4208
  /* Check if this response means the transfer errored. */
4209
0
  if(http_should_fail(data, data->req.httpcode)) {
4210
0
    failf(data, "The requested URL returned error: %d",
4211
0
          k->httpcode);
4212
0
    result = CURLE_HTTP_RETURNED_ERROR;
4213
0
    goto out;
4214
0
  }
4215
4216
  /* Curl_http_auth_act() checks what authentication methods that are
4217
   * available and decides which one (if any) to use. It will set 'newurl' if
4218
   * an auth method was picked. */
4219
0
  result = Curl_http_auth_act(data);
4220
0
  if(result)
4221
0
    goto out;
4222
4223
0
  if(k->httpcode >= 300) {
4224
0
    result = http_handle_send_error(data);
4225
0
    if(result)
4226
0
      goto out;
4227
0
  }
4228
4229
  /* final response without error, prepare to receive the body */
4230
0
  result = http_firstwrite(data);
4231
0
  if(result)
4232
0
    goto out;
4233
4234
  /* This is the last response that we get for the current request. Check on
4235
   * the body size and determine if the response is complete. */
4236
0
  result = http_size(data);
4237
0
  if(result)
4238
0
    goto out;
4239
4240
  /* If we requested a "no body", this is a good time to get
4241
   * out and return home.
4242
   */
4243
0
  if(data->req.no_body)
4244
0
    k->download_done = TRUE;
4245
4246
  /* If max download size is *zero* (nothing) we already have nothing and can
4247
     safely return ok now! For HTTP/2, we would like to call
4248
     http2_handle_stream_close to properly close a stream. In order to do
4249
     this, we keep reading until we close the stream. */
4250
0
  if((k->maxdownload == 0) && (k->httpversion_sent < 20))
4251
0
    k->download_done = TRUE;
4252
4253
0
out:
4254
0
  if(last_hd)
4255
    /* if not written yet, write it now */
4256
0
    result = Curl_1st_fatal(result,
4257
0
                            http_write_header(data, last_hd, last_hd_len));
4258
0
  if(conn_changed)
4259
    /* poke the multi handle to allow pending pipewait to retry */
4260
0
    Curl_multi_connchanged(data->multi);
4261
0
  return result;
4262
0
}
4263
4264
static CURLcode http_rw_hd(struct Curl_easy *data,
4265
                           const char *hd, size_t hdlen,
4266
                           const char *buf_remain, size_t blen,
4267
                           size_t *pconsumed)
4268
0
{
4269
0
  CURLcode result = CURLE_OK;
4270
0
  struct SingleRequest *k = &data->req;
4271
0
  int writetype;
4272
0
  DEBUGASSERT(!hd[hdlen]); /* null-terminated */
4273
4274
0
  *pconsumed = 0;
4275
0
  if((0x0a == *hd) || (0x0d == *hd)) {
4276
    /* Empty header line means end of headers! */
4277
0
    struct dynbuf last_header;
4278
0
    size_t consumed;
4279
4280
0
    curlx_dyn_init(&last_header, hdlen + 1);
4281
0
    result = curlx_dyn_addn(&last_header, hd, hdlen);
4282
0
    if(result)
4283
0
      return result;
4284
4285
    /* analyze the response to find out what to do. */
4286
    /* Caveat: we clear anything in the header brigade, because a
4287
     * response might switch HTTP version which may call use recursively.
4288
     * Not nice, but that is currently the way of things. */
4289
0
    curlx_dyn_reset(&data->state.headerb);
4290
0
    result = http_on_response(data, curlx_dyn_ptr(&last_header),
4291
0
                              curlx_dyn_len(&last_header),
4292
0
                              buf_remain, blen, &consumed);
4293
0
    *pconsumed += consumed;
4294
0
    curlx_dyn_free(&last_header);
4295
0
    return result;
4296
0
  }
4297
4298
  /*
4299
   * Checks for special headers coming up.
4300
   */
4301
4302
0
  writetype = CLIENTWRITE_HEADER;
4303
0
  if(!k->headerline++) {
4304
    /* This is the first header, it MUST be the error code line
4305
       or else we consider this to be the body right away! */
4306
0
    bool fine_statusline = FALSE;
4307
4308
0
    k->httpversion = 0; /* Do not know yet */
4309
0
    if(data->conn->scheme->protocol & PROTO_FAMILY_HTTP) {
4310
      /*
4311
       * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
4312
       *
4313
       * The response code is always a three-digit number in HTTP as the spec
4314
       * says. We allow any three-digit number here, but we cannot make
4315
       * guarantees on future behaviors since it is not within the protocol.
4316
       */
4317
0
      const char *p = hd;
4318
4319
0
      curlx_str_passblanks(&p);
4320
0
      if(!strncmp(p, "HTTP/", 5)) {
4321
0
        p += 5;
4322
0
        switch(*p) {
4323
0
        case '1':
4324
0
          p++;
4325
0
          if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
4326
0
            if(ISBLANK(p[2])) {
4327
0
              k->httpversion = (unsigned char)(10 + (p[1] - '0'));
4328
0
              p += 3;
4329
0
              if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
4330
0
                k->httpcode = ((p[0] - '0') * 100) + ((p[1] - '0') * 10) +
4331
0
                  (p[2] - '0');
4332
                /* RFC 9112 requires a single space following the status code,
4333
                   but the browsers do not so let's not insist */
4334
0
                fine_statusline = TRUE;
4335
0
              }
4336
0
            }
4337
0
          }
4338
0
          if(!fine_statusline) {
4339
0
            failf(data, "Unsupported HTTP/1 subversion in response");
4340
0
            return CURLE_UNSUPPORTED_PROTOCOL;
4341
0
          }
4342
0
          break;
4343
0
        case '2':
4344
0
        case '3':
4345
0
          if(!ISBLANK(p[1]))
4346
0
            break;
4347
0
          k->httpversion = (unsigned char)((*p - '0') * 10);
4348
0
          p += 2;
4349
0
          if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
4350
0
            k->httpcode = ((p[0] - '0') * 100) + ((p[1] - '0') * 10) +
4351
0
              (p[2] - '0');
4352
0
            p += 3;
4353
0
            if(!ISBLANK(*p))
4354
0
              break;
4355
0
            fine_statusline = TRUE;
4356
0
          }
4357
0
          break;
4358
0
        default: /* unsupported */
4359
0
          failf(data, "Unsupported HTTP version in response");
4360
0
          return CURLE_UNSUPPORTED_PROTOCOL;
4361
0
        }
4362
0
      }
4363
4364
0
      if(!fine_statusline) {
4365
        /* If user has set option HTTP200ALIASES,
4366
           compare header line against list of aliases */
4367
0
        statusline check = checkhttpprefix(data, hd, hdlen);
4368
0
        if(check == STATUS_DONE) {
4369
0
          fine_statusline = TRUE;
4370
0
          k->httpcode = 200;
4371
0
          k->httpversion = 10;
4372
0
        }
4373
0
      }
4374
0
    }
4375
0
    else if(data->conn->scheme->protocol & CURLPROTO_RTSP) {
4376
0
      const char *p = hd;
4377
0
      struct Curl_str ver;
4378
0
      curl_off_t status;
4379
      /* we set the max string a little excessive to forgive some leading
4380
         spaces */
4381
0
      if(!curlx_str_until(&p, &ver, 32, ' ') &&
4382
0
         !curlx_str_single(&p, ' ') &&
4383
0
         !curlx_str_number(&p, &status, 999)) {
4384
0
        curlx_str_trimblanks(&ver);
4385
0
        if(curlx_str_cmp(&ver, "RTSP/1.0")) {
4386
0
          k->httpcode = (int)status;
4387
0
          fine_statusline = TRUE;
4388
0
          k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
4389
0
        }
4390
0
      }
4391
0
      if(!fine_statusline)
4392
0
        return CURLE_WEIRD_SERVER_REPLY;
4393
0
    }
4394
4395
0
    if(fine_statusline) {
4396
0
      result = http_statusline(data, data->conn);
4397
0
      if(result)
4398
0
        return result;
4399
0
      writetype |= CLIENTWRITE_STATUS;
4400
0
    }
4401
0
    else {
4402
0
      k->header = FALSE;   /* this is not a header line */
4403
0
      return CURLE_WEIRD_SERVER_REPLY;
4404
0
    }
4405
0
  }
4406
4407
0
  result = Curl_verify_header(data, hd, hdlen);
4408
0
  if(result)
4409
0
    return result;
4410
4411
0
  result = http_header(data, hd, hdlen);
4412
0
  if(result)
4413
0
    return result;
4414
4415
  /*
4416
   * Taken in one (more) header. Write it to the client.
4417
   */
4418
0
  Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
4419
4420
0
  if(k->httpcode / 100 == 1)
4421
0
    writetype |= CLIENTWRITE_1XX;
4422
0
  result = Curl_client_write(data, writetype, hd, hdlen);
4423
0
  if(result)
4424
0
    return result;
4425
4426
0
  result = Curl_bump_headersize(data, hdlen, FALSE);
4427
0
  if(result)
4428
0
    return result;
4429
4430
0
  return CURLE_OK;
4431
0
}
4432
4433
/* remove trailing CRLF then all trailing whitespace */
4434
void Curl_http_to_fold(struct dynbuf *bf)
4435
0
{
4436
0
  size_t len = curlx_dyn_len(bf);
4437
0
  const char *hd = curlx_dyn_ptr(bf);
4438
0
  if(len && (hd[len - 1] == '\n'))
4439
0
    len--;
4440
0
  if(len && (hd[len - 1] == '\r'))
4441
0
    len--;
4442
0
  while(len && ISBLANK(hd[len - 1])) /* strip off trailing whitespace */
4443
0
    len--;
4444
0
  curlx_dyn_setlen(bf, len);
4445
0
}
4446
4447
static void unfold_header(struct Curl_easy *data)
4448
0
{
4449
0
  Curl_http_to_fold(&data->state.headerb);
4450
0
  data->state.leading_unfold = TRUE;
4451
0
}
4452
4453
/*
4454
 * Read any HTTP header lines from the server and pass them to the client app.
4455
 */
4456
static CURLcode http_parse_headers(struct Curl_easy *data,
4457
                                   const char *buf, size_t blen,
4458
                                   size_t *pconsumed)
4459
0
{
4460
0
  struct connectdata *conn = data->conn;
4461
0
  CURLcode result = CURLE_OK;
4462
0
  struct SingleRequest *k = &data->req;
4463
0
  const char *end_ptr;
4464
0
  bool leftover_body = FALSE;
4465
4466
  /* we have bytes for the next header, make sure it is not a folded header
4467
     before passing it on */
4468
0
  if(data->state.maybe_folded && blen) {
4469
0
    if(ISBLANK(buf[0])) {
4470
      /* folded, remove the trailing newlines and append the next header */
4471
0
      unfold_header(data);
4472
0
    }
4473
0
    else {
4474
      /* the header data we hold is a complete header, pass it on */
4475
0
      size_t ignore_this;
4476
0
      result = http_rw_hd(data, curlx_dyn_ptr(&data->state.headerb),
4477
0
                          curlx_dyn_len(&data->state.headerb),
4478
0
                          NULL, 0, &ignore_this);
4479
0
      curlx_dyn_reset(&data->state.headerb);
4480
0
      if(result)
4481
0
        return result;
4482
0
    }
4483
0
    data->state.maybe_folded = FALSE;
4484
0
  }
4485
4486
  /* header line within buffer loop */
4487
0
  *pconsumed = 0;
4488
0
  while(blen && k->header) {
4489
0
    size_t consumed;
4490
0
    size_t hlen;
4491
0
    const char *hd;
4492
0
    size_t unfold_len = 0;
4493
4494
0
    if(data->state.leading_unfold) {
4495
      /* immediately after an unfold, keep only a single whitespace */
4496
0
      while(blen && ISBLANK(buf[0])) {
4497
0
        buf++;
4498
0
        blen--;
4499
0
        unfold_len++;
4500
0
      }
4501
0
      if(blen) {
4502
        /* insert a single space */
4503
0
        result = curlx_dyn_addn(&data->state.headerb, " ", 1);
4504
0
        if(result)
4505
0
          return result;
4506
0
        data->state.leading_unfold = FALSE; /* done now */
4507
0
      }
4508
0
    }
4509
4510
0
    end_ptr = memchr(buf, '\n', blen);
4511
0
    if(!end_ptr) {
4512
      /* Not a complete header line within buffer, append the data to
4513
         the end of the headerbuff. */
4514
0
      result = curlx_dyn_addn(&data->state.headerb, buf, blen);
4515
0
      if(result)
4516
0
        return result;
4517
0
      *pconsumed += blen + unfold_len;
4518
4519
0
      if(!k->headerline) {
4520
        /* check if this looks like a protocol header */
4521
0
        statusline st =
4522
0
          checkprotoprefix(data, conn,
4523
0
                           curlx_dyn_ptr(&data->state.headerb),
4524
0
                           curlx_dyn_len(&data->state.headerb));
4525
4526
0
        if(st == STATUS_BAD) {
4527
          /* this is not the beginning of a protocol first header line.
4528
           * Cannot be 0.9 if version was detected or connection was reused. */
4529
0
          k->header = FALSE;
4530
0
          streamclose(conn);
4531
0
          if((k->httpversion >= 10) || conn->bits.reuse) {
4532
0
            failf(data, "Invalid status line");
4533
0
            return CURLE_WEIRD_SERVER_REPLY;
4534
0
          }
4535
0
          if(!data->state.http_neg.accept_09) {
4536
0
            failf(data, "Received HTTP/0.9 when not allowed");
4537
0
            return CURLE_UNSUPPORTED_PROTOCOL;
4538
0
          }
4539
0
          leftover_body = TRUE;
4540
0
          goto out;
4541
0
        }
4542
0
      }
4543
0
      goto out; /* read more and try again */
4544
0
    }
4545
4546
    /* the size of the remaining header line */
4547
0
    consumed = (end_ptr - buf) + 1;
4548
4549
0
    result = curlx_dyn_addn(&data->state.headerb, buf, consumed);
4550
0
    if(result)
4551
0
      return result;
4552
0
    blen -= consumed;
4553
0
    buf += consumed;
4554
0
    *pconsumed += consumed + unfold_len;
4555
4556
    /****
4557
     * We now have a FULL header line in 'headerb'.
4558
     *****/
4559
4560
0
    hlen = curlx_dyn_len(&data->state.headerb);
4561
0
    hd = curlx_dyn_ptr(&data->state.headerb);
4562
4563
0
    if(!k->headerline) {
4564
      /* the first read "header", the status line */
4565
0
      statusline st = checkprotoprefix(data, conn, hd, hlen);
4566
0
      if(st == STATUS_BAD) {
4567
0
        streamclose(conn);
4568
        /* this is not the beginning of a protocol first header line.
4569
         * Cannot be 0.9 if version was detected or connection was reused. */
4570
0
        if((k->httpversion >= 10) || conn->bits.reuse) {
4571
0
          failf(data, "Invalid status line");
4572
0
          return CURLE_WEIRD_SERVER_REPLY;
4573
0
        }
4574
0
        if(!data->state.http_neg.accept_09) {
4575
0
          failf(data, "Received HTTP/0.9 when not allowed");
4576
0
          return CURLE_UNSUPPORTED_PROTOCOL;
4577
0
        }
4578
0
        k->header = FALSE;
4579
0
        leftover_body = TRUE;
4580
0
        goto out;
4581
0
      }
4582
0
    }
4583
0
    else {
4584
0
      if(hlen && !ISNEWLINE(hd[0])) {
4585
        /* this is NOT the header separator */
4586
4587
        /* if we have bytes for the next header, check for folding */
4588
0
        if(blen && ISBLANK(buf[0])) {
4589
          /* remove the trailing CRLF and append the next header */
4590
0
          unfold_header(data);
4591
0
          continue;
4592
0
        }
4593
0
        else if(!blen) {
4594
          /* this might be a folded header so deal with it in next invoke */
4595
0
          data->state.maybe_folded = TRUE;
4596
0
          break;
4597
0
        }
4598
0
      }
4599
0
    }
4600
4601
0
    result = http_rw_hd(data, hd, hlen, buf, blen, &consumed);
4602
    /* We are done with this line. We reset because response
4603
     * processing might switch to HTTP/2 and that might call us
4604
     * directly again. */
4605
0
    curlx_dyn_reset(&data->state.headerb);
4606
0
    if(consumed) {
4607
0
      blen -= consumed;
4608
0
      buf += consumed;
4609
0
      *pconsumed += consumed;
4610
0
    }
4611
0
    if(result)
4612
0
      return result;
4613
0
  }
4614
4615
  /* We might have reached the end of the header part here, but
4616
     there might be a non-header part left in the end of the read
4617
     buffer. */
4618
0
out:
4619
0
  if(!k->header && !leftover_body) {
4620
0
    curlx_dyn_free(&data->state.headerb);
4621
0
  }
4622
0
  return CURLE_OK;
4623
0
}
4624
4625
CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
4626
                                 const char *hd, size_t hdlen,
4627
                                 bool is_eos)
4628
0
{
4629
0
  CURLcode result;
4630
0
  size_t consumed;
4631
0
  char tmp = 0;
4632
0
  DEBUGASSERT(!hd[hdlen]); /* null-terminated */
4633
4634
0
  result = http_rw_hd(data, hd, hdlen, &tmp, 0, &consumed);
4635
0
  if(!result && is_eos) {
4636
0
    result = Curl_client_write(data, (CLIENTWRITE_BODY | CLIENTWRITE_EOS),
4637
0
                               &tmp, 0);
4638
0
  }
4639
0
  return result;
4640
0
}
4641
4642
/*
4643
 * HTTP protocol `write_resp` implementation. Parse headers
4644
 * when not done yet and otherwise return without consuming data.
4645
 */
4646
CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
4647
                                  const char *buf, size_t blen,
4648
                                  size_t *pconsumed)
4649
0
{
4650
0
  if(!data->req.header) {
4651
0
    *pconsumed = 0;
4652
0
    return CURLE_OK;
4653
0
  }
4654
0
  else {
4655
0
    CURLcode result;
4656
4657
0
    result = http_parse_headers(data, buf, blen, pconsumed);
4658
0
    if(!result && !data->req.header) {
4659
0
      if(!data->req.no_body && curlx_dyn_len(&data->state.headerb)) {
4660
        /* leftover from parsing something that turned out not
4661
         * to be a header, only happens if we allow for
4662
         * HTTP/0.9 like responses */
4663
0
        result = Curl_client_write(data, CLIENTWRITE_BODY,
4664
0
                                   curlx_dyn_ptr(&data->state.headerb),
4665
0
                                   curlx_dyn_len(&data->state.headerb));
4666
0
      }
4667
0
      curlx_dyn_free(&data->state.headerb);
4668
0
    }
4669
0
    return result;
4670
0
  }
4671
0
}
4672
4673
CURLcode Curl_http_write_resp(struct Curl_easy *data,
4674
                              const char *buf, size_t blen,
4675
                              bool is_eos)
4676
0
{
4677
0
  CURLcode result;
4678
0
  size_t consumed;
4679
0
  int flags;
4680
4681
0
  result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
4682
0
  if(result || data->req.done)
4683
0
    goto out;
4684
4685
0
  DEBUGASSERT(consumed <= blen);
4686
0
  blen -= consumed;
4687
0
  buf += consumed;
4688
  /* either all was consumed in header parsing, or we have data left
4689
   * and are done with headers, e.g. it is BODY data */
4690
0
  DEBUGASSERT(!blen || !data->req.header);
4691
0
  if(!data->req.header && (blen || is_eos)) {
4692
    /* BODY data after header been parsed, write and consume */
4693
0
    flags = CLIENTWRITE_BODY;
4694
0
    if(is_eos)
4695
0
      flags |= CLIENTWRITE_EOS;
4696
0
    result = Curl_client_write(data, flags, buf, blen);
4697
0
  }
4698
0
out:
4699
0
  return result;
4700
0
}
4701
4702
/* Decode HTTP status code string. */
4703
CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len)
4704
0
{
4705
0
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
4706
0
  int status = 0;
4707
0
  int i;
4708
4709
0
  if(len != 3)
4710
0
    goto out;
4711
4712
0
  for(i = 0; i < 3; ++i) {
4713
0
    char c = s[i];
4714
4715
0
    if(c < '0' || c > '9')
4716
0
      goto out;
4717
4718
0
    status *= 10;
4719
0
    status += c - '0';
4720
0
  }
4721
0
  result = CURLE_OK;
4722
0
out:
4723
0
  *pstatus = result ? -1 : status;
4724
0
  return result;
4725
0
}
4726
4727
CURLcode Curl_http_req_make(struct httpreq **preq,
4728
                            const char *method, size_t m_len,
4729
                            const char *scheme, size_t s_len,
4730
                            const char *authority, size_t a_len,
4731
                            const char *path, size_t p_len)
4732
0
{
4733
0
  struct httpreq *req;
4734
0
  CURLcode result = CURLE_OUT_OF_MEMORY;
4735
4736
0
  DEBUGASSERT(method && m_len);
4737
4738
0
  req = curlx_calloc(1, sizeof(*req) + m_len);
4739
0
  if(!req)
4740
0
    goto out;
4741
#if defined(__GNUC__) && __GNUC__ >= 13
4742
#pragma GCC diagnostic push
4743
/* error: 'memcpy' offset [137, 142] from the object at 'req' is out of
4744
   the bounds of referenced subobject 'method' with type 'char[1]' at
4745
   offset 136 */
4746
#pragma GCC diagnostic ignored "-Warray-bounds"
4747
#endif
4748
0
  memcpy(req->method, method, m_len);
4749
#if defined(__GNUC__) && __GNUC__ >= 13
4750
#pragma GCC diagnostic pop
4751
#endif
4752
0
  if(scheme) {
4753
0
    req->scheme = curlx_memdup0(scheme, s_len);
4754
0
    if(!req->scheme)
4755
0
      goto out;
4756
0
  }
4757
0
  if(authority) {
4758
0
    req->authority = curlx_memdup0(authority, a_len);
4759
0
    if(!req->authority)
4760
0
      goto out;
4761
0
  }
4762
0
  if(path) {
4763
0
    req->path = curlx_memdup0(path, p_len);
4764
0
    if(!req->path)
4765
0
      goto out;
4766
0
  }
4767
0
  Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
4768
0
  Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
4769
0
  result = CURLE_OK;
4770
4771
0
out:
4772
0
  if(result && req)
4773
0
    Curl_http_req_free(req);
4774
0
  *preq = result ? NULL : req;
4775
0
  return result;
4776
0
}
4777
4778
static CURLcode req_assign_url_authority(struct httpreq *req, CURLU *url)
4779
0
{
4780
0
  char *host, *port;
4781
0
  struct dynbuf buf;
4782
0
  CURLUcode uc;
4783
0
  CURLcode result = CURLE_URL_MALFORMAT;
4784
4785
0
  host = port = NULL;
4786
0
  curlx_dyn_init(&buf, DYN_HTTP_REQUEST);
4787
4788
0
  uc = curl_url_get(url, CURLUPART_HOST, &host, 0);
4789
0
  if(uc && uc != CURLUE_NO_HOST)
4790
0
    goto out;
4791
0
  if(!host) {
4792
0
    req->authority = NULL;
4793
0
    result = CURLE_OK;
4794
0
    goto out;
4795
0
  }
4796
4797
0
  uc = curl_url_get(url, CURLUPART_PORT, &port, CURLU_NO_DEFAULT_PORT);
4798
0
  if(uc && uc != CURLUE_NO_PORT)
4799
0
    goto out;
4800
4801
0
  result = curlx_dyn_add(&buf, host);
4802
0
  if(result)
4803
0
    goto out;
4804
0
  if(port) {
4805
0
    result = curlx_dyn_addf(&buf, ":%s", port);
4806
0
    if(result)
4807
0
      goto out;
4808
0
  }
4809
0
  req->authority = curlx_dyn_ptr(&buf);
4810
0
out:
4811
0
  curlx_free(host);
4812
0
  curlx_free(port);
4813
0
  if(result)
4814
0
    curlx_dyn_free(&buf);
4815
0
  return result;
4816
0
}
4817
4818
static CURLcode req_assign_url_path(struct httpreq *req, CURLU *url)
4819
0
{
4820
0
  char *path, *query;
4821
0
  struct dynbuf buf;
4822
0
  CURLUcode uc;
4823
0
  CURLcode result = CURLE_URL_MALFORMAT;
4824
4825
0
  path = query = NULL;
4826
0
  curlx_dyn_init(&buf, DYN_HTTP_REQUEST);
4827
4828
0
  uc = curl_url_get(url, CURLUPART_PATH, &path, 0);
4829
0
  if(uc)
4830
0
    goto out;
4831
0
  uc = curl_url_get(url, CURLUPART_QUERY, &query, 0);
4832
0
  if(uc && uc != CURLUE_NO_QUERY)
4833
0
    goto out;
4834
4835
0
  if(!query) {
4836
0
    req->path = path;
4837
0
    path = NULL;
4838
0
  }
4839
0
  else {
4840
0
    result = curlx_dyn_add(&buf, path);
4841
0
    if(!result)
4842
0
      result = curlx_dyn_addf(&buf, "?%s", query);
4843
0
    if(result)
4844
0
      goto out;
4845
0
    req->path = curlx_dyn_ptr(&buf);
4846
0
  }
4847
0
  result = CURLE_OK;
4848
4849
0
out:
4850
0
  curlx_free(path);
4851
0
  curlx_free(query);
4852
0
  if(result)
4853
0
    curlx_dyn_free(&buf);
4854
0
  return result;
4855
0
}
4856
4857
CURLcode Curl_http_req_make2(struct httpreq **preq,
4858
                             const char *method, size_t m_len,
4859
                             CURLU *url, const char *scheme_default)
4860
0
{
4861
0
  struct httpreq *req;
4862
0
  CURLcode result = CURLE_OUT_OF_MEMORY;
4863
0
  CURLUcode uc;
4864
4865
0
  DEBUGASSERT(method && m_len);
4866
4867
0
  req = curlx_calloc(1, sizeof(*req) + m_len);
4868
0
  if(!req)
4869
0
    goto out;
4870
0
  memcpy(req->method, method, m_len);
4871
4872
0
  uc = curl_url_get(url, CURLUPART_SCHEME, &req->scheme, 0);
4873
0
  if(uc && uc != CURLUE_NO_SCHEME)
4874
0
    goto out;
4875
0
  if(!req->scheme && scheme_default) {
4876
0
    req->scheme = curlx_strdup(scheme_default);
4877
0
    if(!req->scheme)
4878
0
      goto out;
4879
0
  }
4880
4881
0
  result = req_assign_url_authority(req, url);
4882
0
  if(result)
4883
0
    goto out;
4884
0
  result = req_assign_url_path(req, url);
4885
0
  if(result)
4886
0
    goto out;
4887
4888
0
  Curl_dynhds_init(&req->headers, 0, DYN_HTTP_REQUEST);
4889
0
  Curl_dynhds_init(&req->trailers, 0, DYN_HTTP_REQUEST);
4890
0
  result = CURLE_OK;
4891
4892
0
out:
4893
0
  if(result && req)
4894
0
    Curl_http_req_free(req);
4895
0
  *preq = result ? NULL : req;
4896
0
  return result;
4897
0
}
4898
4899
void Curl_http_req_free(struct httpreq *req)
4900
0
{
4901
0
  if(req) {
4902
0
    curlx_free(req->scheme);
4903
0
    curlx_free(req->authority);
4904
0
    curlx_free(req->path);
4905
0
    Curl_dynhds_free(&req->headers);
4906
0
    Curl_dynhds_free(&req->trailers);
4907
0
    curlx_free(req);
4908
0
  }
4909
0
}
4910
4911
struct name_const {
4912
  const char *name;
4913
  size_t namelen;
4914
};
4915
4916
static const struct name_const H2_NON_FIELD[] = {
4917
  { STRCONST("Host") },
4918
  { STRCONST("Upgrade") },
4919
  { STRCONST("Connection") },
4920
  { STRCONST("Keep-Alive") },
4921
  { STRCONST("Proxy-Connection") },
4922
  { STRCONST("Transfer-Encoding") },
4923
};
4924
4925
static bool h2_permissible_field(struct dynhds_entry *e)
4926
0
{
4927
0
  size_t i;
4928
0
  for(i = 0; i < CURL_ARRAYSIZE(H2_NON_FIELD); ++i) {
4929
0
    if(e->namelen == H2_NON_FIELD[i].namelen &&
4930
0
       curl_strnequal(H2_NON_FIELD[i].name, e->name, e->namelen))
4931
0
      return FALSE;
4932
0
  }
4933
0
  return TRUE;
4934
0
}
4935
4936
static bool http_TE_has_token(const char *fvalue, const char *token)
4937
0
{
4938
0
  while(*fvalue) {
4939
0
    struct Curl_str name;
4940
4941
    /* skip to first token */
4942
0
    while(ISBLANK(*fvalue) || *fvalue == ',')
4943
0
      fvalue++;
4944
0
    if(curlx_str_cspn(&fvalue, &name, " \t\r;,"))
4945
0
      return FALSE;
4946
0
    if(curlx_str_casecompare(&name, token))
4947
0
      return TRUE;
4948
4949
    /* skip any remainder after token, e.g. parameters with quoted strings */
4950
0
    while(*fvalue && *fvalue != ',') {
4951
0
      if(*fvalue == '"') {
4952
0
        struct Curl_str qw;
4953
        /* if we do not cleanly find a quoted word here, the header value
4954
         * does not follow HTTP syntax and we reject */
4955
0
        if(curlx_str_quotedword(&fvalue, &qw, CURL_MAX_HTTP_HEADER))
4956
0
          return FALSE;
4957
0
      }
4958
0
      else
4959
0
        fvalue++;
4960
0
    }
4961
0
  }
4962
0
  return FALSE;
4963
0
}
4964
4965
CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
4966
                             struct httpreq *req, struct Curl_easy *data)
4967
0
{
4968
0
  const char *scheme = NULL, *authority = NULL;
4969
0
  struct dynhds_entry *e;
4970
0
  size_t i;
4971
0
  CURLcode result;
4972
4973
0
  DEBUGASSERT(req);
4974
0
  DEBUGASSERT(h2_headers);
4975
4976
0
  if(req->scheme) {
4977
0
    scheme = req->scheme;
4978
0
  }
4979
0
  else if(strcmp("CONNECT", req->method)) {
4980
0
    scheme = Curl_checkheaders(data, STRCONST(HTTP_PSEUDO_SCHEME));
4981
0
    if(scheme) {
4982
0
      scheme += sizeof(HTTP_PSEUDO_SCHEME);
4983
0
      curlx_str_passblanks(&scheme);
4984
0
      infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme);
4985
0
    }
4986
0
    else {
4987
0
      scheme = data->state.origin->scheme->name;
4988
0
    }
4989
0
  }
4990
4991
0
  if(req->authority) {
4992
0
    authority = req->authority;
4993
0
  }
4994
0
  else {
4995
0
    e = Curl_dynhds_get(&req->headers, STRCONST("Host"));
4996
0
    if(e)
4997
0
      authority = e->value;
4998
0
  }
4999
5000
0
  Curl_dynhds_reset(h2_headers);
5001
0
  Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE);
5002
0
  result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD),
5003
0
                           req->method, strlen(req->method));
5004
0
  if(!result && scheme) {
5005
0
    result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME),
5006
0
                             scheme, strlen(scheme));
5007
0
  }
5008
0
  if(!result && authority) {
5009
0
    result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY),
5010
0
                             authority, strlen(authority));
5011
0
  }
5012
0
  if(!result && req->path) {
5013
0
    result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH),
5014
0
                             req->path, strlen(req->path));
5015
0
  }
5016
0
  for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) {
5017
0
    e = Curl_dynhds_getn(&req->headers, i);
5018
    /* "TE" is special in that it is only permissible when it
5019
     * has only value "trailers". RFC 9113 ch. 8.2.2 */
5020
0
    if(e->namelen == 2 && curl_strequal("TE", e->name)) {
5021
0
      if(http_TE_has_token(e->value, "trailers"))
5022
0
        result = Curl_dynhds_add(h2_headers, e->name, e->namelen,
5023
0
                                 "trailers", CURL_CSTRLEN("trailers"));
5024
0
    }
5025
0
    else if(h2_permissible_field(e)) {
5026
0
      result = Curl_dynhds_add(h2_headers, e->name, e->namelen,
5027
0
                               e->value, e->valuelen);
5028
0
    }
5029
0
  }
5030
5031
0
  return result;
5032
0
}
5033
5034
CURLcode Curl_http_resp_make(struct http_resp **presp,
5035
                             int status,
5036
                             const char *description)
5037
0
{
5038
0
  struct http_resp *resp;
5039
0
  CURLcode result = CURLE_OUT_OF_MEMORY;
5040
5041
0
  resp = curlx_calloc(1, sizeof(*resp));
5042
0
  if(!resp)
5043
0
    goto out;
5044
5045
0
  resp->status = status;
5046
0
  if(description) {
5047
0
    resp->description = curlx_strdup(description);
5048
0
    if(!resp->description)
5049
0
      goto out;
5050
0
  }
5051
0
  Curl_dynhds_init(&resp->headers, 0, DYN_HTTP_REQUEST);
5052
0
  Curl_dynhds_init(&resp->trailers, 0, DYN_HTTP_REQUEST);
5053
0
  result = CURLE_OK;
5054
5055
0
out:
5056
0
  if(result && resp)
5057
0
    Curl_http_resp_free(resp);
5058
0
  *presp = result ? NULL : resp;
5059
0
  return result;
5060
0
}
5061
5062
void Curl_http_resp_free(struct http_resp *resp)
5063
0
{
5064
0
  if(resp) {
5065
0
    curlx_free(resp->description);
5066
0
    Curl_dynhds_free(&resp->headers);
5067
0
    Curl_dynhds_free(&resp->trailers);
5068
0
    if(resp->prev)
5069
0
      Curl_http_resp_free(resp->prev);
5070
0
    curlx_free(resp);
5071
0
  }
5072
0
}
5073
5074
/*
5075
 * HTTP handler interface.
5076
 */
5077
const struct Curl_protocol Curl_protocol_http = {
5078
  Curl_http_setup_conn,                 /* setup_connection */
5079
  Curl_http,                            /* do_it */
5080
  Curl_http_done,                       /* done */
5081
  ZERO_NULL,                            /* do_more */
5082
  ZERO_NULL,                            /* connect_it */
5083
  ZERO_NULL,                            /* connecting */
5084
  ZERO_NULL,                            /* doing */
5085
  ZERO_NULL,                            /* proto_pollset */
5086
  Curl_http_doing_pollset,              /* doing_pollset */
5087
  ZERO_NULL,                            /* domore_pollset */
5088
  Curl_http_perform_pollset,            /* perform_pollset */
5089
  ZERO_NULL,                            /* disconnect */
5090
  Curl_http_write_resp,                 /* write_resp */
5091
  Curl_http_write_resp_hd,              /* write_resp_hd */
5092
  ZERO_NULL,                            /* connection_is_dead */
5093
  ZERO_NULL,                            /* attach connection */
5094
  Curl_http_follow,                     /* follow */
5095
};
5096
5097
#endif /* CURL_DISABLE_HTTP */