Coverage Report

Created: 2025-10-10 06:31

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