Coverage Report

Created: 2026-03-12 06:35

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