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