Coverage Report

Created: 2025-10-30 06:17

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