00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "curl_setup.h"
00024
00025 #ifdef USE_NGHTTP2
00026 #include <nghttp2/nghttp2.h>
00027 #include "urldata.h"
00028 #include "http2.h"
00029 #include "http.h"
00030 #include "sendf.h"
00031 #include "curl_base64.h"
00032 #include "strcase.h"
00033 #include "multiif.h"
00034 #include "conncache.h"
00035 #include "url.h"
00036 #include "connect.h"
00037 #include "strtoofft.h"
00038 #include "strdup.h"
00039
00040 #include "curl_printf.h"
00041 #include "curl_memory.h"
00042 #include "memdebug.h"
00043
00044 #define MIN(x,y) ((x)<(y)?(x):(y))
00045
00046 #if (NGHTTP2_VERSION_NUM < 0x010000)
00047 #error too old nghttp2 version, upgrade!
00048 #endif
00049
00050 #if (NGHTTP2_VERSION_NUM > 0x010800)
00051 #define NGHTTP2_HAS_HTTP2_STRERROR 1
00052 #endif
00053
00054 #if (NGHTTP2_VERSION_NUM >= 0x010900)
00055
00056
00057 #define NGHTTP2_HAS_ERROR_CALLBACK 1
00058 #else
00059 #define nghttp2_session_callbacks_set_error_callback(x,y)
00060 #endif
00061
00062 #if (NGHTTP2_VERSION_NUM >= 0x010c00)
00063 #define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1
00064 #endif
00065
00066 #define HTTP2_HUGE_WINDOW_SIZE (1 << 30)
00067
00068
00069
00070
00071
00072 void Curl_http2_init_state(struct UrlState *state)
00073 {
00074 state->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
00075 }
00076
00077
00078
00079
00080
00081 void Curl_http2_init_userset(struct UserDefined *set)
00082 {
00083 set->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
00084 }
00085
00086 static int http2_perform_getsock(const struct connectdata *conn,
00087 curl_socket_t *sock,
00088
00089
00090
00091 int numsocks)
00092 {
00093 const struct http_conn *c = &conn->proto.httpc;
00094 int bitmap = GETSOCK_BLANK;
00095 (void)numsocks;
00096
00097
00098
00099 sock[0] = conn->sock[FIRSTSOCKET];
00100
00101
00102
00103 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
00104
00105 if(nghttp2_session_want_write(c->h2))
00106 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
00107
00108 return bitmap;
00109 }
00110
00111 static int http2_getsock(struct connectdata *conn,
00112 curl_socket_t *sock,
00113
00114 int numsocks)
00115 {
00116 return http2_perform_getsock(conn, sock, numsocks);
00117 }
00118
00119 static CURLcode http2_disconnect(struct connectdata *conn,
00120 bool dead_connection)
00121 {
00122 struct HTTP *http = conn->data->req.protop;
00123 struct http_conn *c = &conn->proto.httpc;
00124 (void)dead_connection;
00125
00126 DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n"));
00127
00128 nghttp2_session_del(c->h2);
00129 Curl_safefree(c->inbuf);
00130
00131 if(http) {
00132 Curl_add_buffer_free(http->header_recvbuf);
00133 http->header_recvbuf = NULL;
00134 Curl_add_buffer_free(http->trailer_recvbuf);
00135 http->trailer_recvbuf = NULL;
00136 for(; http->push_headers_used > 0; --http->push_headers_used) {
00137 free(http->push_headers[http->push_headers_used - 1]);
00138 }
00139 free(http->push_headers);
00140 http->push_headers = NULL;
00141 }
00142
00143 DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
00144
00145 return CURLE_OK;
00146 }
00147
00148
00149 void Curl_http2_setup_req(struct Curl_easy *data)
00150 {
00151 struct HTTP *http = data->req.protop;
00152
00153 http->nread_header_recvbuf = 0;
00154 http->bodystarted = FALSE;
00155 http->status_code = -1;
00156 http->pausedata = NULL;
00157 http->pauselen = 0;
00158 http->error_code = NGHTTP2_NO_ERROR;
00159 http->closed = FALSE;
00160 http->close_handled = FALSE;
00161 http->mem = data->state.buffer;
00162 http->len = BUFSIZE;
00163 http->memlen = 0;
00164 }
00165
00166
00167 void Curl_http2_setup_conn(struct connectdata *conn)
00168 {
00169 conn->proto.httpc.settings.max_concurrent_streams =
00170 DEFAULT_MAX_CONCURRENT_STREAMS;
00171 }
00172
00173
00174
00175
00176
00177
00178 const struct Curl_handler Curl_handler_http2 = {
00179 "HTTP",
00180 ZERO_NULL,
00181 Curl_http,
00182 Curl_http_done,
00183 ZERO_NULL,
00184 ZERO_NULL,
00185 ZERO_NULL,
00186 ZERO_NULL,
00187 http2_getsock,
00188 http2_getsock,
00189 ZERO_NULL,
00190 http2_perform_getsock,
00191 http2_disconnect,
00192 ZERO_NULL,
00193 PORT_HTTP,
00194 CURLPROTO_HTTP,
00195 PROTOPT_STREAM
00196 };
00197
00198 const struct Curl_handler Curl_handler_http2_ssl = {
00199 "HTTPS",
00200 ZERO_NULL,
00201 Curl_http,
00202 Curl_http_done,
00203 ZERO_NULL,
00204 ZERO_NULL,
00205 ZERO_NULL,
00206 ZERO_NULL,
00207 http2_getsock,
00208 http2_getsock,
00209 ZERO_NULL,
00210 http2_perform_getsock,
00211 http2_disconnect,
00212 ZERO_NULL,
00213 PORT_HTTP,
00214 CURLPROTO_HTTPS,
00215 PROTOPT_SSL | PROTOPT_STREAM
00216 };
00217
00218
00219
00220
00221
00222 int Curl_http2_ver(char *p, size_t len)
00223 {
00224 nghttp2_info *h2 = nghttp2_version(0);
00225 return snprintf(p, len, " nghttp2/%s", h2->version_str);
00226 }
00227
00228
00229
00230
00231
00232 const char *Curl_http2_strerror(uint32_t err)
00233 {
00234 #ifndef NGHTTP2_HAS_HTTP2_STRERROR
00235 const char *str[] = {
00236 "NO_ERROR",
00237 "PROTOCOL_ERROR",
00238 "INTERNAL_ERROR",
00239 "FLOW_CONTROL_ERROR",
00240 "SETTINGS_TIMEOUT",
00241 "STREAM_CLOSED",
00242 "FRAME_SIZE_ERROR",
00243 "REFUSED_STREAM",
00244 "CANCEL",
00245 "COMPRESSION_ERROR",
00246 "CONNECT_ERROR",
00247 "ENHANCE_YOUR_CALM",
00248 "INADEQUATE_SECURITY",
00249 "HTTP_1_1_REQUIRED"
00250 };
00251 return (err < sizeof str / sizeof str[0]) ? str[err] : "unknown";
00252 #else
00253 return nghttp2_http2_strerror(err);
00254 #endif
00255 }
00256
00257
00258
00259
00260
00261
00262 static ssize_t send_callback(nghttp2_session *h2,
00263 const uint8_t *data, size_t length, int flags,
00264 void *userp)
00265 {
00266 struct connectdata *conn = (struct connectdata *)userp;
00267 struct http_conn *c = &conn->proto.httpc;
00268 ssize_t written;
00269 CURLcode result = CURLE_OK;
00270
00271 (void)h2;
00272 (void)flags;
00273
00274 written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET,
00275 data, length, &result);
00276
00277 if(result == CURLE_AGAIN) {
00278 return NGHTTP2_ERR_WOULDBLOCK;
00279 }
00280
00281 if(written == -1) {
00282 failf(conn->data, "Failed sending HTTP2 data");
00283 return NGHTTP2_ERR_CALLBACK_FAILURE;
00284 }
00285
00286 if(!written)
00287 return NGHTTP2_ERR_WOULDBLOCK;
00288
00289 return written;
00290 }
00291
00292
00293
00294
00295 struct curl_pushheaders {
00296 struct Curl_easy *data;
00297 const nghttp2_push_promise *frame;
00298 };
00299
00300
00301
00302
00303 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
00304 {
00305
00306
00307 if(!h || !GOOD_EASY_HANDLE(h->data))
00308 return NULL;
00309 else {
00310 struct HTTP *stream = h->data->req.protop;
00311 if(num < stream->push_headers_used)
00312 return stream->push_headers[num];
00313 }
00314 return NULL;
00315 }
00316
00317
00318
00319
00320 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
00321 {
00322
00323
00324
00325
00326
00327
00328 if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] ||
00329 !strcmp(header, ":") || strchr(header + 1, ':'))
00330 return NULL;
00331 else {
00332 struct HTTP *stream = h->data->req.protop;
00333 size_t len = strlen(header);
00334 size_t i;
00335 for(i=0; i<stream->push_headers_used; i++) {
00336 if(!strncmp(header, stream->push_headers[i], len)) {
00337
00338 if(stream->push_headers[i][len] != ':')
00339 continue;
00340 return &stream->push_headers[i][len+1];
00341 }
00342 }
00343 }
00344 return NULL;
00345 }
00346
00347 static struct Curl_easy *duphandle(struct Curl_easy *data)
00348 {
00349 struct Curl_easy *second = curl_easy_duphandle(data);
00350 if(second) {
00351
00352 struct HTTP *http = calloc(1, sizeof(struct HTTP));
00353 if(!http) {
00354 (void)Curl_close(second);
00355 second = NULL;
00356 }
00357 else {
00358 second->req.protop = http;
00359 http->header_recvbuf = Curl_add_buffer_init();
00360 if(!http->header_recvbuf) {
00361 free(http);
00362 (void)Curl_close(second);
00363 second = NULL;
00364 }
00365 else {
00366 Curl_http2_setup_req(second);
00367 second->state.stream_weight = data->state.stream_weight;
00368 }
00369 }
00370 }
00371 return second;
00372 }
00373
00374
00375 static int push_promise(struct Curl_easy *data,
00376 struct connectdata *conn,
00377 const nghttp2_push_promise *frame)
00378 {
00379 int rv;
00380 DEBUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
00381 frame->promised_stream_id));
00382 if(data->multi->push_cb) {
00383 struct HTTP *stream;
00384 struct HTTP *newstream;
00385 struct curl_pushheaders heads;
00386 CURLMcode rc;
00387 struct http_conn *httpc;
00388 size_t i;
00389
00390 struct Curl_easy *newhandle = duphandle(data);
00391 if(!newhandle) {
00392 infof(data, "failed to duplicate handle\n");
00393 rv = 1;
00394 goto fail;
00395 }
00396
00397 heads.data = data;
00398 heads.frame = frame;
00399
00400 DEBUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
00401
00402 stream = data->req.protop;
00403 if(!stream) {
00404 failf(data, "Internal NULL stream!\n");
00405 rv = 1;
00406 goto fail;
00407 }
00408
00409 rv = data->multi->push_cb(data, newhandle,
00410 stream->push_headers_used, &heads,
00411 data->multi->push_userp);
00412
00413
00414 for(i=0; i<stream->push_headers_used; i++)
00415 free(stream->push_headers[i]);
00416 free(stream->push_headers);
00417 stream->push_headers = NULL;
00418
00419 if(rv) {
00420
00421 (void)Curl_close(newhandle);
00422 goto fail;
00423 }
00424
00425 newstream = newhandle->req.protop;
00426 newstream->stream_id = frame->promised_stream_id;
00427 newhandle->req.maxdownload = -1;
00428 newhandle->req.size = -1;
00429
00430
00431
00432 rc = Curl_multi_add_perform(data->multi, newhandle, conn);
00433 if(rc) {
00434 infof(data, "failed to add handle to multi\n");
00435 Curl_close(newhandle);
00436 rv = 1;
00437 goto fail;
00438 }
00439
00440 httpc = &conn->proto.httpc;
00441 nghttp2_session_set_stream_user_data(httpc->h2,
00442 frame->promised_stream_id, newhandle);
00443 }
00444 else {
00445 DEBUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
00446 rv = 1;
00447 }
00448 fail:
00449 return rv;
00450 }
00451
00452 static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
00453 void *userp)
00454 {
00455 struct connectdata *conn = (struct connectdata *)userp;
00456 struct http_conn *httpc = &conn->proto.httpc;
00457 struct Curl_easy *data_s = NULL;
00458 struct HTTP *stream = NULL;
00459 static int lastStream = -1;
00460 int rv;
00461 size_t left, ncopy;
00462 int32_t stream_id = frame->hd.stream_id;
00463
00464 if(!stream_id) {
00465
00466 if(frame->hd.type == NGHTTP2_SETTINGS) {
00467 uint32_t max_conn = httpc->settings.max_concurrent_streams;
00468 DEBUGF(infof(conn->data, "Got SETTINGS\n"));
00469 httpc->settings.max_concurrent_streams =
00470 nghttp2_session_get_remote_settings(
00471 session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
00472 httpc->settings.enable_push =
00473 nghttp2_session_get_remote_settings(
00474 session, NGHTTP2_SETTINGS_ENABLE_PUSH);
00475 DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
00476 httpc->settings.max_concurrent_streams));
00477 DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
00478 httpc->settings.enable_push?"TRUE":"false"));
00479 if(max_conn != httpc->settings.max_concurrent_streams) {
00480
00481 infof(conn->data,
00482 "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
00483 Curl_multi_connchanged(conn->data->multi);
00484 }
00485 }
00486 return 0;
00487 }
00488 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
00489 if(lastStream != stream_id) {
00490 lastStream = stream_id;
00491 }
00492 if(!data_s) {
00493 DEBUGF(infof(conn->data,
00494 "No Curl_easy associated with stream: %x\n",
00495 stream_id));
00496 return 0;
00497 }
00498
00499 stream = data_s->req.protop;
00500 if(!stream) {
00501 DEBUGF(infof(conn->data, "No proto pointer for stream: %x\n",
00502 stream_id));
00503 return NGHTTP2_ERR_CALLBACK_FAILURE;
00504 }
00505
00506 DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
00507 frame->hd.type, stream_id));
00508
00509 switch(frame->hd.type) {
00510 case NGHTTP2_DATA:
00511
00512 if(!stream->bodystarted) {
00513 rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
00514 stream_id, NGHTTP2_PROTOCOL_ERROR);
00515
00516 if(nghttp2_is_fatal(rv)) {
00517 return NGHTTP2_ERR_CALLBACK_FAILURE;
00518 }
00519 }
00520 break;
00521 case NGHTTP2_HEADERS:
00522 if(stream->bodystarted) {
00523
00524
00525 break;
00526 }
00527
00528
00529
00530 DEBUGASSERT(stream->status_code != -1);
00531
00532
00533 if(stream->status_code / 100 != 1) {
00534 stream->bodystarted = TRUE;
00535 stream->status_code = -1;
00536 }
00537
00538 Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
00539
00540 left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
00541 ncopy = MIN(stream->len, left);
00542
00543 memcpy(&stream->mem[stream->memlen],
00544 stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
00545 ncopy);
00546 stream->nread_header_recvbuf += ncopy;
00547
00548 DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
00549 ncopy, stream_id, stream->mem));
00550
00551 stream->len -= ncopy;
00552 stream->memlen += ncopy;
00553
00554 data_s->state.drain++;
00555 httpc->drain_total++;
00556 {
00557
00558 struct connectdata *conn_s = (struct connectdata *)userp;
00559
00560
00561 if(conn_s->data != data_s)
00562 Curl_expire(data_s, 0);
00563 }
00564 break;
00565 case NGHTTP2_PUSH_PROMISE:
00566 rv = push_promise(data_s, conn, &frame->push_promise);
00567 if(rv) {
00568 rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
00569 frame->push_promise.promised_stream_id,
00570 NGHTTP2_CANCEL);
00571 if(nghttp2_is_fatal(rv)) {
00572 return rv;
00573 }
00574 }
00575 break;
00576 default:
00577 DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n",
00578 frame->hd.type, stream_id));
00579 break;
00580 }
00581 return 0;
00582 }
00583
00584 static int on_invalid_frame_recv(nghttp2_session *session,
00585 const nghttp2_frame *frame,
00586 int lib_error_code, void *userp)
00587 {
00588 struct Curl_easy *data_s = NULL;
00589 (void)userp;
00590
00591 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
00592 if(data_s) {
00593 DEBUGF(infof(data_s,
00594 "on_invalid_frame_recv() was called, error=%d:%s\n",
00595 lib_error_code, nghttp2_strerror(lib_error_code)));
00596 }
00597 return 0;
00598 }
00599
00600 static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
00601 int32_t stream_id,
00602 const uint8_t *data, size_t len, void *userp)
00603 {
00604 struct HTTP *stream;
00605 struct Curl_easy *data_s;
00606 size_t nread;
00607 struct connectdata *conn = (struct connectdata *)userp;
00608 (void)session;
00609 (void)flags;
00610 (void)data;
00611
00612 DEBUGASSERT(stream_id);
00613
00614
00615 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
00616 if(!data_s)
00617
00618
00619 return NGHTTP2_ERR_CALLBACK_FAILURE;
00620
00621 stream = data_s->req.protop;
00622 if(!stream)
00623 return NGHTTP2_ERR_CALLBACK_FAILURE;
00624
00625 nread = MIN(stream->len, len);
00626 memcpy(&stream->mem[stream->memlen], data, nread);
00627
00628 stream->len -= nread;
00629 stream->memlen += nread;
00630
00631 data_s->state.drain++;
00632 conn->proto.httpc.drain_total++;
00633
00634
00635 if(conn->data != data_s)
00636 Curl_expire(data_s, 0);
00637
00638 DEBUGF(infof(data_s, "%zu data received for stream %u "
00639 "(%zu left in buffer %p, total %zu)\n",
00640 nread, stream_id,
00641 stream->len, stream->mem,
00642 stream->memlen));
00643
00644 if(nread < len) {
00645 stream->pausedata = data + nread;
00646 stream->pauselen = len - nread;
00647 DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
00648 ", stream %u\n",
00649 len - nread, stream_id));
00650 data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
00651
00652 return NGHTTP2_ERR_PAUSE;
00653 }
00654
00655
00656
00657 if(conn->data != data_s) {
00658 data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
00659
00660 return NGHTTP2_ERR_PAUSE;
00661 }
00662
00663 return 0;
00664 }
00665
00666 static int before_frame_send(nghttp2_session *session,
00667 const nghttp2_frame *frame,
00668 void *userp)
00669 {
00670 struct Curl_easy *data_s;
00671 (void)userp;
00672
00673 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
00674 if(data_s) {
00675 DEBUGF(infof(data_s, "before_frame_send() was called\n"));
00676 }
00677
00678 return 0;
00679 }
00680 static int on_frame_send(nghttp2_session *session,
00681 const nghttp2_frame *frame,
00682 void *userp)
00683 {
00684 struct Curl_easy *data_s;
00685 (void)userp;
00686
00687 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
00688 if(data_s) {
00689 DEBUGF(infof(data_s, "on_frame_send() was called, length = %zd\n",
00690 frame->hd.length));
00691 }
00692 return 0;
00693 }
00694 static int on_frame_not_send(nghttp2_session *session,
00695 const nghttp2_frame *frame,
00696 int lib_error_code, void *userp)
00697 {
00698 struct Curl_easy *data_s;
00699 (void)userp;
00700
00701 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
00702 if(data_s) {
00703 DEBUGF(infof(data_s,
00704 "on_frame_not_send() was called, lib_error_code = %d\n",
00705 lib_error_code));
00706 }
00707 return 0;
00708 }
00709 static int on_stream_close(nghttp2_session *session, int32_t stream_id,
00710 uint32_t error_code, void *userp)
00711 {
00712 struct Curl_easy *data_s;
00713 struct HTTP *stream;
00714 struct connectdata *conn = (struct connectdata *)userp;
00715 (void)session;
00716 (void)stream_id;
00717
00718 if(stream_id) {
00719
00720
00721 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
00722 if(!data_s) {
00723
00724
00725 return 0;
00726 }
00727 DEBUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
00728 Curl_http2_strerror(error_code), error_code, stream_id));
00729 stream = data_s->req.protop;
00730 if(!stream)
00731 return NGHTTP2_ERR_CALLBACK_FAILURE;
00732
00733 stream->error_code = error_code;
00734 stream->closed = TRUE;
00735 data_s->state.drain++;
00736 conn->proto.httpc.drain_total++;
00737
00738
00739 nghttp2_session_set_stream_user_data(session, stream_id, 0);
00740 DEBUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
00741 }
00742 return 0;
00743 }
00744
00745 static int on_begin_headers(nghttp2_session *session,
00746 const nghttp2_frame *frame, void *userp)
00747 {
00748 struct HTTP *stream;
00749 struct Curl_easy *data_s = NULL;
00750 (void)userp;
00751
00752 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
00753 if(!data_s) {
00754 return 0;
00755 }
00756
00757 DEBUGF(infof(data_s, "on_begin_headers() was called\n"));
00758
00759 if(frame->hd.type != NGHTTP2_HEADERS) {
00760 return 0;
00761 }
00762
00763 stream = data_s->req.protop;
00764 if(!stream || !stream->bodystarted) {
00765 return 0;
00766 }
00767
00768
00769 DEBUGF(infof(data_s, "trailer field started\n"));
00770
00771 assert(stream->trailer_recvbuf == NULL);
00772
00773 stream->trailer_recvbuf = Curl_add_buffer_init();
00774 if(!stream->trailer_recvbuf) {
00775 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
00776 }
00777
00778 return 0;
00779 }
00780
00781
00782
00783 static int decode_status_code(const uint8_t *value, size_t len)
00784 {
00785 int i;
00786 int res;
00787
00788 if(len != 3) {
00789 return -1;
00790 }
00791
00792 res = 0;
00793
00794 for(i = 0; i < 3; ++i) {
00795 char c = value[i];
00796
00797 if(c < '0' || c > '9') {
00798 return -1;
00799 }
00800
00801 res *= 10;
00802 res += c - '0';
00803 }
00804
00805 return res;
00806 }
00807
00808
00809 static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
00810 const uint8_t *name, size_t namelen,
00811 const uint8_t *value, size_t valuelen,
00812 uint8_t flags,
00813 void *userp)
00814 {
00815 struct HTTP *stream;
00816 struct Curl_easy *data_s;
00817 int32_t stream_id = frame->hd.stream_id;
00818 struct connectdata *conn = (struct connectdata *)userp;
00819 (void)flags;
00820
00821 DEBUGASSERT(stream_id);
00822
00823
00824 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
00825 if(!data_s)
00826
00827
00828 return NGHTTP2_ERR_CALLBACK_FAILURE;
00829
00830 stream = data_s->req.protop;
00831 if(!stream) {
00832 failf(data_s, "Internal NULL stream! 5\n");
00833 return NGHTTP2_ERR_CALLBACK_FAILURE;
00834 }
00835
00836
00837
00838 if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
00839 char *h;
00840
00841 if(!stream->push_headers) {
00842 stream->push_headers_alloc = 10;
00843 stream->push_headers = malloc(stream->push_headers_alloc *
00844 sizeof(char *));
00845 stream->push_headers_used = 0;
00846 }
00847 else if(stream->push_headers_used ==
00848 stream->push_headers_alloc) {
00849 char **headp;
00850 stream->push_headers_alloc *= 2;
00851 headp = Curl_saferealloc(stream->push_headers,
00852 stream->push_headers_alloc * sizeof(char *));
00853 if(!headp) {
00854 stream->push_headers = NULL;
00855 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
00856 }
00857 stream->push_headers = headp;
00858 }
00859 h = aprintf("%s:%s", name, value);
00860 if(h)
00861 stream->push_headers[stream->push_headers_used++] = h;
00862 return 0;
00863 }
00864
00865 if(stream->bodystarted) {
00866
00867
00868 uint32_t n = (uint32_t)(namelen + valuelen + 3);
00869
00870 DEBUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
00871 value));
00872
00873 Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n));
00874 Curl_add_buffer(stream->trailer_recvbuf, name, namelen);
00875 Curl_add_buffer(stream->trailer_recvbuf, ": ", 2);
00876 Curl_add_buffer(stream->trailer_recvbuf, value, valuelen);
00877 Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3);
00878
00879 return 0;
00880 }
00881
00882 if(namelen == sizeof(":status") - 1 &&
00883 memcmp(":status", name, namelen) == 0) {
00884
00885
00886
00887 stream->status_code = decode_status_code(value, valuelen);
00888 DEBUGASSERT(stream->status_code != -1);
00889
00890 Curl_add_buffer(stream->header_recvbuf, "HTTP/2 ", 7);
00891 Curl_add_buffer(stream->header_recvbuf, value, valuelen);
00892
00893 Curl_add_buffer(stream->header_recvbuf, " \r\n", 3);
00894
00895 if(conn->data != data_s)
00896 Curl_expire(data_s, 0);
00897
00898 DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
00899 stream->status_code, data_s));
00900 return 0;
00901 }
00902
00903
00904
00905
00906 Curl_add_buffer(stream->header_recvbuf, name, namelen);
00907 Curl_add_buffer(stream->header_recvbuf, ": ", 2);
00908 Curl_add_buffer(stream->header_recvbuf, value, valuelen);
00909 Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
00910
00911 if(conn->data != data_s)
00912 Curl_expire(data_s, 0);
00913
00914 DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
00915 value));
00916
00917 return 0;
00918 }
00919
00920 static ssize_t data_source_read_callback(nghttp2_session *session,
00921 int32_t stream_id,
00922 uint8_t *buf, size_t length,
00923 uint32_t *data_flags,
00924 nghttp2_data_source *source,
00925 void *userp)
00926 {
00927 struct Curl_easy *data_s;
00928 struct HTTP *stream = NULL;
00929 size_t nread;
00930 (void)source;
00931 (void)userp;
00932
00933 if(stream_id) {
00934
00935
00936 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
00937 if(!data_s)
00938
00939
00940 return NGHTTP2_ERR_CALLBACK_FAILURE;
00941
00942 stream = data_s->req.protop;
00943 if(!stream)
00944 return NGHTTP2_ERR_CALLBACK_FAILURE;
00945 }
00946 else
00947 return NGHTTP2_ERR_INVALID_ARGUMENT;
00948
00949 nread = MIN(stream->upload_len, length);
00950 if(nread > 0) {
00951 memcpy(buf, stream->upload_mem, nread);
00952 stream->upload_mem += nread;
00953 stream->upload_len -= nread;
00954 if(data_s->state.infilesize != -1)
00955 stream->upload_left -= nread;
00956 }
00957
00958 if(stream->upload_left == 0)
00959 *data_flags = NGHTTP2_DATA_FLAG_EOF;
00960 else if(nread == 0)
00961 return NGHTTP2_ERR_DEFERRED;
00962
00963 DEBUGF(infof(data_s, "data_source_read_callback: "
00964 "returns %zu bytes stream %u\n",
00965 nread, stream_id));
00966
00967 return nread;
00968 }
00969
00970
00971
00972
00973 static nghttp2_settings_entry settings[] = {
00974 { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 },
00975 { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, HTTP2_HUGE_WINDOW_SIZE },
00976 };
00977
00978 #define H2_BUFSIZE 32768
00979
00980 #ifdef NGHTTP2_HAS_ERROR_CALLBACK
00981 static int error_callback(nghttp2_session *session,
00982 const char *msg,
00983 size_t len,
00984 void *userp)
00985 {
00986 struct connectdata *conn = (struct connectdata *)userp;
00987 (void)session;
00988 infof(conn->data, "http2 error: %.*s\n", len, msg);
00989 return 0;
00990 }
00991 #endif
00992
00993 void Curl_http2_done(struct connectdata *conn, bool premature)
00994 {
00995 struct Curl_easy *data = conn->data;
00996 struct HTTP *http = data->req.protop;
00997 struct http_conn *httpc = &conn->proto.httpc;
00998
00999 if(http->header_recvbuf) {
01000 DEBUGF(infof(data, "free header_recvbuf!!\n"));
01001 Curl_add_buffer_free(http->header_recvbuf);
01002 http->header_recvbuf = NULL;
01003 Curl_add_buffer_free(http->trailer_recvbuf);
01004 http->trailer_recvbuf = NULL;
01005 if(http->push_headers) {
01006
01007 for(; http->push_headers_used > 0; --http->push_headers_used) {
01008 free(http->push_headers[http->push_headers_used - 1]);
01009 }
01010 free(http->push_headers);
01011 http->push_headers = NULL;
01012 }
01013 }
01014
01015 if(premature) {
01016
01017 nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, http->stream_id,
01018 NGHTTP2_STREAM_CLOSED);
01019 if(http->stream_id == httpc->pause_stream_id) {
01020 infof(data, "stopped the pause stream!\n");
01021 httpc->pause_stream_id = 0;
01022 }
01023 }
01024 if(http->stream_id) {
01025 nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0);
01026 http->stream_id = 0;
01027 }
01028 }
01029
01030
01031
01032
01033 CURLcode Curl_http2_init(struct connectdata *conn)
01034 {
01035 if(!conn->proto.httpc.h2) {
01036 int rc;
01037 nghttp2_session_callbacks *callbacks;
01038
01039 conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
01040 if(conn->proto.httpc.inbuf == NULL)
01041 return CURLE_OUT_OF_MEMORY;
01042
01043 rc = nghttp2_session_callbacks_new(&callbacks);
01044
01045 if(rc) {
01046 failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
01047 return CURLE_OUT_OF_MEMORY;
01048 }
01049
01050
01051 nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
01052
01053 nghttp2_session_callbacks_set_on_frame_recv_callback
01054 (callbacks, on_frame_recv);
01055
01056 nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
01057 (callbacks, on_invalid_frame_recv);
01058
01059 nghttp2_session_callbacks_set_on_data_chunk_recv_callback
01060 (callbacks, on_data_chunk_recv);
01061
01062 nghttp2_session_callbacks_set_before_frame_send_callback
01063 (callbacks, before_frame_send);
01064
01065 nghttp2_session_callbacks_set_on_frame_send_callback
01066 (callbacks, on_frame_send);
01067
01068 nghttp2_session_callbacks_set_on_frame_not_send_callback
01069 (callbacks, on_frame_not_send);
01070
01071 nghttp2_session_callbacks_set_on_stream_close_callback
01072 (callbacks, on_stream_close);
01073
01074 nghttp2_session_callbacks_set_on_begin_headers_callback
01075 (callbacks, on_begin_headers);
01076
01077 nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
01078
01079 nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
01080
01081
01082 rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
01083
01084 nghttp2_session_callbacks_del(callbacks);
01085
01086 if(rc) {
01087 failf(conn->data, "Couldn't initialize nghttp2!");
01088 return CURLE_OUT_OF_MEMORY;
01089 }
01090 }
01091 return CURLE_OK;
01092 }
01093
01094
01095
01096
01097 CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
01098 struct connectdata *conn)
01099 {
01100 CURLcode result;
01101 ssize_t binlen;
01102 char *base64;
01103 size_t blen;
01104 struct SingleRequest *k = &conn->data->req;
01105 uint8_t *binsettings = conn->proto.httpc.binsettings;
01106
01107
01108
01109
01110
01111
01112
01113 binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
01114 settings,
01115 sizeof(settings)/sizeof(settings[0]));
01116 if(!binlen) {
01117 failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
01118 return CURLE_FAILED_INIT;
01119 }
01120 conn->proto.httpc.binlen = binlen;
01121
01122 result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
01123 &base64, &blen);
01124 if(result)
01125 return result;
01126
01127 result = Curl_add_bufferf(req,
01128 "Connection: Upgrade, HTTP2-Settings\r\n"
01129 "Upgrade: %s\r\n"
01130 "HTTP2-Settings: %s\r\n",
01131 NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
01132 free(base64);
01133
01134 k->upgr101 = UPGR101_REQUESTED;
01135
01136 return result;
01137 }
01138
01139
01140
01141
01142 static int should_close_session(struct http_conn *httpc)
01143 {
01144 return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) &&
01145 !nghttp2_session_want_write(httpc->h2);
01146 }
01147
01148 static int h2_session_send(struct Curl_easy *data,
01149 nghttp2_session *h2);
01150
01151
01152
01153
01154
01155
01156
01157 static int h2_process_pending_input(struct Curl_easy *data,
01158 struct http_conn *httpc,
01159 CURLcode *err)
01160 {
01161 ssize_t nread;
01162 char *inbuf;
01163 ssize_t rv;
01164
01165 nread = httpc->inbuflen - httpc->nread_inbuf;
01166 inbuf = httpc->inbuf + httpc->nread_inbuf;
01167
01168 rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
01169 if(rv < 0) {
01170 failf(data,
01171 "h2_process_pending_input: nghttp2_session_mem_recv() returned "
01172 "%d:%s\n", rv, nghttp2_strerror((int)rv));
01173 *err = CURLE_RECV_ERROR;
01174 return -1;
01175 }
01176
01177 if(nread == rv) {
01178 DEBUGF(infof(data,
01179 "h2_process_pending_input: All data in connection buffer "
01180 "processed\n"));
01181 httpc->inbuflen = 0;
01182 httpc->nread_inbuf = 0;
01183 }
01184 else {
01185 httpc->nread_inbuf += rv;
01186 DEBUGF(infof(data,
01187 "h2_process_pending_input: %zu bytes left in connection "
01188 "buffer\n",
01189 httpc->inbuflen - httpc->nread_inbuf));
01190 }
01191
01192 rv = h2_session_send(data, httpc->h2);
01193 if(rv != 0) {
01194 *err = CURLE_SEND_ERROR;
01195 return -1;
01196 }
01197
01198 if(should_close_session(httpc)) {
01199 DEBUGF(infof(data,
01200 "h2_process_pending_input: nothing to do in this session\n"));
01201 *err = CURLE_HTTP2;
01202 return -1;
01203 }
01204
01205 return 0;
01206 }
01207
01208
01209
01210
01211 CURLcode Curl_http2_done_sending(struct connectdata *conn)
01212 {
01213 CURLcode result = CURLE_OK;
01214
01215 if((conn->handler == &Curl_handler_http2_ssl) ||
01216 (conn->handler == &Curl_handler_http2)) {
01217
01218
01219 struct HTTP *stream = conn->data->req.protop;
01220
01221 if(stream->upload_left) {
01222
01223 struct http_conn *httpc = &conn->proto.httpc;
01224 nghttp2_session *h2 = httpc->h2;
01225
01226 stream->upload_left = 0;
01227
01228
01229
01230 (void)nghttp2_session_resume_data(h2, stream->stream_id);
01231
01232 (void)h2_process_pending_input(conn->data, httpc, &result);
01233 }
01234 }
01235 return result;
01236 }
01237
01238
01239 static ssize_t http2_handle_stream_close(struct connectdata *conn,
01240 struct Curl_easy *data,
01241 struct HTTP *stream, CURLcode *err)
01242 {
01243 char *trailer_pos, *trailer_end;
01244 CURLcode result;
01245 struct http_conn *httpc = &conn->proto.httpc;
01246
01247 if(httpc->pause_stream_id == stream->stream_id) {
01248 httpc->pause_stream_id = 0;
01249 }
01250
01251 DEBUGASSERT(httpc->drain_total >= data->state.drain);
01252 httpc->drain_total -= data->state.drain;
01253 data->state.drain = 0;
01254
01255 if(httpc->pause_stream_id == 0) {
01256 if(h2_process_pending_input(data, httpc, err) != 0) {
01257 return -1;
01258 }
01259 }
01260
01261 DEBUGASSERT(data->state.drain == 0);
01262
01263
01264 stream->closed = FALSE;
01265 if(stream->error_code != NGHTTP2_NO_ERROR) {
01266 failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)",
01267 stream->stream_id, Curl_http2_strerror(stream->error_code),
01268 stream->error_code);
01269 *err = CURLE_HTTP2_STREAM;
01270 return -1;
01271 }
01272
01273 if(!stream->bodystarted) {
01274 failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
01275 " all response header fields, teated as error",
01276 stream->stream_id);
01277 *err = CURLE_HTTP2_STREAM;
01278 return -1;
01279 }
01280
01281 if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) {
01282 trailer_pos = stream->trailer_recvbuf->buffer;
01283 trailer_end = trailer_pos + stream->trailer_recvbuf->size_used;
01284
01285 for(; trailer_pos < trailer_end;) {
01286 uint32_t n;
01287 memcpy(&n, trailer_pos, sizeof(n));
01288 trailer_pos += sizeof(n);
01289
01290 result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n);
01291 if(result) {
01292 *err = result;
01293 return -1;
01294 }
01295
01296 trailer_pos += n + 1;
01297 }
01298 }
01299
01300 stream->close_handled = TRUE;
01301
01302 DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
01303 return 0;
01304 }
01305
01306
01307
01308
01309
01310
01311
01312 static void h2_pri_spec(struct Curl_easy *data,
01313 nghttp2_priority_spec *pri_spec)
01314 {
01315 struct HTTP *depstream = (data->set.stream_depends_on?
01316 data->set.stream_depends_on->req.protop:NULL);
01317 int32_t depstream_id = depstream? depstream->stream_id:0;
01318 nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
01319 data->set.stream_depends_e);
01320 data->state.stream_weight = data->set.stream_weight;
01321 data->state.stream_depends_e = data->set.stream_depends_e;
01322 data->state.stream_depends_on = data->set.stream_depends_on;
01323 }
01324
01325
01326
01327
01328
01329
01330 static int h2_session_send(struct Curl_easy *data,
01331 nghttp2_session *h2)
01332 {
01333 struct HTTP *stream = data->req.protop;
01334 if((data->set.stream_weight != data->state.stream_weight) ||
01335 (data->set.stream_depends_e != data->state.stream_depends_e) ||
01336 (data->set.stream_depends_on != data->state.stream_depends_on) ) {
01337
01338 nghttp2_priority_spec pri_spec;
01339 int rv;
01340
01341 h2_pri_spec(data, &pri_spec);
01342
01343 DEBUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
01344 stream->stream_id, data));
01345 rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
01346 &pri_spec);
01347 if(rv)
01348 return rv;
01349 }
01350
01351 return nghttp2_session_send(h2);
01352 }
01353
01354 static ssize_t http2_recv(struct connectdata *conn, int sockindex,
01355 char *mem, size_t len, CURLcode *err)
01356 {
01357 CURLcode result = CURLE_OK;
01358 ssize_t rv;
01359 ssize_t nread;
01360 struct http_conn *httpc = &conn->proto.httpc;
01361 struct Curl_easy *data = conn->data;
01362 struct HTTP *stream = data->req.protop;
01363
01364 (void)sockindex;
01365
01366 if(should_close_session(httpc)) {
01367 DEBUGF(infof(data,
01368 "http2_recv: nothing to do in this session\n"));
01369 *err = CURLE_HTTP2;
01370 return -1;
01371 }
01372
01373
01374
01375 stream->upload_mem = NULL;
01376 stream->upload_len = 0;
01377
01378
01379
01380
01381
01382
01383 if(stream->bodystarted &&
01384 stream->nread_header_recvbuf < stream->header_recvbuf->size_used) {
01385
01386 size_t left =
01387 stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
01388 size_t ncopy = MIN(len, left);
01389 memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
01390 ncopy);
01391 stream->nread_header_recvbuf += ncopy;
01392
01393 DEBUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
01394 (int)ncopy));
01395 return ncopy;
01396 }
01397
01398 DEBUGF(infof(data, "http2_recv: easy %p (stream %u)\n",
01399 data, stream->stream_id));
01400
01401 if((data->state.drain) && stream->memlen) {
01402 DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
01403 stream->memlen, stream->stream_id,
01404 stream->mem, mem));
01405 if(mem != stream->mem) {
01406
01407
01408 memmove(mem, stream->mem, stream->memlen);
01409 stream->len = len - stream->memlen;
01410 stream->mem = mem;
01411 }
01412 if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) {
01413
01414
01415 httpc->pause_stream_id = 0;
01416 if(h2_process_pending_input(data, httpc, &result) != 0) {
01417 *err = result;
01418 return -1;
01419 }
01420 }
01421 }
01422 else if(stream->pausedata) {
01423 DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
01424 nread = MIN(len, stream->pauselen);
01425 memcpy(mem, stream->pausedata, nread);
01426
01427 stream->pausedata += nread;
01428 stream->pauselen -= nread;
01429
01430 infof(data, "%zu data bytes written\n", nread);
01431 if(stream->pauselen == 0) {
01432 DEBUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
01433 assert(httpc->pause_stream_id == stream->stream_id);
01434 httpc->pause_stream_id = 0;
01435
01436 stream->pausedata = NULL;
01437 stream->pauselen = 0;
01438
01439
01440
01441
01442
01443
01444
01445
01446 if(h2_process_pending_input(data, httpc, &result) != 0) {
01447 *err = result;
01448 return -1;
01449 }
01450 }
01451 DEBUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
01452 nread, stream->stream_id));
01453 return nread;
01454 }
01455 else if(httpc->pause_stream_id) {
01456
01457
01458
01459
01460
01461
01462
01463
01464 DEBUGF(infof(data, "stream %x is paused, pause id: %x\n",
01465 stream->stream_id, httpc->pause_stream_id));
01466 *err = CURLE_AGAIN;
01467 return -1;
01468 }
01469 else {
01470 char *inbuf;
01471
01472
01473 stream->mem = mem;
01474 stream->len = len;
01475 stream->memlen = 0;
01476
01477 if(httpc->inbuflen == 0) {
01478 nread = ((Curl_recv *)httpc->recv_underlying)(
01479 conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
01480
01481 if(nread == -1) {
01482 if(result != CURLE_AGAIN)
01483 failf(data, "Failed receiving HTTP2 data");
01484 else if(stream->closed)
01485
01486 return http2_handle_stream_close(conn, data, stream, err);
01487
01488 *err = result;
01489 return -1;
01490 }
01491
01492 if(nread == 0) {
01493 failf(data, "Unexpected EOF");
01494 *err = CURLE_RECV_ERROR;
01495 return -1;
01496 }
01497
01498 DEBUGF(infof(data, "nread=%zd\n", nread));
01499
01500 httpc->inbuflen = nread;
01501 inbuf = httpc->inbuf;
01502 }
01503 else {
01504 nread = httpc->inbuflen - httpc->nread_inbuf;
01505 inbuf = httpc->inbuf + httpc->nread_inbuf;
01506
01507 DEBUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
01508 nread));
01509 }
01510 rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
01511
01512 if(nghttp2_is_fatal((int)rv)) {
01513 failf(data, "nghttp2_session_mem_recv() returned %d:%s\n",
01514 rv, nghttp2_strerror((int)rv));
01515 *err = CURLE_RECV_ERROR;
01516 return 0;
01517 }
01518 DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
01519 if(nread == rv) {
01520 DEBUGF(infof(data, "All data in connection buffer processed\n"));
01521 httpc->inbuflen = 0;
01522 httpc->nread_inbuf = 0;
01523 }
01524 else {
01525 httpc->nread_inbuf += rv;
01526 DEBUGF(infof(data, "%zu bytes left in connection buffer\n",
01527 httpc->inbuflen - httpc->nread_inbuf));
01528 }
01529
01530
01531 rv = h2_session_send(data, httpc->h2);
01532 if(rv != 0) {
01533 *err = CURLE_SEND_ERROR;
01534 return 0;
01535 }
01536
01537 if(should_close_session(httpc)) {
01538 DEBUGF(infof(data, "http2_recv: nothing to do in this session\n"));
01539 *err = CURLE_HTTP2;
01540 return -1;
01541 }
01542 }
01543 if(stream->memlen) {
01544 ssize_t retlen = stream->memlen;
01545 DEBUGF(infof(data, "http2_recv: returns %zd for stream %u\n",
01546 retlen, stream->stream_id));
01547 stream->memlen = 0;
01548
01549 if(httpc->pause_stream_id == stream->stream_id) {
01550
01551
01552 DEBUGF(infof(data, "Data returned for PAUSED stream %u\n",
01553 stream->stream_id));
01554 }
01555 else if(!stream->closed) {
01556 DEBUGASSERT(httpc->drain_total >= data->state.drain);
01557 httpc->drain_total -= data->state.drain;
01558 data->state.drain = 0;
01559 }
01560
01561 return retlen;
01562 }
01563
01564
01565 if(stream->closed) {
01566 return http2_handle_stream_close(conn, data, stream, err);
01567 }
01568 *err = CURLE_AGAIN;
01569 DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
01570 stream->stream_id));
01571 return -1;
01572 }
01573
01574
01575
01576 #define AUTHORITY_DST_IDX 3
01577
01578 #define HEADER_OVERFLOW(x) \
01579 (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen)
01580
01581
01582
01583
01584
01585
01586 static bool contains_trailers(const char *p, size_t len)
01587 {
01588 const char *end = p + len;
01589 for(;;) {
01590 for(; p != end && (*p == ' ' || *p == '\t'); ++p)
01591 ;
01592 if(p == end || (size_t)(end - p) < sizeof("trailers") - 1)
01593 return FALSE;
01594 if(strncasecompare("trailers", p, sizeof("trailers") - 1)) {
01595 p += sizeof("trailers") - 1;
01596 for(; p != end && (*p == ' ' || *p == '\t'); ++p)
01597 ;
01598 if(p == end || *p == ',')
01599 return TRUE;
01600 }
01601
01602 for(; p != end && *p != ','; ++p)
01603 ;
01604 if(p == end)
01605 return FALSE;
01606 ++p;
01607 }
01608 }
01609
01610 typedef enum {
01611
01612 HEADERINST_FORWARD,
01613
01614 HEADERINST_IGNORE,
01615
01616 HEADERINST_TE_TRAILERS
01617 } header_instruction;
01618
01619
01620 static header_instruction inspect_header(const char *name, size_t namelen,
01621 const char *value, size_t valuelen) {
01622 switch(namelen) {
01623 case 2:
01624 if(!strncasecompare("te", name, namelen))
01625 return HEADERINST_FORWARD;
01626
01627 return contains_trailers(value, valuelen) ?
01628 HEADERINST_TE_TRAILERS : HEADERINST_IGNORE;
01629 case 7:
01630 return strncasecompare("upgrade", name, namelen) ?
01631 HEADERINST_IGNORE : HEADERINST_FORWARD;
01632 case 10:
01633 return (strncasecompare("connection", name, namelen) ||
01634 strncasecompare("keep-alive", name, namelen)) ?
01635 HEADERINST_IGNORE : HEADERINST_FORWARD;
01636 case 16:
01637 return strncasecompare("proxy-connection", name, namelen) ?
01638 HEADERINST_IGNORE : HEADERINST_FORWARD;
01639 case 17:
01640 return strncasecompare("transfer-encoding", name, namelen) ?
01641 HEADERINST_IGNORE : HEADERINST_FORWARD;
01642 default:
01643 return HEADERINST_FORWARD;
01644 }
01645 }
01646
01647 static ssize_t http2_send(struct connectdata *conn, int sockindex,
01648 const void *mem, size_t len, CURLcode *err)
01649 {
01650
01651
01652
01653
01654
01655 int rv;
01656 struct http_conn *httpc = &conn->proto.httpc;
01657 struct HTTP *stream = conn->data->req.protop;
01658 nghttp2_nv *nva = NULL;
01659 size_t nheader;
01660 size_t i;
01661 size_t authority_idx;
01662 char *hdbuf = (char *)mem;
01663 char *end, *line_end;
01664 nghttp2_data_provider data_prd;
01665 int32_t stream_id;
01666 nghttp2_session *h2 = httpc->h2;
01667 nghttp2_priority_spec pri_spec;
01668
01669 (void)sockindex;
01670
01671 DEBUGF(infof(conn->data, "http2_send len=%zu\n", len));
01672
01673 if(stream->stream_id != -1) {
01674 if(stream->close_handled) {
01675 infof(conn->data, "stream %d closed\n", stream->stream_id);
01676 *err = CURLE_HTTP2_STREAM;
01677 return -1;
01678 }
01679 else if(stream->closed) {
01680 return http2_handle_stream_close(conn, conn->data, stream, err);
01681 }
01682
01683
01684 stream->upload_mem = mem;
01685 stream->upload_len = len;
01686 nghttp2_session_resume_data(h2, stream->stream_id);
01687 rv = h2_session_send(conn->data, h2);
01688 if(nghttp2_is_fatal(rv)) {
01689 *err = CURLE_SEND_ERROR;
01690 return -1;
01691 }
01692 len -= stream->upload_len;
01693
01694
01695
01696 stream->upload_mem = NULL;
01697 stream->upload_len = 0;
01698
01699 if(should_close_session(httpc)) {
01700 DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
01701 *err = CURLE_HTTP2;
01702 return -1;
01703 }
01704
01705 if(stream->upload_left) {
01706
01707
01708
01709
01710 nghttp2_session_resume_data(h2, stream->stream_id);
01711 }
01712
01713 DEBUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len,
01714 stream->stream_id));
01715 return len;
01716 }
01717
01718
01719
01720
01721 nheader = 0;
01722 for(i = 1; i < len; ++i) {
01723 if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
01724 ++nheader;
01725 ++i;
01726 }
01727 }
01728 if(nheader < 2)
01729 goto fail;
01730
01731
01732
01733
01734 nheader += 1;
01735 nva = malloc(sizeof(nghttp2_nv) * nheader);
01736 if(nva == NULL) {
01737 *err = CURLE_OUT_OF_MEMORY;
01738 return -1;
01739 }
01740
01741
01742 line_end = strstr(hdbuf, "\r\n");
01743
01744
01745 end = memchr(hdbuf, ' ', line_end - hdbuf);
01746 if(!end || end == hdbuf)
01747 goto fail;
01748 nva[0].name = (unsigned char *)":method";
01749 nva[0].namelen = strlen((char *)nva[0].name);
01750 nva[0].value = (unsigned char *)hdbuf;
01751 nva[0].valuelen = (size_t)(end - hdbuf);
01752 nva[0].flags = NGHTTP2_NV_FLAG_NONE;
01753 if(HEADER_OVERFLOW(nva[0])) {
01754 failf(conn->data, "Failed sending HTTP request: Header overflow");
01755 goto fail;
01756 }
01757
01758 hdbuf = end + 1;
01759
01760
01761 end = NULL;
01762 for(i = (size_t)(line_end - hdbuf); i; --i) {
01763 if(hdbuf[i - 1] == ' ') {
01764 end = &hdbuf[i - 1];
01765 break;
01766 }
01767 }
01768 if(!end || end == hdbuf)
01769 goto fail;
01770 nva[1].name = (unsigned char *)":path";
01771 nva[1].namelen = strlen((char *)nva[1].name);
01772 nva[1].value = (unsigned char *)hdbuf;
01773 nva[1].valuelen = (size_t)(end - hdbuf);
01774 nva[1].flags = NGHTTP2_NV_FLAG_NONE;
01775 if(HEADER_OVERFLOW(nva[1])) {
01776 failf(conn->data, "Failed sending HTTP request: Header overflow");
01777 goto fail;
01778 }
01779
01780 hdbuf = end + 1;
01781
01782 end = line_end;
01783 nva[2].name = (unsigned char *)":scheme";
01784 nva[2].namelen = strlen((char *)nva[2].name);
01785 if(conn->handler->flags & PROTOPT_SSL)
01786 nva[2].value = (unsigned char *)"https";
01787 else
01788 nva[2].value = (unsigned char *)"http";
01789 nva[2].valuelen = strlen((char *)nva[2].value);
01790 nva[2].flags = NGHTTP2_NV_FLAG_NONE;
01791 if(HEADER_OVERFLOW(nva[2])) {
01792 failf(conn->data, "Failed sending HTTP request: Header overflow");
01793 goto fail;
01794 }
01795
01796 authority_idx = 0;
01797 i = 3;
01798 while(i < nheader) {
01799 size_t hlen;
01800
01801 hdbuf = line_end + 2;
01802
01803 line_end = strstr(hdbuf, "\r\n");
01804 if(line_end == hdbuf)
01805 goto fail;
01806
01807
01808 if(*hdbuf == ' ' || *hdbuf == '\t')
01809 goto fail;
01810
01811 for(end = hdbuf; end < line_end && *end != ':'; ++end)
01812 ;
01813 if(end == hdbuf || end == line_end)
01814 goto fail;
01815 hlen = end - hdbuf;
01816
01817 if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
01818 authority_idx = i;
01819 nva[i].name = (unsigned char *)":authority";
01820 nva[i].namelen = strlen((char *)nva[i].name);
01821 }
01822 else {
01823 nva[i].name = (unsigned char *)hdbuf;
01824 nva[i].namelen = (size_t)(end - hdbuf);
01825 }
01826 hdbuf = end + 1;
01827 while(*hdbuf == ' ' || *hdbuf == '\t')
01828 ++hdbuf;
01829 end = line_end;
01830
01831 switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
01832 end - hdbuf)) {
01833 case HEADERINST_IGNORE:
01834
01835 --nheader;
01836 continue;
01837 case HEADERINST_TE_TRAILERS:
01838 nva[i].value = (uint8_t*)"trailers";
01839 nva[i].valuelen = sizeof("trailers") - 1;
01840 break;
01841 default:
01842 nva[i].value = (unsigned char *)hdbuf;
01843 nva[i].valuelen = (size_t)(end - hdbuf);
01844 }
01845
01846 nva[i].flags = NGHTTP2_NV_FLAG_NONE;
01847 if(HEADER_OVERFLOW(nva[i])) {
01848 failf(conn->data, "Failed sending HTTP request: Header overflow");
01849 goto fail;
01850 }
01851 ++i;
01852 }
01853
01854
01855 if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
01856 nghttp2_nv authority = nva[authority_idx];
01857 for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
01858 nva[i] = nva[i - 1];
01859 }
01860 nva[i] = authority;
01861 }
01862
01863
01864
01865 {
01866 size_t acc = 0;
01867 const size_t max_acc = 60000;
01868
01869 for(i = 0; i < nheader; ++i) {
01870 if(nva[i].namelen > max_acc - acc)
01871 break;
01872 acc += nva[i].namelen;
01873
01874 if(nva[i].valuelen > max_acc - acc)
01875 break;
01876 acc += nva[i].valuelen;
01877
01878 DEBUGF(infof(conn->data, "h2 header: %.*s:%.*s\n",
01879 nva[i].namelen, nva[i].name,
01880 nva[i].valuelen, nva[i].value));
01881 }
01882
01883 if(i != nheader) {
01884 infof(conn->data, "http2_send: Warning: The cumulative length of all "
01885 "headers exceeds %zu bytes and that could cause the "
01886 "stream to be rejected.\n", max_acc);
01887 }
01888 }
01889
01890 h2_pri_spec(conn->data, &pri_spec);
01891
01892 switch(conn->data->set.httpreq) {
01893 case HTTPREQ_POST:
01894 case HTTPREQ_POST_FORM:
01895 case HTTPREQ_PUT:
01896 if(conn->data->state.infilesize != -1)
01897 stream->upload_left = conn->data->state.infilesize;
01898 else
01899
01900 stream->upload_left = -1;
01901
01902 data_prd.read_callback = data_source_read_callback;
01903 data_prd.source.ptr = NULL;
01904 stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
01905 &data_prd, conn->data);
01906 break;
01907 default:
01908 stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
01909 NULL, conn->data);
01910 }
01911
01912 Curl_safefree(nva);
01913
01914 if(stream_id < 0) {
01915 DEBUGF(infof(conn->data, "http2_send() send error\n"));
01916 *err = CURLE_SEND_ERROR;
01917 return -1;
01918 }
01919
01920 infof(conn->data, "Using Stream ID: %x (easy handle %p)\n",
01921 stream_id, conn->data);
01922 stream->stream_id = stream_id;
01923
01924
01925
01926 rv = nghttp2_session_send(h2);
01927
01928 if(rv != 0) {
01929 *err = CURLE_SEND_ERROR;
01930 return -1;
01931 }
01932
01933 if(should_close_session(httpc)) {
01934 DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
01935 *err = CURLE_HTTP2;
01936 return -1;
01937 }
01938
01939 if(stream->stream_id != -1) {
01940
01941
01942
01943
01944
01945
01946
01947
01948 nghttp2_session_resume_data(h2, stream->stream_id);
01949 }
01950
01951 return len;
01952
01953 fail:
01954 free(nva);
01955 *err = CURLE_SEND_ERROR;
01956 return -1;
01957 }
01958
01959 CURLcode Curl_http2_setup(struct connectdata *conn)
01960 {
01961 CURLcode result;
01962 struct http_conn *httpc = &conn->proto.httpc;
01963 struct HTTP *stream = conn->data->req.protop;
01964
01965 stream->stream_id = -1;
01966
01967 if(!stream->header_recvbuf)
01968 stream->header_recvbuf = Curl_add_buffer_init();
01969
01970 if((conn->handler == &Curl_handler_http2_ssl) ||
01971 (conn->handler == &Curl_handler_http2))
01972 return CURLE_OK;
01973
01974 if(conn->handler->flags & PROTOPT_SSL)
01975 conn->handler = &Curl_handler_http2_ssl;
01976 else
01977 conn->handler = &Curl_handler_http2;
01978
01979 result = Curl_http2_init(conn);
01980 if(result)
01981 return result;
01982
01983 infof(conn->data, "Using HTTP2, server supports multi-use\n");
01984 stream->upload_left = 0;
01985 stream->upload_mem = NULL;
01986 stream->upload_len = 0;
01987
01988 httpc->inbuflen = 0;
01989 httpc->nread_inbuf = 0;
01990
01991 httpc->pause_stream_id = 0;
01992 httpc->drain_total = 0;
01993
01994 conn->bits.multiplex = TRUE;
01995 conn->httpversion = 20;
01996 conn->bundle->multiuse = BUNDLE_MULTIPLEX;
01997
01998 infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
01999 Curl_multi_connchanged(conn->data->multi);
02000
02001 return CURLE_OK;
02002 }
02003
02004 CURLcode Curl_http2_switched(struct connectdata *conn,
02005 const char *mem, size_t nread)
02006 {
02007 CURLcode result;
02008 struct http_conn *httpc = &conn->proto.httpc;
02009 int rv;
02010 ssize_t nproc;
02011 struct Curl_easy *data = conn->data;
02012 struct HTTP *stream = conn->data->req.protop;
02013
02014 result = Curl_http2_setup(conn);
02015 if(result)
02016 return result;
02017
02018 httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
02019 httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
02020 conn->recv[FIRSTSOCKET] = http2_recv;
02021 conn->send[FIRSTSOCKET] = http2_send;
02022
02023 if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
02024
02025 stream->stream_id = 1;
02026
02027 rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
02028 httpc->binlen, NULL);
02029 if(rv != 0) {
02030 failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
02031 nghttp2_strerror(rv), rv);
02032 return CURLE_HTTP2;
02033 }
02034
02035 nghttp2_session_set_stream_user_data(httpc->h2,
02036 stream->stream_id,
02037 conn->data);
02038 }
02039 else {
02040
02041 stream->stream_id = -1;
02042 rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, settings,
02043 sizeof(settings) / sizeof(settings[0]));
02044 if(rv != 0) {
02045 failf(data, "nghttp2_submit_settings() failed: %s(%d)",
02046 nghttp2_strerror(rv), rv);
02047 return CURLE_HTTP2;
02048 }
02049 }
02050
02051 #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
02052 rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0,
02053 HTTP2_HUGE_WINDOW_SIZE);
02054 if(rv != 0) {
02055 failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
02056 nghttp2_strerror(rv), rv);
02057 return CURLE_HTTP2;
02058 }
02059 #endif
02060
02061
02062
02063
02064
02065 if(H2_BUFSIZE < nread) {
02066 failf(data, "connection buffer size is too small to store data following "
02067 "HTTP Upgrade response header: buflen=%zu, datalen=%zu",
02068 H2_BUFSIZE, nread);
02069 return CURLE_HTTP2;
02070 }
02071
02072 infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer"
02073 " after upgrade: len=%zu\n",
02074 nread);
02075
02076 if(nread)
02077 memcpy(httpc->inbuf, mem, nread);
02078 httpc->inbuflen = nread;
02079
02080 nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf,
02081 httpc->inbuflen);
02082
02083 if(nghttp2_is_fatal((int)nproc)) {
02084 failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
02085 nghttp2_strerror((int)nproc), (int)nproc);
02086 return CURLE_HTTP2;
02087 }
02088
02089 DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));
02090
02091 if((ssize_t)nread == nproc) {
02092 httpc->inbuflen = 0;
02093 httpc->nread_inbuf = 0;
02094 }
02095 else {
02096 httpc->nread_inbuf += nproc;
02097 }
02098
02099
02100 rv = h2_session_send(data, httpc->h2);
02101
02102 if(rv != 0) {
02103 failf(data, "nghttp2_session_send() failed: %s(%d)",
02104 nghttp2_strerror(rv), rv);
02105 return CURLE_HTTP2;
02106 }
02107
02108 if(should_close_session(httpc)) {
02109 DEBUGF(infof(data,
02110 "nghttp2_session_send(): nothing to do in this session\n"));
02111 return CURLE_HTTP2;
02112 }
02113
02114 return CURLE_OK;
02115 }
02116
02117 void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child,
02118 bool exclusive)
02119 {
02120 struct Curl_http2_dep **tail;
02121 struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep));
02122 dep->data = child;
02123
02124 if(parent->set.stream_dependents && exclusive) {
02125 struct Curl_http2_dep *node = parent->set.stream_dependents;
02126 while(node) {
02127 node->data->set.stream_depends_on = child;
02128 node = node->next;
02129 }
02130
02131 tail = &child->set.stream_dependents;
02132 while(*tail)
02133 tail = &(*tail)->next;
02134
02135 DEBUGASSERT(!*tail);
02136 *tail = parent->set.stream_dependents;
02137 parent->set.stream_dependents = 0;
02138 }
02139
02140 tail = &parent->set.stream_dependents;
02141 while(*tail) {
02142 (*tail)->data->set.stream_depends_e = FALSE;
02143 tail = &(*tail)->next;
02144 }
02145
02146 DEBUGASSERT(!*tail);
02147 *tail = dep;
02148
02149 child->set.stream_depends_on = parent;
02150 child->set.stream_depends_e = exclusive;
02151 }
02152
02153 void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child)
02154 {
02155 struct Curl_http2_dep *last = 0;
02156 struct Curl_http2_dep *data = parent->set.stream_dependents;
02157 DEBUGASSERT(child->set.stream_depends_on == parent);
02158
02159 while(data && data->data != child) {
02160 last = data;
02161 data = data->next;
02162 }
02163
02164 DEBUGASSERT(data);
02165
02166 if(data) {
02167 if(last) {
02168 last->next = data->next;
02169 }
02170 else {
02171 parent->set.stream_dependents = data->next;
02172 }
02173 free(data);
02174 }
02175
02176 child->set.stream_depends_on = 0;
02177 child->set.stream_depends_e = FALSE;
02178 }
02179
02180 void Curl_http2_cleanup_dependencies(struct Curl_easy *data)
02181 {
02182 while(data->set.stream_dependents) {
02183 struct Curl_easy *tmp = data->set.stream_dependents->data;
02184 Curl_http2_remove_child(data, tmp);
02185 if(data->set.stream_depends_on)
02186 Curl_http2_add_child(data->set.stream_depends_on, tmp, FALSE);
02187 }
02188
02189 if(data->set.stream_depends_on)
02190 Curl_http2_remove_child(data->set.stream_depends_on, data);
02191 }
02192
02193 #else
02194
02195
02196
02197 #define CURL_DISABLE_TYPECHECK
02198 #include <curl/curl.h>
02199
02200 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
02201 {
02202 (void) h;
02203 (void) num;
02204 return NULL;
02205 }
02206
02207 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
02208 {
02209 (void) h;
02210 (void) header;
02211 return NULL;
02212 }
02213
02214 #endif