1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel (at) 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 #ifdef USE_NGHTTP2 26 #include <nghttp2/nghttp2.h> 27 #include "urldata.h" 28 #include "http2.h" 29 #include "http.h" 30 #include "sendf.h" 31 #include "select.h" 32 #include "curl_base64.h" 33 #include "strcase.h" 34 #include "multiif.h" 35 #include "url.h" 36 #include "connect.h" 37 #include "strtoofft.h" 38 #include "strdup.h" 39 /* The last 3 #include files should be in this order */ 40 #include "curl_printf.h" 41 #include "curl_memory.h" 42 #include "memdebug.h" 43 44 #define H2_BUFSIZE 32768 45 46 #if (NGHTTP2_VERSION_NUM < 0x010000) 47 #error too old nghttp2 version, upgrade! 48 #endif 49 50 #if (NGHTTP2_VERSION_NUM > 0x010800) 51 #define NGHTTP2_HAS_HTTP2_STRERROR 1 52 #endif 53 54 #if (NGHTTP2_VERSION_NUM >= 0x010900) 55 /* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or 56 later */ 57 #define NGHTTP2_HAS_ERROR_CALLBACK 1 58 #else 59 #define nghttp2_session_callbacks_set_error_callback(x,y) 60 #endif 61 62 #if (NGHTTP2_VERSION_NUM >= 0x010c00) 63 #define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1 64 #endif 65 66 #define HTTP2_HUGE_WINDOW_SIZE (1 << 30) 67 68 #ifdef DEBUG_HTTP2 69 #define H2BUGF(x) x 70 #else 71 #define H2BUGF(x) do { } WHILE_FALSE 72 #endif 73 74 75 static ssize_t http2_recv(struct connectdata *conn, int sockindex, 76 char *mem, size_t len, CURLcode *err); 77 static bool http2_connisdead(struct connectdata *conn); 78 static int h2_session_send(struct Curl_easy *data, 79 nghttp2_session *h2); 80 static int h2_process_pending_input(struct connectdata *conn, 81 struct http_conn *httpc, 82 CURLcode *err); 83 84 /* 85 * Curl_http2_init_state() is called when the easy handle is created and 86 * allows for HTTP/2 specific init of state. 87 */ 88 void Curl_http2_init_state(struct UrlState *state) 89 { 90 state->stream_weight = NGHTTP2_DEFAULT_WEIGHT; 91 } 92 93 /* 94 * Curl_http2_init_userset() is called when the easy handle is created and 95 * allows for HTTP/2 specific user-set fields. 96 */ 97 void Curl_http2_init_userset(struct UserDefined *set) 98 { 99 set->stream_weight = NGHTTP2_DEFAULT_WEIGHT; 100 } 101 102 static int http2_perform_getsock(const struct connectdata *conn, 103 curl_socket_t *sock, /* points to 104 numsocks 105 number of 106 sockets */ 107 int numsocks) 108 { 109 const struct http_conn *c = &conn->proto.httpc; 110 struct SingleRequest *k = &conn->data->req; 111 int bitmap = GETSOCK_BLANK; 112 (void)numsocks; 113 114 /* TODO We should check underlying socket state if it is SSL socket 115 because of renegotiation. */ 116 sock[0] = conn->sock[FIRSTSOCKET]; 117 118 /* in a HTTP/2 connection we can basically always get a frame so we should 119 always be ready for one */ 120 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); 121 122 /* we're still uploading or the HTTP/2 layer wants to send data */ 123 if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) || 124 nghttp2_session_want_write(c->h2)) 125 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); 126 127 return bitmap; 128 } 129 130 static int http2_getsock(struct connectdata *conn, 131 curl_socket_t *sock, /* points to numsocks 132 number of sockets */ 133 int numsocks) 134 { 135 return http2_perform_getsock(conn, sock, numsocks); 136 } 137 138 /* 139 * http2_stream_free() free HTTP2 stream related data 140 */ 141 static void http2_stream_free(struct HTTP *http) 142 { 143 if(http) { 144 Curl_add_buffer_free(&http->header_recvbuf); 145 Curl_add_buffer_free(&http->trailer_recvbuf); 146 for(; http->push_headers_used > 0; --http->push_headers_used) { 147 free(http->push_headers[http->push_headers_used - 1]); 148 } 149 free(http->push_headers); 150 http->push_headers = NULL; 151 } 152 } 153 154 /* 155 * Disconnects *a* connection used for HTTP/2. It might be an old one from the 156 * connection cache and not the "main" one. Don't touch the easy handle! 157 */ 158 159 static CURLcode http2_disconnect(struct connectdata *conn, 160 bool dead_connection) 161 { 162 struct http_conn *c = &conn->proto.httpc; 163 (void)dead_connection; 164 165 H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n")); 166 167 nghttp2_session_del(c->h2); 168 Curl_safefree(c->inbuf); 169 170 H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n")); 171 172 return CURLE_OK; 173 } 174 175 /* 176 * The server may send us data at any point (e.g. PING frames). Therefore, 177 * we cannot assume that an HTTP/2 socket is dead just because it is readable. 178 * 179 * Instead, if it is readable, run Curl_connalive() to peek at the socket 180 * and distinguish between closed and data. 181 */ 182 static bool http2_connisdead(struct connectdata *conn) 183 { 184 int sval; 185 bool dead = TRUE; 186 187 if(conn->bits.close) 188 return TRUE; 189 190 sval = SOCKET_READABLE(conn->sock[FIRSTSOCKET], 0); 191 if(sval == 0) { 192 /* timeout */ 193 dead = FALSE; 194 } 195 else if(sval & CURL_CSELECT_ERR) { 196 /* socket is in an error state */ 197 dead = TRUE; 198 } 199 else if(sval & CURL_CSELECT_IN) { 200 /* readable with no error. could still be closed */ 201 dead = !Curl_connalive(conn); 202 if(!dead) { 203 /* This happens before we've sent off a request and the connection is 204 not in use by any other transfer, there shouldn't be any data here, 205 only "protocol frames" */ 206 CURLcode result; 207 struct http_conn *httpc = &conn->proto.httpc; 208 ssize_t nread = -1; 209 if(httpc->recv_underlying) 210 /* if called "too early", this pointer isn't setup yet! */ 211 nread = ((Curl_recv *)httpc->recv_underlying)( 212 conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result); 213 if(nread != -1) { 214 infof(conn->data, 215 "%d bytes stray data read before trying h2 connection\n", 216 (int)nread); 217 httpc->nread_inbuf = 0; 218 httpc->inbuflen = nread; 219 (void)h2_process_pending_input(conn, httpc, &result); 220 } 221 else 222 /* the read failed so let's say this is dead anyway */ 223 dead = TRUE; 224 } 225 } 226 227 return dead; 228 } 229 230 static unsigned int http2_conncheck(struct connectdata *check, 231 unsigned int checks_to_perform) 232 { 233 unsigned int ret_val = CONNRESULT_NONE; 234 struct http_conn *c = &check->proto.httpc; 235 int rc; 236 bool send_frames = false; 237 238 if(checks_to_perform & CONNCHECK_ISDEAD) { 239 if(http2_connisdead(check)) 240 ret_val |= CONNRESULT_DEAD; 241 } 242 243 if(checks_to_perform & CONNCHECK_KEEPALIVE) { 244 struct curltime now = Curl_now(); 245 time_t elapsed = Curl_timediff(now, check->keepalive); 246 247 if(elapsed > check->upkeep_interval_ms) { 248 /* Perform an HTTP/2 PING */ 249 rc = nghttp2_submit_ping(c->h2, 0, ZERO_NULL); 250 if(!rc) { 251 /* Successfully added a PING frame to the session. Need to flag this 252 so the frame is sent. */ 253 send_frames = true; 254 } 255 else { 256 failf(check->data, "nghttp2_submit_ping() failed: %s(%d)", 257 nghttp2_strerror(rc), rc); 258 } 259 260 check->keepalive = now; 261 } 262 } 263 264 if(send_frames) { 265 rc = nghttp2_session_send(c->h2); 266 if(rc) 267 failf(check->data, "nghttp2_session_send() failed: %s(%d)", 268 nghttp2_strerror(rc), rc); 269 } 270 271 return ret_val; 272 } 273 274 /* called from Curl_http_setup_conn */ 275 void Curl_http2_setup_req(struct Curl_easy *data) 276 { 277 struct HTTP *http = data->req.protop; 278 279 http->nread_header_recvbuf = 0; 280 http->bodystarted = FALSE; 281 http->status_code = -1; 282 http->pausedata = NULL; 283 http->pauselen = 0; 284 http->closed = FALSE; 285 http->close_handled = FALSE; 286 http->mem = data->state.buffer; 287 http->len = data->set.buffer_size; 288 http->memlen = 0; 289 } 290 291 /* called from Curl_http_setup_conn */ 292 void Curl_http2_setup_conn(struct connectdata *conn) 293 { 294 conn->proto.httpc.settings.max_concurrent_streams = 295 DEFAULT_MAX_CONCURRENT_STREAMS; 296 conn->proto.httpc.error_code = NGHTTP2_NO_ERROR; 297 } 298 299 /* 300 * HTTP2 handler interface. This isn't added to the general list of protocols 301 * but will be used at run-time when the protocol is dynamically switched from 302 * HTTP to HTTP2. 303 */ 304 static const struct Curl_handler Curl_handler_http2 = { 305 "HTTP", /* scheme */ 306 ZERO_NULL, /* setup_connection */ 307 Curl_http, /* do_it */ 308 Curl_http_done, /* done */ 309 ZERO_NULL, /* do_more */ 310 ZERO_NULL, /* connect_it */ 311 ZERO_NULL, /* connecting */ 312 ZERO_NULL, /* doing */ 313 http2_getsock, /* proto_getsock */ 314 http2_getsock, /* doing_getsock */ 315 ZERO_NULL, /* domore_getsock */ 316 http2_perform_getsock, /* perform_getsock */ 317 http2_disconnect, /* disconnect */ 318 ZERO_NULL, /* readwrite */ 319 http2_conncheck, /* connection_check */ 320 PORT_HTTP, /* defport */ 321 CURLPROTO_HTTP, /* protocol */ 322 PROTOPT_STREAM /* flags */ 323 }; 324 325 static const struct Curl_handler Curl_handler_http2_ssl = { 326 "HTTPS", /* scheme */ 327 ZERO_NULL, /* setup_connection */ 328 Curl_http, /* do_it */ 329 Curl_http_done, /* done */ 330 ZERO_NULL, /* do_more */ 331 ZERO_NULL, /* connect_it */ 332 ZERO_NULL, /* connecting */ 333 ZERO_NULL, /* doing */ 334 http2_getsock, /* proto_getsock */ 335 http2_getsock, /* doing_getsock */ 336 ZERO_NULL, /* domore_getsock */ 337 http2_perform_getsock, /* perform_getsock */ 338 http2_disconnect, /* disconnect */ 339 ZERO_NULL, /* readwrite */ 340 http2_conncheck, /* connection_check */ 341 PORT_HTTP, /* defport */ 342 CURLPROTO_HTTPS, /* protocol */ 343 PROTOPT_SSL | PROTOPT_STREAM /* flags */ 344 }; 345 346 /* 347 * Store nghttp2 version info in this buffer, Prefix with a space. Return 348 * total length written. 349 */ 350 int Curl_http2_ver(char *p, size_t len) 351 { 352 nghttp2_info *h2 = nghttp2_version(0); 353 return msnprintf(p, len, " nghttp2/%s", h2->version_str); 354 } 355 356 /* HTTP/2 error code to name based on the Error Code Registry. 357 https://tools.ietf.org/html/rfc7540#page-77 358 nghttp2_error_code enums are identical. 359 */ 360 static const char *http2_strerror(uint32_t err) 361 { 362 #ifndef NGHTTP2_HAS_HTTP2_STRERROR 363 const char *str[] = { 364 "NO_ERROR", /* 0x0 */ 365 "PROTOCOL_ERROR", /* 0x1 */ 366 "INTERNAL_ERROR", /* 0x2 */ 367 "FLOW_CONTROL_ERROR", /* 0x3 */ 368 "SETTINGS_TIMEOUT", /* 0x4 */ 369 "STREAM_CLOSED", /* 0x5 */ 370 "FRAME_SIZE_ERROR", /* 0x6 */ 371 "REFUSED_STREAM", /* 0x7 */ 372 "CANCEL", /* 0x8 */ 373 "COMPRESSION_ERROR", /* 0x9 */ 374 "CONNECT_ERROR", /* 0xA */ 375 "ENHANCE_YOUR_CALM", /* 0xB */ 376 "INADEQUATE_SECURITY", /* 0xC */ 377 "HTTP_1_1_REQUIRED" /* 0xD */ 378 }; 379 return (err < sizeof(str) / sizeof(str[0])) ? str[err] : "unknown"; 380 #else 381 return nghttp2_http2_strerror(err); 382 #endif 383 } 384 385 /* 386 * The implementation of nghttp2_send_callback type. Here we write |data| with 387 * size |length| to the network and return the number of bytes actually 388 * written. See the documentation of nghttp2_send_callback for the details. 389 */ 390 static ssize_t send_callback(nghttp2_session *h2, 391 const uint8_t *data, size_t length, int flags, 392 void *userp) 393 { 394 struct connectdata *conn = (struct connectdata *)userp; 395 struct http_conn *c = &conn->proto.httpc; 396 ssize_t written; 397 CURLcode result = CURLE_OK; 398 399 (void)h2; 400 (void)flags; 401 402 if(!c->send_underlying) 403 /* called before setup properly! */ 404 return NGHTTP2_ERR_CALLBACK_FAILURE; 405 406 written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET, 407 data, length, &result); 408 409 if(result == CURLE_AGAIN) { 410 return NGHTTP2_ERR_WOULDBLOCK; 411 } 412 413 if(written == -1) { 414 failf(conn->data, "Failed sending HTTP2 data"); 415 return NGHTTP2_ERR_CALLBACK_FAILURE; 416 } 417 418 if(!written) 419 return NGHTTP2_ERR_WOULDBLOCK; 420 421 return written; 422 } 423 424 425 /* We pass a pointer to this struct in the push callback, but the contents of 426 the struct are hidden from the user. */ 427 struct curl_pushheaders { 428 struct Curl_easy *data; 429 const nghttp2_push_promise *frame; 430 }; 431 432 /* 433 * push header access function. Only to be used from within the push callback 434 */ 435 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) 436 { 437 /* Verify that we got a good easy handle in the push header struct, mostly to 438 detect rubbish input fast(er). */ 439 if(!h || !GOOD_EASY_HANDLE(h->data)) 440 return NULL; 441 else { 442 struct HTTP *stream = h->data->req.protop; 443 if(num < stream->push_headers_used) 444 return stream->push_headers[num]; 445 } 446 return NULL; 447 } 448 449 /* 450 * push header access function. Only to be used from within the push callback 451 */ 452 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) 453 { 454 /* Verify that we got a good easy handle in the push header struct, 455 mostly to detect rubbish input fast(er). Also empty header name 456 is just a rubbish too. We have to allow ":" at the beginning of 457 the header, but header == ":" must be rejected. If we have ':' in 458 the middle of header, it could be matched in middle of the value, 459 this is because we do prefix match.*/ 460 if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || 461 !strcmp(header, ":") || strchr(header + 1, ':')) 462 return NULL; 463 else { 464 struct HTTP *stream = h->data->req.protop; 465 size_t len = strlen(header); 466 size_t i; 467 for(i = 0; i<stream->push_headers_used; i++) { 468 if(!strncmp(header, stream->push_headers[i], len)) { 469 /* sub-match, make sure that it is followed by a colon */ 470 if(stream->push_headers[i][len] != ':') 471 continue; 472 return &stream->push_headers[i][len + 1]; 473 } 474 } 475 } 476 return NULL; 477 } 478 479 /* 480 * This specific transfer on this connection has been "drained". 481 */ 482 static void drained_transfer(struct Curl_easy *data, 483 struct http_conn *httpc) 484 { 485 DEBUGASSERT(httpc->drain_total >= data->state.drain); 486 httpc->drain_total -= data->state.drain; 487 data->state.drain = 0; 488 } 489 490 /* 491 * Mark this transfer to get "drained". 492 */ 493 static void drain_this(struct Curl_easy *data, 494 struct http_conn *httpc) 495 { 496 data->state.drain++; 497 httpc->drain_total++; 498 DEBUGASSERT(httpc->drain_total >= data->state.drain); 499 } 500 501 static struct Curl_easy *duphandle(struct Curl_easy *data) 502 { 503 struct Curl_easy *second = curl_easy_duphandle(data); 504 if(second) { 505 /* setup the request struct */ 506 struct HTTP *http = calloc(1, sizeof(struct HTTP)); 507 if(!http) { 508 (void)Curl_close(second); 509 second = NULL; 510 } 511 else { 512 second->req.protop = http; 513 http->header_recvbuf = Curl_add_buffer_init(); 514 if(!http->header_recvbuf) { 515 free(http); 516 (void)Curl_close(second); 517 second = NULL; 518 } 519 else { 520 Curl_http2_setup_req(second); 521 second->state.stream_weight = data->state.stream_weight; 522 } 523 } 524 } 525 return second; 526 } 527 528 529 static int push_promise(struct Curl_easy *data, 530 struct connectdata *conn, 531 const nghttp2_push_promise *frame) 532 { 533 int rv; 534 H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!\n", 535 frame->promised_stream_id)); 536 if(data->multi->push_cb) { 537 struct HTTP *stream; 538 struct HTTP *newstream; 539 struct curl_pushheaders heads; 540 CURLMcode rc; 541 struct http_conn *httpc; 542 size_t i; 543 /* clone the parent */ 544 struct Curl_easy *newhandle = duphandle(data); 545 if(!newhandle) { 546 infof(data, "failed to duplicate handle\n"); 547 rv = 1; /* FAIL HARD */ 548 goto fail; 549 } 550 551 heads.data = data; 552 heads.frame = frame; 553 /* ask the application */ 554 H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n")); 555 556 stream = data->req.protop; 557 if(!stream) { 558 failf(data, "Internal NULL stream!\n"); 559 (void)Curl_close(newhandle); 560 rv = 1; 561 goto fail; 562 } 563 564 Curl_set_in_callback(data, true); 565 rv = data->multi->push_cb(data, newhandle, 566 stream->push_headers_used, &heads, 567 data->multi->push_userp); 568 Curl_set_in_callback(data, false); 569 570 /* free the headers again */ 571 for(i = 0; i<stream->push_headers_used; i++) 572 free(stream->push_headers[i]); 573 free(stream->push_headers); 574 stream->push_headers = NULL; 575 stream->push_headers_used = 0; 576 577 if(rv) { 578 /* denied, kill off the new handle again */ 579 http2_stream_free(newhandle->req.protop); 580 newhandle->req.protop = NULL; 581 (void)Curl_close(newhandle); 582 goto fail; 583 } 584 585 newstream = newhandle->req.protop; 586 newstream->stream_id = frame->promised_stream_id; 587 newhandle->req.maxdownload = -1; 588 newhandle->req.size = -1; 589 590 /* approved, add to the multi handle and immediately switch to PERFORM 591 state with the given connection !*/ 592 rc = Curl_multi_add_perform(data->multi, newhandle, conn); 593 if(rc) { 594 infof(data, "failed to add handle to multi\n"); 595 http2_stream_free(newhandle->req.protop); 596 newhandle->req.protop = NULL; 597 Curl_close(newhandle); 598 rv = 1; 599 goto fail; 600 } 601 602 httpc = &conn->proto.httpc; 603 rv = nghttp2_session_set_stream_user_data(httpc->h2, 604 frame->promised_stream_id, 605 newhandle); 606 if(rv) { 607 infof(data, "failed to set user_data for stream %d\n", 608 frame->promised_stream_id); 609 DEBUGASSERT(0); 610 goto fail; 611 } 612 } 613 else { 614 H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n")); 615 rv = 1; 616 } 617 fail: 618 return rv; 619 } 620 621 /* 622 * multi_connchanged() is called to tell that there is a connection in 623 * this multi handle that has changed state (pipelining become possible, the 624 * number of allowed streams changed or similar), and a subsequent use of this 625 * multi handle should move CONNECT_PEND handles back to CONNECT to have them 626 * retry. 627 */ 628 static void multi_connchanged(struct Curl_multi *multi) 629 { 630 multi->recheckstate = TRUE; 631 } 632 633 static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, 634 void *userp) 635 { 636 struct connectdata *conn = (struct connectdata *)userp; 637 struct http_conn *httpc = &conn->proto.httpc; 638 struct Curl_easy *data_s = NULL; 639 struct HTTP *stream = NULL; 640 int rv; 641 size_t left, ncopy; 642 int32_t stream_id = frame->hd.stream_id; 643 CURLcode result; 644 645 if(!stream_id) { 646 /* stream ID zero is for connection-oriented stuff */ 647 if(frame->hd.type == NGHTTP2_SETTINGS) { 648 uint32_t max_conn = httpc->settings.max_concurrent_streams; 649 H2BUGF(infof(conn->data, "Got SETTINGS\n")); 650 httpc->settings.max_concurrent_streams = 651 nghttp2_session_get_remote_settings( 652 session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); 653 httpc->settings.enable_push = 654 nghttp2_session_get_remote_settings( 655 session, NGHTTP2_SETTINGS_ENABLE_PUSH); 656 H2BUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n", 657 httpc->settings.max_concurrent_streams)); 658 H2BUGF(infof(conn->data, "ENABLE_PUSH == %s\n", 659 httpc->settings.enable_push?"TRUE":"false")); 660 if(max_conn != httpc->settings.max_concurrent_streams) { 661 /* only signal change if the value actually changed */ 662 infof(conn->data, 663 "Connection state changed (MAX_CONCURRENT_STREAMS == %u)!\n", 664 httpc->settings.max_concurrent_streams); 665 multi_connchanged(conn->data->multi); 666 } 667 } 668 return 0; 669 } 670 data_s = nghttp2_session_get_stream_user_data(session, stream_id); 671 if(!data_s) { 672 H2BUGF(infof(conn->data, 673 "No Curl_easy associated with stream: %x\n", 674 stream_id)); 675 return 0; 676 } 677 678 stream = data_s->req.protop; 679 if(!stream) { 680 H2BUGF(infof(data_s, "No proto pointer for stream: %x\n", 681 stream_id)); 682 return NGHTTP2_ERR_CALLBACK_FAILURE; 683 } 684 685 H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x\n", 686 frame->hd.type, stream_id)); 687 688 switch(frame->hd.type) { 689 case NGHTTP2_DATA: 690 /* If body started on this stream, then receiving DATA is illegal. */ 691 if(!stream->bodystarted) { 692 rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, 693 stream_id, NGHTTP2_PROTOCOL_ERROR); 694 695 if(nghttp2_is_fatal(rv)) { 696 return NGHTTP2_ERR_CALLBACK_FAILURE; 697 } 698 } 699 break; 700 case NGHTTP2_HEADERS: 701 if(stream->bodystarted) { 702 /* Only valid HEADERS after body started is trailer HEADERS. We 703 buffer them in on_header callback. */ 704 break; 705 } 706 707 /* nghttp2 guarantees that :status is received, and we store it to 708 stream->status_code. Fuzzing has proven this can still be reached 709 without status code having been set. */ 710 if(stream->status_code == -1) 711 return NGHTTP2_ERR_CALLBACK_FAILURE; 712 713 /* Only final status code signals the end of header */ 714 if(stream->status_code / 100 != 1) { 715 stream->bodystarted = TRUE; 716 stream->status_code = -1; 717 } 718 719 result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2); 720 if(result) 721 return NGHTTP2_ERR_CALLBACK_FAILURE; 722 723 left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf; 724 ncopy = CURLMIN(stream->len, left); 725 726 memcpy(&stream->mem[stream->memlen], 727 stream->header_recvbuf->buffer + stream->nread_header_recvbuf, 728 ncopy); 729 stream->nread_header_recvbuf += ncopy; 730 731 H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n", 732 ncopy, stream_id, stream->mem)); 733 734 stream->len -= ncopy; 735 stream->memlen += ncopy; 736 737 drain_this(data_s, httpc); 738 { 739 /* get the pointer from userp again since it was re-assigned above */ 740 struct connectdata *conn_s = (struct connectdata *)userp; 741 742 /* if we receive data for another handle, wake that up */ 743 if(conn_s->data != data_s) 744 Curl_expire(data_s, 0, EXPIRE_RUN_NOW); 745 } 746 break; 747 case NGHTTP2_PUSH_PROMISE: 748 rv = push_promise(data_s, conn, &frame->push_promise); 749 if(rv) { /* deny! */ 750 rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, 751 frame->push_promise.promised_stream_id, 752 NGHTTP2_CANCEL); 753 if(nghttp2_is_fatal(rv)) { 754 return rv; 755 } 756 } 757 break; 758 default: 759 H2BUGF(infof(data_s, "Got frame type %x for stream %u!\n", 760 frame->hd.type, stream_id)); 761 break; 762 } 763 return 0; 764 } 765 766 static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, 767 int32_t stream_id, 768 const uint8_t *data, size_t len, void *userp) 769 { 770 struct HTTP *stream; 771 struct Curl_easy *data_s; 772 size_t nread; 773 struct connectdata *conn = (struct connectdata *)userp; 774 (void)session; 775 (void)flags; 776 (void)data; 777 778 DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ 779 780 /* get the stream from the hash based on Stream ID */ 781 data_s = nghttp2_session_get_stream_user_data(session, stream_id); 782 if(!data_s) 783 /* Receiving a Stream ID not in the hash should not happen, this is an 784 internal error more than anything else! */ 785 return NGHTTP2_ERR_CALLBACK_FAILURE; 786 787 stream = data_s->req.protop; 788 if(!stream) 789 return NGHTTP2_ERR_CALLBACK_FAILURE; 790 791 nread = CURLMIN(stream->len, len); 792 memcpy(&stream->mem[stream->memlen], data, nread); 793 794 stream->len -= nread; 795 stream->memlen += nread; 796 797 drain_this(data_s, &conn->proto.httpc); 798 799 /* if we receive data for another handle, wake that up */ 800 if(conn->data != data_s) 801 Curl_expire(data_s, 0, EXPIRE_RUN_NOW); 802 803 H2BUGF(infof(data_s, "%zu data received for stream %u " 804 "(%zu left in buffer %p, total %zu)\n", 805 nread, stream_id, 806 stream->len, stream->mem, 807 stream->memlen)); 808 809 if(nread < len) { 810 stream->pausedata = data + nread; 811 stream->pauselen = len - nread; 812 H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer" 813 ", stream %u\n", 814 len - nread, stream_id)); 815 data_s->conn->proto.httpc.pause_stream_id = stream_id; 816 817 return NGHTTP2_ERR_PAUSE; 818 } 819 820 /* pause execution of nghttp2 if we received data for another handle 821 in order to process them first. */ 822 if(conn->data != data_s) { 823 data_s->conn->proto.httpc.pause_stream_id = stream_id; 824 825 return NGHTTP2_ERR_PAUSE; 826 } 827 828 return 0; 829 } 830 831 static int on_stream_close(nghttp2_session *session, int32_t stream_id, 832 uint32_t error_code, void *userp) 833 { 834 struct Curl_easy *data_s; 835 struct HTTP *stream; 836 struct connectdata *conn = (struct connectdata *)userp; 837 int rv; 838 (void)session; 839 (void)stream_id; 840 841 if(stream_id) { 842 struct http_conn *httpc; 843 /* get the stream from the hash based on Stream ID, stream ID zero is for 844 connection-oriented stuff */ 845 data_s = nghttp2_session_get_stream_user_data(session, stream_id); 846 if(!data_s) { 847 /* We could get stream ID not in the hash. For example, if we 848 decided to reject stream (e.g., PUSH_PROMISE). */ 849 return 0; 850 } 851 H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n", 852 http2_strerror(error_code), error_code, stream_id)); 853 stream = data_s->req.protop; 854 if(!stream) 855 return NGHTTP2_ERR_CALLBACK_FAILURE; 856 857 stream->closed = TRUE; 858 httpc = &conn->proto.httpc; 859 drain_this(data_s, httpc); 860 httpc->error_code = error_code; 861 862 /* remove the entry from the hash as the stream is now gone */ 863 rv = nghttp2_session_set_stream_user_data(session, stream_id, 0); 864 if(rv) { 865 infof(data_s, "http/2: failed to clear user_data for stream %d!\n", 866 stream_id); 867 DEBUGASSERT(0); 868 } 869 if(stream_id == httpc->pause_stream_id) { 870 H2BUGF(infof(data_s, "Stopped the pause stream!\n")); 871 httpc->pause_stream_id = 0; 872 } 873 H2BUGF(infof(data_s, "Removed stream %u hash!\n", stream_id)); 874 stream->stream_id = 0; /* cleared */ 875 } 876 return 0; 877 } 878 879 static int on_begin_headers(nghttp2_session *session, 880 const nghttp2_frame *frame, void *userp) 881 { 882 struct HTTP *stream; 883 struct Curl_easy *data_s = NULL; 884 (void)userp; 885 886 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); 887 if(!data_s) { 888 return 0; 889 } 890 891 H2BUGF(infof(data_s, "on_begin_headers() was called\n")); 892 893 if(frame->hd.type != NGHTTP2_HEADERS) { 894 return 0; 895 } 896 897 stream = data_s->req.protop; 898 if(!stream || !stream->bodystarted) { 899 return 0; 900 } 901 902 if(!stream->trailer_recvbuf) { 903 stream->trailer_recvbuf = Curl_add_buffer_init(); 904 if(!stream->trailer_recvbuf) { 905 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 906 } 907 } 908 return 0; 909 } 910 911 /* Decode HTTP status code. Returns -1 if no valid status code was 912 decoded. */ 913 static int decode_status_code(const uint8_t *value, size_t len) 914 { 915 int i; 916 int res; 917 918 if(len != 3) { 919 return -1; 920 } 921 922 res = 0; 923 924 for(i = 0; i < 3; ++i) { 925 char c = value[i]; 926 927 if(c < '0' || c > '9') { 928 return -1; 929 } 930 931 res *= 10; 932 res += c - '0'; 933 } 934 935 return res; 936 } 937 938 /* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */ 939 static int on_header(nghttp2_session *session, const nghttp2_frame *frame, 940 const uint8_t *name, size_t namelen, 941 const uint8_t *value, size_t valuelen, 942 uint8_t flags, 943 void *userp) 944 { 945 struct HTTP *stream; 946 struct Curl_easy *data_s; 947 int32_t stream_id = frame->hd.stream_id; 948 struct connectdata *conn = (struct connectdata *)userp; 949 CURLcode result; 950 (void)flags; 951 952 DEBUGASSERT(stream_id); /* should never be a zero stream ID here */ 953 954 /* get the stream from the hash based on Stream ID */ 955 data_s = nghttp2_session_get_stream_user_data(session, stream_id); 956 if(!data_s) 957 /* Receiving a Stream ID not in the hash should not happen, this is an 958 internal error more than anything else! */ 959 return NGHTTP2_ERR_CALLBACK_FAILURE; 960 961 stream = data_s->req.protop; 962 if(!stream) { 963 failf(data_s, "Internal NULL stream! 5\n"); 964 return NGHTTP2_ERR_CALLBACK_FAILURE; 965 } 966 967 /* Store received PUSH_PROMISE headers to be used when the subsequent 968 PUSH_PROMISE callback comes */ 969 if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { 970 char *h; 971 972 if(!strcmp(":authority", (const char *)name)) { 973 /* psuedo headers are lower case */ 974 int rc = 0; 975 char *check = aprintf("%s:%d", conn->host.name, conn->remote_port); 976 if(!check) 977 /* no memory */ 978 return NGHTTP2_ERR_CALLBACK_FAILURE; 979 if(!Curl_strcasecompare(check, (const char *)value)) { 980 /* This is push is not for the same authority that was asked for in 981 * the URL. RFC 7540 section 8.2 says: "A client MUST treat a 982 * PUSH_PROMISE for which the server is not authoritative as a stream 983 * error of type PROTOCOL_ERROR." 984 */ 985 (void)nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, 986 stream_id, NGHTTP2_PROTOCOL_ERROR); 987 rc = NGHTTP2_ERR_CALLBACK_FAILURE; 988 } 989 free(check); 990 if(rc) 991 return rc; 992 } 993 994 if(!stream->push_headers) { 995 stream->push_headers_alloc = 10; 996 stream->push_headers = malloc(stream->push_headers_alloc * 997 sizeof(char *)); 998 if(!stream->push_headers) 999 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 1000 stream->push_headers_used = 0; 1001 } 1002 else if(stream->push_headers_used == 1003 stream->push_headers_alloc) { 1004 char **headp; 1005 stream->push_headers_alloc *= 2; 1006 headp = Curl_saferealloc(stream->push_headers, 1007 stream->push_headers_alloc * sizeof(char *)); 1008 if(!headp) { 1009 stream->push_headers = NULL; 1010 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 1011 } 1012 stream->push_headers = headp; 1013 } 1014 h = aprintf("%s:%s", name, value); 1015 if(h) 1016 stream->push_headers[stream->push_headers_used++] = h; 1017 return 0; 1018 } 1019 1020 if(stream->bodystarted) { 1021 /* This is trailer fields. */ 1022 /* 4 is for ": " and "\r\n". */ 1023 uint32_t n = (uint32_t)(namelen + valuelen + 4); 1024 1025 H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen, 1026 value)); 1027 1028 result = Curl_add_buffer(&stream->trailer_recvbuf, &n, sizeof(n)); 1029 if(result) 1030 return NGHTTP2_ERR_CALLBACK_FAILURE; 1031 result = Curl_add_buffer(&stream->trailer_recvbuf, name, namelen); 1032 if(result) 1033 return NGHTTP2_ERR_CALLBACK_FAILURE; 1034 result = Curl_add_buffer(&stream->trailer_recvbuf, ": ", 2); 1035 if(result) 1036 return NGHTTP2_ERR_CALLBACK_FAILURE; 1037 result = Curl_add_buffer(&stream->trailer_recvbuf, value, valuelen); 1038 if(result) 1039 return NGHTTP2_ERR_CALLBACK_FAILURE; 1040 result = Curl_add_buffer(&stream->trailer_recvbuf, "\r\n\0", 3); 1041 if(result) 1042 return NGHTTP2_ERR_CALLBACK_FAILURE; 1043 1044 return 0; 1045 } 1046 1047 if(namelen == sizeof(":status") - 1 && 1048 memcmp(":status", name, namelen) == 0) { 1049 /* nghttp2 guarantees :status is received first and only once, and 1050 value is 3 digits status code, and decode_status_code always 1051 succeeds. */ 1052 stream->status_code = decode_status_code(value, valuelen); 1053 DEBUGASSERT(stream->status_code != -1); 1054 1055 result = Curl_add_buffer(&stream->header_recvbuf, "HTTP/2 ", 7); 1056 if(result) 1057 return NGHTTP2_ERR_CALLBACK_FAILURE; 1058 result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen); 1059 if(result) 1060 return NGHTTP2_ERR_CALLBACK_FAILURE; 1061 /* the space character after the status code is mandatory */ 1062 result = Curl_add_buffer(&stream->header_recvbuf, " \r\n", 3); 1063 if(result) 1064 return NGHTTP2_ERR_CALLBACK_FAILURE; 1065 /* if we receive data for another handle, wake that up */ 1066 if(conn->data != data_s) 1067 Curl_expire(data_s, 0, EXPIRE_RUN_NOW); 1068 1069 H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n", 1070 stream->status_code, data_s)); 1071 return 0; 1072 } 1073 1074 /* nghttp2 guarantees that namelen > 0, and :status was already 1075 received, and this is not pseudo-header field . */ 1076 /* convert to a HTTP1-style header */ 1077 result = Curl_add_buffer(&stream->header_recvbuf, name, namelen); 1078 if(result) 1079 return NGHTTP2_ERR_CALLBACK_FAILURE; 1080 result = Curl_add_buffer(&stream->header_recvbuf, ": ", 2); 1081 if(result) 1082 return NGHTTP2_ERR_CALLBACK_FAILURE; 1083 result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen); 1084 if(result) 1085 return NGHTTP2_ERR_CALLBACK_FAILURE; 1086 result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2); 1087 if(result) 1088 return NGHTTP2_ERR_CALLBACK_FAILURE; 1089 /* if we receive data for another handle, wake that up */ 1090 if(conn->data != data_s) 1091 Curl_expire(data_s, 0, EXPIRE_RUN_NOW); 1092 1093 H2BUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen, 1094 value)); 1095 1096 return 0; /* 0 is successful */ 1097 } 1098 1099 static ssize_t data_source_read_callback(nghttp2_session *session, 1100 int32_t stream_id, 1101 uint8_t *buf, size_t length, 1102 uint32_t *data_flags, 1103 nghttp2_data_source *source, 1104 void *userp) 1105 { 1106 struct Curl_easy *data_s; 1107 struct HTTP *stream = NULL; 1108 size_t nread; 1109 (void)source; 1110 (void)userp; 1111 1112 if(stream_id) { 1113 /* get the stream from the hash based on Stream ID, stream ID zero is for 1114 connection-oriented stuff */ 1115 data_s = nghttp2_session_get_stream_user_data(session, stream_id); 1116 if(!data_s) 1117 /* Receiving a Stream ID not in the hash should not happen, this is an 1118 internal error more than anything else! */ 1119 return NGHTTP2_ERR_CALLBACK_FAILURE; 1120 1121 stream = data_s->req.protop; 1122 if(!stream) 1123 return NGHTTP2_ERR_CALLBACK_FAILURE; 1124 } 1125 else 1126 return NGHTTP2_ERR_INVALID_ARGUMENT; 1127 1128 nread = CURLMIN(stream->upload_len, length); 1129 if(nread > 0) { 1130 memcpy(buf, stream->upload_mem, nread); 1131 stream->upload_mem += nread; 1132 stream->upload_len -= nread; 1133 if(data_s->state.infilesize != -1) 1134 stream->upload_left -= nread; 1135 } 1136 1137 if(stream->upload_left == 0) 1138 *data_flags = NGHTTP2_DATA_FLAG_EOF; 1139 else if(nread == 0) 1140 return NGHTTP2_ERR_DEFERRED; 1141 1142 H2BUGF(infof(data_s, "data_source_read_callback: " 1143 "returns %zu bytes stream %u\n", 1144 nread, stream_id)); 1145 1146 return nread; 1147 } 1148 1149 #if defined(NGHTTP2_HAS_ERROR_CALLBACK) && \ 1150 !defined(CURL_DISABLE_VERBOSE_STRINGS) 1151 static int error_callback(nghttp2_session *session, 1152 const char *msg, 1153 size_t len, 1154 void *userp) 1155 { 1156 struct connectdata *conn = (struct connectdata *)userp; 1157 (void)session; 1158 infof(conn->data, "http2 error: %.*s\n", len, msg); 1159 return 0; 1160 } 1161 #endif 1162 1163 static void populate_settings(struct connectdata *conn, 1164 struct http_conn *httpc) 1165 { 1166 nghttp2_settings_entry *iv = httpc->local_settings; 1167 1168 iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; 1169 iv[0].value = 100; 1170 1171 iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; 1172 iv[1].value = HTTP2_HUGE_WINDOW_SIZE; 1173 1174 iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; 1175 iv[2].value = conn->data->multi->push_cb != NULL; 1176 1177 httpc->local_settings_num = 3; 1178 } 1179 1180 void Curl_http2_done(struct connectdata *conn, bool premature) 1181 { 1182 struct Curl_easy *data = conn->data; 1183 struct HTTP *http = data->req.protop; 1184 struct http_conn *httpc = &conn->proto.httpc; 1185 1186 /* there might be allocated resources done before this got the 'h2' pointer 1187 setup */ 1188 if(http->header_recvbuf) { 1189 Curl_add_buffer_free(&http->header_recvbuf); 1190 Curl_add_buffer_free(&http->trailer_recvbuf); 1191 if(http->push_headers) { 1192 /* if they weren't used and then freed before */ 1193 for(; http->push_headers_used > 0; --http->push_headers_used) { 1194 free(http->push_headers[http->push_headers_used - 1]); 1195 } 1196 free(http->push_headers); 1197 http->push_headers = NULL; 1198 } 1199 } 1200 1201 if(!httpc->h2) /* not HTTP/2 ? */ 1202 return; 1203 1204 if(data->state.drain) 1205 drained_transfer(data, httpc); 1206 1207 if(premature) { 1208 /* RST_STREAM */ 1209 if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, 1210 http->stream_id, NGHTTP2_STREAM_CLOSED)) 1211 (void)nghttp2_session_send(httpc->h2); 1212 1213 if(http->stream_id == httpc->pause_stream_id) { 1214 infof(data, "stopped the pause stream!\n"); 1215 httpc->pause_stream_id = 0; 1216 } 1217 } 1218 /* -1 means unassigned and 0 means cleared */ 1219 if(http->stream_id > 0) { 1220 int rv = nghttp2_session_set_stream_user_data(httpc->h2, 1221 http->stream_id, 0); 1222 if(rv) { 1223 infof(data, "http/2: failed to clear user_data for stream %d!\n", 1224 http->stream_id); 1225 DEBUGASSERT(0); 1226 } 1227 http->stream_id = 0; 1228 } 1229 } 1230 1231 /* 1232 * Initialize nghttp2 for a Curl connection 1233 */ 1234 static CURLcode http2_init(struct connectdata *conn) 1235 { 1236 if(!conn->proto.httpc.h2) { 1237 int rc; 1238 nghttp2_session_callbacks *callbacks; 1239 1240 conn->proto.httpc.inbuf = malloc(H2_BUFSIZE); 1241 if(conn->proto.httpc.inbuf == NULL) 1242 return CURLE_OUT_OF_MEMORY; 1243 1244 rc = nghttp2_session_callbacks_new(&callbacks); 1245 1246 if(rc) { 1247 failf(conn->data, "Couldn't initialize nghttp2 callbacks!"); 1248 return CURLE_OUT_OF_MEMORY; /* most likely at least */ 1249 } 1250 1251 /* nghttp2_send_callback */ 1252 nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); 1253 /* nghttp2_on_frame_recv_callback */ 1254 nghttp2_session_callbacks_set_on_frame_recv_callback 1255 (callbacks, on_frame_recv); 1256 /* nghttp2_on_data_chunk_recv_callback */ 1257 nghttp2_session_callbacks_set_on_data_chunk_recv_callback 1258 (callbacks, on_data_chunk_recv); 1259 /* nghttp2_on_stream_close_callback */ 1260 nghttp2_session_callbacks_set_on_stream_close_callback 1261 (callbacks, on_stream_close); 1262 /* nghttp2_on_begin_headers_callback */ 1263 nghttp2_session_callbacks_set_on_begin_headers_callback 1264 (callbacks, on_begin_headers); 1265 /* nghttp2_on_header_callback */ 1266 nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header); 1267 1268 #ifndef CURL_DISABLE_VERBOSE_STRINGS 1269 nghttp2_session_callbacks_set_error_callback(callbacks, error_callback); 1270 #endif 1271 1272 /* The nghttp2 session is not yet setup, do it */ 1273 rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn); 1274 1275 nghttp2_session_callbacks_del(callbacks); 1276 1277 if(rc) { 1278 failf(conn->data, "Couldn't initialize nghttp2!"); 1279 return CURLE_OUT_OF_MEMORY; /* most likely at least */ 1280 } 1281 } 1282 return CURLE_OK; 1283 } 1284 1285 /* 1286 * Append headers to ask for a HTTP1.1 to HTTP2 upgrade. 1287 */ 1288 CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, 1289 struct connectdata *conn) 1290 { 1291 CURLcode result; 1292 ssize_t binlen; 1293 char *base64; 1294 size_t blen; 1295 struct SingleRequest *k = &conn->data->req; 1296 uint8_t *binsettings = conn->proto.httpc.binsettings; 1297 struct http_conn *httpc = &conn->proto.httpc; 1298 1299 populate_settings(conn, httpc); 1300 1301 /* this returns number of bytes it wrote */ 1302 binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN, 1303 httpc->local_settings, 1304 httpc->local_settings_num); 1305 if(!binlen) { 1306 failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); 1307 Curl_add_buffer_free(&req); 1308 return CURLE_FAILED_INIT; 1309 } 1310 conn->proto.httpc.binlen = binlen; 1311 1312 result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen, 1313 &base64, &blen); 1314 if(result) { 1315 Curl_add_buffer_free(&req); 1316 return result; 1317 } 1318 1319 result = Curl_add_bufferf(&req, 1320 "Connection: Upgrade, HTTP2-Settings\r\n" 1321 "Upgrade: %s\r\n" 1322 "HTTP2-Settings: %s\r\n", 1323 NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); 1324 free(base64); 1325 1326 k->upgr101 = UPGR101_REQUESTED; 1327 1328 return result; 1329 } 1330 1331 /* 1332 * Returns nonzero if current HTTP/2 session should be closed. 1333 */ 1334 static int should_close_session(struct http_conn *httpc) 1335 { 1336 return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) && 1337 !nghttp2_session_want_write(httpc->h2); 1338 } 1339 1340 /* 1341 * h2_process_pending_input() processes pending input left in 1342 * httpc->inbuf. Then, call h2_session_send() to send pending data. 1343 * This function returns 0 if it succeeds, or -1 and error code will 1344 * be assigned to *err. 1345 */ 1346 static int h2_process_pending_input(struct connectdata *conn, 1347 struct http_conn *httpc, 1348 CURLcode *err) 1349 { 1350 ssize_t nread; 1351 char *inbuf; 1352 ssize_t rv; 1353 struct Curl_easy *data = conn->data; 1354 1355 nread = httpc->inbuflen - httpc->nread_inbuf; 1356 inbuf = httpc->inbuf + httpc->nread_inbuf; 1357 1358 rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); 1359 if(rv < 0) { 1360 failf(data, 1361 "h2_process_pending_input: nghttp2_session_mem_recv() returned " 1362 "%zd:%s\n", rv, nghttp2_strerror((int)rv)); 1363 *err = CURLE_RECV_ERROR; 1364 return -1; 1365 } 1366 1367 if(nread == rv) { 1368 H2BUGF(infof(data, 1369 "h2_process_pending_input: All data in connection buffer " 1370 "processed\n")); 1371 httpc->inbuflen = 0; 1372 httpc->nread_inbuf = 0; 1373 } 1374 else { 1375 httpc->nread_inbuf += rv; 1376 H2BUGF(infof(data, 1377 "h2_process_pending_input: %zu bytes left in connection " 1378 "buffer\n", 1379 httpc->inbuflen - httpc->nread_inbuf)); 1380 } 1381 1382 rv = h2_session_send(data, httpc->h2); 1383 if(rv != 0) { 1384 *err = CURLE_SEND_ERROR; 1385 return -1; 1386 } 1387 1388 if(should_close_session(httpc)) { 1389 H2BUGF(infof(data, 1390 "h2_process_pending_input: nothing to do in this session\n")); 1391 if(httpc->error_code) 1392 *err = CURLE_HTTP2; 1393 else { 1394 /* not an error per se, but should still close the connection */ 1395 connclose(conn, "GOAWAY received"); 1396 *err = CURLE_OK; 1397 } 1398 return -1; 1399 } 1400 1401 return 0; 1402 } 1403 1404 /* 1405 * Called from transfer.c:done_sending when we stop uploading. 1406 */ 1407 CURLcode Curl_http2_done_sending(struct connectdata *conn) 1408 { 1409 CURLcode result = CURLE_OK; 1410 1411 if((conn->handler == &Curl_handler_http2_ssl) || 1412 (conn->handler == &Curl_handler_http2)) { 1413 /* make sure this is only attempted for HTTP/2 transfers */ 1414 1415 struct HTTP *stream = conn->data->req.protop; 1416 1417 if(stream->upload_left) { 1418 /* If the stream still thinks there's data left to upload. */ 1419 struct http_conn *httpc = &conn->proto.httpc; 1420 nghttp2_session *h2 = httpc->h2; 1421 1422 stream->upload_left = 0; /* DONE! */ 1423 1424 /* resume sending here to trigger the callback to get called again so 1425 that it can signal EOF to nghttp2 */ 1426 (void)nghttp2_session_resume_data(h2, stream->stream_id); 1427 1428 (void)h2_process_pending_input(conn, httpc, &result); 1429 } 1430 } 1431 return result; 1432 } 1433 1434 static ssize_t http2_handle_stream_close(struct connectdata *conn, 1435 struct Curl_easy *data, 1436 struct HTTP *stream, CURLcode *err) 1437 { 1438 char *trailer_pos, *trailer_end; 1439 CURLcode result; 1440 struct http_conn *httpc = &conn->proto.httpc; 1441 1442 if(httpc->pause_stream_id == stream->stream_id) { 1443 httpc->pause_stream_id = 0; 1444 } 1445 1446 drained_transfer(data, httpc); 1447 1448 if(httpc->pause_stream_id == 0) { 1449 if(h2_process_pending_input(conn, httpc, err) != 0) { 1450 return -1; 1451 } 1452 } 1453 1454 DEBUGASSERT(data->state.drain == 0); 1455 1456 /* Reset to FALSE to prevent infinite loop in readwrite_data function. */ 1457 stream->closed = FALSE; 1458 if(httpc->error_code == NGHTTP2_REFUSED_STREAM) { 1459 H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!\n", 1460 stream->stream_id)); 1461 connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */ 1462 data->state.refused_stream = TRUE; 1463 *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ 1464 return -1; 1465 } 1466 else if(httpc->error_code != NGHTTP2_NO_ERROR) { 1467 failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)", 1468 stream->stream_id, http2_strerror(httpc->error_code), 1469 httpc->error_code); 1470 *err = CURLE_HTTP2_STREAM; 1471 return -1; 1472 } 1473 1474 if(!stream->bodystarted) { 1475 failf(data, "HTTP/2 stream %d was closed cleanly, but before getting " 1476 " all response header fields, treated as error", 1477 stream->stream_id); 1478 *err = CURLE_HTTP2_STREAM; 1479 return -1; 1480 } 1481 1482 if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) { 1483 trailer_pos = stream->trailer_recvbuf->buffer; 1484 trailer_end = trailer_pos + stream->trailer_recvbuf->size_used; 1485 1486 for(; trailer_pos < trailer_end;) { 1487 uint32_t n; 1488 memcpy(&n, trailer_pos, sizeof(n)); 1489 trailer_pos += sizeof(n); 1490 1491 result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n); 1492 if(result) { 1493 *err = result; 1494 return -1; 1495 } 1496 1497 trailer_pos += n + 1; 1498 } 1499 } 1500 1501 stream->close_handled = TRUE; 1502 1503 H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); 1504 return 0; 1505 } 1506 1507 /* 1508 * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight 1509 * and dependency to the peer. It also stores the updated values in the state 1510 * struct. 1511 */ 1512 1513 static void h2_pri_spec(struct Curl_easy *data, 1514 nghttp2_priority_spec *pri_spec) 1515 { 1516 struct HTTP *depstream = (data->set.stream_depends_on? 1517 data->set.stream_depends_on->req.protop:NULL); 1518 int32_t depstream_id = depstream? depstream->stream_id:0; 1519 nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight, 1520 data->set.stream_depends_e); 1521 data->state.stream_weight = data->set.stream_weight; 1522 data->state.stream_depends_e = data->set.stream_depends_e; 1523 data->state.stream_depends_on = data->set.stream_depends_on; 1524 } 1525 1526 /* 1527 * h2_session_send() checks if there's been an update in the priority / 1528 * dependency settings and if so it submits a PRIORITY frame with the updated 1529 * info. 1530 */ 1531 static int h2_session_send(struct Curl_easy *data, 1532 nghttp2_session *h2) 1533 { 1534 struct HTTP *stream = data->req.protop; 1535 if((data->set.stream_weight != data->state.stream_weight) || 1536 (data->set.stream_depends_e != data->state.stream_depends_e) || 1537 (data->set.stream_depends_on != data->state.stream_depends_on) ) { 1538 /* send new weight and/or dependency */ 1539 nghttp2_priority_spec pri_spec; 1540 int rv; 1541 1542 h2_pri_spec(data, &pri_spec); 1543 1544 H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n", 1545 stream->stream_id, data)); 1546 rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id, 1547 &pri_spec); 1548 if(rv) 1549 return rv; 1550 } 1551 1552 return nghttp2_session_send(h2); 1553 } 1554 1555 static ssize_t http2_recv(struct connectdata *conn, int sockindex, 1556 char *mem, size_t len, CURLcode *err) 1557 { 1558 CURLcode result = CURLE_OK; 1559 ssize_t rv; 1560 ssize_t nread; 1561 struct http_conn *httpc = &conn->proto.httpc; 1562 struct Curl_easy *data = conn->data; 1563 struct HTTP *stream = data->req.protop; 1564 1565 (void)sockindex; /* we always do HTTP2 on sockindex 0 */ 1566 1567 if(should_close_session(httpc)) { 1568 H2BUGF(infof(data, 1569 "http2_recv: nothing to do in this session\n")); 1570 *err = CURLE_HTTP2; 1571 return -1; 1572 } 1573 1574 /* Nullify here because we call nghttp2_session_send() and they 1575 might refer to the old buffer. */ 1576 stream->upload_mem = NULL; 1577 stream->upload_len = 0; 1578 1579 /* 1580 * At this point 'stream' is just in the Curl_easy the connection 1581 * identifies as its owner at this time. 1582 */ 1583 1584 if(stream->bodystarted && 1585 stream->nread_header_recvbuf < stream->header_recvbuf->size_used) { 1586 /* If there is body data pending for this stream to return, do that */ 1587 size_t left = 1588 stream->header_recvbuf->size_used - stream->nread_header_recvbuf; 1589 size_t ncopy = CURLMIN(len, left); 1590 memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf, 1591 ncopy); 1592 stream->nread_header_recvbuf += ncopy; 1593 1594 H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n", 1595 (int)ncopy)); 1596 return ncopy; 1597 } 1598 1599 H2BUGF(infof(data, "http2_recv: easy %p (stream %u)\n", 1600 data, stream->stream_id)); 1601 1602 if((data->state.drain) && stream->memlen) { 1603 H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n", 1604 stream->memlen, stream->stream_id, 1605 stream->mem, mem)); 1606 if(mem != stream->mem) { 1607 /* if we didn't get the same buffer this time, we must move the data to 1608 the beginning */ 1609 memmove(mem, stream->mem, stream->memlen); 1610 stream->len = len - stream->memlen; 1611 stream->mem = mem; 1612 } 1613 if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) { 1614 /* We have paused nghttp2, but we have no pause data (see 1615 on_data_chunk_recv). */ 1616 httpc->pause_stream_id = 0; 1617 if(h2_process_pending_input(conn, httpc, &result) != 0) { 1618 *err = result; 1619 return -1; 1620 } 1621 } 1622 } 1623 else if(stream->pausedata) { 1624 DEBUGASSERT(httpc->pause_stream_id == stream->stream_id); 1625 nread = CURLMIN(len, stream->pauselen); 1626 memcpy(mem, stream->pausedata, nread); 1627 1628 stream->pausedata += nread; 1629 stream->pauselen -= nread; 1630 1631 infof(data, "%zd data bytes written\n", nread); 1632 if(stream->pauselen == 0) { 1633 H2BUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id)); 1634 DEBUGASSERT(httpc->pause_stream_id == stream->stream_id); 1635 httpc->pause_stream_id = 0; 1636 1637 stream->pausedata = NULL; 1638 stream->pauselen = 0; 1639 1640 /* When NGHTTP2_ERR_PAUSE is returned from 1641 data_source_read_callback, we might not process DATA frame 1642 fully. Calling nghttp2_session_mem_recv() again will 1643 continue to process DATA frame, but if there is no incoming 1644 frames, then we have to call it again with 0-length data. 1645 Without this, on_stream_close callback will not be called, 1646 and stream could be hanged. */ 1647 if(h2_process_pending_input(conn, httpc, &result) != 0) { 1648 *err = result; 1649 return -1; 1650 } 1651 } 1652 H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n", 1653 nread, stream->stream_id)); 1654 return nread; 1655 } 1656 else if(httpc->pause_stream_id) { 1657 /* If a stream paused nghttp2_session_mem_recv previously, and has 1658 not processed all data, it still refers to the buffer in 1659 nghttp2_session. If we call nghttp2_session_mem_recv(), we may 1660 overwrite that buffer. To avoid that situation, just return 1661 here with CURLE_AGAIN. This could be busy loop since data in 1662 socket is not read. But it seems that usually streams are 1663 notified with its drain property, and socket is read again 1664 quickly. */ 1665 H2BUGF(infof(data, "stream %x is paused, pause id: %x\n", 1666 stream->stream_id, httpc->pause_stream_id)); 1667 *err = CURLE_AGAIN; 1668 return -1; 1669 } 1670 else { 1671 char *inbuf; 1672 /* remember where to store incoming data for this stream and how big the 1673 buffer is */ 1674 stream->mem = mem; 1675 stream->len = len; 1676 stream->memlen = 0; 1677 1678 if(httpc->inbuflen == 0) { 1679 nread = ((Curl_recv *)httpc->recv_underlying)( 1680 conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result); 1681 1682 if(nread == -1) { 1683 if(result != CURLE_AGAIN) 1684 failf(data, "Failed receiving HTTP2 data"); 1685 else if(stream->closed) 1686 /* received when the stream was already closed! */ 1687 return http2_handle_stream_close(conn, data, stream, err); 1688 1689 *err = result; 1690 return -1; 1691 } 1692 1693 if(nread == 0) { 1694 H2BUGF(infof(data, "end of stream\n")); 1695 *err = CURLE_OK; 1696 return 0; 1697 } 1698 1699 H2BUGF(infof(data, "nread=%zd\n", nread)); 1700 1701 httpc->inbuflen = nread; 1702 inbuf = httpc->inbuf; 1703 } 1704 else { 1705 nread = httpc->inbuflen - httpc->nread_inbuf; 1706 inbuf = httpc->inbuf + httpc->nread_inbuf; 1707 1708 H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd\n", 1709 nread)); 1710 } 1711 rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); 1712 1713 if(nghttp2_is_fatal((int)rv)) { 1714 failf(data, "nghttp2_session_mem_recv() returned %zd:%s\n", 1715 rv, nghttp2_strerror((int)rv)); 1716 *err = CURLE_RECV_ERROR; 1717 return -1; 1718 } 1719 H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv)); 1720 if(nread == rv) { 1721 H2BUGF(infof(data, "All data in connection buffer processed\n")); 1722 httpc->inbuflen = 0; 1723 httpc->nread_inbuf = 0; 1724 } 1725 else { 1726 httpc->nread_inbuf += rv; 1727 H2BUGF(infof(data, "%zu bytes left in connection buffer\n", 1728 httpc->inbuflen - httpc->nread_inbuf)); 1729 } 1730 /* Always send pending frames in nghttp2 session, because 1731 nghttp2_session_mem_recv() may queue new frame */ 1732 rv = h2_session_send(data, httpc->h2); 1733 if(rv != 0) { 1734 *err = CURLE_SEND_ERROR; 1735 return -1; 1736 } 1737 1738 if(should_close_session(httpc)) { 1739 H2BUGF(infof(data, "http2_recv: nothing to do in this session\n")); 1740 *err = CURLE_HTTP2; 1741 return -1; 1742 } 1743 } 1744 if(stream->memlen) { 1745 ssize_t retlen = stream->memlen; 1746 H2BUGF(infof(data, "http2_recv: returns %zd for stream %u\n", 1747 retlen, stream->stream_id)); 1748 stream->memlen = 0; 1749 1750 if(httpc->pause_stream_id == stream->stream_id) { 1751 /* data for this stream is returned now, but this stream caused a pause 1752 already so we need it called again asap */ 1753 H2BUGF(infof(data, "Data returned for PAUSED stream %u\n", 1754 stream->stream_id)); 1755 } 1756 else if(!stream->closed) { 1757 drained_transfer(data, httpc); 1758 } 1759 1760 return retlen; 1761 } 1762 /* If stream is closed, return 0 to signal the http routine to close 1763 the connection */ 1764 if(stream->closed) { 1765 return http2_handle_stream_close(conn, data, stream, err); 1766 } 1767 *err = CURLE_AGAIN; 1768 H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u\n", 1769 stream->stream_id)); 1770 return -1; 1771 } 1772 1773 /* Index where :authority header field will appear in request header 1774 field list. */ 1775 #define AUTHORITY_DST_IDX 3 1776 1777 #define HEADER_OVERFLOW(x) \ 1778 (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen) 1779 1780 /* 1781 * Check header memory for the token "trailers". 1782 * Parse the tokens as separated by comma and surrounded by whitespace. 1783 * Returns TRUE if found or FALSE if not. 1784 */ 1785 static bool contains_trailers(const char *p, size_t len) 1786 { 1787 const char *end = p + len; 1788 for(;;) { 1789 for(; p != end && (*p == ' ' || *p == '\t'); ++p) 1790 ; 1791 if(p == end || (size_t)(end - p) < sizeof("trailers") - 1) 1792 return FALSE; 1793 if(strncasecompare("trailers", p, sizeof("trailers") - 1)) { 1794 p += sizeof("trailers") - 1; 1795 for(; p != end && (*p == ' ' || *p == '\t'); ++p) 1796 ; 1797 if(p == end || *p == ',') 1798 return TRUE; 1799 } 1800 /* skip to next token */ 1801 for(; p != end && *p != ','; ++p) 1802 ; 1803 if(p == end) 1804 return FALSE; 1805 ++p; 1806 } 1807 } 1808 1809 typedef enum { 1810 /* Send header to server */ 1811 HEADERINST_FORWARD, 1812 /* Don't send header to server */ 1813 HEADERINST_IGNORE, 1814 /* Discard header, and replace it with "te: trailers" */ 1815 HEADERINST_TE_TRAILERS 1816 } header_instruction; 1817 1818 /* Decides how to treat given header field. */ 1819 static header_instruction inspect_header(const char *name, size_t namelen, 1820 const char *value, size_t valuelen) { 1821 switch(namelen) { 1822 case 2: 1823 if(!strncasecompare("te", name, namelen)) 1824 return HEADERINST_FORWARD; 1825 1826 return contains_trailers(value, valuelen) ? 1827 HEADERINST_TE_TRAILERS : HEADERINST_IGNORE; 1828 case 7: 1829 return strncasecompare("upgrade", name, namelen) ? 1830 HEADERINST_IGNORE : HEADERINST_FORWARD; 1831 case 10: 1832 return (strncasecompare("connection", name, namelen) || 1833 strncasecompare("keep-alive", name, namelen)) ? 1834 HEADERINST_IGNORE : HEADERINST_FORWARD; 1835 case 16: 1836 return strncasecompare("proxy-connection", name, namelen) ? 1837 HEADERINST_IGNORE : HEADERINST_FORWARD; 1838 case 17: 1839 return strncasecompare("transfer-encoding", name, namelen) ? 1840 HEADERINST_IGNORE : HEADERINST_FORWARD; 1841 default: 1842 return HEADERINST_FORWARD; 1843 } 1844 } 1845 1846 static ssize_t http2_send(struct connectdata *conn, int sockindex, 1847 const void *mem, size_t len, CURLcode *err) 1848 { 1849 /* 1850 * BIG TODO: Currently, we send request in this function, but this 1851 * function is also used to send request body. It would be nice to 1852 * add dedicated function for request. 1853 */ 1854 int rv; 1855 struct http_conn *httpc = &conn->proto.httpc; 1856 struct HTTP *stream = conn->data->req.protop; 1857 nghttp2_nv *nva = NULL; 1858 size_t nheader; 1859 size_t i; 1860 size_t authority_idx; 1861 char *hdbuf = (char *)mem; 1862 char *end, *line_end; 1863 nghttp2_data_provider data_prd; 1864 int32_t stream_id; 1865 nghttp2_session *h2 = httpc->h2; 1866 nghttp2_priority_spec pri_spec; 1867 1868 (void)sockindex; 1869 1870 H2BUGF(infof(conn->data, "http2_send len=%zu\n", len)); 1871 1872 if(stream->stream_id != -1) { 1873 if(stream->close_handled) { 1874 infof(conn->data, "stream %d closed\n", stream->stream_id); 1875 *err = CURLE_HTTP2_STREAM; 1876 return -1; 1877 } 1878 else if(stream->closed) { 1879 return http2_handle_stream_close(conn, conn->data, stream, err); 1880 } 1881 /* If stream_id != -1, we have dispatched request HEADERS, and now 1882 are going to send or sending request body in DATA frame */ 1883 stream->upload_mem = mem; 1884 stream->upload_len = len; 1885 nghttp2_session_resume_data(h2, stream->stream_id); 1886 rv = h2_session_send(conn->data, h2); 1887 if(nghttp2_is_fatal(rv)) { 1888 *err = CURLE_SEND_ERROR; 1889 return -1; 1890 } 1891 len -= stream->upload_len; 1892 1893 /* Nullify here because we call nghttp2_session_send() and they 1894 might refer to the old buffer. */ 1895 stream->upload_mem = NULL; 1896 stream->upload_len = 0; 1897 1898 if(should_close_session(httpc)) { 1899 H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); 1900 *err = CURLE_HTTP2; 1901 return -1; 1902 } 1903 1904 if(stream->upload_left) { 1905 /* we are sure that we have more data to send here. Calling the 1906 following API will make nghttp2_session_want_write() return 1907 nonzero if remote window allows it, which then libcurl checks 1908 socket is writable or not. See http2_perform_getsock(). */ 1909 nghttp2_session_resume_data(h2, stream->stream_id); 1910 } 1911 1912 H2BUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len, 1913 stream->stream_id)); 1914 return len; 1915 } 1916 1917 /* Calculate number of headers contained in [mem, mem + len) */ 1918 /* Here, we assume the curl http code generate *correct* HTTP header 1919 field block */ 1920 nheader = 0; 1921 for(i = 1; i < len; ++i) { 1922 if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') { 1923 ++nheader; 1924 ++i; 1925 } 1926 } 1927 if(nheader < 2) 1928 goto fail; 1929 1930 /* We counted additional 2 \r\n in the first and last line. We need 3 1931 new headers: :method, :path and :scheme. Therefore we need one 1932 more space. */ 1933 nheader += 1; 1934 nva = malloc(sizeof(nghttp2_nv) * nheader); 1935 if(nva == NULL) { 1936 *err = CURLE_OUT_OF_MEMORY; 1937 return -1; 1938 } 1939 1940 /* Extract :method, :path from request line 1941 We do line endings with CRLF so checking for CR is enough */ 1942 line_end = memchr(hdbuf, '\r', len); 1943 if(!line_end) 1944 goto fail; 1945 1946 /* Method does not contain spaces */ 1947 end = memchr(hdbuf, ' ', line_end - hdbuf); 1948 if(!end || end == hdbuf) 1949 goto fail; 1950 nva[0].name = (unsigned char *)":method"; 1951 nva[0].namelen = strlen((char *)nva[0].name); 1952 nva[0].value = (unsigned char *)hdbuf; 1953 nva[0].valuelen = (size_t)(end - hdbuf); 1954 nva[0].flags = NGHTTP2_NV_FLAG_NONE; 1955 if(HEADER_OVERFLOW(nva[0])) { 1956 failf(conn->data, "Failed sending HTTP request: Header overflow"); 1957 goto fail; 1958 } 1959 1960 hdbuf = end + 1; 1961 1962 /* Path may contain spaces so scan backwards */ 1963 end = NULL; 1964 for(i = (size_t)(line_end - hdbuf); i; --i) { 1965 if(hdbuf[i - 1] == ' ') { 1966 end = &hdbuf[i - 1]; 1967 break; 1968 } 1969 } 1970 if(!end || end == hdbuf) 1971 goto fail; 1972 nva[1].name = (unsigned char *)":path"; 1973 nva[1].namelen = strlen((char *)nva[1].name); 1974 nva[1].value = (unsigned char *)hdbuf; 1975 nva[1].valuelen = (size_t)(end - hdbuf); 1976 nva[1].flags = NGHTTP2_NV_FLAG_NONE; 1977 if(HEADER_OVERFLOW(nva[1])) { 1978 failf(conn->data, "Failed sending HTTP request: Header overflow"); 1979 goto fail; 1980 } 1981 1982 nva[2].name = (unsigned char *)":scheme"; 1983 nva[2].namelen = strlen((char *)nva[2].name); 1984 if(conn->handler->flags & PROTOPT_SSL) 1985 nva[2].value = (unsigned char *)"https"; 1986 else 1987 nva[2].value = (unsigned char *)"http"; 1988 nva[2].valuelen = strlen((char *)nva[2].value); 1989 nva[2].flags = NGHTTP2_NV_FLAG_NONE; 1990 if(HEADER_OVERFLOW(nva[2])) { 1991 failf(conn->data, "Failed sending HTTP request: Header overflow"); 1992 goto fail; 1993 } 1994 1995 authority_idx = 0; 1996 i = 3; 1997 while(i < nheader) { 1998 size_t hlen; 1999 2000 hdbuf = line_end + 2; 2001 2002 /* check for next CR, but only within the piece of data left in the given 2003 buffer */ 2004 line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem)); 2005 if(!line_end || (line_end == hdbuf)) 2006 goto fail; 2007 2008 /* header continuation lines are not supported */ 2009 if(*hdbuf == ' ' || *hdbuf == '\t') 2010 goto fail; 2011 2012 for(end = hdbuf; end < line_end && *end != ':'; ++end) 2013 ; 2014 if(end == hdbuf || end == line_end) 2015 goto fail; 2016 hlen = end - hdbuf; 2017 2018 if(hlen == 4 && strncasecompare("host", hdbuf, 4)) { 2019 authority_idx = i; 2020 nva[i].name = (unsigned char *)":authority"; 2021 nva[i].namelen = strlen((char *)nva[i].name); 2022 } 2023 else { 2024 nva[i].name = (unsigned char *)hdbuf; 2025 nva[i].namelen = (size_t)(end - hdbuf); 2026 } 2027 hdbuf = end + 1; 2028 while(*hdbuf == ' ' || *hdbuf == '\t') 2029 ++hdbuf; 2030 end = line_end; 2031 2032 switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf, 2033 end - hdbuf)) { 2034 case HEADERINST_IGNORE: 2035 /* skip header fields prohibited by HTTP/2 specification. */ 2036 --nheader; 2037 continue; 2038 case HEADERINST_TE_TRAILERS: 2039 nva[i].value = (uint8_t*)"trailers"; 2040 nva[i].valuelen = sizeof("trailers") - 1; 2041 break; 2042 default: 2043 nva[i].value = (unsigned char *)hdbuf; 2044 nva[i].valuelen = (size_t)(end - hdbuf); 2045 } 2046 2047 nva[i].flags = NGHTTP2_NV_FLAG_NONE; 2048 if(HEADER_OVERFLOW(nva[i])) { 2049 failf(conn->data, "Failed sending HTTP request: Header overflow"); 2050 goto fail; 2051 } 2052 ++i; 2053 } 2054 2055 /* :authority must come before non-pseudo header fields */ 2056 if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) { 2057 nghttp2_nv authority = nva[authority_idx]; 2058 for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) { 2059 nva[i] = nva[i - 1]; 2060 } 2061 nva[i] = authority; 2062 } 2063 2064 /* Warn stream may be rejected if cumulative length of headers is too large. 2065 It appears nghttp2 will not send a header frame larger than 64KB. */ 2066 #define MAX_ACC 60000 /* <64KB to account for some overhead */ 2067 { 2068 size_t acc = 0; 2069 2070 for(i = 0; i < nheader; ++i) { 2071 acc += nva[i].namelen + nva[i].valuelen; 2072 2073 H2BUGF(infof(conn->data, "h2 header: %.*s:%.*s\n", 2074 nva[i].namelen, nva[i].name, 2075 nva[i].valuelen, nva[i].value)); 2076 } 2077 2078 if(acc > MAX_ACC) { 2079 infof(conn->data, "http2_send: Warning: The cumulative length of all " 2080 "headers exceeds %zu bytes and that could cause the " 2081 "stream to be rejected.\n", MAX_ACC); 2082 } 2083 } 2084 2085 h2_pri_spec(conn->data, &pri_spec); 2086 2087 switch(conn->data->set.httpreq) { 2088 case HTTPREQ_POST: 2089 case HTTPREQ_POST_FORM: 2090 case HTTPREQ_POST_MIME: 2091 case HTTPREQ_PUT: 2092 if(conn->data->state.infilesize != -1) 2093 stream->upload_left = conn->data->state.infilesize; 2094 else 2095 /* data sending without specifying the data amount up front */ 2096 stream->upload_left = -1; /* unknown, but not zero */ 2097 2098 data_prd.read_callback = data_source_read_callback; 2099 data_prd.source.ptr = NULL; 2100 stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, 2101 &data_prd, conn->data); 2102 break; 2103 default: 2104 stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, 2105 NULL, conn->data); 2106 } 2107 2108 Curl_safefree(nva); 2109 2110 if(stream_id < 0) { 2111 H2BUGF(infof(conn->data, "http2_send() send error\n")); 2112 *err = CURLE_SEND_ERROR; 2113 return -1; 2114 } 2115 2116 infof(conn->data, "Using Stream ID: %x (easy handle %p)\n", 2117 stream_id, (void *)conn->data); 2118 stream->stream_id = stream_id; 2119 2120 /* this does not call h2_session_send() since there can not have been any 2121 * priority upodate since the nghttp2_submit_request() call above */ 2122 rv = nghttp2_session_send(h2); 2123 2124 if(rv != 0) { 2125 *err = CURLE_SEND_ERROR; 2126 return -1; 2127 } 2128 2129 if(should_close_session(httpc)) { 2130 H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); 2131 *err = CURLE_HTTP2; 2132 return -1; 2133 } 2134 2135 if(stream->stream_id != -1) { 2136 /* If whole HEADERS frame was sent off to the underlying socket, 2137 the nghttp2 library calls data_source_read_callback. But only 2138 it found that no data available, so it deferred the DATA 2139 transmission. Which means that nghttp2_session_want_write() 2140 returns 0 on http2_perform_getsock(), which results that no 2141 writable socket check is performed. To workaround this, we 2142 issue nghttp2_session_resume_data() here to bring back DATA 2143 transmission from deferred state. */ 2144 nghttp2_session_resume_data(h2, stream->stream_id); 2145 } 2146 2147 return len; 2148 2149 fail: 2150 free(nva); 2151 *err = CURLE_SEND_ERROR; 2152 return -1; 2153 } 2154 2155 CURLcode Curl_http2_setup(struct connectdata *conn) 2156 { 2157 CURLcode result; 2158 struct http_conn *httpc = &conn->proto.httpc; 2159 struct HTTP *stream = conn->data->req.protop; 2160 2161 stream->stream_id = -1; 2162 2163 if(!stream->header_recvbuf) { 2164 stream->header_recvbuf = Curl_add_buffer_init(); 2165 if(!stream->header_recvbuf) 2166 return CURLE_OUT_OF_MEMORY; 2167 } 2168 2169 if((conn->handler == &Curl_handler_http2_ssl) || 2170 (conn->handler == &Curl_handler_http2)) 2171 return CURLE_OK; /* already done */ 2172 2173 if(conn->handler->flags & PROTOPT_SSL) 2174 conn->handler = &Curl_handler_http2_ssl; 2175 else 2176 conn->handler = &Curl_handler_http2; 2177 2178 result = http2_init(conn); 2179 if(result) { 2180 Curl_add_buffer_free(&stream->header_recvbuf); 2181 return result; 2182 } 2183 2184 infof(conn->data, "Using HTTP2, server supports multi-use\n"); 2185 stream->upload_left = 0; 2186 stream->upload_mem = NULL; 2187 stream->upload_len = 0; 2188 2189 httpc->inbuflen = 0; 2190 httpc->nread_inbuf = 0; 2191 2192 httpc->pause_stream_id = 0; 2193 httpc->drain_total = 0; 2194 2195 conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ 2196 conn->httpversion = 20; 2197 conn->bundle->multiuse = BUNDLE_MULTIPLEX; 2198 2199 infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n"); 2200 multi_connchanged(conn->data->multi); 2201 2202 return CURLE_OK; 2203 } 2204 2205 CURLcode Curl_http2_switched(struct connectdata *conn, 2206 const char *mem, size_t nread) 2207 { 2208 CURLcode result; 2209 struct http_conn *httpc = &conn->proto.httpc; 2210 int rv; 2211 ssize_t nproc; 2212 struct Curl_easy *data = conn->data; 2213 struct HTTP *stream = conn->data->req.protop; 2214 2215 result = Curl_http2_setup(conn); 2216 if(result) 2217 return result; 2218 2219 httpc->recv_underlying = conn->recv[FIRSTSOCKET]; 2220 httpc->send_underlying = conn->send[FIRSTSOCKET]; 2221 conn->recv[FIRSTSOCKET] = http2_recv; 2222 conn->send[FIRSTSOCKET] = http2_send; 2223 2224 if(conn->data->req.upgr101 == UPGR101_RECEIVED) { 2225 /* stream 1 is opened implicitly on upgrade */ 2226 stream->stream_id = 1; 2227 /* queue SETTINGS frame (again) */ 2228 rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings, 2229 httpc->binlen, NULL); 2230 if(rv != 0) { 2231 failf(data, "nghttp2_session_upgrade() failed: %s(%d)", 2232 nghttp2_strerror(rv), rv); 2233 return CURLE_HTTP2; 2234 } 2235 2236 rv = nghttp2_session_set_stream_user_data(httpc->h2, 2237 stream->stream_id, 2238 data); 2239 if(rv) { 2240 infof(data, "http/2: failed to set user_data for stream %d!\n", 2241 stream->stream_id); 2242 DEBUGASSERT(0); 2243 } 2244 } 2245 else { 2246 populate_settings(conn, httpc); 2247 2248 /* stream ID is unknown at this point */ 2249 stream->stream_id = -1; 2250 rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, 2251 httpc->local_settings, 2252 httpc->local_settings_num); 2253 if(rv != 0) { 2254 failf(data, "nghttp2_submit_settings() failed: %s(%d)", 2255 nghttp2_strerror(rv), rv); 2256 return CURLE_HTTP2; 2257 } 2258 } 2259 2260 #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 2261 rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0, 2262 HTTP2_HUGE_WINDOW_SIZE); 2263 if(rv != 0) { 2264 failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", 2265 nghttp2_strerror(rv), rv); 2266 return CURLE_HTTP2; 2267 } 2268 #endif 2269 2270 /* we are going to copy mem to httpc->inbuf. This is required since 2271 mem is part of buffer pointed by stream->mem, and callbacks 2272 called by nghttp2_session_mem_recv() will write stream specific 2273 data into stream->mem, overwriting data already there. */ 2274 if(H2_BUFSIZE < nread) { 2275 failf(data, "connection buffer size is too small to store data following " 2276 "HTTP Upgrade response header: buflen=%zu, datalen=%zu", 2277 H2_BUFSIZE, nread); 2278 return CURLE_HTTP2; 2279 } 2280 2281 infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer" 2282 " after upgrade: len=%zu\n", 2283 nread); 2284 2285 if(nread) 2286 memcpy(httpc->inbuf, mem, nread); 2287 httpc->inbuflen = nread; 2288 2289 nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf, 2290 httpc->inbuflen); 2291 2292 if(nghttp2_is_fatal((int)nproc)) { 2293 failf(data, "nghttp2_session_mem_recv() failed: %s(%d)", 2294 nghttp2_strerror((int)nproc), (int)nproc); 2295 return CURLE_HTTP2; 2296 } 2297 2298 H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc)); 2299 2300 if((ssize_t)nread == nproc) { 2301 httpc->inbuflen = 0; 2302 httpc->nread_inbuf = 0; 2303 } 2304 else { 2305 httpc->nread_inbuf += nproc; 2306 } 2307 2308 /* Try to send some frames since we may read SETTINGS already. */ 2309 rv = h2_session_send(data, httpc->h2); 2310 2311 if(rv != 0) { 2312 failf(data, "nghttp2_session_send() failed: %s(%d)", 2313 nghttp2_strerror(rv), rv); 2314 return CURLE_HTTP2; 2315 } 2316 2317 if(should_close_session(httpc)) { 2318 H2BUGF(infof(data, 2319 "nghttp2_session_send(): nothing to do in this session\n")); 2320 return CURLE_HTTP2; 2321 } 2322 2323 return CURLE_OK; 2324 } 2325 2326 CURLcode Curl_http2_add_child(struct Curl_easy *parent, 2327 struct Curl_easy *child, 2328 bool exclusive) 2329 { 2330 if(parent) { 2331 struct Curl_http2_dep **tail; 2332 struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep)); 2333 if(!dep) 2334 return CURLE_OUT_OF_MEMORY; 2335 dep->data = child; 2336 2337 if(parent->set.stream_dependents && exclusive) { 2338 struct Curl_http2_dep *node = parent->set.stream_dependents; 2339 while(node) { 2340 node->data->set.stream_depends_on = child; 2341 node = node->next; 2342 } 2343 2344 tail = &child->set.stream_dependents; 2345 while(*tail) 2346 tail = &(*tail)->next; 2347 2348 DEBUGASSERT(!*tail); 2349 *tail = parent->set.stream_dependents; 2350 parent->set.stream_dependents = 0; 2351 } 2352 2353 tail = &parent->set.stream_dependents; 2354 while(*tail) { 2355 (*tail)->data->set.stream_depends_e = FALSE; 2356 tail = &(*tail)->next; 2357 } 2358 2359 DEBUGASSERT(!*tail); 2360 *tail = dep; 2361 } 2362 2363 child->set.stream_depends_on = parent; 2364 child->set.stream_depends_e = exclusive; 2365 return CURLE_OK; 2366 } 2367 2368 void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child) 2369 { 2370 struct Curl_http2_dep *last = 0; 2371 struct Curl_http2_dep *data = parent->set.stream_dependents; 2372 DEBUGASSERT(child->set.stream_depends_on == parent); 2373 2374 while(data && data->data != child) { 2375 last = data; 2376 data = data->next; 2377 } 2378 2379 DEBUGASSERT(data); 2380 2381 if(data) { 2382 if(last) { 2383 last->next = data->next; 2384 } 2385 else { 2386 parent->set.stream_dependents = data->next; 2387 } 2388 free(data); 2389 } 2390 2391 child->set.stream_depends_on = 0; 2392 child->set.stream_depends_e = FALSE; 2393 } 2394 2395 void Curl_http2_cleanup_dependencies(struct Curl_easy *data) 2396 { 2397 while(data->set.stream_dependents) { 2398 struct Curl_easy *tmp = data->set.stream_dependents->data; 2399 Curl_http2_remove_child(data, tmp); 2400 if(data->set.stream_depends_on) 2401 Curl_http2_add_child(data->set.stream_depends_on, tmp, FALSE); 2402 } 2403 2404 if(data->set.stream_depends_on) 2405 Curl_http2_remove_child(data->set.stream_depends_on, data); 2406 } 2407 2408 /* Only call this function for a transfer that already got a HTTP/2 2409 CURLE_HTTP2_STREAM error! */ 2410 bool Curl_h2_http_1_1_error(struct connectdata *conn) 2411 { 2412 struct http_conn *httpc = &conn->proto.httpc; 2413 return (httpc->error_code == NGHTTP2_HTTP_1_1_REQUIRED); 2414 } 2415 2416 #else /* !USE_NGHTTP2 */ 2417 2418 /* Satisfy external references even if http2 is not compiled in. */ 2419 2420 #define CURL_DISABLE_TYPECHECK 2421 #include <curl/curl.h> 2422 2423 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) 2424 { 2425 (void) h; 2426 (void) num; 2427 return NULL; 2428 } 2429 2430 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) 2431 { 2432 (void) h; 2433 (void) header; 2434 return NULL; 2435 } 2436 2437 #endif /* USE_NGHTTP2 */ 2438