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