xref: /third_party/curl/lib/c-hyper.c (revision 13498266)
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.haxx.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/* Curl's integration with Hyper. This replaces certain functions in http.c,
26 * based on configuration #defines. This implementation supports HTTP/1.1 but
27 * not HTTP/2.
28 */
29#include "curl_setup.h"
30
31#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
32
33#ifdef HAVE_NETINET_IN_H
34#include <netinet/in.h>
35#endif
36
37#ifdef HAVE_NETDB_H
38#include <netdb.h>
39#endif
40#ifdef HAVE_ARPA_INET_H
41#include <arpa/inet.h>
42#endif
43#ifdef HAVE_NET_IF_H
44#include <net/if.h>
45#endif
46#ifdef HAVE_SYS_IOCTL_H
47#include <sys/ioctl.h>
48#endif
49
50#ifdef HAVE_SYS_PARAM_H
51#include <sys/param.h>
52#endif
53
54#include <hyper.h>
55#include "urldata.h"
56#include "sendf.h"
57#include "transfer.h"
58#include "multiif.h"
59#include "progress.h"
60#include "content_encoding.h"
61#include "ws.h"
62
63/* The last 3 #include files should be in this order */
64#include "curl_printf.h"
65#include "curl_memory.h"
66#include "memdebug.h"
67
68typedef enum {
69    USERDATA_NOT_SET = 0, /* for tasks with no userdata set; must be zero */
70    USERDATA_RESP_BODY
71} userdata_t;
72
73size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
74                       uint8_t *buf, size_t buflen)
75{
76  struct Curl_easy *data = userp;
77  struct connectdata *conn = data->conn;
78  CURLcode result;
79  ssize_t nread;
80  DEBUGASSERT(conn);
81  (void)ctx;
82
83  DEBUGF(infof(data, "Curl_hyper_recv(%zu)", buflen));
84  result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread);
85  if(result == CURLE_AGAIN) {
86    /* would block, register interest */
87    DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> EAGAIN", buflen));
88    if(data->hyp.read_waker)
89      hyper_waker_free(data->hyp.read_waker);
90    data->hyp.read_waker = hyper_context_waker(ctx);
91    if(!data->hyp.read_waker) {
92      failf(data, "Couldn't make the read hyper_context_waker");
93      return HYPER_IO_ERROR;
94    }
95    return HYPER_IO_PENDING;
96  }
97  else if(result) {
98    failf(data, "Curl_read failed");
99    return HYPER_IO_ERROR;
100  }
101  DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> %zd", buflen, nread));
102  return (size_t)nread;
103}
104
105size_t Curl_hyper_send(void *userp, hyper_context *ctx,
106                       const uint8_t *buf, size_t buflen)
107{
108  struct Curl_easy *data = userp;
109  struct connectdata *conn = data->conn;
110  CURLcode result;
111  ssize_t nwrote;
112
113  DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen));
114  result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote);
115  if(!result && !nwrote)
116    result = CURLE_AGAIN;
117  if(result == CURLE_AGAIN) {
118    DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen));
119    /* would block, register interest */
120    if(data->hyp.write_waker)
121      hyper_waker_free(data->hyp.write_waker);
122    data->hyp.write_waker = hyper_context_waker(ctx);
123    if(!data->hyp.write_waker) {
124      failf(data, "Couldn't make the write hyper_context_waker");
125      return HYPER_IO_ERROR;
126    }
127    return HYPER_IO_PENDING;
128  }
129  else if(result) {
130    failf(data, "Curl_write failed");
131    return HYPER_IO_ERROR;
132  }
133  DEBUGF(infof(data, "Curl_hyper_send(%zu) -> %zd", buflen, nwrote));
134  return (size_t)nwrote;
135}
136
137static int hyper_each_header(void *userdata,
138                             const uint8_t *name,
139                             size_t name_len,
140                             const uint8_t *value,
141                             size_t value_len)
142{
143  struct Curl_easy *data = (struct Curl_easy *)userdata;
144  size_t len;
145  char *headp;
146  CURLcode result;
147  int writetype;
148
149  if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) {
150    failf(data, "Too long response header");
151    data->state.hresult = CURLE_TOO_LARGE;
152    return HYPER_ITER_BREAK;
153  }
154
155  if(!data->req.bytecount)
156    Curl_pgrsTime(data, TIMER_STARTTRANSFER);
157
158  Curl_dyn_reset(&data->state.headerb);
159  if(name_len) {
160    if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n",
161                     (int) name_len, name, (int) value_len, value))
162      return HYPER_ITER_BREAK;
163  }
164  else {
165    if(Curl_dyn_addn(&data->state.headerb, STRCONST("\r\n")))
166      return HYPER_ITER_BREAK;
167  }
168  len = Curl_dyn_len(&data->state.headerb);
169  headp = Curl_dyn_ptr(&data->state.headerb);
170
171  result = Curl_http_header(data, data->conn, headp);
172  if(result) {
173    data->state.hresult = result;
174    return HYPER_ITER_BREAK;
175  }
176
177  Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
178
179  writetype = CLIENTWRITE_HEADER;
180  if(data->state.hconnect)
181    writetype |= CLIENTWRITE_CONNECT;
182  if(data->req.httpcode/100 == 1)
183    writetype |= CLIENTWRITE_1XX;
184  result = Curl_client_write(data, writetype, headp, len);
185  if(result) {
186    data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
187    return HYPER_ITER_BREAK;
188  }
189
190  result = Curl_bump_headersize(data, len, FALSE);
191  if(result) {
192    data->state.hresult = result;
193    return HYPER_ITER_BREAK;
194  }
195  return HYPER_ITER_CONTINUE;
196}
197
198static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
199{
200  char *buf = (char *)hyper_buf_bytes(chunk);
201  size_t len = hyper_buf_len(chunk);
202  struct Curl_easy *data = (struct Curl_easy *)userdata;
203  struct SingleRequest *k = &data->req;
204  CURLcode result = CURLE_OK;
205
206  if(0 == k->bodywrites) {
207    bool done = FALSE;
208#if defined(USE_NTLM)
209    struct connectdata *conn = data->conn;
210    if(conn->bits.close &&
211       (((data->req.httpcode == 401) &&
212         (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
213        ((data->req.httpcode == 407) &&
214         (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
215      infof(data, "Connection closed while negotiating NTLM");
216      data->state.authproblem = TRUE;
217      Curl_safefree(data->req.newurl);
218    }
219#endif
220    if(data->state.expect100header) {
221      Curl_expire_done(data, EXPIRE_100_TIMEOUT);
222      if(data->req.httpcode < 400) {
223        k->exp100 = EXP100_SEND_DATA;
224        if(data->hyp.exp100_waker) {
225          hyper_waker_wake(data->hyp.exp100_waker);
226          data->hyp.exp100_waker = NULL;
227        }
228      }
229      else { /* >= 4xx */
230        k->exp100 = EXP100_FAILED;
231      }
232    }
233    if(data->state.hconnect && (data->req.httpcode/100 != 2) &&
234       data->state.authproxy.done) {
235      done = TRUE;
236      result = CURLE_OK;
237    }
238    else
239      result = Curl_http_firstwrite(data, data->conn, &done);
240    if(result || done) {
241      infof(data, "Return early from hyper_body_chunk");
242      data->state.hresult = result;
243      return HYPER_ITER_BREAK;
244    }
245  }
246  result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
247
248  if(result) {
249    data->state.hresult = result;
250    return HYPER_ITER_BREAK;
251  }
252
253  return HYPER_ITER_CONTINUE;
254}
255
256/*
257 * Hyper does not consider the status line, the first line in an HTTP/1
258 * response, to be a header. The libcurl API does. This function sends the
259 * status line in the header callback. */
260static CURLcode status_line(struct Curl_easy *data,
261                            struct connectdata *conn,
262                            uint16_t http_status,
263                            int http_version,
264                            const uint8_t *reason, size_t rlen)
265{
266  CURLcode result;
267  size_t len;
268  const char *vstr;
269  int writetype;
270  vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
271    (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
272
273  /* We need to set 'httpcodeq' for functions that check the response code in
274     a single place. */
275  data->req.httpcode = http_status;
276
277  if(data->state.hconnect)
278    /* CONNECT */
279    data->info.httpproxycode = http_status;
280  else {
281    conn->httpversion =
282      http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
283      (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
284    if(http_version == HYPER_HTTP_VERSION_1_0)
285      data->state.httpwant = CURL_HTTP_VERSION_1_0;
286
287    result = Curl_http_statusline(data, conn);
288    if(result)
289      return result;
290  }
291
292  Curl_dyn_reset(&data->state.headerb);
293
294  result = Curl_dyn_addf(&data->state.headerb, "HTTP/%s %03d %.*s\r\n",
295                         vstr,
296                         (int)http_status,
297                         (int)rlen, reason);
298  if(result)
299    return result;
300  len = Curl_dyn_len(&data->state.headerb);
301  Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
302             len);
303
304  writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS;
305  if(data->state.hconnect)
306    writetype |= CLIENTWRITE_CONNECT;
307  result = Curl_client_write(data, writetype,
308                             Curl_dyn_ptr(&data->state.headerb), len);
309  if(result)
310    return result;
311
312  result = Curl_bump_headersize(data, len, FALSE);
313  return result;
314}
315
316/*
317 * Hyper does not pass on the last empty response header. The libcurl API
318 * does. This function sends an empty header in the header callback.
319 */
320static CURLcode empty_header(struct Curl_easy *data)
321{
322  CURLcode result = Curl_http_size(data);
323  if(!result) {
324    result = hyper_each_header(data, NULL, 0, NULL, 0) ?
325      CURLE_WRITE_ERROR : CURLE_OK;
326    if(result)
327      failf(data, "hyperstream: couldn't pass blank header");
328    /* Hyper does chunked decoding itself. If it was added during
329     * response header processing, remove it again. */
330    Curl_cwriter_remove_by_name(data, "chunked");
331  }
332  return result;
333}
334
335CURLcode Curl_hyper_stream(struct Curl_easy *data,
336                           struct connectdata *conn,
337                           int *didwhat,
338                           bool *done,
339                           int select_res)
340{
341  hyper_response *resp = NULL;
342  uint16_t http_status;
343  int http_version;
344  hyper_headers *headers = NULL;
345  hyper_body *resp_body = NULL;
346  struct hyptransfer *h = &data->hyp;
347  hyper_task *task;
348  hyper_task *foreach;
349  const uint8_t *reasonp;
350  size_t reason_len;
351  CURLcode result = CURLE_OK;
352  struct SingleRequest *k = &data->req;
353  (void)conn;
354
355  if(k->exp100 > EXP100_SEND_DATA) {
356    struct curltime now = Curl_now();
357    timediff_t ms = Curl_timediff(now, k->start100);
358    if(ms >= data->set.expect_100_timeout) {
359      /* we've waited long enough, continue anyway */
360      k->exp100 = EXP100_SEND_DATA;
361      k->keepon |= KEEP_SEND;
362      Curl_expire_done(data, EXPIRE_100_TIMEOUT);
363      infof(data, "Done waiting for 100-continue");
364      if(data->hyp.exp100_waker) {
365        hyper_waker_wake(data->hyp.exp100_waker);
366        data->hyp.exp100_waker = NULL;
367      }
368    }
369  }
370
371  if(select_res & CURL_CSELECT_IN) {
372    if(h->read_waker)
373      hyper_waker_wake(h->read_waker);
374    h->read_waker = NULL;
375  }
376  if(select_res & CURL_CSELECT_OUT) {
377    if(h->write_waker)
378      hyper_waker_wake(h->write_waker);
379    h->write_waker = NULL;
380  }
381
382  *done = FALSE;
383  do {
384    hyper_task_return_type t;
385    task = hyper_executor_poll(h->exec);
386    if(!task) {
387      *didwhat = KEEP_RECV;
388      break;
389    }
390    t = hyper_task_type(task);
391    if(t == HYPER_TASK_ERROR) {
392      hyper_error *hypererr = hyper_task_value(task);
393      hyper_task_free(task);
394      if(data->state.hresult) {
395        /* override Hyper's view, might not even be an error */
396        result = data->state.hresult;
397        infof(data, "hyperstream is done (by early callback)");
398      }
399      else {
400        uint8_t errbuf[256];
401        size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
402        hyper_code code = hyper_error_code(hypererr);
403        failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
404        switch(code) {
405        case HYPERE_ABORTED_BY_CALLBACK:
406          result = CURLE_OK;
407          break;
408        case HYPERE_UNEXPECTED_EOF:
409          if(!data->req.bytecount)
410            result = CURLE_GOT_NOTHING;
411          else
412            result = CURLE_RECV_ERROR;
413          break;
414        case HYPERE_INVALID_PEER_MESSAGE:
415          /* bump headerbytecount to avoid the count remaining at zero and
416             appearing to not having read anything from the peer at all */
417          data->req.headerbytecount++;
418          result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */
419          break;
420        default:
421          result = CURLE_RECV_ERROR;
422          break;
423        }
424      }
425      *done = TRUE;
426      hyper_error_free(hypererr);
427      break;
428    }
429    else if(t == HYPER_TASK_EMPTY) {
430      void *userdata = hyper_task_userdata(task);
431      hyper_task_free(task);
432      if((userdata_t)userdata == USERDATA_RESP_BODY) {
433        /* end of transfer */
434        *done = TRUE;
435        infof(data, "hyperstream is done");
436        if(!k->bodywrites) {
437          /* hyper doesn't always call the body write callback */
438          bool stilldone;
439          result = Curl_http_firstwrite(data, data->conn, &stilldone);
440        }
441        break;
442      }
443      else {
444        /* A background task for hyper; ignore */
445        continue;
446      }
447    }
448
449    DEBUGASSERT(HYPER_TASK_RESPONSE);
450
451    resp = hyper_task_value(task);
452    hyper_task_free(task);
453
454    *didwhat = KEEP_RECV;
455    if(!resp) {
456      failf(data, "hyperstream: couldn't get response");
457      return CURLE_RECV_ERROR;
458    }
459
460    http_status = hyper_response_status(resp);
461    http_version = hyper_response_version(resp);
462    reasonp = hyper_response_reason_phrase(resp);
463    reason_len = hyper_response_reason_phrase_len(resp);
464
465    if(http_status == 417 && data->state.expect100header) {
466      infof(data, "Got 417 while waiting for a 100");
467      data->state.disableexpect = TRUE;
468      data->req.newurl = strdup(data->state.url);
469      Curl_done_sending(data, k);
470    }
471
472    result = status_line(data, conn,
473                         http_status, http_version, reasonp, reason_len);
474    if(result)
475      break;
476
477    headers = hyper_response_headers(resp);
478    if(!headers) {
479      failf(data, "hyperstream: couldn't get response headers");
480      result = CURLE_RECV_ERROR;
481      break;
482    }
483
484    /* the headers are already received */
485    hyper_headers_foreach(headers, hyper_each_header, data);
486    if(data->state.hresult) {
487      result = data->state.hresult;
488      break;
489    }
490
491    result = empty_header(data);
492    if(result)
493      break;
494
495    k->deductheadercount =
496      (100 <= http_status && 199 >= http_status)?k->headerbytecount:0;
497#ifdef USE_WEBSOCKETS
498    if(k->upgr101 == UPGR101_WS) {
499      if(http_status == 101) {
500        /* verify the response */
501        result = Curl_ws_accept(data, NULL, 0);
502        if(result)
503          return result;
504      }
505      else {
506        failf(data, "Expected 101, got %u", k->httpcode);
507        result = CURLE_HTTP_RETURNED_ERROR;
508        break;
509      }
510    }
511#endif
512
513    /* Curl_http_auth_act() checks what authentication methods that are
514     * available and decides which one (if any) to use. It will set 'newurl'
515     * if an auth method was picked. */
516    result = Curl_http_auth_act(data);
517    if(result)
518      break;
519
520    resp_body = hyper_response_body(resp);
521    if(!resp_body) {
522      failf(data, "hyperstream: couldn't get response body");
523      result = CURLE_RECV_ERROR;
524      break;
525    }
526    foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
527    if(!foreach) {
528      failf(data, "hyperstream: body foreach failed");
529      result = CURLE_OUT_OF_MEMORY;
530      break;
531    }
532    hyper_task_set_userdata(foreach, (void *)USERDATA_RESP_BODY);
533    if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
534      failf(data, "Couldn't hyper_executor_push the body-foreach");
535      result = CURLE_OUT_OF_MEMORY;
536      break;
537    }
538
539    hyper_response_free(resp);
540    resp = NULL;
541  } while(1);
542  if(resp)
543    hyper_response_free(resp);
544  return result;
545}
546
547static CURLcode debug_request(struct Curl_easy *data,
548                              const char *method,
549                              const char *path)
550{
551  char *req = aprintf("%s %s HTTP/1.1\r\n", method, path);
552  if(!req)
553    return CURLE_OUT_OF_MEMORY;
554  Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req));
555  free(req);
556  return CURLE_OK;
557}
558
559/*
560 * Given a full header line "name: value" (optional CRLF in the input, should
561 * be in the output), add to Hyper and send to the debug callback.
562 *
563 * Supports multiple headers.
564 */
565
566CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
567                           const char *line)
568{
569  const char *p;
570  const char *n;
571  size_t nlen;
572  const char *v;
573  size_t vlen;
574  bool newline = TRUE;
575  int numh = 0;
576
577  if(!line)
578    return CURLE_OK;
579  n = line;
580  do {
581    size_t linelen = 0;
582
583    p = strchr(n, ':');
584    if(!p)
585      /* this is fine if we already added at least one header */
586      return numh ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
587    nlen = p - n;
588    p++; /* move past the colon */
589    while(*p == ' ')
590      p++;
591    v = p;
592    p = strchr(v, '\r');
593    if(!p) {
594      p = strchr(v, '\n');
595      if(p)
596        linelen = 1; /* LF only */
597      else {
598        p = strchr(v, '\0');
599        newline = FALSE; /* no newline */
600      }
601    }
602    else
603      linelen = 2; /* CRLF ending */
604    linelen += (p - n);
605    vlen = p - v;
606
607    if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
608                                      (uint8_t *)v, vlen)) {
609      failf(data, "hyper refused to add header '%s'", line);
610      return CURLE_OUT_OF_MEMORY;
611    }
612    if(data->set.verbose) {
613      char *ptr = NULL;
614      if(!newline) {
615        ptr = aprintf("%.*s\r\n", (int)linelen, line);
616        if(!ptr)
617          return CURLE_OUT_OF_MEMORY;
618        Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2);
619        free(ptr);
620      }
621      else
622        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)n, linelen);
623    }
624    numh++;
625    n += linelen;
626  } while(newline);
627  return CURLE_OK;
628}
629
630static CURLcode request_target(struct Curl_easy *data,
631                               struct connectdata *conn,
632                               const char *method,
633                               hyper_request *req)
634{
635  CURLcode result;
636  struct dynbuf r;
637
638  Curl_dyn_init(&r, DYN_HTTP_REQUEST);
639
640  result = Curl_http_target(data, conn, &r);
641  if(result)
642    return result;
643
644  if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
645                                       Curl_dyn_len(&r))) {
646    failf(data, "error setting uri to hyper");
647    result = CURLE_OUT_OF_MEMORY;
648  }
649  else
650    result = debug_request(data, method, Curl_dyn_ptr(&r));
651
652  Curl_dyn_free(&r);
653
654  return result;
655}
656
657static int uploadpostfields(void *userdata, hyper_context *ctx,
658                            hyper_buf **chunk)
659{
660  struct Curl_easy *data = (struct Curl_easy *)userdata;
661  (void)ctx;
662  if(data->req.exp100 > EXP100_SEND_DATA) {
663    if(data->req.exp100 == EXP100_FAILED)
664      return HYPER_POLL_ERROR;
665
666    /* still waiting confirmation */
667    if(data->hyp.exp100_waker)
668      hyper_waker_free(data->hyp.exp100_waker);
669    data->hyp.exp100_waker = hyper_context_waker(ctx);
670    return HYPER_POLL_PENDING;
671  }
672  if(data->req.upload_done)
673    *chunk = NULL; /* nothing more to deliver */
674  else {
675    /* send everything off in a single go */
676    hyper_buf *copy = hyper_buf_copy(data->set.postfields,
677                                     (size_t)data->req.p.http->postsize);
678    if(copy)
679      *chunk = copy;
680    else {
681      data->state.hresult = CURLE_OUT_OF_MEMORY;
682      return HYPER_POLL_ERROR;
683    }
684    /* increasing the writebytecount here is a little premature but we
685       don't know exactly when the body is sent */
686    data->req.writebytecount += (size_t)data->req.p.http->postsize;
687    Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
688    data->req.upload_done = TRUE;
689  }
690  return HYPER_POLL_READY;
691}
692
693static int uploadstreamed(void *userdata, hyper_context *ctx,
694                          hyper_buf **chunk)
695{
696  size_t fillcount;
697  struct Curl_easy *data = (struct Curl_easy *)userdata;
698  struct connectdata *conn = (struct connectdata *)data->conn;
699  CURLcode result;
700  (void)ctx;
701
702  if(data->req.exp100 > EXP100_SEND_DATA) {
703    if(data->req.exp100 == EXP100_FAILED)
704      return HYPER_POLL_ERROR;
705
706    /* still waiting confirmation */
707    if(data->hyp.exp100_waker)
708      hyper_waker_free(data->hyp.exp100_waker);
709    data->hyp.exp100_waker = hyper_context_waker(ctx);
710    return HYPER_POLL_PENDING;
711  }
712
713  if(data->req.upload_chunky && conn->bits.authneg) {
714    fillcount = 0;
715    data->req.upload_chunky = FALSE;
716    result = CURLE_OK;
717  }
718  else {
719    result = Curl_fillreadbuffer(data, data->set.upload_buffer_size,
720                                 &fillcount);
721  }
722  if(result) {
723    data->state.hresult = result;
724    return HYPER_POLL_ERROR;
725  }
726  if(!fillcount) {
727    if((data->req.keepon & KEEP_SEND_PAUSE) != KEEP_SEND_PAUSE)
728      /* done! */
729      *chunk = NULL;
730    else {
731      /* paused, save a waker */
732      if(data->hyp.send_body_waker)
733        hyper_waker_free(data->hyp.send_body_waker);
734      data->hyp.send_body_waker = hyper_context_waker(ctx);
735      return HYPER_POLL_PENDING;
736    }
737  }
738  else {
739    hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
740    if(copy)
741      *chunk = copy;
742    else {
743      data->state.hresult = CURLE_OUT_OF_MEMORY;
744      return HYPER_POLL_ERROR;
745    }
746    /* increasing the writebytecount here is a little premature but we
747       don't know exactly when the body is sent */
748    data->req.writebytecount += fillcount;
749    Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
750  }
751  return HYPER_POLL_READY;
752}
753
754/*
755 * bodysend() sets up headers in the outgoing request for an HTTP transfer that
756 * sends a body
757 */
758
759static CURLcode bodysend(struct Curl_easy *data,
760                         struct connectdata *conn,
761                         hyper_headers *headers,
762                         hyper_request *hyperreq,
763                         Curl_HttpReq httpreq)
764{
765  struct HTTP *http = data->req.p.http;
766  CURLcode result = CURLE_OK;
767  struct dynbuf req;
768  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
769    Curl_pgrsSetUploadSize(data, 0); /* no request body */
770  else {
771    hyper_body *body;
772    Curl_dyn_init(&req, DYN_HTTP_REQUEST);
773    result = Curl_http_bodysend(data, conn, &req, httpreq);
774
775    if(!result)
776      result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
777
778    Curl_dyn_free(&req);
779
780    body = hyper_body_new();
781    hyper_body_set_userdata(body, data);
782    if(data->set.postfields)
783      hyper_body_set_data_func(body, uploadpostfields);
784    else {
785      result = Curl_get_upload_buffer(data);
786      if(result) {
787        hyper_body_free(body);
788        return result;
789      }
790      /* init the "upload from here" pointer */
791      data->req.upload_fromhere = data->state.ulbuf;
792      hyper_body_set_data_func(body, uploadstreamed);
793    }
794    if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
795      /* fail */
796      result = CURLE_OUT_OF_MEMORY;
797    }
798  }
799  http->sending = HTTPSEND_BODY;
800  return result;
801}
802
803static CURLcode cookies(struct Curl_easy *data,
804                        struct connectdata *conn,
805                        hyper_headers *headers)
806{
807  struct dynbuf req;
808  CURLcode result;
809  Curl_dyn_init(&req, DYN_HTTP_REQUEST);
810
811  result = Curl_http_cookies(data, conn, &req);
812  if(!result)
813    result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
814  Curl_dyn_free(&req);
815  return result;
816}
817
818/* called on 1xx responses */
819static void http1xx_cb(void *arg, struct hyper_response *resp)
820{
821  struct Curl_easy *data = (struct Curl_easy *)arg;
822  hyper_headers *headers = NULL;
823  CURLcode result = CURLE_OK;
824  uint16_t http_status;
825  int http_version;
826  const uint8_t *reasonp;
827  size_t reason_len;
828
829  infof(data, "Got HTTP 1xx informational");
830
831  http_status = hyper_response_status(resp);
832  http_version = hyper_response_version(resp);
833  reasonp = hyper_response_reason_phrase(resp);
834  reason_len = hyper_response_reason_phrase_len(resp);
835
836  result = status_line(data, data->conn,
837                       http_status, http_version, reasonp, reason_len);
838  if(!result) {
839    headers = hyper_response_headers(resp);
840    if(!headers) {
841      failf(data, "hyperstream: couldn't get 1xx response headers");
842      result = CURLE_RECV_ERROR;
843    }
844  }
845  data->state.hresult = result;
846
847  if(!result) {
848    /* the headers are already received */
849    hyper_headers_foreach(headers, hyper_each_header, data);
850    /* this callback also sets data->state.hresult on error */
851
852    if(empty_header(data))
853      result = CURLE_OUT_OF_MEMORY;
854  }
855
856  if(data->state.hresult)
857    infof(data, "ERROR in 1xx, bail out");
858}
859
860/*
861 * Curl_http() gets called from the generic multi_do() function when an HTTP
862 * request is to be performed. This creates and sends a properly constructed
863 * HTTP request.
864 */
865CURLcode Curl_http(struct Curl_easy *data, bool *done)
866{
867  struct connectdata *conn = data->conn;
868  struct hyptransfer *h = &data->hyp;
869  hyper_io *io = NULL;
870  hyper_clientconn_options *options = NULL;
871  hyper_task *task = NULL; /* for the handshake */
872  hyper_task *sendtask = NULL; /* for the send */
873  hyper_clientconn *client = NULL;
874  hyper_request *req = NULL;
875  hyper_headers *headers = NULL;
876  hyper_task *handshake = NULL;
877  CURLcode result;
878  const char *p_accept; /* Accept: string */
879  const char *method;
880  Curl_HttpReq httpreq;
881  const char *te = NULL; /* transfer-encoding */
882  hyper_code rc;
883
884  /* Always consider the DO phase done after this function call, even if there
885     may be parts of the request that is not yet sent, since we can deal with
886     the rest of the request in the PERFORM phase. */
887  *done = TRUE;
888  Curl_client_cleanup(data);
889
890  infof(data, "Time for the Hyper dance");
891  memset(h, 0, sizeof(struct hyptransfer));
892
893  result = Curl_http_host(data, conn);
894  if(result)
895    return result;
896
897  Curl_http_method(data, conn, &method, &httpreq);
898
899  DEBUGASSERT(data->req.bytecount ==  0);
900
901  /* setup the authentication headers */
902  {
903    char *pq = NULL;
904    if(data->state.up.query) {
905      pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
906      if(!pq)
907        return CURLE_OUT_OF_MEMORY;
908    }
909    result = Curl_http_output_auth(data, conn, method, httpreq,
910                                   (pq ? pq : data->state.up.path), FALSE);
911    free(pq);
912    if(result)
913      return result;
914  }
915
916  result = Curl_http_resume(data, conn, httpreq);
917  if(result)
918    return result;
919
920  result = Curl_http_range(data, httpreq);
921  if(result)
922    return result;
923
924  result = Curl_http_useragent(data);
925  if(result)
926    return result;
927
928  io = hyper_io_new();
929  if(!io) {
930    failf(data, "Couldn't create hyper IO");
931    result = CURLE_OUT_OF_MEMORY;
932    goto error;
933  }
934  /* tell Hyper how to read/write network data */
935  hyper_io_set_userdata(io, data);
936  hyper_io_set_read(io, Curl_hyper_recv);
937  hyper_io_set_write(io, Curl_hyper_send);
938
939  /* create an executor to poll futures */
940  if(!h->exec) {
941    h->exec = hyper_executor_new();
942    if(!h->exec) {
943      failf(data, "Couldn't create hyper executor");
944      result = CURLE_OUT_OF_MEMORY;
945      goto error;
946    }
947  }
948
949  options = hyper_clientconn_options_new();
950  if(!options) {
951    failf(data, "Couldn't create hyper client options");
952    result = CURLE_OUT_OF_MEMORY;
953    goto error;
954  }
955  if(conn->alpn == CURL_HTTP_VERSION_2) {
956    failf(data, "ALPN protocol h2 not supported with Hyper");
957    result = CURLE_UNSUPPORTED_PROTOCOL;
958    goto error;
959  }
960  hyper_clientconn_options_set_preserve_header_case(options, 1);
961  hyper_clientconn_options_set_preserve_header_order(options, 1);
962  hyper_clientconn_options_http1_allow_multiline_headers(options, 1);
963
964  hyper_clientconn_options_exec(options, h->exec);
965
966  /* "Both the `io` and the `options` are consumed in this function call" */
967  handshake = hyper_clientconn_handshake(io, options);
968  if(!handshake) {
969    failf(data, "Couldn't create hyper client handshake");
970    result = CURLE_OUT_OF_MEMORY;
971    goto error;
972  }
973  io = NULL;
974  options = NULL;
975
976  if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
977    failf(data, "Couldn't hyper_executor_push the handshake");
978    result = CURLE_OUT_OF_MEMORY;
979    goto error;
980  }
981  handshake = NULL; /* ownership passed on */
982
983  task = hyper_executor_poll(h->exec);
984  if(!task) {
985    failf(data, "Couldn't hyper_executor_poll the handshake");
986    result = CURLE_OUT_OF_MEMORY;
987    goto error;
988  }
989
990  client = hyper_task_value(task);
991  hyper_task_free(task);
992
993  req = hyper_request_new();
994  if(!req) {
995    failf(data, "Couldn't hyper_request_new");
996    result = CURLE_OUT_OF_MEMORY;
997    goto error;
998  }
999
1000  if(!Curl_use_http_1_1plus(data, conn)) {
1001    if(HYPERE_OK != hyper_request_set_version(req,
1002                                              HYPER_HTTP_VERSION_1_0)) {
1003      failf(data, "error setting HTTP version");
1004      result = CURLE_OUT_OF_MEMORY;
1005      goto error;
1006    }
1007  }
1008  else {
1009    if(!data->state.disableexpect) {
1010      data->state.expect100header = TRUE;
1011    }
1012  }
1013
1014  if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
1015    failf(data, "error setting method");
1016    result = CURLE_OUT_OF_MEMORY;
1017    goto error;
1018  }
1019
1020  result = request_target(data, conn, method, req);
1021  if(result)
1022    goto error;
1023
1024  headers = hyper_request_headers(req);
1025  if(!headers) {
1026    failf(data, "hyper_request_headers");
1027    result = CURLE_OUT_OF_MEMORY;
1028    goto error;
1029  }
1030
1031  rc = hyper_request_on_informational(req, http1xx_cb, data);
1032  if(rc) {
1033    result = CURLE_OUT_OF_MEMORY;
1034    goto error;
1035  }
1036
1037  result = Curl_http_body(data, conn, httpreq, &te);
1038  if(result)
1039    goto error;
1040
1041  if(data->state.aptr.host) {
1042    result = Curl_hyper_header(data, headers, data->state.aptr.host);
1043    if(result)
1044      goto error;
1045  }
1046
1047  if(data->state.aptr.proxyuserpwd) {
1048    result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
1049    if(result)
1050      goto error;
1051  }
1052
1053  if(data->state.aptr.userpwd) {
1054    result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
1055    if(result)
1056      goto error;
1057  }
1058
1059  if((data->state.use_range && data->state.aptr.rangeline)) {
1060    result = Curl_hyper_header(data, headers, data->state.aptr.rangeline);
1061    if(result)
1062      goto error;
1063  }
1064
1065  if(data->set.str[STRING_USERAGENT] &&
1066     *data->set.str[STRING_USERAGENT] &&
1067     data->state.aptr.uagent) {
1068    result = Curl_hyper_header(data, headers, data->state.aptr.uagent);
1069    if(result)
1070      goto error;
1071  }
1072
1073  p_accept = Curl_checkheaders(data,
1074                               STRCONST("Accept"))?NULL:"Accept: */*\r\n";
1075  if(p_accept) {
1076    result = Curl_hyper_header(data, headers, p_accept);
1077    if(result)
1078      goto error;
1079  }
1080  if(te) {
1081    result = Curl_hyper_header(data, headers, te);
1082    if(result)
1083      goto error;
1084  }
1085
1086#ifndef CURL_DISABLE_ALTSVC
1087  if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) {
1088    char *altused = aprintf("Alt-Used: %s:%d\r\n",
1089                            conn->conn_to_host.name, conn->conn_to_port);
1090    if(!altused) {
1091      result = CURLE_OUT_OF_MEMORY;
1092      goto error;
1093    }
1094    result = Curl_hyper_header(data, headers, altused);
1095    if(result)
1096      goto error;
1097    free(altused);
1098  }
1099#endif
1100
1101#ifndef CURL_DISABLE_PROXY
1102  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
1103     !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
1104     !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
1105    result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive");
1106    if(result)
1107      goto error;
1108  }
1109#endif
1110
1111  Curl_safefree(data->state.aptr.ref);
1112  if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) {
1113    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
1114    if(!data->state.aptr.ref)
1115      result = CURLE_OUT_OF_MEMORY;
1116    else
1117      result = Curl_hyper_header(data, headers, data->state.aptr.ref);
1118    if(result)
1119      goto error;
1120  }
1121
1122#ifdef HAVE_LIBZ
1123  /* we only consider transfer-encoding magic if libz support is built-in */
1124  result = Curl_transferencode(data);
1125  if(result)
1126    goto error;
1127  result = Curl_hyper_header(data, headers, data->state.aptr.te);
1128  if(result)
1129    goto error;
1130#endif
1131
1132  if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
1133     data->set.str[STRING_ENCODING]) {
1134    Curl_safefree(data->state.aptr.accept_encoding);
1135    data->state.aptr.accept_encoding =
1136      aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
1137    if(!data->state.aptr.accept_encoding)
1138      result = CURLE_OUT_OF_MEMORY;
1139    else
1140      result = Curl_hyper_header(data, headers,
1141                                 data->state.aptr.accept_encoding);
1142    if(result)
1143      goto error;
1144  }
1145  else
1146    Curl_safefree(data->state.aptr.accept_encoding);
1147
1148  result = cookies(data, conn, headers);
1149  if(result)
1150    goto error;
1151
1152  if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
1153    result = Curl_ws_request(data, headers);
1154
1155  result = Curl_add_timecondition(data, headers);
1156  if(result)
1157    goto error;
1158
1159  result = Curl_add_custom_headers(data, FALSE, headers);
1160  if(result)
1161    goto error;
1162
1163  result = bodysend(data, conn, headers, req, httpreq);
1164  if(result)
1165    goto error;
1166
1167  Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
1168
1169  if(data->req.upload_chunky && conn->bits.authneg) {
1170    data->req.upload_chunky = TRUE;
1171  }
1172  else {
1173    data->req.upload_chunky = FALSE;
1174  }
1175  sendtask = hyper_clientconn_send(client, req);
1176  if(!sendtask) {
1177    failf(data, "hyper_clientconn_send");
1178    result = CURLE_OUT_OF_MEMORY;
1179    goto error;
1180  }
1181  req = NULL;
1182
1183  if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
1184    failf(data, "Couldn't hyper_executor_push the send");
1185    result = CURLE_OUT_OF_MEMORY;
1186    goto error;
1187  }
1188  sendtask = NULL; /* ownership passed on */
1189
1190  hyper_clientconn_free(client);
1191  client = NULL;
1192
1193  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
1194    /* HTTP GET/HEAD download */
1195    Curl_pgrsSetUploadSize(data, 0); /* nothing */
1196    Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
1197  }
1198  conn->datastream = Curl_hyper_stream;
1199  if(data->state.expect100header)
1200    /* Timeout count starts now since with Hyper we don't know exactly when
1201       the full request has been sent. */
1202    data->req.start100 = Curl_now();
1203
1204  /* clear userpwd and proxyuserpwd to avoid reusing old credentials
1205   * from reused connections */
1206  Curl_safefree(data->state.aptr.userpwd);
1207  Curl_safefree(data->state.aptr.proxyuserpwd);
1208  return CURLE_OK;
1209error:
1210  DEBUGASSERT(result);
1211  if(io)
1212    hyper_io_free(io);
1213
1214  if(options)
1215    hyper_clientconn_options_free(options);
1216
1217  if(handshake)
1218    hyper_task_free(handshake);
1219
1220  if(client)
1221    hyper_clientconn_free(client);
1222
1223  if(req)
1224    hyper_request_free(req);
1225
1226  return result;
1227}
1228
1229void Curl_hyper_done(struct Curl_easy *data)
1230{
1231  struct hyptransfer *h = &data->hyp;
1232  if(h->exec) {
1233    hyper_executor_free(h->exec);
1234    h->exec = NULL;
1235  }
1236  if(h->read_waker) {
1237    hyper_waker_free(h->read_waker);
1238    h->read_waker = NULL;
1239  }
1240  if(h->write_waker) {
1241    hyper_waker_free(h->write_waker);
1242    h->write_waker = NULL;
1243  }
1244  if(h->exp100_waker) {
1245    hyper_waker_free(h->exp100_waker);
1246    h->exp100_waker = NULL;
1247  }
1248}
1249
1250#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
1251