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