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