Coverage Report

Created: 2024-02-25 06:14

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