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