• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2021, 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 
Curl_hyper_recv(void * userp,hyper_context * ctx,uint8_t * buf,size_t buflen)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 
Curl_hyper_send(void * userp,hyper_context * ctx,const uint8_t * buf,size_t buflen)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 
hyper_each_header(void * userdata,const uint8_t * name,size_t name_len,const uint8_t * value,size_t value_len)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_add(&data->state.headerb, "\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 
hyper_body_chunk(void * userdata,const hyper_buf * chunk)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. */
status_line(struct Curl_easy * data,struct connectdata * conn,uint16_t http_status,int http_version,const uint8_t * reason,size_t rlen)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       data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
298       return HYPER_ITER_BREAK;
299     }
300   }
301   data->info.header_size += (long)len;
302   data->req.headerbytecount += (long)len;
303   data->req.httpcode = http_status;
304   return CURLE_OK;
305 }
306 
307 /*
308  * Hyper does not pass on the last empty response header. The libcurl API
309  * does. This function sends an empty header in the header callback.
310  */
empty_header(struct Curl_easy * data)311 static CURLcode empty_header(struct Curl_easy *data)
312 {
313   CURLcode result = Curl_http_size(data);
314   if(!result) {
315     result = hyper_each_header(data, NULL, 0, NULL, 0) ?
316       CURLE_WRITE_ERROR : CURLE_OK;
317     if(result)
318       failf(data, "hyperstream: couldn't pass blank header");
319   }
320   return result;
321 }
322 
Curl_hyper_stream(struct Curl_easy * data,struct connectdata * conn,int * didwhat,bool * done,int select_res)323 CURLcode Curl_hyper_stream(struct Curl_easy *data,
324                            struct connectdata *conn,
325                            int *didwhat,
326                            bool *done,
327                            int select_res)
328 {
329   hyper_response *resp = NULL;
330   uint16_t http_status;
331   int http_version;
332   hyper_headers *headers = NULL;
333   hyper_body *resp_body = NULL;
334   struct hyptransfer *h = &data->hyp;
335   hyper_task *task;
336   hyper_task *foreach;
337   hyper_error *hypererr = NULL;
338   const uint8_t *reasonp;
339   size_t reason_len;
340   CURLcode result = CURLE_OK;
341   struct SingleRequest *k = &data->req;
342   (void)conn;
343 
344   if(k->exp100 > EXP100_SEND_DATA) {
345     struct curltime now = Curl_now();
346     timediff_t ms = Curl_timediff(now, k->start100);
347     if(ms >= data->set.expect_100_timeout) {
348       /* we've waited long enough, continue anyway */
349       k->exp100 = EXP100_SEND_DATA;
350       k->keepon |= KEEP_SEND;
351       Curl_expire_done(data, EXPIRE_100_TIMEOUT);
352       infof(data, "Done waiting for 100-continue");
353       if(data->hyp.exp100_waker) {
354         hyper_waker_wake(data->hyp.exp100_waker);
355         data->hyp.exp100_waker = NULL;
356       }
357     }
358   }
359 
360   if(select_res & CURL_CSELECT_IN) {
361     if(h->read_waker)
362       hyper_waker_wake(h->read_waker);
363     h->read_waker = NULL;
364   }
365   if(select_res & CURL_CSELECT_OUT) {
366     if(h->write_waker)
367       hyper_waker_wake(h->write_waker);
368     h->write_waker = NULL;
369   }
370 
371   *done = FALSE;
372   do {
373     hyper_task_return_type t;
374     task = hyper_executor_poll(h->exec);
375     if(!task) {
376       *didwhat = KEEP_RECV;
377       break;
378     }
379     t = hyper_task_type(task);
380     switch(t) {
381     case HYPER_TASK_ERROR:
382       hypererr = hyper_task_value(task);
383       break;
384     case HYPER_TASK_RESPONSE:
385       resp = hyper_task_value(task);
386       break;
387     default:
388       break;
389     }
390     hyper_task_free(task);
391 
392     if(t == HYPER_TASK_ERROR) {
393       if(data->state.hresult) {
394         /* override Hyper's view, might not even be an error */
395         result = data->state.hresult;
396         infof(data, "hyperstream is done (by early callback)");
397       }
398       else {
399         uint8_t errbuf[256];
400         size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
401         hyper_code code = hyper_error_code(hypererr);
402         failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
403         if(code == HYPERE_ABORTED_BY_CALLBACK)
404           result = CURLE_OK;
405         else if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount)
406           result = CURLE_GOT_NOTHING;
407         else if(code == HYPERE_INVALID_PEER_MESSAGE)
408           result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */
409         else
410           result = CURLE_RECV_ERROR;
411       }
412       *done = TRUE;
413       hyper_error_free(hypererr);
414       break;
415     }
416     else if(h->endtask == task) {
417       /* end of transfer */
418       *done = TRUE;
419       infof(data, "hyperstream is done!");
420       if(!k->bodywrites) {
421         /* hyper doesn't always call the body write callback */
422         bool stilldone;
423         result = Curl_http_firstwrite(data, data->conn, &stilldone);
424       }
425       break;
426     }
427     else if(t != HYPER_TASK_RESPONSE) {
428       *didwhat = KEEP_RECV;
429       break;
430     }
431     /* HYPER_TASK_RESPONSE */
432 
433     *didwhat = KEEP_RECV;
434     if(!resp) {
435       failf(data, "hyperstream: couldn't get response");
436       return CURLE_RECV_ERROR;
437     }
438 
439     http_status = hyper_response_status(resp);
440     http_version = hyper_response_version(resp);
441     reasonp = hyper_response_reason_phrase(resp);
442     reason_len = hyper_response_reason_phrase_len(resp);
443 
444     result = status_line(data, conn,
445                          http_status, http_version, reasonp, reason_len);
446     if(result)
447       break;
448 
449     headers = hyper_response_headers(resp);
450     if(!headers) {
451       failf(data, "hyperstream: couldn't get response headers");
452       result = CURLE_RECV_ERROR;
453       break;
454     }
455 
456     /* the headers are already received */
457     hyper_headers_foreach(headers, hyper_each_header, data);
458     if(data->state.hresult) {
459       result = data->state.hresult;
460       break;
461     }
462 
463     result = empty_header(data);
464     if(result)
465       break;
466 
467     /* Curl_http_auth_act() checks what authentication methods that are
468      * available and decides which one (if any) to use. It will set 'newurl'
469      * if an auth method was picked. */
470     result = Curl_http_auth_act(data);
471     if(result)
472       break;
473 
474     resp_body = hyper_response_body(resp);
475     if(!resp_body) {
476       failf(data, "hyperstream: couldn't get response body");
477       result = CURLE_RECV_ERROR;
478       break;
479     }
480     foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
481     if(!foreach) {
482       failf(data, "hyperstream: body foreach failed");
483       result = CURLE_OUT_OF_MEMORY;
484       break;
485     }
486     DEBUGASSERT(hyper_task_type(foreach) == HYPER_TASK_EMPTY);
487     if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
488       failf(data, "Couldn't hyper_executor_push the body-foreach");
489       result = CURLE_OUT_OF_MEMORY;
490       break;
491     }
492     h->endtask = foreach;
493 
494     hyper_response_free(resp);
495     resp = NULL;
496   } while(1);
497   if(resp)
498     hyper_response_free(resp);
499   return result;
500 }
501 
debug_request(struct Curl_easy * data,const char * method,const char * path,bool h2)502 static CURLcode debug_request(struct Curl_easy *data,
503                               const char *method,
504                               const char *path,
505                               bool h2)
506 {
507   char *req = aprintf("%s %s HTTP/%s\r\n", method, path,
508                       h2?"2":"1.1");
509   if(!req)
510     return CURLE_OUT_OF_MEMORY;
511   Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req));
512   free(req);
513   return CURLE_OK;
514 }
515 
516 /*
517  * Given a full header line "name: value" (optional CRLF in the input, should
518  * be in the output), add to Hyper and send to the debug callback.
519  *
520  * Supports multiple headers.
521  */
522 
Curl_hyper_header(struct Curl_easy * data,hyper_headers * headers,const char * line)523 CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
524                            const char *line)
525 {
526   const char *p;
527   const char *n;
528   size_t nlen;
529   const char *v;
530   size_t vlen;
531   bool newline = TRUE;
532   int numh = 0;
533 
534   if(!line)
535     return CURLE_OK;
536   n = line;
537   do {
538     size_t linelen = 0;
539 
540     p = strchr(n, ':');
541     if(!p)
542       /* this is fine if we already added at least one header */
543       return numh ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
544     nlen = p - n;
545     p++; /* move past the colon */
546     while(*p == ' ')
547       p++;
548     v = p;
549     p = strchr(v, '\r');
550     if(!p) {
551       p = strchr(v, '\n');
552       if(p)
553         linelen = 1; /* LF only */
554       else {
555         p = strchr(v, '\0');
556         newline = FALSE; /* no newline */
557       }
558     }
559     else
560       linelen = 2; /* CRLF ending */
561     linelen += (p - n);
562     vlen = p - v;
563 
564     if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
565                                       (uint8_t *)v, vlen)) {
566       failf(data, "hyper refused to add header '%s'", line);
567       return CURLE_OUT_OF_MEMORY;
568     }
569     if(data->set.verbose) {
570       char *ptr = NULL;
571       if(!newline) {
572         ptr = aprintf("%.*s\r\n", (int)linelen, line);
573         if(!ptr)
574           return CURLE_OUT_OF_MEMORY;
575         Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2);
576         free(ptr);
577       }
578       else
579         Curl_debug(data, CURLINFO_HEADER_OUT, (char *)n, linelen);
580     }
581     numh++;
582     n += linelen;
583   } while(newline);
584   return CURLE_OK;
585 }
586 
request_target(struct Curl_easy * data,struct connectdata * conn,const char * method,bool h2,hyper_request * req)587 static CURLcode request_target(struct Curl_easy *data,
588                                struct connectdata *conn,
589                                const char *method,
590                                bool h2,
591                                hyper_request *req)
592 {
593   CURLcode result;
594   struct dynbuf r;
595 
596   Curl_dyn_init(&r, DYN_HTTP_REQUEST);
597 
598   result = Curl_http_target(data, conn, &r);
599   if(result)
600     return result;
601 
602   if(h2 && hyper_request_set_uri_parts(req,
603                                        /* scheme */
604                                        (uint8_t *)data->state.up.scheme,
605                                        strlen(data->state.up.scheme),
606                                        /* authority */
607                                        (uint8_t *)conn->host.name,
608                                        strlen(conn->host.name),
609                                        /* path_and_query */
610                                        (uint8_t *)Curl_dyn_uptr(&r),
611                                        Curl_dyn_len(&r))) {
612     failf(data, "error setting uri parts to hyper");
613     result = CURLE_OUT_OF_MEMORY;
614   }
615   else if(!h2 && hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
616                                        Curl_dyn_len(&r))) {
617     failf(data, "error setting uri to hyper");
618     result = CURLE_OUT_OF_MEMORY;
619   }
620   else
621     result = debug_request(data, method, Curl_dyn_ptr(&r), h2);
622 
623   Curl_dyn_free(&r);
624 
625   return result;
626 }
627 
uploadpostfields(void * userdata,hyper_context * ctx,hyper_buf ** chunk)628 static int uploadpostfields(void *userdata, hyper_context *ctx,
629                             hyper_buf **chunk)
630 {
631   struct Curl_easy *data = (struct Curl_easy *)userdata;
632   (void)ctx;
633   if(data->req.exp100 > EXP100_SEND_DATA) {
634     if(data->req.exp100 == EXP100_FAILED)
635       return HYPER_POLL_ERROR;
636 
637     /* still waiting confirmation */
638     if(data->hyp.exp100_waker)
639       hyper_waker_free(data->hyp.exp100_waker);
640     data->hyp.exp100_waker = hyper_context_waker(ctx);
641     return HYPER_POLL_PENDING;
642   }
643   if(data->req.upload_done)
644     *chunk = NULL; /* nothing more to deliver */
645   else {
646     /* send everything off in a single go */
647     hyper_buf *copy = hyper_buf_copy(data->set.postfields,
648                                      (size_t)data->req.p.http->postsize);
649     if(copy)
650       *chunk = copy;
651     else {
652       data->state.hresult = CURLE_OUT_OF_MEMORY;
653       return HYPER_POLL_ERROR;
654     }
655     /* increasing the writebytecount here is a little premature but we
656        don't know exactly when the body is sent*/
657     data->req.writebytecount += (size_t)data->req.p.http->postsize;
658     Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
659     data->req.upload_done = TRUE;
660   }
661   return HYPER_POLL_READY;
662 }
663 
uploadstreamed(void * userdata,hyper_context * ctx,hyper_buf ** chunk)664 static int uploadstreamed(void *userdata, hyper_context *ctx,
665                           hyper_buf **chunk)
666 {
667   size_t fillcount;
668   struct Curl_easy *data = (struct Curl_easy *)userdata;
669   CURLcode result;
670   (void)ctx;
671 
672   if(data->req.exp100 > EXP100_SEND_DATA) {
673     if(data->req.exp100 == EXP100_FAILED)
674       return HYPER_POLL_ERROR;
675 
676     /* still waiting confirmation */
677     if(data->hyp.exp100_waker)
678       hyper_waker_free(data->hyp.exp100_waker);
679     data->hyp.exp100_waker = hyper_context_waker(ctx);
680     return HYPER_POLL_PENDING;
681   }
682 
683   result = Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount);
684   if(result) {
685     data->state.hresult = result;
686     return HYPER_POLL_ERROR;
687   }
688   if(!fillcount)
689     /* done! */
690     *chunk = NULL;
691   else {
692     hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
693     if(copy)
694       *chunk = copy;
695     else {
696       data->state.hresult = CURLE_OUT_OF_MEMORY;
697       return HYPER_POLL_ERROR;
698     }
699     /* increasing the writebytecount here is a little premature but we
700        don't know exactly when the body is sent*/
701     data->req.writebytecount += fillcount;
702     Curl_pgrsSetUploadCounter(data, fillcount);
703   }
704   return HYPER_POLL_READY;
705 }
706 
707 /*
708  * bodysend() sets up headers in the outgoing request for a HTTP transfer that
709  * sends a body
710  */
711 
bodysend(struct Curl_easy * data,struct connectdata * conn,hyper_headers * headers,hyper_request * hyperreq,Curl_HttpReq httpreq)712 static CURLcode bodysend(struct Curl_easy *data,
713                          struct connectdata *conn,
714                          hyper_headers *headers,
715                          hyper_request *hyperreq,
716                          Curl_HttpReq httpreq)
717 {
718   struct HTTP *http = data->req.p.http;
719   CURLcode result = CURLE_OK;
720   struct dynbuf req;
721   if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
722     Curl_pgrsSetUploadSize(data, 0); /* no request body */
723   else {
724     hyper_body *body;
725     Curl_dyn_init(&req, DYN_HTTP_REQUEST);
726     result = Curl_http_bodysend(data, conn, &req, httpreq);
727 
728     if(!result)
729       result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
730 
731     Curl_dyn_free(&req);
732 
733     body = hyper_body_new();
734     hyper_body_set_userdata(body, data);
735     if(data->set.postfields)
736       hyper_body_set_data_func(body, uploadpostfields);
737     else {
738       result = Curl_get_upload_buffer(data);
739       if(result)
740         return result;
741       /* init the "upload from here" pointer */
742       data->req.upload_fromhere = data->state.ulbuf;
743       hyper_body_set_data_func(body, uploadstreamed);
744     }
745     if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
746       /* fail */
747       hyper_body_free(body);
748       result = CURLE_OUT_OF_MEMORY;
749     }
750   }
751   http->sending = HTTPSEND_BODY;
752   return result;
753 }
754 
cookies(struct Curl_easy * data,struct connectdata * conn,hyper_headers * headers)755 static CURLcode cookies(struct Curl_easy *data,
756                         struct connectdata *conn,
757                         hyper_headers *headers)
758 {
759   struct dynbuf req;
760   CURLcode result;
761   Curl_dyn_init(&req, DYN_HTTP_REQUEST);
762 
763   result = Curl_http_cookies(data, conn, &req);
764   if(!result)
765     result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
766   Curl_dyn_free(&req);
767   return result;
768 }
769 
770 /* called on 1xx responses */
http1xx_cb(void * arg,struct hyper_response * resp)771 static void http1xx_cb(void *arg, struct hyper_response *resp)
772 {
773   struct Curl_easy *data = (struct Curl_easy *)arg;
774   hyper_headers *headers = NULL;
775   CURLcode result = CURLE_OK;
776   uint16_t http_status;
777   int http_version;
778   const uint8_t *reasonp;
779   size_t reason_len;
780 
781   infof(data, "Got HTTP 1xx informational");
782 
783   http_status = hyper_response_status(resp);
784   http_version = hyper_response_version(resp);
785   reasonp = hyper_response_reason_phrase(resp);
786   reason_len = hyper_response_reason_phrase_len(resp);
787 
788   result = status_line(data, data->conn,
789                        http_status, http_version, reasonp, reason_len);
790   if(!result) {
791     headers = hyper_response_headers(resp);
792     if(!headers) {
793       failf(data, "hyperstream: couldn't get 1xx response headers");
794       result = CURLE_RECV_ERROR;
795     }
796   }
797   data->state.hresult = result;
798 
799   if(!result) {
800     /* the headers are already received */
801     hyper_headers_foreach(headers, hyper_each_header, data);
802     /* this callback also sets data->state.hresult on error */
803 
804     if(empty_header(data))
805       result = CURLE_OUT_OF_MEMORY;
806   }
807 
808   if(data->state.hresult)
809     infof(data, "ERROR in 1xx, bail out!");
810 }
811 
812 /*
813  * Curl_http() gets called from the generic multi_do() function when a HTTP
814  * request is to be performed. This creates and sends a properly constructed
815  * HTTP request.
816  */
Curl_http(struct Curl_easy * data,bool * done)817 CURLcode Curl_http(struct Curl_easy *data, bool *done)
818 {
819   struct connectdata *conn = data->conn;
820   struct hyptransfer *h = &data->hyp;
821   hyper_io *io = NULL;
822   hyper_clientconn_options *options = NULL;
823   hyper_task *task = NULL; /* for the handshake */
824   hyper_task *sendtask = NULL; /* for the send */
825   hyper_clientconn *client = NULL;
826   hyper_request *req = NULL;
827   hyper_headers *headers = NULL;
828   hyper_task *handshake = NULL;
829   CURLcode result;
830   const char *p_accept; /* Accept: string */
831   const char *method;
832   Curl_HttpReq httpreq;
833   bool h2 = FALSE;
834   const char *te = NULL; /* transfer-encoding */
835   hyper_code rc;
836 
837   /* Always consider the DO phase done after this function call, even if there
838      may be parts of the request that is not yet sent, since we can deal with
839      the rest of the request in the PERFORM phase. */
840   *done = TRUE;
841 
842   infof(data, "Time for the Hyper dance");
843   memset(h, 0, sizeof(struct hyptransfer));
844 
845   result = Curl_http_host(data, conn);
846   if(result)
847     return result;
848 
849   Curl_http_method(data, conn, &method, &httpreq);
850 
851   /* setup the authentication headers */
852   {
853     char *pq = NULL;
854     if(data->state.up.query) {
855       pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
856       if(!pq)
857         return CURLE_OUT_OF_MEMORY;
858     }
859     result = Curl_http_output_auth(data, conn, method, httpreq,
860                                    (pq ? pq : data->state.up.path), FALSE);
861     free(pq);
862     if(result)
863       return result;
864   }
865 
866   result = Curl_http_resume(data, conn, httpreq);
867   if(result)
868     return result;
869 
870   result = Curl_http_range(data, httpreq);
871   if(result)
872     return result;
873 
874   result = Curl_http_useragent(data);
875   if(result)
876     return result;
877 
878   io = hyper_io_new();
879   if(!io) {
880     failf(data, "Couldn't create hyper IO");
881     result = CURLE_OUT_OF_MEMORY;
882     goto error;
883   }
884   /* tell Hyper how to read/write network data */
885   hyper_io_set_userdata(io, data);
886   hyper_io_set_read(io, Curl_hyper_recv);
887   hyper_io_set_write(io, Curl_hyper_send);
888 
889   /* create an executor to poll futures */
890   if(!h->exec) {
891     h->exec = hyper_executor_new();
892     if(!h->exec) {
893       failf(data, "Couldn't create hyper executor");
894       result = CURLE_OUT_OF_MEMORY;
895       goto error;
896     }
897   }
898 
899   options = hyper_clientconn_options_new();
900   if(!options) {
901     failf(data, "Couldn't create hyper client options");
902     result = CURLE_OUT_OF_MEMORY;
903     goto error;
904   }
905   if(conn->negnpn == CURL_HTTP_VERSION_2) {
906     hyper_clientconn_options_http2(options, 1);
907     h2 = TRUE;
908   }
909 
910   hyper_clientconn_options_exec(options, h->exec);
911 
912   /* "Both the `io` and the `options` are consumed in this function call" */
913   handshake = hyper_clientconn_handshake(io, options);
914   if(!handshake) {
915     failf(data, "Couldn't create hyper client handshake");
916     result = CURLE_OUT_OF_MEMORY;
917     goto error;
918   }
919   io = NULL;
920   options = NULL;
921 
922   if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
923     failf(data, "Couldn't hyper_executor_push the handshake");
924     result = CURLE_OUT_OF_MEMORY;
925     goto error;
926   }
927   handshake = NULL; /* ownership passed on */
928 
929   task = hyper_executor_poll(h->exec);
930   if(!task) {
931     failf(data, "Couldn't hyper_executor_poll the handshake");
932     result = CURLE_OUT_OF_MEMORY;
933     goto error;
934   }
935 
936   client = hyper_task_value(task);
937   hyper_task_free(task);
938 
939   req = hyper_request_new();
940   if(!req) {
941     failf(data, "Couldn't hyper_request_new");
942     result = CURLE_OUT_OF_MEMORY;
943     goto error;
944   }
945 
946   if(!Curl_use_http_1_1plus(data, conn)) {
947     if(HYPERE_OK != hyper_request_set_version(req,
948                                               HYPER_HTTP_VERSION_1_0)) {
949       failf(data, "error setting HTTP version");
950       result = CURLE_OUT_OF_MEMORY;
951       goto error;
952     }
953   }
954 
955   if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
956     failf(data, "error setting method");
957     result = CURLE_OUT_OF_MEMORY;
958     goto error;
959   }
960 
961   result = request_target(data, conn, method, h2, req);
962   if(result)
963     goto error;
964 
965   headers = hyper_request_headers(req);
966   if(!headers) {
967     failf(data, "hyper_request_headers");
968     result = CURLE_OUT_OF_MEMORY;
969     goto error;
970   }
971 
972   rc = hyper_request_on_informational(req, http1xx_cb, data);
973   if(rc) {
974     result = CURLE_OUT_OF_MEMORY;
975     goto error;
976   }
977 
978   result = Curl_http_body(data, conn, httpreq, &te);
979   if(result)
980     goto error;
981 
982   if(!h2) {
983     if(data->state.aptr.host) {
984       result = Curl_hyper_header(data, headers, data->state.aptr.host);
985       if(result)
986         goto error;
987     }
988   }
989   else {
990     /* For HTTP/2, we show the Host: header as if we sent it, to make it look
991        like for HTTP/1 but it isn't actually sent since :authority is then
992        used. */
993     result = Curl_debug(data, CURLINFO_HEADER_OUT, data->state.aptr.host,
994                         strlen(data->state.aptr.host));
995     if(result)
996       goto error;
997   }
998 
999   if(data->state.aptr.proxyuserpwd) {
1000     result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
1001     if(result)
1002       goto error;
1003   }
1004 
1005   if(data->state.aptr.userpwd) {
1006     result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
1007     if(result)
1008       goto error;
1009   }
1010 
1011   if((data->state.use_range && data->state.aptr.rangeline)) {
1012     result = Curl_hyper_header(data, headers, data->state.aptr.rangeline);
1013     if(result)
1014       goto error;
1015   }
1016 
1017   if(data->set.str[STRING_USERAGENT] &&
1018      *data->set.str[STRING_USERAGENT] &&
1019      data->state.aptr.uagent) {
1020     result = Curl_hyper_header(data, headers, data->state.aptr.uagent);
1021     if(result)
1022       goto error;
1023   }
1024 
1025   p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
1026   if(p_accept) {
1027     result = Curl_hyper_header(data, headers, p_accept);
1028     if(result)
1029       goto error;
1030   }
1031   if(te) {
1032     result = Curl_hyper_header(data, headers, te);
1033     if(result)
1034       goto error;
1035   }
1036 
1037 #ifndef CURL_DISABLE_PROXY
1038   if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
1039      !Curl_checkheaders(data, "Proxy-Connection") &&
1040      !Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
1041     result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive");
1042     if(result)
1043       goto error;
1044   }
1045 #endif
1046 
1047   Curl_safefree(data->state.aptr.ref);
1048   if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
1049     data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
1050     if(!data->state.aptr.ref)
1051       result = CURLE_OUT_OF_MEMORY;
1052     else
1053       result = Curl_hyper_header(data, headers, data->state.aptr.ref);
1054     if(result)
1055       goto error;
1056   }
1057 
1058   if(!Curl_checkheaders(data, "Accept-Encoding") &&
1059      data->set.str[STRING_ENCODING]) {
1060     Curl_safefree(data->state.aptr.accept_encoding);
1061     data->state.aptr.accept_encoding =
1062       aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
1063     if(!data->state.aptr.accept_encoding)
1064       result = CURLE_OUT_OF_MEMORY;
1065     else
1066       result = Curl_hyper_header(data, headers,
1067                                  data->state.aptr.accept_encoding);
1068     if(result)
1069       goto error;
1070   }
1071   else
1072     Curl_safefree(data->state.aptr.accept_encoding);
1073 
1074 #ifdef HAVE_LIBZ
1075   /* we only consider transfer-encoding magic if libz support is built-in */
1076   result = Curl_transferencode(data);
1077   if(result)
1078     goto error;
1079   result = Curl_hyper_header(data, headers, data->state.aptr.te);
1080   if(result)
1081     goto error;
1082 #endif
1083 
1084   result = cookies(data, conn, headers);
1085   if(result)
1086     goto error;
1087 
1088   result = Curl_add_timecondition(data, headers);
1089   if(result)
1090     goto error;
1091 
1092   result = Curl_add_custom_headers(data, FALSE, headers);
1093   if(result)
1094     goto error;
1095 
1096   result = bodysend(data, conn, headers, req, httpreq);
1097   if(result)
1098     goto error;
1099 
1100   result = Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
1101   if(result)
1102     goto error;
1103 
1104   data->req.upload_chunky = FALSE;
1105   sendtask = hyper_clientconn_send(client, req);
1106   if(!sendtask) {
1107     failf(data, "hyper_clientconn_send");
1108     result = CURLE_OUT_OF_MEMORY;
1109     goto error;
1110   }
1111 
1112   if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
1113     failf(data, "Couldn't hyper_executor_push the send");
1114     result = CURLE_OUT_OF_MEMORY;
1115     goto error;
1116   }
1117 
1118   hyper_clientconn_free(client);
1119 
1120   if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
1121     /* HTTP GET/HEAD download */
1122     Curl_pgrsSetUploadSize(data, 0); /* nothing */
1123     Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
1124   }
1125   conn->datastream = Curl_hyper_stream;
1126   if(data->state.expect100header)
1127     /* Timeout count starts now since with Hyper we don't know exactly when
1128        the full request has been sent. */
1129     data->req.start100 = Curl_now();
1130 
1131   /* clear userpwd and proxyuserpwd to avoid re-using old credentials
1132    * from re-used connections */
1133   Curl_safefree(data->state.aptr.userpwd);
1134   Curl_safefree(data->state.aptr.proxyuserpwd);
1135   return CURLE_OK;
1136   error:
1137   DEBUGASSERT(result);
1138   if(io)
1139     hyper_io_free(io);
1140 
1141   if(options)
1142     hyper_clientconn_options_free(options);
1143 
1144   if(handshake)
1145     hyper_task_free(handshake);
1146 
1147   return result;
1148 }
1149 
Curl_hyper_done(struct Curl_easy * data)1150 void Curl_hyper_done(struct Curl_easy *data)
1151 {
1152   struct hyptransfer *h = &data->hyp;
1153   if(h->exec) {
1154     hyper_executor_free(h->exec);
1155     h->exec = NULL;
1156   }
1157   if(h->read_waker) {
1158     hyper_waker_free(h->read_waker);
1159     h->read_waker = NULL;
1160   }
1161   if(h->write_waker) {
1162     hyper_waker_free(h->write_waker);
1163     h->write_waker = NULL;
1164   }
1165   if(h->exp100_waker) {
1166     hyper_waker_free(h->exp100_waker);
1167     h->exp100_waker = NULL;
1168   }
1169 }
1170 
1171 #endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
1172