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