Coverage Report

Created: 2025-08-03 06:36

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