Coverage Report

Created: 2026-07-14 07:09

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