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 
68 typedef enum {
69     USERDATA_NOT_SET = 0, /* for tasks with no userdata set; must be zero */
70     USERDATA_RESP_BODY
71 } userdata_t;
72 
Curl_hyper_recv(void *userp, hyper_context *ctx, uint8_t *buf, size_t buflen)73 size_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 
Curl_hyper_send(void *userp, hyper_context *ctx, const uint8_t *buf, size_t buflen)105 size_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 
hyper_each_header(void *userdata, const uint8_t *name, size_t name_len, const uint8_t *value, size_t value_len)137 static 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 
hyper_body_chunk(void *userdata, const hyper_buf *chunk)198 static 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. */
status_line(struct Curl_easy *data, struct connectdata *conn, uint16_t http_status, int http_version, const uint8_t *reason, size_t rlen)260 static 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  */
empty_header(struct Curl_easy *data)320 static 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 
Curl_hyper_stream(struct Curl_easy *data, struct connectdata *conn, int *didwhat, bool *done, int select_res)335 CURLcode 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 
debug_request(struct Curl_easy *data, const char *method, const char *path)547 static 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 
Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers, const char *line)566 CURLcode 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 
request_target(struct Curl_easy *data, struct connectdata *conn, const char *method, hyper_request *req)630 static 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 
uploadpostfields(void *userdata, hyper_context *ctx, hyper_buf **chunk)657 static 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 
uploadstreamed(void *userdata, hyper_context *ctx, hyper_buf **chunk)693 static 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 
bodysend(struct Curl_easy *data, struct connectdata *conn, hyper_headers *headers, hyper_request *hyperreq, Curl_HttpReq httpreq)759 static 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 
cookies(struct Curl_easy *data, struct connectdata *conn, hyper_headers *headers)803 static 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 */
http1xx_cb(void *arg, struct hyper_response *resp)819 static 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  */
Curl_http(struct Curl_easy *data, bool *done)865 CURLcode 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;
1209 error:
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 
Curl_hyper_done(struct Curl_easy *data)1229 void 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