Coverage Report

Created: 2025-12-04 06:52

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