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