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