Coverage Report

Created: 2025-08-26 07:17

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