Coverage Report

Created: 2023-12-08 06:48

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