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