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