1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, 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 http://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#define _MPRINTF_REPLACE 27#include <curl/mprintf.h> 28 29#include <nghttp2/nghttp2.h> 30#include "urldata.h" 31#include "http2.h" 32#include "http.h" 33#include "sendf.h" 34#include "curl_base64.h" 35#include "curl_memory.h" 36#include "rawstr.h" 37#include "multiif.h" 38 39/* include memdebug.h last */ 40#include "memdebug.h" 41 42#if (NGHTTP2_VERSION_NUM < 0x000300) 43#error too old nghttp2 version, upgrade! 44#endif 45 46static int http2_perform_getsock(const struct connectdata *conn, 47 curl_socket_t *sock, /* points to 48 numsocks 49 number of 50 sockets */ 51 int numsocks) 52{ 53 const struct http_conn *httpc = &conn->proto.httpc; 54 int bitmap = GETSOCK_BLANK; 55 (void)numsocks; 56 57 /* TODO We should check underlying socket state if it is SSL socket 58 because of renegotiation. */ 59 sock[0] = conn->sock[FIRSTSOCKET]; 60 61 if(nghttp2_session_want_read(httpc->h2)) 62 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); 63 64 if(nghttp2_session_want_write(httpc->h2)) 65 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); 66 67 return bitmap; 68} 69 70static int http2_getsock(struct connectdata *conn, 71 curl_socket_t *sock, /* points to numsocks 72 number of sockets */ 73 int numsocks) 74{ 75 return http2_perform_getsock(conn, sock, numsocks); 76} 77 78static CURLcode http2_disconnect(struct connectdata *conn, 79 bool dead_connection) 80{ 81 struct http_conn *httpc = &conn->proto.httpc; 82 (void)dead_connection; 83 84 infof(conn->data, "HTTP/2 DISCONNECT starts now\n"); 85 86 nghttp2_session_del(httpc->h2); 87 88 Curl_safefree(httpc->header_recvbuf->buffer); 89 Curl_safefree(httpc->header_recvbuf); 90 91 Curl_safefree(httpc->inbuf); 92 93 infof(conn->data, "HTTP/2 DISCONNECT done\n"); 94 95 return CURLE_OK; 96} 97 98/* 99 * HTTP2 handler interface. This isn't added to the general list of protocols 100 * but will be used at run-time when the protocol is dynamically switched from 101 * HTTP to HTTP2. 102 */ 103const struct Curl_handler Curl_handler_http2 = { 104 "HTTP2", /* scheme */ 105 ZERO_NULL, /* setup_connection */ 106 Curl_http, /* do_it */ 107 ZERO_NULL, /* done */ 108 ZERO_NULL, /* do_more */ 109 ZERO_NULL, /* connect_it */ 110 ZERO_NULL, /* connecting */ 111 ZERO_NULL, /* doing */ 112 http2_getsock, /* proto_getsock */ 113 http2_getsock, /* doing_getsock */ 114 ZERO_NULL, /* domore_getsock */ 115 http2_perform_getsock, /* perform_getsock */ 116 http2_disconnect, /* disconnect */ 117 ZERO_NULL, /* readwrite */ 118 PORT_HTTP, /* defport */ 119 CURLPROTO_HTTP, /* protocol */ 120 PROTOPT_NONE /* flags */ 121}; 122 123const struct Curl_handler Curl_handler_http2_ssl = { 124 "HTTP2", /* scheme */ 125 ZERO_NULL, /* setup_connection */ 126 Curl_http, /* do_it */ 127 ZERO_NULL, /* done */ 128 ZERO_NULL, /* do_more */ 129 ZERO_NULL, /* connect_it */ 130 ZERO_NULL, /* connecting */ 131 ZERO_NULL, /* doing */ 132 http2_getsock, /* proto_getsock */ 133 http2_getsock, /* doing_getsock */ 134 ZERO_NULL, /* domore_getsock */ 135 http2_perform_getsock, /* perform_getsock */ 136 http2_disconnect, /* disconnect */ 137 ZERO_NULL, /* readwrite */ 138 PORT_HTTP, /* defport */ 139 CURLPROTO_HTTPS, /* protocol */ 140 PROTOPT_SSL /* flags */ 141}; 142 143/* 144 * Store nghttp2 version info in this buffer, Prefix with a space. Return 145 * total length written. 146 */ 147int Curl_http2_ver(char *p, size_t len) 148{ 149 nghttp2_info *h2 = nghttp2_version(0); 150 return snprintf(p, len, " nghttp2/%s", h2->version_str); 151} 152 153/* 154 * The implementation of nghttp2_send_callback type. Here we write |data| with 155 * size |length| to the network and return the number of bytes actually 156 * written. See the documentation of nghttp2_send_callback for the details. 157 */ 158static ssize_t send_callback(nghttp2_session *h2, 159 const uint8_t *data, size_t length, int flags, 160 void *userp) 161{ 162 struct connectdata *conn = (struct connectdata *)userp; 163 struct http_conn *httpc = &conn->proto.httpc; 164 ssize_t written; 165 CURLcode rc; 166 (void)h2; 167 (void)flags; 168 169 rc = 0; 170 written = ((Curl_send*)httpc->send_underlying)(conn, FIRSTSOCKET, 171 data, length, &rc); 172 173 if(rc == CURLE_AGAIN) { 174 return NGHTTP2_ERR_WOULDBLOCK; 175 } 176 177 if(written == -1) { 178 failf(conn->data, "Failed sending HTTP2 data"); 179 return NGHTTP2_ERR_CALLBACK_FAILURE; 180 } 181 182 if(!written) 183 return NGHTTP2_ERR_WOULDBLOCK; 184 185 return written; 186} 187 188static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, 189 void *userp) 190{ 191 struct connectdata *conn = (struct connectdata *)userp; 192 struct http_conn *c = &conn->proto.httpc; 193 int rv; 194 (void)session; 195 (void)frame; 196 infof(conn->data, "on_frame_recv() was called with header %x\n", 197 frame->hd.type); 198 switch(frame->hd.type) { 199 case NGHTTP2_HEADERS: 200 if(frame->headers.cat != NGHTTP2_HCAT_RESPONSE) 201 break; 202 c->bodystarted = TRUE; 203 Curl_add_buffer(c->header_recvbuf, "\r\n", 2); 204 c->nread_header_recvbuf = c->len < c->header_recvbuf->size_used ? 205 c->len : c->header_recvbuf->size_used; 206 207 memcpy(c->mem, c->header_recvbuf->buffer, c->nread_header_recvbuf); 208 209 c->mem += c->nread_header_recvbuf; 210 c->len -= c->nread_header_recvbuf; 211 break; 212 case NGHTTP2_PUSH_PROMISE: 213 rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, 214 frame->hd.stream_id, NGHTTP2_CANCEL); 215 if(nghttp2_is_fatal(rv)) { 216 return rv; 217 } 218 break; 219 } 220 return 0; 221} 222 223static int on_invalid_frame_recv(nghttp2_session *session, 224 const nghttp2_frame *frame, 225 nghttp2_error_code error_code, void *userp) 226{ 227 struct connectdata *conn = (struct connectdata *)userp; 228 (void)session; 229 (void)frame; 230 infof(conn->data, "on_invalid_frame_recv() was called, error_code = %d\n", 231 error_code); 232 return 0; 233} 234 235static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, 236 int32_t stream_id, 237 const uint8_t *data, size_t len, void *userp) 238{ 239 struct connectdata *conn = (struct connectdata *)userp; 240 struct http_conn *c = &conn->proto.httpc; 241 size_t nread; 242 (void)session; 243 (void)flags; 244 (void)data; 245 infof(conn->data, "on_data_chunk_recv() " 246 "len = %u, stream = %x\n", len, stream_id); 247 248 if(stream_id != c->stream_id) { 249 return 0; 250 } 251 252 nread = c->len < len ? c->len : len; 253 memcpy(c->mem, data, nread); 254 255 c->mem += nread; 256 c->len -= nread; 257 258 infof(conn->data, "%zu data written\n", nread); 259 260 if(nread < len) { 261 c->data = data + nread; 262 c->datalen = len - nread; 263 return NGHTTP2_ERR_PAUSE; 264 } 265 return 0; 266} 267 268static int before_frame_send(nghttp2_session *session, 269 const nghttp2_frame *frame, 270 void *userp) 271{ 272 struct connectdata *conn = (struct connectdata *)userp; 273 (void)session; 274 (void)frame; 275 infof(conn->data, "before_frame_send() was called\n"); 276 return 0; 277} 278static int on_frame_send(nghttp2_session *session, 279 const nghttp2_frame *frame, 280 void *userp) 281{ 282 struct connectdata *conn = (struct connectdata *)userp; 283 (void)session; 284 (void)frame; 285 infof(conn->data, "on_frame_send() was called\n"); 286 return 0; 287} 288static int on_frame_not_send(nghttp2_session *session, 289 const nghttp2_frame *frame, 290 int lib_error_code, void *userp) 291{ 292 struct connectdata *conn = (struct connectdata *)userp; 293 (void)session; 294 (void)frame; 295 infof(conn->data, "on_frame_not_send() was called, lib_error_code = %d\n", 296 lib_error_code); 297 return 0; 298} 299static int on_stream_close(nghttp2_session *session, int32_t stream_id, 300 nghttp2_error_code error_code, void *userp) 301{ 302 struct connectdata *conn = (struct connectdata *)userp; 303 struct http_conn *c = &conn->proto.httpc; 304 (void)session; 305 (void)stream_id; 306 infof(conn->data, "on_stream_close() was called, error_code = %d\n", 307 error_code); 308 309 if(stream_id != c->stream_id) { 310 return 0; 311 } 312 313 c->closed = TRUE; 314 315 return 0; 316} 317 318static int on_unknown_frame_recv(nghttp2_session *session, 319 const uint8_t *head, size_t headlen, 320 const uint8_t *payload, size_t payloadlen, 321 void *userp) 322{ 323 struct connectdata *conn = (struct connectdata *)userp; 324 (void)session; 325 (void)head; 326 (void)headlen; 327 (void)payload; 328 (void)payloadlen; 329 infof(conn->data, "on_unknown_frame_recv() was called\n"); 330 return 0; 331} 332static int on_begin_headers(nghttp2_session *session, 333 const nghttp2_frame *frame, void *userp) 334{ 335 struct connectdata *conn = (struct connectdata *)userp; 336 (void)session; 337 (void)frame; 338 infof(conn->data, "on_begin_headers() was called\n"); 339 return 0; 340} 341 342static const char STATUS[] = ":status"; 343 344/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */ 345static int on_header(nghttp2_session *session, const nghttp2_frame *frame, 346 const uint8_t *name, size_t namelen, 347 const uint8_t *value, size_t valuelen, 348 uint8_t flags, 349 void *userp) 350{ 351 struct connectdata *conn = (struct connectdata *)userp; 352 struct http_conn *c = &conn->proto.httpc; 353 (void)session; 354 (void)frame; 355 (void)flags; 356 357 if(frame->hd.stream_id != c->stream_id) { 358 return 0; 359 } 360 361 if(namelen == sizeof(":status") - 1 && 362 memcmp(STATUS, name, namelen) == 0) { 363 snprintf(c->header_recvbuf->buffer, 13, "HTTP/2.0 %s", value); 364 c->header_recvbuf->buffer[12] = '\r'; 365 return 0; 366 } 367 else { 368 /* convert to a HTTP1-style header */ 369 infof(conn->data, "got header\n"); 370 Curl_add_buffer(c->header_recvbuf, name, namelen); 371 Curl_add_buffer(c->header_recvbuf, ":", 1); 372 Curl_add_buffer(c->header_recvbuf, value, valuelen); 373 Curl_add_buffer(c->header_recvbuf, "\r\n", 2); 374 } 375 376 return 0; /* 0 is successful */ 377} 378 379/* 380 * This is all callbacks nghttp2 calls 381 */ 382static const nghttp2_session_callbacks callbacks = { 383 send_callback, /* nghttp2_send_callback */ 384 NULL, /* nghttp2_recv_callback */ 385 on_frame_recv, /* nghttp2_on_frame_recv_callback */ 386 on_invalid_frame_recv, /* nghttp2_on_invalid_frame_recv_callback */ 387 on_data_chunk_recv, /* nghttp2_on_data_chunk_recv_callback */ 388 before_frame_send, /* nghttp2_before_frame_send_callback */ 389 on_frame_send, /* nghttp2_on_frame_send_callback */ 390 on_frame_not_send, /* nghttp2_on_frame_not_send_callback */ 391 on_stream_close, /* nghttp2_on_stream_close_callback */ 392 on_unknown_frame_recv, /* nghttp2_on_unknown_frame_recv_callback */ 393 on_begin_headers, /* nghttp2_on_begin_headers_callback */ 394 on_header /* nghttp2_on_header_callback */ 395#if NGHTTP2_VERSION_NUM >= 0x000400 396 , NULL /* nghttp2_select_padding_callback */ 397#endif 398}; 399 400static ssize_t data_source_read_callback(nghttp2_session *session, 401 int32_t stream_id, 402 uint8_t *buf, size_t length, 403 uint32_t *data_flags, 404 nghttp2_data_source *source, 405 void *userp) 406{ 407 struct connectdata *conn = (struct connectdata *)userp; 408 struct http_conn *c = &conn->proto.httpc; 409 size_t nread; 410 (void)session; 411 (void)stream_id; 412 (void)source; 413 414 nread = c->upload_len < length ? c->upload_len : length; 415 if(nread > 0) { 416 memcpy(buf, c->upload_mem, nread); 417 c->upload_mem += nread; 418 c->upload_len -= nread; 419 c->upload_left -= nread; 420 } 421 422 if(c->upload_left == 0) 423 *data_flags = 1; 424 else if(nread == 0) 425 return NGHTTP2_ERR_DEFERRED; 426 427 return nread; 428} 429 430/* 431 * The HTTP2 settings we send in the Upgrade request 432 */ 433static nghttp2_settings_entry settings[] = { 434 { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }, 435 { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, NGHTTP2_INITIAL_WINDOW_SIZE }, 436}; 437 438#define H2_BUFSIZE 4096 439 440/* 441 * Initialize nghttp2 for a Curl connection 442 */ 443CURLcode Curl_http2_init(struct connectdata *conn) 444{ 445 if(!conn->proto.httpc.h2) { 446 int rc; 447 conn->proto.httpc.inbuf = malloc(H2_BUFSIZE); 448 if(conn->proto.httpc.inbuf == NULL) 449 return CURLE_OUT_OF_MEMORY; 450 451 /* The nghttp2 session is not yet setup, do it */ 452 rc = nghttp2_session_client_new(&conn->proto.httpc.h2, 453 &callbacks, conn); 454 if(rc) { 455 failf(conn->data, "Couldn't initialize nghttp2!"); 456 return CURLE_OUT_OF_MEMORY; /* most likely at least */ 457 } 458 } 459 return CURLE_OK; 460} 461 462/* 463 * Send a request using http2 464 */ 465CURLcode Curl_http2_send_request(struct connectdata *conn) 466{ 467 (void)conn; 468 return CURLE_OK; 469} 470 471/* 472 * Append headers to ask for a HTTP1.1 to HTTP2 upgrade. 473 */ 474CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, 475 struct connectdata *conn) 476{ 477 CURLcode result; 478 ssize_t binlen; 479 char *base64; 480 size_t blen; 481 struct SingleRequest *k = &conn->data->req; 482 uint8_t *binsettings = conn->proto.httpc.binsettings; 483 484 result = Curl_http2_init(conn); 485 if(result) 486 return result; 487 488 result = Curl_http2_setup(conn); 489 if(result) 490 return result; 491 492 /* As long as we have a fixed set of settings, we don't have to dynamically 493 * figure out the base64 strings since it'll always be the same. However, 494 * the settings will likely not be fixed every time in the future. 495 */ 496 497 /* this returns number of bytes it wrote */ 498 binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN, 499 settings, 500 sizeof(settings)/sizeof(settings[0])); 501 if(!binlen) { 502 failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); 503 return CURLE_FAILED_INIT; 504 } 505 conn->proto.httpc.binlen = binlen; 506 507 result = Curl_base64_encode(conn->data, (const char *)binsettings, binlen, 508 &base64, &blen); 509 if(result) 510 return result; 511 512 result = Curl_add_bufferf(req, 513 "Connection: Upgrade, HTTP2-Settings\r\n" 514 "Upgrade: %s\r\n" 515 "HTTP2-Settings: %s\r\n", 516 NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); 517 Curl_safefree(base64); 518 519 k->upgr101 = UPGR101_REQUESTED; 520 521 return result; 522} 523 524/* 525 * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return 526 * a regular CURLcode value. 527 */ 528static ssize_t http2_recv(struct connectdata *conn, int sockindex, 529 char *mem, size_t len, CURLcode *err) 530{ 531 CURLcode rc; 532 ssize_t rv; 533 ssize_t nread; 534 struct http_conn *httpc = &conn->proto.httpc; 535 536 (void)sockindex; /* we always do HTTP2 on sockindex 0 */ 537 538 if(httpc->closed) { 539 return 0; 540 } 541 542 /* Nullify here because we call nghttp2_session_send() and they 543 might refer to the old buffer. */ 544 httpc->upload_mem = NULL; 545 httpc->upload_len = 0; 546 547 if(httpc->bodystarted && 548 httpc->nread_header_recvbuf < httpc->header_recvbuf->size_used) { 549 size_t left = 550 httpc->header_recvbuf->size_used - httpc->nread_header_recvbuf; 551 size_t ncopy = len < left ? len : left; 552 memcpy(mem, httpc->header_recvbuf->buffer + httpc->nread_header_recvbuf, 553 ncopy); 554 httpc->nread_header_recvbuf += ncopy; 555 return ncopy; 556 } 557 558 if(httpc->data) { 559 nread = len < httpc->datalen ? len : httpc->datalen; 560 memcpy(mem, httpc->data, nread); 561 562 httpc->data += nread; 563 httpc->datalen -= nread; 564 565 infof(conn->data, "%zu data written\n", nread); 566 if(httpc->datalen == 0) { 567 httpc->data = NULL; 568 httpc->datalen = 0; 569 } 570 return nread; 571 } 572 573 conn->proto.httpc.mem = mem; 574 conn->proto.httpc.len = len; 575 576 infof(conn->data, "http2_recv: %d bytes buffer\n", 577 conn->proto.httpc.len); 578 579 rc = 0; 580 nread = ((Curl_recv*)httpc->recv_underlying)(conn, FIRSTSOCKET, 581 httpc->inbuf, H2_BUFSIZE, &rc); 582 583 if(rc == CURLE_AGAIN) { 584 *err = rc; 585 return -1; 586 } 587 588 if(nread == -1) { 589 failf(conn->data, "Failed receiving HTTP2 data"); 590 *err = rc; 591 return 0; 592 } 593 594 infof(conn->data, "nread=%zd\n", nread); 595 rv = nghttp2_session_mem_recv(httpc->h2, 596 (const uint8_t *)httpc->inbuf, nread); 597 598 if(nghttp2_is_fatal((int)rv)) { 599 failf(conn->data, "nghttp2_session_mem_recv() returned %d:%s\n", 600 rv, nghttp2_strerror((int)rv)); 601 *err = CURLE_RECV_ERROR; 602 return 0; 603 } 604 infof(conn->data, "nghttp2_session_mem_recv() returns %zd\n", rv); 605 /* Always send pending frames in nghttp2 session, because 606 nghttp2_session_mem_recv() may queue new frame */ 607 rv = nghttp2_session_send(httpc->h2); 608 if(rv != 0) { 609 *err = CURLE_SEND_ERROR; 610 return 0; 611 } 612 if(len != httpc->len) { 613 return len - conn->proto.httpc.len; 614 } 615 /* If stream is closed, return 0 to signal the http routine to close 616 the connection */ 617 if(httpc->closed) { 618 return 0; 619 } 620 *err = CURLE_AGAIN; 621 return -1; 622} 623 624/* return number of received (decrypted) bytes */ 625static ssize_t http2_send(struct connectdata *conn, int sockindex, 626 const void *mem, size_t len, CURLcode *err) 627{ 628 /* 629 * BIG TODO: Currently, we send request in this function, but this 630 * function is also used to send request body. It would be nice to 631 * add dedicated function for request. 632 */ 633 int rv; 634 struct http_conn *httpc = &conn->proto.httpc; 635 nghttp2_nv *nva; 636 size_t nheader; 637 size_t i; 638 char *hdbuf = (char*)mem; 639 char *end; 640 nghttp2_data_provider data_prd; 641 int32_t stream_id; 642 643 (void)sockindex; 644 645 infof(conn->data, "http2_send len=%zu\n", len); 646 647 if(httpc->stream_id != -1) { 648 /* If stream_id != -1, we have dispatched request HEADERS, and now 649 are going to send or sending request body in DATA frame */ 650 httpc->upload_mem = mem; 651 httpc->upload_len = len; 652 nghttp2_session_resume_data(httpc->h2, httpc->stream_id); 653 rv = nghttp2_session_send(httpc->h2); 654 if(nghttp2_is_fatal(rv)) { 655 *err = CURLE_SEND_ERROR; 656 return -1; 657 } 658 return len - httpc->upload_len; 659 } 660 661 /* Calculate number of headers contained in [mem, mem + len) */ 662 /* Here, we assume the curl http code generate *correct* HTTP header 663 field block */ 664 nheader = 0; 665 for(i = 0; i < len; ++i) { 666 if(hdbuf[i] == 0x0a) { 667 ++nheader; 668 } 669 } 670 /* We counted additional 2 \n in the first and last line. We need 3 671 new headers: :method, :path and :scheme. Therefore we need one 672 more space. */ 673 nheader += 1; 674 nva = malloc(sizeof(nghttp2_nv) * nheader); 675 if(nva == NULL) { 676 *err = CURLE_OUT_OF_MEMORY; 677 return -1; 678 } 679 /* Extract :method, :path from request line */ 680 end = strchr(hdbuf, ' '); 681 nva[0].name = (unsigned char *)":method"; 682 nva[0].namelen = (uint16_t)strlen((char *)nva[0].name); 683 nva[0].value = (unsigned char *)hdbuf; 684 nva[0].valuelen = (uint16_t)(end - hdbuf); 685 nva[0].flags = NGHTTP2_NV_FLAG_NONE; 686 687 hdbuf = end + 1; 688 689 end = strchr(hdbuf, ' '); 690 nva[1].name = (unsigned char *)":path"; 691 nva[1].namelen = (uint16_t)strlen((char *)nva[1].name); 692 nva[1].value = (unsigned char *)hdbuf; 693 nva[1].valuelen = (uint16_t)(end - hdbuf); 694 nva[1].flags = NGHTTP2_NV_FLAG_NONE; 695 696 nva[2].name = (unsigned char *)":scheme"; 697 nva[2].namelen = (uint16_t)strlen((char *)nva[2].name); 698 if(conn->handler->flags & PROTOPT_SSL) 699 nva[2].value = (unsigned char *)"https"; 700 else 701 nva[2].value = (unsigned char *)"http"; 702 nva[2].valuelen = (uint16_t)strlen((char *)nva[2].value); 703 nva[2].flags = NGHTTP2_NV_FLAG_NONE; 704 705 hdbuf = strchr(hdbuf, 0x0a); 706 ++hdbuf; 707 708 for(i = 3; i < nheader; ++i) { 709 end = strchr(hdbuf, ':'); 710 assert(end); 711 if(end - hdbuf == 4 && Curl_raw_nequal("host", hdbuf, 4)) { 712 nva[i].name = (unsigned char *)":authority"; 713 nva[i].namelen = (uint16_t)strlen((char *)nva[i].name); 714 } 715 else { 716 nva[i].name = (unsigned char *)hdbuf; 717 nva[i].namelen = (uint16_t)(end - hdbuf); 718 } 719 hdbuf = end + 1; 720 for(; *hdbuf == ' '; ++hdbuf); 721 end = strchr(hdbuf, 0x0d); 722 assert(end); 723 nva[i].value = (unsigned char *)hdbuf; 724 nva[i].valuelen = (uint16_t)(end - hdbuf); 725 nva[i].flags = NGHTTP2_NV_FLAG_NONE; 726 727 hdbuf = end + 2; 728 /* Inspect Content-Length header field and retrieve the request 729 entity length so that we can set END_STREAM to the last DATA 730 frame. */ 731 if(nva[i].namelen == 14 && 732 Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { 733 size_t j; 734 for(j = 0; j < nva[i].valuelen; ++j) { 735 httpc->upload_left *= 10; 736 httpc->upload_left += nva[i].value[j] - '0'; 737 } 738 infof(conn->data, "request content-length=%zu\n", httpc->upload_left); 739 } 740 } 741 742 switch(conn->data->set.httpreq) { 743 case HTTPREQ_POST: 744 case HTTPREQ_POST_FORM: 745 case HTTPREQ_PUT: 746 data_prd.read_callback = data_source_read_callback; 747 data_prd.source.ptr = NULL; 748 stream_id = nghttp2_submit_request(httpc->h2, NULL, nva, nheader, 749 &data_prd, NULL); 750 break; 751 default: 752 stream_id = nghttp2_submit_request(httpc->h2, NULL, nva, nheader, 753 NULL, NULL); 754 } 755 756 Curl_safefree(nva); 757 758 if(stream_id < 0) { 759 *err = CURLE_SEND_ERROR; 760 return -1; 761 } 762 763 httpc->stream_id = stream_id; 764 765 rv = nghttp2_session_send(httpc->h2); 766 767 if(rv != 0) { 768 *err = CURLE_SEND_ERROR; 769 return -1; 770 } 771 772 if(httpc->stream_id != -1) { 773 /* If whole HEADERS frame was sent off to the underlying socket, 774 the nghttp2 library calls data_source_read_callback. But only 775 it found that no data available, so it deferred the DATA 776 transmission. Which means that nghttp2_session_want_write() 777 returns 0 on http2_perform_getsock(), which results that no 778 writable socket check is performed. To workaround this, we 779 issue nghttp2_session_resume_data() here to bring back DATA 780 transmission from deferred state. */ 781 nghttp2_session_resume_data(httpc->h2, httpc->stream_id); 782 } 783 784 return len; 785} 786 787CURLcode Curl_http2_setup(struct connectdata *conn) 788{ 789 struct http_conn *httpc = &conn->proto.httpc; 790 if(conn->handler->flags & PROTOPT_SSL) 791 conn->handler = &Curl_handler_http2_ssl; 792 else 793 conn->handler = &Curl_handler_http2; 794 795 infof(conn->data, "Using HTTP2\n"); 796 httpc->bodystarted = FALSE; 797 httpc->closed = FALSE; 798 httpc->header_recvbuf = Curl_add_buffer_init(); 799 httpc->nread_header_recvbuf = 0; 800 httpc->data = NULL; 801 httpc->datalen = 0; 802 httpc->upload_left = 0; 803 httpc->upload_mem = NULL; 804 httpc->upload_len = 0; 805 httpc->stream_id = -1; 806 807 conn->httpversion = 20; 808 809 /* Put place holder for status line */ 810 return Curl_add_buffer(httpc->header_recvbuf, "HTTP/2.0 200\r\n", 14); 811} 812 813int Curl_http2_switched(struct connectdata *conn) 814{ 815 /* TODO: May get CURLE_AGAIN */ 816 CURLcode rc; 817 struct http_conn *httpc = &conn->proto.httpc; 818 int rv; 819 820 httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET]; 821 httpc->send_underlying = (sending)conn->send[FIRSTSOCKET]; 822 conn->recv[FIRSTSOCKET] = http2_recv; 823 conn->send[FIRSTSOCKET] = http2_send; 824 825 rv = (int) ((Curl_send*)httpc->send_underlying) 826 (conn, FIRSTSOCKET, 827 NGHTTP2_CLIENT_CONNECTION_PREFACE, 828 NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN, 829 &rc); 830 assert(rv == 24); 831 if(conn->data->req.upgr101 == UPGR101_RECEIVED) { 832 /* stream 1 is opened implicitly on upgrade */ 833 httpc->stream_id = 1; 834 /* queue SETTINGS frame (again) */ 835 rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings, 836 httpc->binlen, NULL); 837 if(rv != 0) { 838 failf(conn->data, "nghttp2_session_upgrade() failed: %s(%d)", 839 nghttp2_strerror(rv), rv); 840 return -1; 841 } 842 } 843 else { 844 /* stream ID is unknown at this point */ 845 httpc->stream_id = -1; 846 rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0); 847 if(rv != 0) { 848 failf(conn->data, "nghttp2_submit_settings() failed: %s(%d)", 849 nghttp2_strerror(rv), rv); 850 return -1; 851 } 852 } 853 return 0; 854} 855 856#endif 857