Coverage Report

Created: 2026-04-29 07:01

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