Coverage Report

Created: 2025-12-03 07:02

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