Coverage Report

Created: 2024-05-04 12:45

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