Coverage Report

Created: 2026-07-16 06:10

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