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