Coverage Report

Created: 2025-06-09 07:02

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