Coverage Report

Created: 2023-06-07 07:02

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