• 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   writetype = CLIENTWRITE_HEADER;
160   if(data->set.include_header)
161     writetype |= CLIENTWRITE_BODY;
162   result = Curl_client_write(data, writetype, headp, len);
163   if(result) {
164     data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
165     return HYPER_ITER_BREAK;
166   }
167 
168   data->info.header_size += (long)len;
169   data->req.headerbytecount += (long)len;
170   return HYPER_ITER_CONTINUE;
171 }
172 
hyper_body_chunk(void * userdata,const hyper_buf * chunk)173 static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
174 {
175   char *buf = (char *)hyper_buf_bytes(chunk);
176   size_t len = hyper_buf_len(chunk);
177   struct Curl_easy *data = (struct Curl_easy *)userdata;
178   struct SingleRequest *k = &data->req;
179   CURLcode result;
180 
181   if(0 == k->bodywrites++) {
182     bool done = FALSE;
183 #if defined(USE_NTLM)
184     struct connectdata *conn = data->conn;
185     if(conn->bits.close &&
186        (((data->req.httpcode == 401) &&
187          (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
188         ((data->req.httpcode == 407) &&
189          (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
190       infof(data, "Connection closed while negotiating NTLM");
191       data->state.authproblem = TRUE;
192       Curl_safefree(data->req.newurl);
193     }
194 #endif
195     if(data->state.hconnect &&
196        (data->req.httpcode/100 != 2)) {
197       done = TRUE;
198       result = CURLE_OK;
199     }
200     else
201       result = Curl_http_firstwrite(data, data->conn, &done);
202     if(result || done) {
203       infof(data, "Return early from hyper_body_chunk");
204       data->state.hresult = result;
205       return HYPER_ITER_BREAK;
206     }
207   }
208   if(k->ignorebody)
209     return HYPER_ITER_CONTINUE;
210   if(0 == len)
211     return HYPER_ITER_CONTINUE;
212   Curl_debug(data, CURLINFO_DATA_IN, buf, len);
213   if(!data->set.http_ce_skip && k->writer_stack)
214     /* content-encoded data */
215     result = Curl_unencode_write(data, k->writer_stack, buf, len);
216   else
217     result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
218 
219   if(result) {
220     data->state.hresult = result;
221     return HYPER_ITER_BREAK;
222   }
223 
224   data->req.bytecount += len;
225   Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
226   return HYPER_ITER_CONTINUE;
227 }
228 
229 /*
230  * Hyper does not consider the status line, the first line in a HTTP/1
231  * response, to be a header. The libcurl API does. This function sends the
232  * 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)233 static CURLcode status_line(struct Curl_easy *data,
234                             struct connectdata *conn,
235                             uint16_t http_status,
236                             int http_version,
237                             const uint8_t *reason, size_t rlen)
238 {
239   CURLcode result;
240   size_t len;
241   const char *vstr;
242   int writetype;
243   vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
244     (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
245   conn->httpversion =
246     http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
247     (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
248   data->req.httpcode = http_status;
249 
250   result = Curl_http_statusline(data, conn);
251   if(result)
252     return result;
253 
254   Curl_dyn_reset(&data->state.headerb);
255 
256   result = Curl_dyn_addf(&data->state.headerb, "HTTP/%s %03d %.*s\r\n",
257                          vstr,
258                          (int)http_status,
259                          (int)rlen, reason);
260   if(result)
261     return result;
262   len = Curl_dyn_len(&data->state.headerb);
263   Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
264              len);
265   writetype = CLIENTWRITE_HEADER;
266   if(data->set.include_header)
267     writetype |= CLIENTWRITE_BODY;
268   result = Curl_client_write(data, writetype,
269                              Curl_dyn_ptr(&data->state.headerb), len);
270   if(result) {
271     data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
272     return HYPER_ITER_BREAK;
273   }
274 
275   data->info.header_size += (long)len;
276   data->req.headerbytecount += (long)len;
277   data->req.httpcode = http_status;
278   return CURLE_OK;
279 }
280 
281 /*
282  * Hyper does not pass on the last empty response header. The libcurl API
283  * does. This function sends an empty header in the header callback.
284  */
empty_header(struct Curl_easy * data)285 static CURLcode empty_header(struct Curl_easy *data)
286 {
287   return hyper_each_header(data, NULL, 0, NULL, 0) ?
288     CURLE_WRITE_ERROR : CURLE_OK;
289 }
290 
Curl_hyper_stream(struct Curl_easy * data,struct connectdata * conn,int * didwhat,bool * done,int select_res)291 CURLcode Curl_hyper_stream(struct Curl_easy *data,
292                            struct connectdata *conn,
293                            int *didwhat,
294                            bool *done,
295                            int select_res)
296 {
297   hyper_response *resp = NULL;
298   uint16_t http_status;
299   int http_version;
300   hyper_headers *headers = NULL;
301   hyper_body *resp_body = NULL;
302   struct hyptransfer *h = &data->hyp;
303   hyper_task *task;
304   hyper_task *foreach;
305   hyper_error *hypererr = NULL;
306   const uint8_t *reasonp;
307   size_t reason_len;
308   CURLcode result = CURLE_OK;
309   (void)conn;
310 
311   if(select_res & CURL_CSELECT_IN) {
312     if(h->read_waker)
313       hyper_waker_wake(h->read_waker);
314     h->read_waker = NULL;
315   }
316   if(select_res & CURL_CSELECT_OUT) {
317     if(h->write_waker)
318       hyper_waker_wake(h->write_waker);
319     h->write_waker = NULL;
320   }
321 
322   *done = FALSE;
323   do {
324     hyper_task_return_type t;
325     task = hyper_executor_poll(h->exec);
326     if(!task) {
327       *didwhat = KEEP_RECV;
328       break;
329     }
330     t = hyper_task_type(task);
331     switch(t) {
332     case HYPER_TASK_ERROR:
333       hypererr = hyper_task_value(task);
334       break;
335     case HYPER_TASK_RESPONSE:
336       resp = hyper_task_value(task);
337       break;
338     default:
339       break;
340     }
341     hyper_task_free(task);
342 
343     if(t == HYPER_TASK_ERROR) {
344       hyper_code errnum = hyper_error_code(hypererr);
345       if(errnum == HYPERE_ABORTED_BY_CALLBACK) {
346         /* override Hyper's view, might not even be an error */
347         result = data->state.hresult;
348         infof(data, "hyperstream is done (by early callback)");
349       }
350       else {
351         uint8_t errbuf[256];
352         size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
353         hyper_code code = hyper_error_code(hypererr);
354         failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
355         if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount)
356           result = CURLE_GOT_NOTHING;
357         else if(code == HYPERE_INVALID_PEER_MESSAGE)
358           result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */
359         else
360           result = CURLE_RECV_ERROR;
361       }
362       *done = TRUE;
363       hyper_error_free(hypererr);
364       break;
365     }
366     else if(h->endtask == task) {
367       /* end of transfer */
368       *done = TRUE;
369       infof(data, "hyperstream is done!");
370       break;
371     }
372     else if(t != HYPER_TASK_RESPONSE) {
373       *didwhat = KEEP_RECV;
374       break;
375     }
376     /* HYPER_TASK_RESPONSE */
377 
378     *didwhat = KEEP_RECV;
379     if(!resp) {
380       failf(data, "hyperstream: couldn't get response");
381       return CURLE_RECV_ERROR;
382     }
383 
384     http_status = hyper_response_status(resp);
385     http_version = hyper_response_version(resp);
386     reasonp = hyper_response_reason_phrase(resp);
387     reason_len = hyper_response_reason_phrase_len(resp);
388 
389     result = status_line(data, conn,
390                          http_status, http_version, reasonp, reason_len);
391     if(result)
392       break;
393 
394     headers = hyper_response_headers(resp);
395     if(!headers) {
396       failf(data, "hyperstream: couldn't get response headers");
397       result = CURLE_RECV_ERROR;
398       break;
399     }
400 
401     /* the headers are already received */
402     hyper_headers_foreach(headers, hyper_each_header, data);
403     if(data->state.hresult) {
404       result = data->state.hresult;
405       break;
406     }
407 
408     if(empty_header(data)) {
409       failf(data, "hyperstream: couldn't pass blank header");
410       result = CURLE_OUT_OF_MEMORY;
411       break;
412     }
413 
414     /* Curl_http_auth_act() checks what authentication methods that are
415      * available and decides which one (if any) to use. It will set 'newurl'
416      * if an auth method was picked. */
417     result = Curl_http_auth_act(data);
418     if(result)
419       break;
420 
421     resp_body = hyper_response_body(resp);
422     if(!resp_body) {
423       failf(data, "hyperstream: couldn't get response body");
424       result = CURLE_RECV_ERROR;
425       break;
426     }
427     foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
428     if(!foreach) {
429       failf(data, "hyperstream: body foreach failed");
430       result = CURLE_OUT_OF_MEMORY;
431       break;
432     }
433     DEBUGASSERT(hyper_task_type(foreach) == HYPER_TASK_EMPTY);
434     if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
435       failf(data, "Couldn't hyper_executor_push the body-foreach");
436       result = CURLE_OUT_OF_MEMORY;
437       break;
438     }
439     h->endtask = foreach;
440 
441     hyper_response_free(resp);
442     resp = NULL;
443   } while(1);
444   if(resp)
445     hyper_response_free(resp);
446   return result;
447 }
448 
debug_request(struct Curl_easy * data,const char * method,const char * path,bool h2)449 static CURLcode debug_request(struct Curl_easy *data,
450                               const char *method,
451                               const char *path,
452                               bool h2)
453 {
454   char *req = aprintf("%s %s HTTP/%s\r\n", method, path,
455                       h2?"2":"1.1");
456   if(!req)
457     return CURLE_OUT_OF_MEMORY;
458   Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req));
459   free(req);
460   return CURLE_OK;
461 }
462 
463 /*
464  * Given a full header line "name: value" (optional CRLF in the input, should
465  * be in the output), add to Hyper and send to the debug callback.
466  *
467  * Supports multiple headers.
468  */
469 
Curl_hyper_header(struct Curl_easy * data,hyper_headers * headers,const char * line)470 CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
471                            const char *line)
472 {
473   const char *p;
474   const char *n;
475   size_t nlen;
476   const char *v;
477   size_t vlen;
478   bool newline = TRUE;
479   int numh = 0;
480 
481   if(!line)
482     return CURLE_OK;
483   n = line;
484   do {
485     size_t linelen = 0;
486 
487     p = strchr(n, ':');
488     if(!p)
489       /* this is fine if we already added at least one header */
490       return numh ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
491     nlen = p - n;
492     p++; /* move past the colon */
493     while(*p == ' ')
494       p++;
495     v = p;
496     p = strchr(v, '\r');
497     if(!p) {
498       p = strchr(v, '\n');
499       if(p)
500         linelen = 1; /* LF only */
501       else {
502         p = strchr(v, '\0');
503         newline = FALSE; /* no newline */
504       }
505     }
506     else
507       linelen = 2; /* CRLF ending */
508     linelen += (p - n);
509     vlen = p - v;
510 
511     if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
512                                       (uint8_t *)v, vlen)) {
513       failf(data, "hyper refused to add header '%s'", line);
514       return CURLE_OUT_OF_MEMORY;
515     }
516     if(data->set.verbose) {
517       char *ptr = NULL;
518       if(!newline) {
519         ptr = aprintf("%.*s\r\n", (int)linelen, line);
520         if(!ptr)
521           return CURLE_OUT_OF_MEMORY;
522         Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2);
523         free(ptr);
524       }
525       else
526         Curl_debug(data, CURLINFO_HEADER_OUT, (char *)line, linelen);
527     }
528     numh++;
529     n += linelen;
530   } while(newline);
531   return CURLE_OK;
532 }
533 
request_target(struct Curl_easy * data,struct connectdata * conn,const char * method,bool h2,hyper_request * req)534 static CURLcode request_target(struct Curl_easy *data,
535                                struct connectdata *conn,
536                                const char *method,
537                                bool h2,
538                                hyper_request *req)
539 {
540   CURLcode result;
541   struct dynbuf r;
542 
543   Curl_dyn_init(&r, DYN_HTTP_REQUEST);
544 
545   result = Curl_http_target(data, conn, &r);
546   if(result)
547     return result;
548 
549   if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
550                            Curl_dyn_len(&r))) {
551     failf(data, "error setting path");
552     result = CURLE_OUT_OF_MEMORY;
553   }
554   else
555     result = debug_request(data, method, Curl_dyn_ptr(&r), h2);
556 
557   Curl_dyn_free(&r);
558 
559   return result;
560 }
561 
uploadpostfields(void * userdata,hyper_context * ctx,hyper_buf ** chunk)562 static int uploadpostfields(void *userdata, hyper_context *ctx,
563                             hyper_buf **chunk)
564 {
565   struct Curl_easy *data = (struct Curl_easy *)userdata;
566   (void)ctx;
567   if(data->req.upload_done)
568     *chunk = NULL; /* nothing more to deliver */
569   else {
570     /* send everything off in a single go */
571     hyper_buf *copy = hyper_buf_copy(data->set.postfields,
572                                      (size_t)data->req.p.http->postsize);
573     if(copy)
574       *chunk = copy;
575     else {
576       data->state.hresult = CURLE_OUT_OF_MEMORY;
577       return HYPER_POLL_ERROR;
578     }
579     /* increasing the writebytecount here is a little premature but we
580        don't know exactly when the body is sent*/
581     data->req.writebytecount += (size_t)data->req.p.http->postsize;
582     Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
583     data->req.upload_done = TRUE;
584   }
585   return HYPER_POLL_READY;
586 }
587 
uploadstreamed(void * userdata,hyper_context * ctx,hyper_buf ** chunk)588 static int uploadstreamed(void *userdata, hyper_context *ctx,
589                           hyper_buf **chunk)
590 {
591   size_t fillcount;
592   struct Curl_easy *data = (struct Curl_easy *)userdata;
593   CURLcode result =
594     Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount);
595   (void)ctx;
596   if(result) {
597     data->state.hresult = result;
598     return HYPER_POLL_ERROR;
599   }
600   if(!fillcount)
601     /* done! */
602     *chunk = NULL;
603   else {
604     hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
605     if(copy)
606       *chunk = copy;
607     else {
608       data->state.hresult = CURLE_OUT_OF_MEMORY;
609       return HYPER_POLL_ERROR;
610     }
611     /* increasing the writebytecount here is a little premature but we
612        don't know exactly when the body is sent*/
613     data->req.writebytecount += fillcount;
614     Curl_pgrsSetUploadCounter(data, fillcount);
615   }
616   return HYPER_POLL_READY;
617 }
618 
619 /*
620  * bodysend() sets up headers in the outgoing request for a HTTP transfer that
621  * sends a body
622  */
623 
bodysend(struct Curl_easy * data,struct connectdata * conn,hyper_headers * headers,hyper_request * hyperreq,Curl_HttpReq httpreq)624 static CURLcode bodysend(struct Curl_easy *data,
625                          struct connectdata *conn,
626                          hyper_headers *headers,
627                          hyper_request *hyperreq,
628                          Curl_HttpReq httpreq)
629 {
630   CURLcode result = CURLE_OK;
631   struct dynbuf req;
632   if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
633     Curl_pgrsSetUploadSize(data, 0); /* no request body */
634   else {
635     hyper_body *body;
636     Curl_dyn_init(&req, DYN_HTTP_REQUEST);
637     result = Curl_http_bodysend(data, conn, &req, httpreq);
638 
639     if(!result)
640       result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
641 
642     Curl_dyn_free(&req);
643 
644     body = hyper_body_new();
645     hyper_body_set_userdata(body, data);
646     if(data->set.postfields)
647       hyper_body_set_data_func(body, uploadpostfields);
648     else {
649       result = Curl_get_upload_buffer(data);
650       if(result)
651         return result;
652       /* init the "upload from here" pointer */
653       data->req.upload_fromhere = data->state.ulbuf;
654       hyper_body_set_data_func(body, uploadstreamed);
655     }
656     if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
657       /* fail */
658       hyper_body_free(body);
659       result = CURLE_OUT_OF_MEMORY;
660     }
661   }
662   return result;
663 }
664 
cookies(struct Curl_easy * data,struct connectdata * conn,hyper_headers * headers)665 static CURLcode cookies(struct Curl_easy *data,
666                         struct connectdata *conn,
667                         hyper_headers *headers)
668 {
669   struct dynbuf req;
670   CURLcode result;
671   Curl_dyn_init(&req, DYN_HTTP_REQUEST);
672 
673   result = Curl_http_cookies(data, conn, &req);
674   if(!result)
675     result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
676   Curl_dyn_free(&req);
677   return result;
678 }
679 
680 /*
681  * Curl_http() gets called from the generic multi_do() function when a HTTP
682  * request is to be performed. This creates and sends a properly constructed
683  * HTTP request.
684  */
Curl_http(struct Curl_easy * data,bool * done)685 CURLcode Curl_http(struct Curl_easy *data, bool *done)
686 {
687   struct connectdata *conn = data->conn;
688   struct hyptransfer *h = &data->hyp;
689   hyper_io *io = NULL;
690   hyper_clientconn_options *options = NULL;
691   hyper_task *task = NULL; /* for the handshake */
692   hyper_task *sendtask = NULL; /* for the send */
693   hyper_clientconn *client = NULL;
694   hyper_request *req = NULL;
695   hyper_headers *headers = NULL;
696   hyper_task *handshake = NULL;
697   hyper_error *hypererr = NULL;
698   CURLcode result;
699   const char *p_accept; /* Accept: string */
700   const char *method;
701   Curl_HttpReq httpreq;
702   bool h2 = FALSE;
703   const char *te = NULL; /* transfer-encoding */
704 
705   /* Always consider the DO phase done after this function call, even if there
706      may be parts of the request that is not yet sent, since we can deal with
707      the rest of the request in the PERFORM phase. */
708   *done = TRUE;
709 
710   infof(data, "Time for the Hyper dance");
711   memset(h, 0, sizeof(struct hyptransfer));
712 
713   result = Curl_http_host(data, conn);
714   if(result)
715     return result;
716 
717   Curl_http_method(data, conn, &method, &httpreq);
718 
719   /* setup the authentication headers */
720   {
721     char *pq = NULL;
722     if(data->state.up.query) {
723       pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
724       if(!pq)
725         return CURLE_OUT_OF_MEMORY;
726     }
727     result = Curl_http_output_auth(data, conn, method, httpreq,
728                                    (pq ? pq : data->state.up.path), FALSE);
729     free(pq);
730     if(result)
731       return result;
732   }
733 
734   result = Curl_http_resume(data, conn, httpreq);
735   if(result)
736     return result;
737 
738   result = Curl_http_range(data, httpreq);
739   if(result)
740     return result;
741 
742   result = Curl_http_useragent(data);
743   if(result)
744     return result;
745 
746   io = hyper_io_new();
747   if(!io) {
748     failf(data, "Couldn't create hyper IO");
749     goto error;
750   }
751   /* tell Hyper how to read/write network data */
752   hyper_io_set_userdata(io, data);
753   hyper_io_set_read(io, Curl_hyper_recv);
754   hyper_io_set_write(io, Curl_hyper_send);
755 
756   /* create an executor to poll futures */
757   if(!h->exec) {
758     h->exec = hyper_executor_new();
759     if(!h->exec) {
760       failf(data, "Couldn't create hyper executor");
761       goto error;
762     }
763   }
764 
765   options = hyper_clientconn_options_new();
766   if(!options) {
767     failf(data, "Couldn't create hyper client options");
768     goto error;
769   }
770   if(conn->negnpn == CURL_HTTP_VERSION_2) {
771     hyper_clientconn_options_http2(options, 1);
772     h2 = TRUE;
773   }
774 
775   hyper_clientconn_options_exec(options, h->exec);
776 
777   /* "Both the `io` and the `options` are consumed in this function call" */
778   handshake = hyper_clientconn_handshake(io, options);
779   if(!handshake) {
780     failf(data, "Couldn't create hyper client handshake");
781     goto error;
782   }
783   io = NULL;
784   options = NULL;
785 
786   if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
787     failf(data, "Couldn't hyper_executor_push the handshake");
788     goto error;
789   }
790   handshake = NULL; /* ownership passed on */
791 
792   task = hyper_executor_poll(h->exec);
793   if(!task) {
794     failf(data, "Couldn't hyper_executor_poll the handshake");
795     goto error;
796   }
797 
798   client = hyper_task_value(task);
799   hyper_task_free(task);
800 
801   req = hyper_request_new();
802   if(!req) {
803     failf(data, "Couldn't hyper_request_new");
804     goto error;
805   }
806 
807   if(data->state.httpwant == CURL_HTTP_VERSION_1_0) {
808     if(HYPERE_OK != hyper_request_set_version(req,
809                                               HYPER_HTTP_VERSION_1_0)) {
810       failf(data, "error setting HTTP version");
811       goto error;
812     }
813   }
814 
815   if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
816     failf(data, "error setting method");
817     goto error;
818   }
819 
820   result = request_target(data, conn, method, h2, req);
821   if(result)
822     goto error;
823 
824   headers = hyper_request_headers(req);
825   if(!headers) {
826     failf(data, "hyper_request_headers");
827     goto error;
828   }
829 
830   result = Curl_http_body(data, conn, httpreq, &te);
831   if(result)
832     return result;
833 
834   if(data->state.aptr.host &&
835      Curl_hyper_header(data, headers, data->state.aptr.host))
836     goto error;
837 
838   if(data->state.aptr.proxyuserpwd &&
839      Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
840     goto error;
841 
842   if(data->state.aptr.userpwd &&
843      Curl_hyper_header(data, headers, data->state.aptr.userpwd))
844     goto error;
845 
846   if((data->state.use_range && data->state.aptr.rangeline) &&
847      Curl_hyper_header(data, headers, data->state.aptr.rangeline))
848     goto error;
849 
850   if(data->set.str[STRING_USERAGENT] &&
851      *data->set.str[STRING_USERAGENT] &&
852      data->state.aptr.uagent &&
853      Curl_hyper_header(data, headers, data->state.aptr.uagent))
854     goto error;
855 
856   p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
857   if(p_accept && Curl_hyper_header(data, headers, p_accept))
858     goto error;
859 
860   if(te && Curl_hyper_header(data, headers, te))
861     goto error;
862 
863 #ifndef CURL_DISABLE_PROXY
864   if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
865      !Curl_checkheaders(data, "Proxy-Connection") &&
866      !Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
867     if(Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
868       goto error;
869   }
870 #endif
871 
872   Curl_safefree(data->state.aptr.ref);
873   if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
874     data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
875     if(!data->state.aptr.ref)
876       return CURLE_OUT_OF_MEMORY;
877     if(Curl_hyper_header(data, headers, data->state.aptr.ref))
878       goto error;
879   }
880 
881   if(!Curl_checkheaders(data, "Accept-Encoding") &&
882      data->set.str[STRING_ENCODING]) {
883     Curl_safefree(data->state.aptr.accept_encoding);
884     data->state.aptr.accept_encoding =
885       aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
886     if(!data->state.aptr.accept_encoding)
887       return CURLE_OUT_OF_MEMORY;
888     if(Curl_hyper_header(data, headers, data->state.aptr.accept_encoding))
889       goto error;
890   }
891   else
892     Curl_safefree(data->state.aptr.accept_encoding);
893 
894 #ifdef HAVE_LIBZ
895   /* we only consider transfer-encoding magic if libz support is built-in */
896   result = Curl_transferencode(data);
897   if(result)
898     return result;
899   if(Curl_hyper_header(data, headers, data->state.aptr.te))
900     goto error;
901 #endif
902 
903   result = cookies(data, conn, headers);
904   if(result)
905     return result;
906 
907   result = Curl_add_timecondition(data, headers);
908   if(result)
909     return result;
910 
911   result = Curl_add_custom_headers(data, FALSE, headers);
912   if(result)
913     return result;
914 
915   result = bodysend(data, conn, headers, req, httpreq);
916   if(result)
917     return result;
918 
919   Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
920 
921   data->req.upload_chunky = FALSE;
922   sendtask = hyper_clientconn_send(client, req);
923   if(!sendtask) {
924     failf(data, "hyper_clientconn_send");
925     goto error;
926   }
927 
928   if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
929     failf(data, "Couldn't hyper_executor_push the send");
930     goto error;
931   }
932 
933   hyper_clientconn_free(client);
934 
935   do {
936     task = hyper_executor_poll(h->exec);
937     if(task) {
938       bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
939       if(error)
940         hypererr = hyper_task_value(task);
941       hyper_task_free(task);
942       if(error)
943         goto error;
944     }
945   } while(task);
946 
947   if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
948     /* HTTP GET/HEAD download */
949     Curl_pgrsSetUploadSize(data, 0); /* nothing */
950     Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
951   }
952   conn->datastream = Curl_hyper_stream;
953 
954   /* clear userpwd and proxyuserpwd to avoid re-using old credentials
955    * from re-used connections */
956   Curl_safefree(data->state.aptr.userpwd);
957   Curl_safefree(data->state.aptr.proxyuserpwd);
958   return CURLE_OK;
959   error:
960 
961   if(io)
962     hyper_io_free(io);
963 
964   if(options)
965     hyper_clientconn_options_free(options);
966 
967   if(handshake)
968     hyper_task_free(handshake);
969 
970   if(hypererr) {
971     uint8_t errbuf[256];
972     size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
973     hyper_code code = hyper_error_code(hypererr);
974     failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
975     hyper_error_free(hypererr);
976     if(data->state.hresult)
977       return data->state.hresult;
978   }
979   return CURLE_OUT_OF_MEMORY;
980 }
981 
Curl_hyper_done(struct Curl_easy * data)982 void Curl_hyper_done(struct Curl_easy *data)
983 {
984   struct hyptransfer *h = &data->hyp;
985   if(h->exec) {
986     hyper_executor_free(h->exec);
987     h->exec = NULL;
988   }
989   if(h->read_waker) {
990     hyper_waker_free(h->read_waker);
991     h->read_waker = NULL;
992   }
993   if(h->write_waker) {
994     hyper_waker_free(h->write_waker);
995     h->write_waker = NULL;
996   }
997 }
998 
999 #endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
1000