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