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