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