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
68static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
69 char *mem, size_t len, CURLcode *err);
70static bool http2_connisdead(struct Curl_easy *data,
71 struct connectdata *conn);
72static int h2_session_send(struct Curl_easy *data,
73 nghttp2_session *h2);
74static 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 */
82void 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 */
91void Curl_http2_init_userset(struct UserDefined *set)
92{
93 set->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
94}
95
96static 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 */
122static 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
139static 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 */
166static 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 */
219static 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 */
228static struct Curl_easy *get_transfer(struct http_conn *c)
229{
230 DEBUGASSERT(c && c->trnsfr);
231 return c->trnsfr;
232}
233
234static 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 */
281void 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 */
297void 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 */
308static 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
331static 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 */
357void 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 */
368static 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. */
406struct 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 */
414char *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 */
431char *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 */
461static 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 */
472static 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
480static 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
499static 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
550static 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 */
660static void multi_connchanged(struct Curl_multi *multi)
661{
662 multi->recheckstate = TRUE;
663}
664
665static 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 DEBUGASSERT(stream->mem);
767 H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p",
768 ncopy, stream_id, stream->mem));
769
770 stream->len -= ncopy;
771 stream->memlen += ncopy;
772
773 drain_this(data_s, httpc);
774 /* if we receive data for another handle, wake that up */
775 if(get_transfer(httpc) != data_s)
776 Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
777 break;
778 case NGHTTP2_PUSH_PROMISE:
779 rv = push_promise(data_s, conn, &frame->push_promise);
780 if(rv) { /* deny! */
781 int h2;
782 DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
783 h2 = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
784 frame->push_promise.promised_stream_id,
785 NGHTTP2_CANCEL);
786 if(nghttp2_is_fatal(h2))
787 return NGHTTP2_ERR_CALLBACK_FAILURE;
788 else if(rv == CURL_PUSH_ERROROUT) {
789 DEBUGF(infof(data_s, "Fail the parent stream (too)"));
790 return NGHTTP2_ERR_CALLBACK_FAILURE;
791 }
792 }
793 break;
794 default:
795 H2BUGF(infof(data_s, "Got frame type %x for stream %u!",
796 frame->hd.type, stream_id));
797 break;
798 }
799 return 0;
800}
801
802static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
803 int32_t stream_id,
804 const uint8_t *mem, size_t len, void *userp)
805{
806 struct HTTP *stream;
807 struct Curl_easy *data_s;
808 size_t nread;
809 struct connectdata *conn = (struct connectdata *)userp;
810 struct http_conn *httpc = &conn->proto.httpc;
811 (void)session;
812 (void)flags;
813
814 DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
815
816 /* get the stream from the hash based on Stream ID */
817 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
818 if(!data_s)
819 /* Receiving a Stream ID not in the hash should not happen, this is an
820 internal error more than anything else! */
821 return NGHTTP2_ERR_CALLBACK_FAILURE;
822
823 stream = data_s->req.p.http;
824 if(!stream)
825 return NGHTTP2_ERR_CALLBACK_FAILURE;
826
827 nread = CURLMIN(stream->len, len);
828 memcpy(&stream->mem[stream->memlen], mem, nread);
829
830 stream->len -= nread;
831 stream->memlen += nread;
832
833 drain_this(data_s, &conn->proto.httpc);
834
835 /* if we receive data for another handle, wake that up */
836 if(get_transfer(httpc) != data_s)
837 Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
838
839 H2BUGF(infof(data_s, "%zu data received for stream %u "
840 "(%zu left in buffer %p, total %zu)",
841 nread, stream_id,
842 stream->len, stream->mem,
843 stream->memlen));
844
845 if(nread < len) {
846 stream->pausedata = mem + nread;
847 stream->pauselen = len - nread;
848 H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
849 ", stream %u",
850 len - nread, stream_id));
851 data_s->conn->proto.httpc.pause_stream_id = stream_id;
852
853 return NGHTTP2_ERR_PAUSE;
854 }
855
856 /* pause execution of nghttp2 if we received data for another handle
857 in order to process them first. */
858 if(get_transfer(httpc) != data_s) {
859 data_s->conn->proto.httpc.pause_stream_id = stream_id;
860
861 return NGHTTP2_ERR_PAUSE;
862 }
863
864 return 0;
865}
866
867static int on_stream_close(nghttp2_session *session, int32_t stream_id,
868 uint32_t error_code, void *userp)
869{
870 struct Curl_easy *data_s;
871 struct HTTP *stream;
872 struct connectdata *conn = (struct connectdata *)userp;
873 int rv;
874 (void)session;
875 (void)stream_id;
876
877 if(stream_id) {
878 struct http_conn *httpc;
879 /* get the stream from the hash based on Stream ID, stream ID zero is for
880 connection-oriented stuff */
881 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
882 if(!data_s) {
883 /* We could get stream ID not in the hash. For example, if we
884 decided to reject stream (e.g., PUSH_PROMISE). */
885 return 0;
886 }
887 H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u",
888 nghttp2_http2_strerror(error_code), error_code, stream_id));
889 stream = data_s->req.p.http;
890 if(!stream)
891 return NGHTTP2_ERR_CALLBACK_FAILURE;
892
893 stream->closed = TRUE;
894 httpc = &conn->proto.httpc;
895 drain_this(data_s, httpc);
896 Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
897 stream->error = error_code;
898
899 /* remove the entry from the hash as the stream is now gone */
900 rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
901 if(rv) {
902 infof(data_s, "http/2: failed to clear user_data for stream %d!",
903 stream_id);
904 DEBUGASSERT(0);
905 }
906 if(stream_id == httpc->pause_stream_id) {
907 H2BUGF(infof(data_s, "Stopped the pause stream!"));
908 httpc->pause_stream_id = 0;
909 }
910 H2BUGF(infof(data_s, "Removed stream %u hash!", stream_id));
911 stream->stream_id = 0; /* cleared */
912 }
913 return 0;
914}
915
916static int on_begin_headers(nghttp2_session *session,
917 const nghttp2_frame *frame, void *userp)
918{
919 struct HTTP *stream;
920 struct Curl_easy *data_s = NULL;
921 (void)userp;
922
923 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
924 if(!data_s) {
925 return 0;
926 }
927
928 H2BUGF(infof(data_s, "on_begin_headers() was called"));
929
930 if(frame->hd.type != NGHTTP2_HEADERS) {
931 return 0;
932 }
933
934 stream = data_s->req.p.http;
935 if(!stream || !stream->bodystarted) {
936 return 0;
937 }
938
939 return 0;
940}
941
942/* Decode HTTP status code. Returns -1 if no valid status code was
943 decoded. */
944static int decode_status_code(const uint8_t *value, size_t len)
945{
946 int i;
947 int res;
948
949 if(len != 3) {
950 return -1;
951 }
952
953 res = 0;
954
955 for(i = 0; i < 3; ++i) {
956 char c = value[i];
957
958 if(c < '0' || c > '9') {
959 return -1;
960 }
961
962 res *= 10;
963 res += c - '0';
964 }
965
966 return res;
967}
968
969/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
970static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
971 const uint8_t *name, size_t namelen,
972 const uint8_t *value, size_t valuelen,
973 uint8_t flags,
974 void *userp)
975{
976 struct HTTP *stream;
977 struct Curl_easy *data_s;
978 int32_t stream_id = frame->hd.stream_id;
979 struct connectdata *conn = (struct connectdata *)userp;
980 struct http_conn *httpc = &conn->proto.httpc;
981 CURLcode result;
982 (void)flags;
983
984 DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
985
986 /* get the stream from the hash based on Stream ID */
987 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
988 if(!data_s)
989 /* Receiving a Stream ID not in the hash should not happen, this is an
990 internal error more than anything else! */
991 return NGHTTP2_ERR_CALLBACK_FAILURE;
992
993 stream = data_s->req.p.http;
994 if(!stream) {
995 failf(data_s, "Internal NULL stream!");
996 return NGHTTP2_ERR_CALLBACK_FAILURE;
997 }
998
999 /* Store received PUSH_PROMISE headers to be used when the subsequent
1000 PUSH_PROMISE callback comes */
1001 if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
1002 char *h;
1003
1004 if(!strcmp(":authority", (const char *)name)) {
1005 /* pseudo headers are lower case */
1006 int rc = 0;
1007 char *check = aprintf("%s:%d", conn->host.name, conn->remote_port);
1008 if(!check)
1009 /* no memory */
1010 return NGHTTP2_ERR_CALLBACK_FAILURE;
1011 if(!Curl_strcasecompare(check, (const char *)value) &&
1012 ((conn->remote_port != conn->given->defport) ||
1013 !Curl_strcasecompare(conn->host.name, (const char *)value))) {
1014 /* This is push is not for the same authority that was asked for in
1015 * the URL. RFC 7540 section 8.2 says: "A client MUST treat a
1016 * PUSH_PROMISE for which the server is not authoritative as a stream
1017 * error of type PROTOCOL_ERROR."
1018 */
1019 (void)nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
1020 stream_id, NGHTTP2_PROTOCOL_ERROR);
1021 rc = NGHTTP2_ERR_CALLBACK_FAILURE;
1022 }
1023 free(check);
1024 if(rc)
1025 return rc;
1026 }
1027
1028 if(!stream->push_headers) {
1029 stream->push_headers_alloc = 10;
1030 stream->push_headers = malloc(stream->push_headers_alloc *
1031 sizeof(char *));
1032 if(!stream->push_headers)
1033 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1034 stream->push_headers_used = 0;
1035 }
1036 else if(stream->push_headers_used ==
1037 stream->push_headers_alloc) {
1038 char **headp;
1039 stream->push_headers_alloc *= 2;
1040 headp = Curl_saferealloc(stream->push_headers,
1041 stream->push_headers_alloc * sizeof(char *));
1042 if(!headp) {
1043 stream->push_headers = NULL;
1044 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1045 }
1046 stream->push_headers = headp;
1047 }
1048 h = aprintf("%s:%s", name, value);
1049 if(h)
1050 stream->push_headers[stream->push_headers_used++] = h;
1051 return 0;
1052 }
1053
1054 if(stream->bodystarted) {
1055 /* This is a trailer */
1056 H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s", namelen, name, valuelen,
1057 value));
1058 result = Curl_dyn_addf(&stream->trailer_recvbuf,
1059 "%.*s: %.*s\r\n", namelen, name,
1060 valuelen, value);
1061 if(result)
1062 return NGHTTP2_ERR_CALLBACK_FAILURE;
1063
1064 return 0;
1065 }
1066
1067 if(namelen == sizeof(":status") - 1 &&
1068 memcmp(":status", name, namelen) == 0) {
1069 /* nghttp2 guarantees :status is received first and only once, and
1070 value is 3 digits status code, and decode_status_code always
1071 succeeds. */
1072 stream->status_code = decode_status_code(value, valuelen);
1073 DEBUGASSERT(stream->status_code != -1);
1074
1075 result = Curl_dyn_add(&stream->header_recvbuf, "HTTP/2 ");
1076 if(result)
1077 return NGHTTP2_ERR_CALLBACK_FAILURE;
1078 result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen);
1079 if(result)
1080 return NGHTTP2_ERR_CALLBACK_FAILURE;
1081 /* the space character after the status code is mandatory */
1082 result = Curl_dyn_add(&stream->header_recvbuf, " \r\n");
1083 if(result)
1084 return NGHTTP2_ERR_CALLBACK_FAILURE;
1085 /* if we receive data for another handle, wake that up */
1086 if(get_transfer(httpc) != data_s)
1087 Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
1088
1089 H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)",
1090 stream->status_code, data_s));
1091 return 0;
1092 }
1093
1094 /* nghttp2 guarantees that namelen > 0, and :status was already
1095 received, and this is not pseudo-header field . */
1096 /* convert to a HTTP1-style header */
1097 result = Curl_dyn_addn(&stream->header_recvbuf, name, namelen);
1098 if(result)
1099 return NGHTTP2_ERR_CALLBACK_FAILURE;
1100 result = Curl_dyn_add(&stream->header_recvbuf, ": ");
1101 if(result)
1102 return NGHTTP2_ERR_CALLBACK_FAILURE;
1103 result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen);
1104 if(result)
1105 return NGHTTP2_ERR_CALLBACK_FAILURE;
1106 result = Curl_dyn_add(&stream->header_recvbuf, "\r\n");
1107 if(result)
1108 return NGHTTP2_ERR_CALLBACK_FAILURE;
1109 /* if we receive data for another handle, wake that up */
1110 if(get_transfer(httpc) != data_s)
1111 Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
1112
1113 H2BUGF(infof(data_s, "h2 header: %.*s: %.*s", namelen, name, valuelen,
1114 value));
1115
1116 return 0; /* 0 is successful */
1117}
1118
1119static ssize_t data_source_read_callback(nghttp2_session *session,
1120 int32_t stream_id,
1121 uint8_t *buf, size_t length,
1122 uint32_t *data_flags,
1123 nghttp2_data_source *source,
1124 void *userp)
1125{
1126 struct Curl_easy *data_s;
1127 struct HTTP *stream = NULL;
1128 size_t nread;
1129 (void)source;
1130 (void)userp;
1131
1132 if(stream_id) {
1133 /* get the stream from the hash based on Stream ID, stream ID zero is for
1134 connection-oriented stuff */
1135 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
1136 if(!data_s)
1137 /* Receiving a Stream ID not in the hash should not happen, this is an
1138 internal error more than anything else! */
1139 return NGHTTP2_ERR_CALLBACK_FAILURE;
1140
1141 stream = data_s->req.p.http;
1142 if(!stream)
1143 return NGHTTP2_ERR_CALLBACK_FAILURE;
1144 }
1145 else
1146 return NGHTTP2_ERR_INVALID_ARGUMENT;
1147
1148 nread = CURLMIN(stream->upload_len, length);
1149 if(nread > 0) {
1150 memcpy(buf, stream->upload_mem, nread);
1151 stream->upload_mem += nread;
1152 stream->upload_len -= nread;
1153 if(data_s->state.infilesize != -1)
1154 stream->upload_left -= nread;
1155 }
1156
1157 if(stream->upload_left == 0)
1158 *data_flags = NGHTTP2_DATA_FLAG_EOF;
1159 else if(nread == 0)
1160 return NGHTTP2_ERR_DEFERRED;
1161
1162 H2BUGF(infof(data_s, "data_source_read_callback: "
1163 "returns %zu bytes stream %u",
1164 nread, stream_id));
1165
1166 return nread;
1167}
1168
1169#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
1170static int error_callback(nghttp2_session *session,
1171 const char *msg,
1172 size_t len,
1173 void *userp)
1174{
1175 (void)session;
1176 (void)msg;
1177 (void)len;
1178 (void)userp;
1179 return 0;
1180}
1181#endif
1182
1183static void populate_settings(struct Curl_easy *data,
1184 struct http_conn *httpc)
1185{
1186 nghttp2_settings_entry *iv = httpc->local_settings;
1187
1188 iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
1189 iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
1190
1191 iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
1192 iv[1].value = HTTP2_HUGE_WINDOW_SIZE;
1193
1194 iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
1195 iv[2].value = data->multi->push_cb != NULL;
1196
1197 httpc->local_settings_num = 3;
1198}
1199
1200void Curl_http2_done(struct Curl_easy *data, bool premature)
1201{
1202 struct HTTP *http = data->req.p.http;
1203 struct http_conn *httpc = &data->conn->proto.httpc;
1204
1205 /* there might be allocated resources done before this got the 'h2' pointer
1206 setup */
1207 Curl_dyn_free(&http->header_recvbuf);
1208 Curl_dyn_free(&http->trailer_recvbuf);
1209 if(http->push_headers) {
1210 /* if they weren't used and then freed before */
1211 for(; http->push_headers_used > 0; --http->push_headers_used) {
1212 free(http->push_headers[http->push_headers_used - 1]);
1213 }
1214 free(http->push_headers);
1215 http->push_headers = NULL;
1216 }
1217
1218 if(!(data->conn->handler->protocol&PROTO_FAMILY_HTTP) ||
1219 !httpc->h2) /* not HTTP/2 ? */
1220 return;
1221
1222 if(premature) {
1223 /* RST_STREAM */
1224 set_transfer(httpc, data); /* set the transfer */
1225 if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE,
1226 http->stream_id, NGHTTP2_STREAM_CLOSED))
1227 (void)nghttp2_session_send(httpc->h2);
1228
1229 if(http->stream_id == httpc->pause_stream_id) {
1230 infof(data, "stopped the pause stream!");
1231 httpc->pause_stream_id = 0;
1232 }
1233 }
1234
1235 if(data->state.drain)
1236 drained_transfer(data, httpc);
1237
1238 /* -1 means unassigned and 0 means cleared */
1239 if(http->stream_id > 0) {
1240 int rv = nghttp2_session_set_stream_user_data(httpc->h2,
1241 http->stream_id, 0);
1242 if(rv) {
1243 infof(data, "http/2: failed to clear user_data for stream %d!",
1244 http->stream_id);
1245 DEBUGASSERT(0);
1246 }
1247 set_transfer(httpc, NULL);
1248 http->stream_id = 0;
1249 }
1250}
1251
1252/*
1253 * Initialize nghttp2 for a Curl connection
1254 */
1255static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
1256{
1257 if(!conn->proto.httpc.h2) {
1258 int rc;
1259 nghttp2_session_callbacks *callbacks;
1260
1261 conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
1262 if(!conn->proto.httpc.inbuf)
1263 return CURLE_OUT_OF_MEMORY;
1264
1265 rc = nghttp2_session_callbacks_new(&callbacks);
1266
1267 if(rc) {
1268 failf(data, "Couldn't initialize nghttp2 callbacks!");
1269 return CURLE_OUT_OF_MEMORY; /* most likely at least */
1270 }
1271
1272 /* nghttp2_send_callback */
1273 nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
1274 /* nghttp2_on_frame_recv_callback */
1275 nghttp2_session_callbacks_set_on_frame_recv_callback
1276 (callbacks, on_frame_recv);
1277 /* nghttp2_on_data_chunk_recv_callback */
1278 nghttp2_session_callbacks_set_on_data_chunk_recv_callback
1279 (callbacks, on_data_chunk_recv);
1280 /* nghttp2_on_stream_close_callback */
1281 nghttp2_session_callbacks_set_on_stream_close_callback
1282 (callbacks, on_stream_close);
1283 /* nghttp2_on_begin_headers_callback */
1284 nghttp2_session_callbacks_set_on_begin_headers_callback
1285 (callbacks, on_begin_headers);
1286 /* nghttp2_on_header_callback */
1287 nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
1288
1289 nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
1290
1291 /* The nghttp2 session is not yet setup, do it */
1292 rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
1293
1294 nghttp2_session_callbacks_del(callbacks);
1295
1296 if(rc) {
1297 failf(data, "Couldn't initialize nghttp2!");
1298 return CURLE_OUT_OF_MEMORY; /* most likely at least */
1299 }
1300 }
1301 return CURLE_OK;
1302}
1303
1304/*
1305 * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
1306 */
1307CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
1308 struct Curl_easy *data)
1309{
1310 CURLcode result;
1311 ssize_t binlen;
1312 char *base64;
1313 size_t blen;
1314 struct connectdata *conn = data->conn;
1315 struct SingleRequest *k = &data->req;
1316 uint8_t *binsettings = conn->proto.httpc.binsettings;
1317 struct http_conn *httpc = &conn->proto.httpc;
1318
1319 populate_settings(data, httpc);
1320
1321 /* this returns number of bytes it wrote */
1322 binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
1323 httpc->local_settings,
1324 httpc->local_settings_num);
1325 if(binlen <= 0) {
1326 failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
1327 Curl_dyn_free(req);
1328 return CURLE_FAILED_INIT;
1329 }
1330 conn->proto.httpc.binlen = binlen;
1331
1332 result = Curl_base64url_encode(data, (const char *)binsettings, binlen,
1333 &base64, &blen);
1334 if(result) {
1335 Curl_dyn_free(req);
1336 return result;
1337 }
1338
1339 result = Curl_dyn_addf(req,
1340 "Connection: Upgrade, HTTP2-Settings\r\n"
1341 "Upgrade: %s\r\n"
1342 "HTTP2-Settings: %s\r\n",
1343 NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
1344 free(base64);
1345
1346 k->upgr101 = UPGR101_REQUESTED;
1347
1348 return result;
1349}
1350
1351/*
1352 * Returns nonzero if current HTTP/2 session should be closed.
1353 */
1354static int should_close_session(struct http_conn *httpc)
1355{
1356 return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) &&
1357 !nghttp2_session_want_write(httpc->h2);
1358}
1359
1360/*
1361 * h2_process_pending_input() processes pending input left in
1362 * httpc->inbuf. Then, call h2_session_send() to send pending data.
1363 * This function returns 0 if it succeeds, or -1 and error code will
1364 * be assigned to *err.
1365 */
1366static int h2_process_pending_input(struct Curl_easy *data,
1367 struct http_conn *httpc,
1368 CURLcode *err)
1369{
1370 ssize_t nread;
1371 char *inbuf;
1372 ssize_t rv;
1373
1374 nread = httpc->inbuflen - httpc->nread_inbuf;
1375 inbuf = httpc->inbuf + httpc->nread_inbuf;
1376
1377 set_transfer(httpc, data); /* set the transfer */
1378 rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
1379 if(rv < 0) {
1380 failf(data,
1381 "h2_process_pending_input: nghttp2_session_mem_recv() returned "
1382 "%zd:%s", rv, nghttp2_strerror((int)rv));
1383 *err = CURLE_RECV_ERROR;
1384 return -1;
1385 }
1386
1387 if(nread == rv) {
1388 H2BUGF(infof(data,
1389 "h2_process_pending_input: All data in connection buffer "
1390 "processed"));
1391 httpc->inbuflen = 0;
1392 httpc->nread_inbuf = 0;
1393 }
1394 else {
1395 httpc->nread_inbuf += rv;
1396 H2BUGF(infof(data,
1397 "h2_process_pending_input: %zu bytes left in connection "
1398 "buffer",
1399 httpc->inbuflen - httpc->nread_inbuf));
1400 }
1401
1402 rv = h2_session_send(data, httpc->h2);
1403 if(rv) {
1404 *err = CURLE_SEND_ERROR;
1405 return -1;
1406 }
1407
1408 if(nghttp2_session_check_request_allowed(httpc->h2) == 0) {
1409 /* No more requests are allowed in the current session, so
1410 the connection may not be reused. This is set when a
1411 GOAWAY frame has been received or when the limit of stream
1412 identifiers has been reached. */
1413 connclose(data->conn, "http/2: No new requests allowed");
1414 }
1415
1416 if(should_close_session(httpc)) {
1417 struct HTTP *stream = data->req.p.http;
1418 H2BUGF(infof(data,
1419 "h2_process_pending_input: nothing to do in this session"));
1420 if(stream->error)
1421 *err = CURLE_HTTP2;
1422 else {
1423 /* not an error per se, but should still close the connection */
1424 connclose(data->conn, "GOAWAY received");
1425 *err = CURLE_OK;
1426 }
1427 return -1;
1428 }
1429 return 0;
1430}
1431
1432/*
1433 * Called from transfer.c:done_sending when we stop uploading.
1434 */
1435CURLcode Curl_http2_done_sending(struct Curl_easy *data,
1436 struct connectdata *conn)
1437{
1438 CURLcode result = CURLE_OK;
1439
1440 if((conn->handler == &Curl_handler_http2_ssl) ||
1441 (conn->handler == &Curl_handler_http2)) {
1442 /* make sure this is only attempted for HTTP/2 transfers */
1443 struct HTTP *stream = data->req.p.http;
1444 struct http_conn *httpc = &conn->proto.httpc;
1445 nghttp2_session *h2 = httpc->h2;
1446
1447 if(stream->upload_left) {
1448 /* If the stream still thinks there's data left to upload. */
1449
1450 stream->upload_left = 0; /* DONE! */
1451
1452 /* resume sending here to trigger the callback to get called again so
1453 that it can signal EOF to nghttp2 */
1454 (void)nghttp2_session_resume_data(h2, stream->stream_id);
1455 (void)h2_process_pending_input(data, httpc, &result);
1456 }
1457
1458 /* If nghttp2 still has pending frames unsent */
1459 if(nghttp2_session_want_write(h2)) {
1460 struct SingleRequest *k = &data->req;
1461 int rv;
1462
1463 H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)", data));
1464
1465 /* and attempt to send the pending frames */
1466 rv = h2_session_send(data, h2);
1467 if(rv)
1468 result = CURLE_SEND_ERROR;
1469
1470 if(nghttp2_session_want_write(h2)) {
1471 /* re-set KEEP_SEND to make sure we are called again */
1472 k->keepon |= KEEP_SEND;
1473 }
1474 }
1475 }
1476 return result;
1477}
1478
1479static ssize_t http2_handle_stream_close(struct connectdata *conn,
1480 struct Curl_easy *data,
1481 struct HTTP *stream, CURLcode *err)
1482{
1483 struct http_conn *httpc = &conn->proto.httpc;
1484
1485 if(httpc->pause_stream_id == stream->stream_id) {
1486 httpc->pause_stream_id = 0;
1487 }
1488
1489 drained_transfer(data, httpc);
1490
1491 if(httpc->pause_stream_id == 0) {
1492 if(h2_process_pending_input(data, httpc, err) != 0) {
1493 return -1;
1494 }
1495 }
1496
1497 DEBUGASSERT(data->state.drain == 0);
1498
1499 /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
1500 stream->closed = FALSE;
1501 if(stream->error == NGHTTP2_REFUSED_STREAM) {
1502 H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!",
1503 stream->stream_id));
1504 connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */
1505 data->state.refused_stream = TRUE;
1506 *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
1507 return -1;
1508 }
1509 else if(stream->error != NGHTTP2_NO_ERROR) {
1510 failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)",
1511 stream->stream_id, nghttp2_http2_strerror(stream->error),
1512 stream->error);
1513 *err = CURLE_HTTP2_STREAM;
1514 return -1;
1515 }
1516
1517 if(!stream->bodystarted) {
1518 failf(data, "HTTP/2 stream %d was closed cleanly, but before getting "
1519 " all response header fields, treated as error",
1520 stream->stream_id);
1521 *err = CURLE_HTTP2_STREAM;
1522 return -1;
1523 }
1524
1525 if(Curl_dyn_len(&stream->trailer_recvbuf)) {
1526 char *trailp = Curl_dyn_ptr(&stream->trailer_recvbuf);
1527 char *lf;
1528
1529 do {
1530 size_t len = 0;
1531 CURLcode result;
1532 /* each trailer line ends with a newline */
1533 lf = strchr(trailp, '\n');
1534 if(!lf)
1535 break;
1536 len = lf + 1 - trailp;
1537
1538 Curl_debug(data, CURLINFO_HEADER_IN, trailp, len);
1539 /* pass the trailers one by one to the callback */
1540 result = Curl_client_write(data, CLIENTWRITE_HEADER, trailp, len);
1541 if(result) {
1542 *err = result;
1543 return -1;
1544 }
1545 trailp = ++lf;
1546 } while(lf);
1547 }
1548
1549 stream->close_handled = TRUE;
1550
1551 H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close"));
1552 return 0;
1553}
1554
1555/*
1556 * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
1557 * and dependency to the peer. It also stores the updated values in the state
1558 * struct.
1559 */
1560
1561static void h2_pri_spec(struct Curl_easy *data,
1562 nghttp2_priority_spec *pri_spec)
1563{
1564 struct HTTP *depstream = (data->set.stream_depends_on?
1565 data->set.stream_depends_on->req.p.http:NULL);
1566 int32_t depstream_id = depstream? depstream->stream_id:0;
1567 nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
1568 data->set.stream_depends_e);
1569 data->state.stream_weight = data->set.stream_weight;
1570 data->state.stream_depends_e = data->set.stream_depends_e;
1571 data->state.stream_depends_on = data->set.stream_depends_on;
1572}
1573
1574/*
1575 * h2_session_send() checks if there's been an update in the priority /
1576 * dependency settings and if so it submits a PRIORITY frame with the updated
1577 * info.
1578 */
1579static int h2_session_send(struct Curl_easy *data,
1580 nghttp2_session *h2)
1581{
1582 struct HTTP *stream = data->req.p.http;
1583 struct http_conn *httpc = &data->conn->proto.httpc;
1584 set_transfer(httpc, data);
1585 if((data->set.stream_weight != data->state.stream_weight) ||
1586 (data->set.stream_depends_e != data->state.stream_depends_e) ||
1587 (data->set.stream_depends_on != data->state.stream_depends_on) ) {
1588 /* send new weight and/or dependency */
1589 nghttp2_priority_spec pri_spec;
1590 int rv;
1591
1592 h2_pri_spec(data, &pri_spec);
1593
1594 H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)",
1595 stream->stream_id, data));
1596 DEBUGASSERT(stream->stream_id != -1);
1597 rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
1598 &pri_spec);
1599 if(rv)
1600 return rv;
1601 }
1602
1603 return nghttp2_session_send(h2);
1604}
1605
1606static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
1607 char *mem, size_t len, CURLcode *err)
1608{
1609 ssize_t nread;
1610 struct connectdata *conn = data->conn;
1611 struct http_conn *httpc = &conn->proto.httpc;
1612 struct HTTP *stream = data->req.p.http;
1613
1614 (void)sockindex; /* we always do HTTP2 on sockindex 0 */
1615
1616 if(should_close_session(httpc)) {
1617 H2BUGF(infof(data,
1618 "http2_recv: nothing to do in this session"));
1619 if(conn->bits.close) {
1620 /* already marked for closure, return OK and we're done */
1621 *err = CURLE_OK;
1622 return 0;
1623 }
1624 *err = CURLE_HTTP2;
1625 return -1;
1626 }
1627
1628 /* Nullify here because we call nghttp2_session_send() and they
1629 might refer to the old buffer. */
1630 stream->upload_mem = NULL;
1631 stream->upload_len = 0;
1632
1633 /*
1634 * At this point 'stream' is just in the Curl_easy the connection
1635 * identifies as its owner at this time.
1636 */
1637
1638 if(stream->bodystarted &&
1639 stream->nread_header_recvbuf < Curl_dyn_len(&stream->header_recvbuf)) {
1640 /* If there is header data pending for this stream to return, do that */
1641 size_t left =
1642 Curl_dyn_len(&stream->header_recvbuf) - stream->nread_header_recvbuf;
1643 size_t ncopy = CURLMIN(len, left);
1644 memcpy(mem, Curl_dyn_ptr(&stream->header_recvbuf) +
1645 stream->nread_header_recvbuf, ncopy);
1646 stream->nread_header_recvbuf += ncopy;
1647
1648 H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf",
1649 (int)ncopy));
1650 return ncopy;
1651 }
1652
1653 H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u",
1654 data, stream->stream_id,
1655 nghttp2_session_get_local_window_size(httpc->h2),
1656 nghttp2_session_get_stream_local_window_size(httpc->h2,
1657 stream->stream_id)
1658 ));
1659
1660 if((data->state.drain) && stream->memlen) {
1661 H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)",
1662 stream->memlen, stream->stream_id,
1663 stream->mem, mem));
1664 if(mem != stream->mem) {
1665 /* if we didn't get the same buffer this time, we must move the data to
1666 the beginning */
1667 memmove(mem, stream->mem, stream->memlen);
1668 stream->len = len - stream->memlen;
1669 stream->mem = mem;
1670 }
1671 if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) {
1672 /* We have paused nghttp2, but we have no pause data (see
1673 on_data_chunk_recv). */
1674 httpc->pause_stream_id = 0;
1675 if(h2_process_pending_input(data, httpc, err) != 0) {
1676 return -1;
1677 }
1678 }
1679 }
1680 else if(stream->pausedata) {
1681 DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
1682 nread = CURLMIN(len, stream->pauselen);
1683 memcpy(mem, stream->pausedata, nread);
1684
1685 stream->pausedata += nread;
1686 stream->pauselen -= nread;
1687
1688 if(stream->pauselen == 0) {
1689 H2BUGF(infof(data, "Unpaused by stream %u", stream->stream_id));
1690 DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
1691 httpc->pause_stream_id = 0;
1692
1693 stream->pausedata = NULL;
1694 stream->pauselen = 0;
1695
1696 /* When NGHTTP2_ERR_PAUSE is returned from
1697 data_source_read_callback, we might not process DATA frame
1698 fully. Calling nghttp2_session_mem_recv() again will
1699 continue to process DATA frame, but if there is no incoming
1700 frames, then we have to call it again with 0-length data.
1701 Without this, on_stream_close callback will not be called,
1702 and stream could be hanged. */
1703 if(h2_process_pending_input(data, httpc, err) != 0) {
1704 return -1;
1705 }
1706 }
1707 H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u",
1708 nread, stream->stream_id));
1709 return nread;
1710 }
1711 else if(httpc->pause_stream_id) {
1712 /* If a stream paused nghttp2_session_mem_recv previously, and has
1713 not processed all data, it still refers to the buffer in
1714 nghttp2_session. If we call nghttp2_session_mem_recv(), we may
1715 overwrite that buffer. To avoid that situation, just return
1716 here with CURLE_AGAIN. This could be busy loop since data in
1717 socket is not read. But it seems that usually streams are
1718 notified with its drain property, and socket is read again
1719 quickly. */
1720 if(stream->closed)
1721 /* closed overrides paused */
1722 return 0;
1723 H2BUGF(infof(data, "stream %x is paused, pause id: %x",
1724 stream->stream_id, httpc->pause_stream_id));
1725 *err = CURLE_AGAIN;
1726 return -1;
1727 }
1728 else {
1729 /* remember where to store incoming data for this stream and how big the
1730 buffer is */
1731 stream->mem = mem;
1732 stream->len = len;
1733 stream->memlen = 0;
1734
1735 if(httpc->inbuflen == 0) {
1736 nread = ((Curl_recv *)httpc->recv_underlying)(
1737 data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, err);
1738
1739 if(nread == -1) {
1740 if(*err != CURLE_AGAIN)
1741 failf(data, "Failed receiving HTTP2 data");
1742 else if(stream->closed)
1743 /* received when the stream was already closed! */
1744 return http2_handle_stream_close(conn, data, stream, err);
1745
1746 return -1;
1747 }
1748
1749 if(nread == 0) {
1750 if(!stream->closed) {
1751 /* This will happen when the server or proxy server is SIGKILLed
1752 during data transfer. We should emit an error since our data
1753 received may be incomplete. */
1754 failf(data, "HTTP/2 stream %d was not closed cleanly before"
1755 " end of the underlying stream",
1756 stream->stream_id);
1757 *err = CURLE_HTTP2_STREAM;
1758 return -1;
1759 }
1760
1761 H2BUGF(infof(data, "end of stream"));
1762 *err = CURLE_OK;
1763 return 0;
1764 }
1765
1766 H2BUGF(infof(data, "nread=%zd", nread));
1767
1768 httpc->inbuflen = nread;
1769
1770 DEBUGASSERT(httpc->nread_inbuf == 0);
1771 }
1772 else {
1773 nread = httpc->inbuflen - httpc->nread_inbuf;
1774 (void)nread; /* silence warning, used in debug */
1775 H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd",
1776 nread));
1777 }
1778
1779 if(h2_process_pending_input(data, httpc, err))
1780 return -1;
1781 }
1782 if(stream->memlen) {
1783 ssize_t retlen = stream->memlen;
1784 H2BUGF(infof(data, "http2_recv: returns %zd for stream %u",
1785 retlen, stream->stream_id));
1786 stream->memlen = 0;
1787
1788 if(httpc->pause_stream_id == stream->stream_id) {
1789 /* data for this stream is returned now, but this stream caused a pause
1790 already so we need it called again asap */
1791 H2BUGF(infof(data, "Data returned for PAUSED stream %u",
1792 stream->stream_id));
1793 }
1794 else if(!stream->closed) {
1795 drained_transfer(data, httpc);
1796 }
1797 else
1798 /* this stream is closed, trigger a another read ASAP to detect that */
1799 Curl_expire(data, 0, EXPIRE_RUN_NOW);
1800
1801 return retlen;
1802 }
1803 if(stream->closed)
1804 return http2_handle_stream_close(conn, data, stream, err);
1805 *err = CURLE_AGAIN;
1806 H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u",
1807 stream->stream_id));
1808 return -1;
1809}
1810
1811/* Index where :authority header field will appear in request header
1812 field list. */
1813#define AUTHORITY_DST_IDX 3
1814
1815/* USHRT_MAX is 65535 == 0xffff */
1816#define HEADER_OVERFLOW(x) \
1817 (x.namelen > 0xffff || x.valuelen > 0xffff - x.namelen)
1818
1819/*
1820 * Check header memory for the token "trailers".
1821 * Parse the tokens as separated by comma and surrounded by whitespace.
1822 * Returns TRUE if found or FALSE if not.
1823 */
1824static bool contains_trailers(const char *p, size_t len)
1825{
1826 const char *end = p + len;
1827 for(;;) {
1828 for(; p != end && (*p == ' ' || *p == '\t'); ++p)
1829 ;
1830 if(p == end || (size_t)(end - p) < sizeof("trailers") - 1)
1831 return FALSE;
1832 if(strncasecompare("trailers", p, sizeof("trailers") - 1)) {
1833 p += sizeof("trailers") - 1;
1834 for(; p != end && (*p == ' ' || *p == '\t'); ++p)
1835 ;
1836 if(p == end || *p == ',')
1837 return TRUE;
1838 }
1839 /* skip to next token */
1840 for(; p != end && *p != ','; ++p)
1841 ;
1842 if(p == end)
1843 return FALSE;
1844 ++p;
1845 }
1846}
1847
1848typedef enum {
1849 /* Send header to server */
1850 HEADERINST_FORWARD,
1851 /* Don't send header to server */
1852 HEADERINST_IGNORE,
1853 /* Discard header, and replace it with "te: trailers" */
1854 HEADERINST_TE_TRAILERS
1855} header_instruction;
1856
1857/* Decides how to treat given header field. */
1858static header_instruction inspect_header(const char *name, size_t namelen,
1859 const char *value, size_t valuelen) {
1860 switch(namelen) {
1861 case 2:
1862 if(!strncasecompare("te", name, namelen))
1863 return HEADERINST_FORWARD;
1864
1865 return contains_trailers(value, valuelen) ?
1866 HEADERINST_TE_TRAILERS : HEADERINST_IGNORE;
1867 case 7:
1868 return strncasecompare("upgrade", name, namelen) ?
1869 HEADERINST_IGNORE : HEADERINST_FORWARD;
1870 case 10:
1871 return (strncasecompare("connection", name, namelen) ||
1872 strncasecompare("keep-alive", name, namelen)) ?
1873 HEADERINST_IGNORE : HEADERINST_FORWARD;
1874 case 16:
1875 return strncasecompare("proxy-connection", name, namelen) ?
1876 HEADERINST_IGNORE : HEADERINST_FORWARD;
1877 case 17:
1878 return strncasecompare("transfer-encoding", name, namelen) ?
1879 HEADERINST_IGNORE : HEADERINST_FORWARD;
1880 default:
1881 return HEADERINST_FORWARD;
1882 }
1883}
1884
1885static ssize_t http2_send(struct Curl_easy *data, int sockindex,
1886 const void *mem, size_t len, CURLcode *err)
1887{
1888 /*
1889 * Currently, we send request in this function, but this function is also
1890 * used to send request body. It would be nice to add dedicated function for
1891 * request.
1892 */
1893 int rv;
1894 struct connectdata *conn = data->conn;
1895 struct http_conn *httpc = &conn->proto.httpc;
1896 struct HTTP *stream = data->req.p.http;
1897 nghttp2_nv *nva = NULL;
1898 size_t nheader;
1899 size_t i;
1900 size_t authority_idx;
1901 char *hdbuf = (char *)mem;
1902 char *end, *line_end;
1903 nghttp2_data_provider data_prd;
1904 int32_t stream_id;
1905 nghttp2_session *h2 = httpc->h2;
1906 nghttp2_priority_spec pri_spec;
1907
1908 (void)sockindex;
1909
1910 H2BUGF(infof(data, "http2_send len=%zu", len));
1911
1912 if(stream->stream_id != -1) {
1913 if(stream->close_handled) {
1914 infof(data, "stream %d closed", stream->stream_id);
1915 *err = CURLE_HTTP2_STREAM;
1916 return -1;
1917 }
1918 else if(stream->closed) {
1919 return http2_handle_stream_close(conn, data, stream, err);
1920 }
1921 /* If stream_id != -1, we have dispatched request HEADERS, and now
1922 are going to send or sending request body in DATA frame */
1923 stream->upload_mem = mem;
1924 stream->upload_len = len;
1925 rv = nghttp2_session_resume_data(h2, stream->stream_id);
1926 if(nghttp2_is_fatal(rv)) {
1927 *err = CURLE_SEND_ERROR;
1928 return -1;
1929 }
1930 rv = h2_session_send(data, h2);
1931 if(nghttp2_is_fatal(rv)) {
1932 *err = CURLE_SEND_ERROR;
1933 return -1;
1934 }
1935 len -= stream->upload_len;
1936
1937 /* Nullify here because we call nghttp2_session_send() and they
1938 might refer to the old buffer. */
1939 stream->upload_mem = NULL;
1940 stream->upload_len = 0;
1941
1942 if(should_close_session(httpc)) {
1943 H2BUGF(infof(data, "http2_send: nothing to do in this session"));
1944 *err = CURLE_HTTP2;
1945 return -1;
1946 }
1947
1948 if(stream->upload_left) {
1949 /* we are sure that we have more data to send here. Calling the
1950 following API will make nghttp2_session_want_write() return
1951 nonzero if remote window allows it, which then libcurl checks
1952 socket is writable or not. See http2_perform_getsock(). */
1953 nghttp2_session_resume_data(h2, stream->stream_id);
1954 }
1955
1956 H2BUGF(infof(data, "http2_send returns %zu for stream %u", len,
1957 stream->stream_id));
1958 return len;
1959 }
1960
1961 /* Calculate number of headers contained in [mem, mem + len) */
1962 /* Here, we assume the curl http code generate *correct* HTTP header
1963 field block */
1964 nheader = 0;
1965 for(i = 1; i < len; ++i) {
1966 if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
1967 ++nheader;
1968 ++i;
1969 }
1970 }
1971 if(nheader < 2)
1972 goto fail;
1973
1974 /* We counted additional 2 \r\n in the first and last line. We need 3
1975 new headers: :method, :path and :scheme. Therefore we need one
1976 more space. */
1977 nheader += 1;
1978 nva = malloc(sizeof(nghttp2_nv) * nheader);
1979 if(!nva) {
1980 *err = CURLE_OUT_OF_MEMORY;
1981 return -1;
1982 }
1983
1984 /* Extract :method, :path from request line
1985 We do line endings with CRLF so checking for CR is enough */
1986 line_end = memchr(hdbuf, '\r', len);
1987 if(!line_end)
1988 goto fail;
1989
1990 /* Method does not contain spaces */
1991 end = memchr(hdbuf, ' ', line_end - hdbuf);
1992 if(!end || end == hdbuf)
1993 goto fail;
1994 nva[0].name = (unsigned char *)":method";
1995 nva[0].namelen = strlen((char *)nva[0].name);
1996 nva[0].value = (unsigned char *)hdbuf;
1997 nva[0].valuelen = (size_t)(end - hdbuf);
1998 nva[0].flags = NGHTTP2_NV_FLAG_NONE;
1999 if(HEADER_OVERFLOW(nva[0])) {
2000 failf(data, "Failed sending HTTP request: Header overflow");
2001 goto fail;
2002 }
2003
2004 hdbuf = end + 1;
2005
2006 /* Path may contain spaces so scan backwards */
2007 end = NULL;
2008 for(i = (size_t)(line_end - hdbuf); i; --i) {
2009 if(hdbuf[i - 1] == ' ') {
2010 end = &hdbuf[i - 1];
2011 break;
2012 }
2013 }
2014 if(!end || end == hdbuf)
2015 goto fail;
2016 nva[1].name = (unsigned char *)":path";
2017 nva[1].namelen = strlen((char *)nva[1].name);
2018 nva[1].value = (unsigned char *)hdbuf;
2019 nva[1].valuelen = (size_t)(end - hdbuf);
2020 nva[1].flags = NGHTTP2_NV_FLAG_NONE;
2021 if(HEADER_OVERFLOW(nva[1])) {
2022 failf(data, "Failed sending HTTP request: Header overflow");
2023 goto fail;
2024 }
2025
2026 nva[2].name = (unsigned char *)":scheme";
2027 nva[2].namelen = strlen((char *)nva[2].name);
2028 if(conn->handler->flags & PROTOPT_SSL)
2029 nva[2].value = (unsigned char *)"https";
2030 else
2031 nva[2].value = (unsigned char *)"http";
2032 nva[2].valuelen = strlen((char *)nva[2].value);
2033 nva[2].flags = NGHTTP2_NV_FLAG_NONE;
2034 if(HEADER_OVERFLOW(nva[2])) {
2035 failf(data, "Failed sending HTTP request: Header overflow");
2036 goto fail;
2037 }
2038
2039 authority_idx = 0;
2040 i = 3;
2041 while(i < nheader) {
2042 size_t hlen;
2043
2044 hdbuf = line_end + 2;
2045
2046 /* check for next CR, but only within the piece of data left in the given
2047 buffer */
2048 line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
2049 if(!line_end || (line_end == hdbuf))
2050 goto fail;
2051
2052 /* header continuation lines are not supported */
2053 if(*hdbuf == ' ' || *hdbuf == '\t')
2054 goto fail;
2055
2056 for(end = hdbuf; end < line_end && *end != ':'; ++end)
2057 ;
2058 if(end == hdbuf || end == line_end)
2059 goto fail;
2060 hlen = end - hdbuf;
2061
2062 if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
2063 authority_idx = i;
2064 nva[i].name = (unsigned char *)":authority";
2065 nva[i].namelen = strlen((char *)nva[i].name);
2066 }
2067 else {
2068 nva[i].namelen = (size_t)(end - hdbuf);
2069 /* Lower case the header name for HTTP/2 */
2070 Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen);
2071 nva[i].name = (unsigned char *)hdbuf;
2072 }
2073 hdbuf = end + 1;
2074 while(*hdbuf == ' ' || *hdbuf == '\t')
2075 ++hdbuf;
2076 end = line_end;
2077
2078 switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
2079 end - hdbuf)) {
2080 case HEADERINST_IGNORE:
2081 /* skip header fields prohibited by HTTP/2 specification. */
2082 --nheader;
2083 continue;
2084 case HEADERINST_TE_TRAILERS:
2085 nva[i].value = (uint8_t*)"trailers";
2086 nva[i].valuelen = sizeof("trailers") - 1;
2087 break;
2088 default:
2089 nva[i].value = (unsigned char *)hdbuf;
2090 nva[i].valuelen = (size_t)(end - hdbuf);
2091 }
2092
2093 nva[i].flags = NGHTTP2_NV_FLAG_NONE;
2094 if(HEADER_OVERFLOW(nva[i])) {
2095 failf(data, "Failed sending HTTP request: Header overflow");
2096 goto fail;
2097 }
2098 ++i;
2099 }
2100
2101 /* :authority must come before non-pseudo header fields */
2102 if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
2103 nghttp2_nv authority = nva[authority_idx];
2104 for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
2105 nva[i] = nva[i - 1];
2106 }
2107 nva[i] = authority;
2108 }
2109
2110 /* Warn stream may be rejected if cumulative length of headers is too large.
2111 It appears nghttp2 will not send a header frame larger than 64KB. */
2112#define MAX_ACC 60000 /* <64KB to account for some overhead */
2113 {
2114 size_t acc = 0;
2115
2116 for(i = 0; i < nheader; ++i) {
2117 acc += nva[i].namelen + nva[i].valuelen;
2118
2119 H2BUGF(infof(data, "h2 header: %.*s:%.*s",
2120 nva[i].namelen, nva[i].name,
2121 nva[i].valuelen, nva[i].value));
2122 }
2123
2124 if(acc > MAX_ACC) {
2125 infof(data, "http2_send: Warning: The cumulative length of all "
2126 "headers exceeds %d bytes and that could cause the "
2127 "stream to be rejected.", MAX_ACC);
2128 }
2129 }
2130
2131 h2_pri_spec(data, &pri_spec);
2132
2133 H2BUGF(infof(data, "http2_send request allowed %d (easy handle %p)",
2134 nghttp2_session_check_request_allowed(h2), (void *)data));
2135
2136 switch(data->state.httpreq) {
2137 case HTTPREQ_POST:
2138 case HTTPREQ_POST_FORM:
2139 case HTTPREQ_POST_MIME:
2140 case HTTPREQ_PUT:
2141 if(data->state.infilesize != -1)
2142 stream->upload_left = data->state.infilesize;
2143 else
2144 /* data sending without specifying the data amount up front */
2145 stream->upload_left = -1; /* unknown, but not zero */
2146
2147 data_prd.read_callback = data_source_read_callback;
2148 data_prd.source.ptr = NULL;
2149 stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
2150 &data_prd, data);
2151 break;
2152 default:
2153 stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
2154 NULL, data);
2155 }
2156
2157 Curl_safefree(nva);
2158
2159 if(stream_id < 0) {
2160 H2BUGF(infof(data,
2161 "http2_send() nghttp2_submit_request error (%s)%d",
2162 nghttp2_strerror(stream_id), stream_id));
2163 *err = CURLE_SEND_ERROR;
2164 return -1;
2165 }
2166
2167 infof(data, "Using Stream ID: %x (easy handle %p)",
2168 stream_id, (void *)data);
2169 stream->stream_id = stream_id;
2170
2171 rv = h2_session_send(data, h2);
2172 if(rv) {
2173 H2BUGF(infof(data,
2174 "http2_send() nghttp2_session_send error (%s)%d",
2175 nghttp2_strerror(rv), rv));
2176
2177 *err = CURLE_SEND_ERROR;
2178 return -1;
2179 }
2180
2181 if(should_close_session(httpc)) {
2182 H2BUGF(infof(data, "http2_send: nothing to do in this session"));
2183 *err = CURLE_HTTP2;
2184 return -1;
2185 }
2186
2187 /* If whole HEADERS frame was sent off to the underlying socket, the nghttp2
2188 library calls data_source_read_callback. But only it found that no data
2189 available, so it deferred the DATA transmission. Which means that
2190 nghttp2_session_want_write() returns 0 on http2_perform_getsock(), which
2191 results that no writable socket check is performed. To workaround this,
2192 we issue nghttp2_session_resume_data() here to bring back DATA
2193 transmission from deferred state. */
2194 nghttp2_session_resume_data(h2, stream->stream_id);
2195
2196 return len;
2197
2198fail:
2199 free(nva);
2200 *err = CURLE_SEND_ERROR;
2201 return -1;
2202}
2203
2204CURLcode Curl_http2_setup(struct Curl_easy *data,
2205 struct connectdata *conn)
2206{
2207 CURLcode result;
2208 struct http_conn *httpc = &conn->proto.httpc;
2209 struct HTTP *stream = data->req.p.http;
2210
2211 DEBUGASSERT(data->state.buffer);
2212
2213 stream->stream_id = -1;
2214
2215 Curl_dyn_init(&stream->header_recvbuf, DYN_H2_HEADERS);
2216 Curl_dyn_init(&stream->trailer_recvbuf, DYN_H2_TRAILERS);
2217
2218 stream->upload_left = 0;
2219 stream->upload_mem = NULL;
2220 stream->upload_len = 0;
2221 stream->mem = data->state.buffer;
2222 stream->len = data->set.buffer_size;
2223
2224 multi_connchanged(data->multi);
2225 /* below this point only connection related inits are done, which only needs
2226 to be done once per connection */
2227
2228 if((conn->handler == &Curl_handler_http2_ssl) ||
2229 (conn->handler == &Curl_handler_http2))
2230 return CURLE_OK; /* already done */
2231
2232 if(conn->handler->flags & PROTOPT_SSL)
2233 conn->handler = &Curl_handler_http2_ssl;
2234 else
2235 conn->handler = &Curl_handler_http2;
2236
2237 result = http2_init(data, conn);
2238 if(result) {
2239 Curl_dyn_free(&stream->header_recvbuf);
2240 return result;
2241 }
2242
2243 infof(data, "Using HTTP2, server supports multiplexing");
2244
2245 conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
2246 conn->httpversion = 20;
2247 conn->bundle->multiuse = BUNDLE_MULTIPLEX;
2248
2249 httpc->inbuflen = 0;
2250 httpc->nread_inbuf = 0;
2251
2252 httpc->pause_stream_id = 0;
2253 httpc->drain_total = 0;
2254
2255 infof(data, "Connection state changed (HTTP/2 confirmed)");
2256
2257 return CURLE_OK;
2258}
2259
2260CURLcode Curl_http2_switched(struct Curl_easy *data,
2261 const char *mem, size_t nread)
2262{
2263 CURLcode result;
2264 struct connectdata *conn = data->conn;
2265 struct http_conn *httpc = &conn->proto.httpc;
2266 int rv;
2267 struct HTTP *stream = data->req.p.http;
2268
2269 result = Curl_http2_setup(data, conn);
2270 if(result)
2271 return result;
2272
2273 httpc->recv_underlying = conn->recv[FIRSTSOCKET];
2274 httpc->send_underlying = conn->send[FIRSTSOCKET];
2275 conn->recv[FIRSTSOCKET] = http2_recv;
2276 conn->send[FIRSTSOCKET] = http2_send;
2277
2278 if(data->req.upgr101 == UPGR101_RECEIVED) {
2279 /* stream 1 is opened implicitly on upgrade */
2280 stream->stream_id = 1;
2281 /* queue SETTINGS frame (again) */
2282 rv = nghttp2_session_upgrade2(httpc->h2, httpc->binsettings, httpc->binlen,
2283 data->state.httpreq == HTTPREQ_HEAD, NULL);
2284 if(rv) {
2285 failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
2286 nghttp2_strerror(rv), rv);
2287 return CURLE_HTTP2;
2288 }
2289
2290 rv = nghttp2_session_set_stream_user_data(httpc->h2,
2291 stream->stream_id,
2292 data);
2293 if(rv) {
2294 infof(data, "http/2: failed to set user_data for stream %d!",
2295 stream->stream_id);
2296 DEBUGASSERT(0);
2297 }
2298 }
2299 else {
2300 populate_settings(data, httpc);
2301
2302 /* stream ID is unknown at this point */
2303 stream->stream_id = -1;
2304 rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE,
2305 httpc->local_settings,
2306 httpc->local_settings_num);
2307 if(rv) {
2308 failf(data, "nghttp2_submit_settings() failed: %s(%d)",
2309 nghttp2_strerror(rv), rv);
2310 return CURLE_HTTP2;
2311 }
2312 }
2313
2314 rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0,
2315 HTTP2_HUGE_WINDOW_SIZE);
2316 if(rv) {
2317 failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
2318 nghttp2_strerror(rv), rv);
2319 return CURLE_HTTP2;
2320 }
2321
2322 /* we are going to copy mem to httpc->inbuf. This is required since
2323 mem is part of buffer pointed by stream->mem, and callbacks
2324 called by nghttp2_session_mem_recv() will write stream specific
2325 data into stream->mem, overwriting data already there. */
2326 if(H2_BUFSIZE < nread) {
2327 failf(data, "connection buffer size is too small to store data following "
2328 "HTTP Upgrade response header: buflen=%d, datalen=%zu",
2329 H2_BUFSIZE, nread);
2330 return CURLE_HTTP2;
2331 }
2332
2333 infof(data, "Copying HTTP/2 data in stream buffer to connection buffer"
2334 " after upgrade: len=%zu",
2335 nread);
2336
2337 if(nread)
2338 memcpy(httpc->inbuf, mem, nread);
2339
2340 httpc->inbuflen = nread;
2341
2342 DEBUGASSERT(httpc->nread_inbuf == 0);
2343
2344 if(-1 == h2_process_pending_input(data, httpc, &result))
2345 return CURLE_HTTP2;
2346
2347 return CURLE_OK;
2348}
2349
2350CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
2351{
2352 DEBUGASSERT(data);
2353 DEBUGASSERT(data->conn);
2354 /* if it isn't HTTP/2, we're done */
2355 if(!(data->conn->handler->protocol & PROTO_FAMILY_HTTP) ||
2356 !data->conn->proto.httpc.h2)
2357 return CURLE_OK;
2358#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
2359 else {
2360 struct HTTP *stream = data->req.p.http;
2361 struct http_conn *httpc = &data->conn->proto.httpc;
2362 uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE;
2363 int rv = nghttp2_session_set_local_window_size(httpc->h2,
2364 NGHTTP2_FLAG_NONE,
2365 stream->stream_id,
2366 window);
2367 if(rv) {
2368 failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
2369 nghttp2_strerror(rv), rv);
2370 return CURLE_HTTP2;
2371 }
2372
2373 /* make sure the window update gets sent */
2374 rv = h2_session_send(data, httpc->h2);
2375 if(rv)
2376 return CURLE_SEND_ERROR;
2377
2378 DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u",
2379 window, stream->stream_id));
2380
2381#ifdef DEBUGBUILD
2382 {
2383 /* read out the stream local window again */
2384 uint32_t window2 =
2385 nghttp2_session_get_stream_local_window_size(httpc->h2,
2386 stream->stream_id);
2387 DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u",
2388 window2, stream->stream_id));
2389 }
2390#endif
2391 }
2392#endif
2393 return CURLE_OK;
2394}
2395
2396CURLcode Curl_http2_add_child(struct Curl_easy *parent,
2397 struct Curl_easy *child,
2398 bool exclusive)
2399{
2400 if(parent) {
2401 struct Curl_http2_dep **tail;
2402 struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep));
2403 if(!dep)
2404 return CURLE_OUT_OF_MEMORY;
2405 dep->data = child;
2406
2407 if(parent->set.stream_dependents && exclusive) {
2408 struct Curl_http2_dep *node = parent->set.stream_dependents;
2409 while(node) {
2410 node->data->set.stream_depends_on = child;
2411 node = node->next;
2412 }
2413
2414 tail = &child->set.stream_dependents;
2415 while(*tail)
2416 tail = &(*tail)->next;
2417
2418 DEBUGASSERT(!*tail);
2419 *tail = parent->set.stream_dependents;
2420 parent->set.stream_dependents = 0;
2421 }
2422
2423 tail = &parent->set.stream_dependents;
2424 while(*tail) {
2425 (*tail)->data->set.stream_depends_e = FALSE;
2426 tail = &(*tail)->next;
2427 }
2428
2429 DEBUGASSERT(!*tail);
2430 *tail = dep;
2431 }
2432
2433 child->set.stream_depends_on = parent;
2434 child->set.stream_depends_e = exclusive;
2435 return CURLE_OK;
2436}
2437
2438void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child)
2439{
2440 struct Curl_http2_dep *last = 0;
2441 struct Curl_http2_dep *data = parent->set.stream_dependents;
2442 DEBUGASSERT(child->set.stream_depends_on == parent);
2443
2444 while(data && data->data != child) {
2445 last = data;
2446 data = data->next;
2447 }
2448
2449 DEBUGASSERT(data);
2450
2451 if(data) {
2452 if(last) {
2453 last->next = data->next;
2454 }
2455 else {
2456 parent->set.stream_dependents = data->next;
2457 }
2458 free(data);
2459 }
2460
2461 child->set.stream_depends_on = 0;
2462 child->set.stream_depends_e = FALSE;
2463}
2464
2465void Curl_http2_cleanup_dependencies(struct Curl_easy *data)
2466{
2467 while(data->set.stream_dependents) {
2468 struct Curl_easy *tmp = data->set.stream_dependents->data;
2469 Curl_http2_remove_child(data, tmp);
2470 if(data->set.stream_depends_on)
2471 Curl_http2_add_child(data->set.stream_depends_on, tmp, FALSE);
2472 }
2473
2474 if(data->set.stream_depends_on)
2475 Curl_http2_remove_child(data->set.stream_depends_on, data);
2476}
2477
2478/* Only call this function for a transfer that already got a HTTP/2
2479 CURLE_HTTP2_STREAM error! */
2480bool Curl_h2_http_1_1_error(struct Curl_easy *data)
2481{
2482 struct HTTP *stream = data->req.p.http;
2483 return (stream->error == NGHTTP2_HTTP_1_1_REQUIRED);
2484}
2485
2486#else /* !USE_NGHTTP2 */
2487
2488/* Satisfy external references even if http2 is not compiled in. */
2489#include <curl/curl.h>
2490
2491char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
2492{
2493 (void) h;
2494 (void) num;
2495 return NULL;
2496}
2497
2498char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
2499{
2500 (void) h;
2501 (void) header;
2502 return NULL;
2503}
2504
2505#endif /* USE_NGHTTP2 */
2506