blob: da001dfd09effdc598ff3680b980574178bedeb0 [file] [log] [blame]
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Elliott Hughescac39802018-04-27 16:19:43 -07008 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07009 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
Alex Deymod15eaac2016-06-28 14:49:26 -070012 * are also available at https://curl.haxx.se/docs/copyright.html.
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070013 *
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
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070026#include <nghttp2/nghttp2.h>
27#include "urldata.h"
28#include "http2.h"
29#include "http.h"
30#include "sendf.h"
Elliott Hughes82be86d2017-09-20 17:00:17 -070031#include "select.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070032#include "curl_base64.h"
Elliott Hughescee03382017-06-23 12:17:18 -070033#include "strcase.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070034#include "multiif.h"
Alex Deymod15eaac2016-06-28 14:49:26 -070035#include "url.h"
36#include "connect.h"
37#include "strtoofft.h"
Elliott Hughescee03382017-06-23 12:17:18 -070038#include "strdup.h"
Alex Deymod15eaac2016-06-28 14:49:26 -070039/* The last 3 #include files should be in this order */
40#include "curl_printf.h"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070041#include "curl_memory.h"
42#include "memdebug.h"
43
Elliott Hughes1ef06ba2018-05-30 15:43:58 -070044#define H2_BUFSIZE 32768
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070045#define MIN(x,y) ((x)<(y)?(x):(y))
46
Alex Deymod15eaac2016-06-28 14:49:26 -070047#if (NGHTTP2_VERSION_NUM < 0x010000)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -070048#error too old nghttp2 version, upgrade!
49#endif
50
Alex Deymod15eaac2016-06-28 14:49:26 -070051#if (NGHTTP2_VERSION_NUM > 0x010800)
52#define NGHTTP2_HAS_HTTP2_STRERROR 1
53#endif
54
55#if (NGHTTP2_VERSION_NUM >= 0x010900)
56/* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or
57 later */
58#define NGHTTP2_HAS_ERROR_CALLBACK 1
59#else
60#define nghttp2_session_callbacks_set_error_callback(x,y)
61#endif
62
Elliott Hughes82be86d2017-09-20 17:00:17 -070063#if (NGHTTP2_VERSION_NUM >= 0x010c00)
64#define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1
65#endif
66
Elliott Hughescee03382017-06-23 12:17:18 -070067#define HTTP2_HUGE_WINDOW_SIZE (1 << 30)
68
Elliott Hughescac39802018-04-27 16:19:43 -070069#ifdef DEBUG_HTTP2
70#define H2BUGF(x) x
71#else
72#define H2BUGF(x) do { } WHILE_FALSE
73#endif
74
Elliott Hughes1ef06ba2018-05-30 15:43:58 -070075
76static ssize_t http2_recv(struct connectdata *conn, int sockindex,
77 char *mem, size_t len, CURLcode *err);
78static bool http2_connisdead(struct connectdata *conn);
79static int h2_session_send(struct Curl_easy *data,
80 nghttp2_session *h2);
81static int h2_process_pending_input(struct connectdata *conn,
82 struct http_conn *httpc,
83 CURLcode *err);
84
Alex Deymod15eaac2016-06-28 14:49:26 -070085/*
86 * Curl_http2_init_state() is called when the easy handle is created and
87 * allows for HTTP/2 specific init of state.
88 */
89void Curl_http2_init_state(struct UrlState *state)
90{
91 state->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
92}
93
94/*
95 * Curl_http2_init_userset() is called when the easy handle is created and
96 * allows for HTTP/2 specific user-set fields.
97 */
98void Curl_http2_init_userset(struct UserDefined *set)
99{
100 set->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
101}
102
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700103static int http2_perform_getsock(const struct connectdata *conn,
104 curl_socket_t *sock, /* points to
105 numsocks
106 number of
107 sockets */
108 int numsocks)
109{
110 const struct http_conn *c = &conn->proto.httpc;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700111 struct SingleRequest *k = &conn->data->req;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700112 int bitmap = GETSOCK_BLANK;
113 (void)numsocks;
114
115 /* TODO We should check underlying socket state if it is SSL socket
116 because of renegotiation. */
117 sock[0] = conn->sock[FIRSTSOCKET];
118
Elliott Hughescee03382017-06-23 12:17:18 -0700119 /* in a HTTP/2 connection we can basically always get a frame so we should
120 always be ready for one */
121 bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700122
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700123 /* we're still uploading or the HTTP/2 layer wants to send data */
124 if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
125 nghttp2_session_want_write(c->h2))
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700126 bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
127
128 return bitmap;
129}
130
131static int http2_getsock(struct connectdata *conn,
132 curl_socket_t *sock, /* points to numsocks
133 number of sockets */
134 int numsocks)
135{
136 return http2_perform_getsock(conn, sock, numsocks);
137}
138
Elliott Hughes82be86d2017-09-20 17:00:17 -0700139/*
140 * http2_stream_free() free HTTP2 stream related data
141 */
142static void http2_stream_free(struct HTTP *http)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700143{
Alex Deymod15eaac2016-06-28 14:49:26 -0700144 if(http) {
145 Curl_add_buffer_free(http->header_recvbuf);
146 http->header_recvbuf = NULL; /* clear the pointer */
147 Curl_add_buffer_free(http->trailer_recvbuf);
148 http->trailer_recvbuf = NULL; /* clear the pointer */
149 for(; http->push_headers_used > 0; --http->push_headers_used) {
150 free(http->push_headers[http->push_headers_used - 1]);
151 }
152 free(http->push_headers);
153 http->push_headers = NULL;
154 }
Elliott Hughes82be86d2017-09-20 17:00:17 -0700155}
156
157static CURLcode http2_disconnect(struct connectdata *conn,
158 bool dead_connection)
159{
160 struct http_conn *c = &conn->proto.httpc;
161 (void)dead_connection;
162
Elliott Hughescac39802018-04-27 16:19:43 -0700163 H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n"));
Elliott Hughes82be86d2017-09-20 17:00:17 -0700164
165 nghttp2_session_del(c->h2);
166 Curl_safefree(c->inbuf);
167 http2_stream_free(conn->data->req.protop);
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700168 conn->data->state.drain = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700169
Elliott Hughescac39802018-04-27 16:19:43 -0700170 H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700171
172 return CURLE_OK;
173}
174
Elliott Hughes82be86d2017-09-20 17:00:17 -0700175/*
176 * The server may send us data at any point (e.g. PING frames). Therefore,
177 * we cannot assume that an HTTP/2 socket is dead just because it is readable.
178 *
179 * Instead, if it is readable, run Curl_connalive() to peek at the socket
180 * and distinguish between closed and data.
181 */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700182static bool http2_connisdead(struct connectdata *conn)
Elliott Hughes82be86d2017-09-20 17:00:17 -0700183{
184 int sval;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700185 bool dead = TRUE;
Elliott Hughes82be86d2017-09-20 17:00:17 -0700186
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700187 if(conn->bits.close)
188 return TRUE;
189
190 sval = SOCKET_READABLE(conn->sock[FIRSTSOCKET], 0);
Elliott Hughes82be86d2017-09-20 17:00:17 -0700191 if(sval == 0) {
192 /* timeout */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700193 dead = FALSE;
Elliott Hughes82be86d2017-09-20 17:00:17 -0700194 }
195 else if(sval & CURL_CSELECT_ERR) {
196 /* socket is in an error state */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700197 dead = TRUE;
Elliott Hughes82be86d2017-09-20 17:00:17 -0700198 }
199 else if(sval & CURL_CSELECT_IN) {
200 /* readable with no error. could still be closed */
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700201 dead = !Curl_connalive(conn);
202 if(!dead) {
203 /* This happens before we've sent off a request and the connection is
204 not in use by any other thransfer, there shouldn't be any data here,
205 only "protocol frames" */
206 CURLcode result;
207 struct http_conn *httpc = &conn->proto.httpc;
208 ssize_t nread = -1;
209 if(httpc->recv_underlying)
210 /* if called "too early", this pointer isn't setup yet! */
211 nread = ((Curl_recv *)httpc->recv_underlying)(
212 conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
213 if(nread != -1) {
214 infof(conn->data,
215 "%d bytes stray data read before trying h2 connection\n",
216 (int)nread);
217 httpc->nread_inbuf = 0;
218 httpc->inbuflen = nread;
219 (void)h2_process_pending_input(conn, httpc, &result);
220 }
221 else
222 /* the read failed so let's say this is dead anyway */
223 dead = TRUE;
224 }
Elliott Hughes82be86d2017-09-20 17:00:17 -0700225 }
226
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700227 return dead;
Elliott Hughes82be86d2017-09-20 17:00:17 -0700228}
229
Elliott Hughes82be86d2017-09-20 17:00:17 -0700230static unsigned int http2_conncheck(struct connectdata *check,
231 unsigned int checks_to_perform)
232{
233 unsigned int ret_val = CONNRESULT_NONE;
234
235 if(checks_to_perform & CONNCHECK_ISDEAD) {
236 if(http2_connisdead(check))
237 ret_val |= CONNRESULT_DEAD;
238 }
239
240 return ret_val;
241}
242
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700243/* called from Curl_http_setup_conn */
Alex Deymoe3149cc2016-10-05 11:18:42 -0700244void Curl_http2_setup_req(struct Curl_easy *data)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700245{
Alex Deymod15eaac2016-06-28 14:49:26 -0700246 struct HTTP *http = data->req.protop;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700247
248 http->nread_header_recvbuf = 0;
249 http->bodystarted = FALSE;
250 http->status_code = -1;
251 http->pausedata = NULL;
252 http->pauselen = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700253 http->closed = FALSE;
Elliott Hughescee03382017-06-23 12:17:18 -0700254 http->close_handled = FALSE;
Alex Deymod15eaac2016-06-28 14:49:26 -0700255 http->mem = data->state.buffer;
Elliott Hughes82be86d2017-09-20 17:00:17 -0700256 http->len = data->set.buffer_size;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700257 http->memlen = 0;
258}
259
Alex Deymod15eaac2016-06-28 14:49:26 -0700260/* called from Curl_http_setup_conn */
261void Curl_http2_setup_conn(struct connectdata *conn)
262{
263 conn->proto.httpc.settings.max_concurrent_streams =
264 DEFAULT_MAX_CONCURRENT_STREAMS;
Elliott Hughescac39802018-04-27 16:19:43 -0700265 conn->proto.httpc.error_code = NGHTTP2_NO_ERROR;
Alex Deymod15eaac2016-06-28 14:49:26 -0700266}
267
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700268/*
269 * HTTP2 handler interface. This isn't added to the general list of protocols
270 * but will be used at run-time when the protocol is dynamically switched from
271 * HTTP to HTTP2.
272 */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700273static const struct Curl_handler Curl_handler_http2 = {
Alex Deymod15eaac2016-06-28 14:49:26 -0700274 "HTTP", /* scheme */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700275 ZERO_NULL, /* setup_connection */
276 Curl_http, /* do_it */
277 Curl_http_done, /* done */
278 ZERO_NULL, /* do_more */
279 ZERO_NULL, /* connect_it */
280 ZERO_NULL, /* connecting */
281 ZERO_NULL, /* doing */
282 http2_getsock, /* proto_getsock */
283 http2_getsock, /* doing_getsock */
284 ZERO_NULL, /* domore_getsock */
285 http2_perform_getsock, /* perform_getsock */
286 http2_disconnect, /* disconnect */
287 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700288 http2_conncheck, /* connection_check */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700289 PORT_HTTP, /* defport */
290 CURLPROTO_HTTP, /* protocol */
Elliott Hughescee03382017-06-23 12:17:18 -0700291 PROTOPT_STREAM /* flags */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700292};
293
Elliott Hughes82be86d2017-09-20 17:00:17 -0700294static const struct Curl_handler Curl_handler_http2_ssl = {
Alex Deymod15eaac2016-06-28 14:49:26 -0700295 "HTTPS", /* scheme */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700296 ZERO_NULL, /* setup_connection */
297 Curl_http, /* do_it */
298 Curl_http_done, /* done */
299 ZERO_NULL, /* do_more */
300 ZERO_NULL, /* connect_it */
301 ZERO_NULL, /* connecting */
302 ZERO_NULL, /* doing */
303 http2_getsock, /* proto_getsock */
304 http2_getsock, /* doing_getsock */
305 ZERO_NULL, /* domore_getsock */
306 http2_perform_getsock, /* perform_getsock */
307 http2_disconnect, /* disconnect */
308 ZERO_NULL, /* readwrite */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700309 http2_conncheck, /* connection_check */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700310 PORT_HTTP, /* defport */
311 CURLPROTO_HTTPS, /* protocol */
Elliott Hughescee03382017-06-23 12:17:18 -0700312 PROTOPT_SSL | PROTOPT_STREAM /* flags */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700313};
314
315/*
316 * Store nghttp2 version info in this buffer, Prefix with a space. Return
317 * total length written.
318 */
319int Curl_http2_ver(char *p, size_t len)
320{
321 nghttp2_info *h2 = nghttp2_version(0);
322 return snprintf(p, len, " nghttp2/%s", h2->version_str);
323}
324
Alex Deymod15eaac2016-06-28 14:49:26 -0700325/* HTTP/2 error code to name based on the Error Code Registry.
326https://tools.ietf.org/html/rfc7540#page-77
327nghttp2_error_code enums are identical.
328*/
Elliott Hughescee03382017-06-23 12:17:18 -0700329const char *Curl_http2_strerror(uint32_t err)
330{
Alex Deymod15eaac2016-06-28 14:49:26 -0700331#ifndef NGHTTP2_HAS_HTTP2_STRERROR
332 const char *str[] = {
333 "NO_ERROR", /* 0x0 */
334 "PROTOCOL_ERROR", /* 0x1 */
335 "INTERNAL_ERROR", /* 0x2 */
336 "FLOW_CONTROL_ERROR", /* 0x3 */
337 "SETTINGS_TIMEOUT", /* 0x4 */
338 "STREAM_CLOSED", /* 0x5 */
339 "FRAME_SIZE_ERROR", /* 0x6 */
340 "REFUSED_STREAM", /* 0x7 */
341 "CANCEL", /* 0x8 */
342 "COMPRESSION_ERROR", /* 0x9 */
343 "CONNECT_ERROR", /* 0xA */
344 "ENHANCE_YOUR_CALM", /* 0xB */
345 "INADEQUATE_SECURITY", /* 0xC */
346 "HTTP_1_1_REQUIRED" /* 0xD */
347 };
348 return (err < sizeof str / sizeof str[0]) ? str[err] : "unknown";
349#else
350 return nghttp2_http2_strerror(err);
351#endif
352}
353
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700354/*
355 * The implementation of nghttp2_send_callback type. Here we write |data| with
356 * size |length| to the network and return the number of bytes actually
357 * written. See the documentation of nghttp2_send_callback for the details.
358 */
359static ssize_t send_callback(nghttp2_session *h2,
360 const uint8_t *data, size_t length, int flags,
361 void *userp)
362{
363 struct connectdata *conn = (struct connectdata *)userp;
364 struct http_conn *c = &conn->proto.httpc;
365 ssize_t written;
366 CURLcode result = CURLE_OK;
367
368 (void)h2;
369 (void)flags;
370
371 written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET,
372 data, length, &result);
373
374 if(result == CURLE_AGAIN) {
375 return NGHTTP2_ERR_WOULDBLOCK;
376 }
377
378 if(written == -1) {
379 failf(conn->data, "Failed sending HTTP2 data");
380 return NGHTTP2_ERR_CALLBACK_FAILURE;
381 }
382
383 if(!written)
384 return NGHTTP2_ERR_WOULDBLOCK;
385
386 return written;
387}
388
Alex Deymod15eaac2016-06-28 14:49:26 -0700389
390/* We pass a pointer to this struct in the push callback, but the contents of
391 the struct are hidden from the user. */
392struct curl_pushheaders {
Alex Deymoe3149cc2016-10-05 11:18:42 -0700393 struct Curl_easy *data;
Alex Deymod15eaac2016-06-28 14:49:26 -0700394 const nghttp2_push_promise *frame;
395};
396
397/*
398 * push header access function. Only to be used from within the push callback
399 */
400char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
401{
402 /* Verify that we got a good easy handle in the push header struct, mostly to
403 detect rubbish input fast(er). */
404 if(!h || !GOOD_EASY_HANDLE(h->data))
405 return NULL;
406 else {
407 struct HTTP *stream = h->data->req.protop;
408 if(num < stream->push_headers_used)
409 return stream->push_headers[num];
410 }
411 return NULL;
412}
413
414/*
415 * push header access function. Only to be used from within the push callback
416 */
417char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
418{
419 /* Verify that we got a good easy handle in the push header struct,
420 mostly to detect rubbish input fast(er). Also empty header name
421 is just a rubbish too. We have to allow ":" at the beginning of
422 the header, but header == ":" must be rejected. If we have ':' in
423 the middle of header, it could be matched in middle of the value,
424 this is because we do prefix match.*/
425 if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] ||
Elliott Hughescee03382017-06-23 12:17:18 -0700426 !strcmp(header, ":") || strchr(header + 1, ':'))
Alex Deymod15eaac2016-06-28 14:49:26 -0700427 return NULL;
428 else {
429 struct HTTP *stream = h->data->req.protop;
430 size_t len = strlen(header);
431 size_t i;
Alex Deymo486467e2017-12-19 19:04:07 +0100432 for(i = 0; i<stream->push_headers_used; i++) {
Alex Deymod15eaac2016-06-28 14:49:26 -0700433 if(!strncmp(header, stream->push_headers[i], len)) {
434 /* sub-match, make sure that it is followed by a colon */
435 if(stream->push_headers[i][len] != ':')
436 continue;
Alex Deymo486467e2017-12-19 19:04:07 +0100437 return &stream->push_headers[i][len + 1];
Alex Deymod15eaac2016-06-28 14:49:26 -0700438 }
439 }
440 }
441 return NULL;
442}
443
Alex Deymoe3149cc2016-10-05 11:18:42 -0700444static struct Curl_easy *duphandle(struct Curl_easy *data)
Alex Deymod15eaac2016-06-28 14:49:26 -0700445{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700446 struct Curl_easy *second = curl_easy_duphandle(data);
Alex Deymod15eaac2016-06-28 14:49:26 -0700447 if(second) {
448 /* setup the request struct */
449 struct HTTP *http = calloc(1, sizeof(struct HTTP));
450 if(!http) {
451 (void)Curl_close(second);
452 second = NULL;
453 }
454 else {
455 second->req.protop = http;
456 http->header_recvbuf = Curl_add_buffer_init();
457 if(!http->header_recvbuf) {
458 free(http);
459 (void)Curl_close(second);
460 second = NULL;
461 }
462 else {
463 Curl_http2_setup_req(second);
464 second->state.stream_weight = data->state.stream_weight;
465 }
466 }
467 }
468 return second;
469}
470
471
Alex Deymoe3149cc2016-10-05 11:18:42 -0700472static int push_promise(struct Curl_easy *data,
Alex Deymod15eaac2016-06-28 14:49:26 -0700473 struct connectdata *conn,
474 const nghttp2_push_promise *frame)
475{
476 int rv;
Elliott Hughescac39802018-04-27 16:19:43 -0700477 H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
Alex Deymod15eaac2016-06-28 14:49:26 -0700478 frame->promised_stream_id));
479 if(data->multi->push_cb) {
480 struct HTTP *stream;
481 struct HTTP *newstream;
482 struct curl_pushheaders heads;
483 CURLMcode rc;
484 struct http_conn *httpc;
485 size_t i;
486 /* clone the parent */
Alex Deymoe3149cc2016-10-05 11:18:42 -0700487 struct Curl_easy *newhandle = duphandle(data);
Alex Deymod15eaac2016-06-28 14:49:26 -0700488 if(!newhandle) {
489 infof(data, "failed to duplicate handle\n");
490 rv = 1; /* FAIL HARD */
491 goto fail;
492 }
493
494 heads.data = data;
495 heads.frame = frame;
496 /* ask the application */
Elliott Hughescac39802018-04-27 16:19:43 -0700497 H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
Alex Deymod15eaac2016-06-28 14:49:26 -0700498
499 stream = data->req.protop;
500 if(!stream) {
501 failf(data, "Internal NULL stream!\n");
Elliott Hughes82be86d2017-09-20 17:00:17 -0700502 (void)Curl_close(newhandle);
Alex Deymod15eaac2016-06-28 14:49:26 -0700503 rv = 1;
504 goto fail;
505 }
506
Elliott Hughescac39802018-04-27 16:19:43 -0700507 Curl_set_in_callback(data, true);
Alex Deymod15eaac2016-06-28 14:49:26 -0700508 rv = data->multi->push_cb(data, newhandle,
509 stream->push_headers_used, &heads,
510 data->multi->push_userp);
Elliott Hughescac39802018-04-27 16:19:43 -0700511 Curl_set_in_callback(data, false);
Alex Deymod15eaac2016-06-28 14:49:26 -0700512
513 /* free the headers again */
Alex Deymo486467e2017-12-19 19:04:07 +0100514 for(i = 0; i<stream->push_headers_used; i++)
Alex Deymod15eaac2016-06-28 14:49:26 -0700515 free(stream->push_headers[i]);
516 free(stream->push_headers);
517 stream->push_headers = NULL;
Elliott Hughes82be86d2017-09-20 17:00:17 -0700518 stream->push_headers_used = 0;
Alex Deymod15eaac2016-06-28 14:49:26 -0700519
520 if(rv) {
521 /* denied, kill off the new handle again */
Elliott Hughes82be86d2017-09-20 17:00:17 -0700522 http2_stream_free(newhandle->req.protop);
Alex Deymod15eaac2016-06-28 14:49:26 -0700523 (void)Curl_close(newhandle);
524 goto fail;
525 }
526
527 newstream = newhandle->req.protop;
528 newstream->stream_id = frame->promised_stream_id;
529 newhandle->req.maxdownload = -1;
530 newhandle->req.size = -1;
531
532 /* approved, add to the multi handle and immediately switch to PERFORM
533 state with the given connection !*/
534 rc = Curl_multi_add_perform(data->multi, newhandle, conn);
535 if(rc) {
536 infof(data, "failed to add handle to multi\n");
Elliott Hughes82be86d2017-09-20 17:00:17 -0700537 http2_stream_free(newhandle->req.protop);
Alex Deymod15eaac2016-06-28 14:49:26 -0700538 Curl_close(newhandle);
539 rv = 1;
540 goto fail;
541 }
542
543 httpc = &conn->proto.httpc;
544 nghttp2_session_set_stream_user_data(httpc->h2,
545 frame->promised_stream_id, newhandle);
546 }
547 else {
Elliott Hughescac39802018-04-27 16:19:43 -0700548 H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
Alex Deymod15eaac2016-06-28 14:49:26 -0700549 rv = 1;
550 }
551 fail:
552 return rv;
553}
554
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700555static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
556 void *userp)
557{
558 struct connectdata *conn = (struct connectdata *)userp;
559 struct http_conn *httpc = &conn->proto.httpc;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700560 struct Curl_easy *data_s = NULL;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700561 struct HTTP *stream = NULL;
562 int rv;
563 size_t left, ncopy;
564 int32_t stream_id = frame->hd.stream_id;
565
Alex Deymod15eaac2016-06-28 14:49:26 -0700566 if(!stream_id) {
567 /* stream ID zero is for connection-oriented stuff */
568 if(frame->hd.type == NGHTTP2_SETTINGS) {
569 uint32_t max_conn = httpc->settings.max_concurrent_streams;
Elliott Hughescac39802018-04-27 16:19:43 -0700570 H2BUGF(infof(conn->data, "Got SETTINGS\n"));
Alex Deymod15eaac2016-06-28 14:49:26 -0700571 httpc->settings.max_concurrent_streams =
572 nghttp2_session_get_remote_settings(
573 session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
574 httpc->settings.enable_push =
575 nghttp2_session_get_remote_settings(
576 session, NGHTTP2_SETTINGS_ENABLE_PUSH);
Elliott Hughescac39802018-04-27 16:19:43 -0700577 H2BUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
Alex Deymod15eaac2016-06-28 14:49:26 -0700578 httpc->settings.max_concurrent_streams));
Elliott Hughescac39802018-04-27 16:19:43 -0700579 H2BUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
Alex Deymod15eaac2016-06-28 14:49:26 -0700580 httpc->settings.enable_push?"TRUE":"false"));
581 if(max_conn != httpc->settings.max_concurrent_streams) {
582 /* only signal change if the value actually changed */
583 infof(conn->data,
Elliott Hughescac39802018-04-27 16:19:43 -0700584 "Connection state changed (MAX_CONCURRENT_STREAMS == %d)!\n",
585 httpc->settings.max_concurrent_streams);
Alex Deymod15eaac2016-06-28 14:49:26 -0700586 Curl_multi_connchanged(conn->data->multi);
587 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700588 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700589 return 0;
Alex Deymod15eaac2016-06-28 14:49:26 -0700590 }
591 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
Alex Deymod15eaac2016-06-28 14:49:26 -0700592 if(!data_s) {
Elliott Hughescac39802018-04-27 16:19:43 -0700593 H2BUGF(infof(conn->data,
Alex Deymoe3149cc2016-10-05 11:18:42 -0700594 "No Curl_easy associated with stream: %x\n",
Alex Deymod15eaac2016-06-28 14:49:26 -0700595 stream_id));
596 return 0;
597 }
598
599 stream = data_s->req.protop;
Elliott Hughescee03382017-06-23 12:17:18 -0700600 if(!stream) {
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700601 H2BUGF(infof(data_s, "No proto pointer for stream: %x\n",
Elliott Hughescee03382017-06-23 12:17:18 -0700602 stream_id));
Alex Deymod15eaac2016-06-28 14:49:26 -0700603 return NGHTTP2_ERR_CALLBACK_FAILURE;
Elliott Hughescee03382017-06-23 12:17:18 -0700604 }
Alex Deymod15eaac2016-06-28 14:49:26 -0700605
Elliott Hughescac39802018-04-27 16:19:43 -0700606 H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
Alex Deymod15eaac2016-06-28 14:49:26 -0700607 frame->hd.type, stream_id));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700608
609 switch(frame->hd.type) {
610 case NGHTTP2_DATA:
611 /* If body started on this stream, then receiving DATA is illegal. */
612 if(!stream->bodystarted) {
613 rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
614 stream_id, NGHTTP2_PROTOCOL_ERROR);
615
616 if(nghttp2_is_fatal(rv)) {
617 return NGHTTP2_ERR_CALLBACK_FAILURE;
618 }
619 }
620 break;
621 case NGHTTP2_HEADERS:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700622 if(stream->bodystarted) {
623 /* Only valid HEADERS after body started is trailer HEADERS. We
Alex Deymod15eaac2016-06-28 14:49:26 -0700624 buffer them in on_header callback. */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700625 break;
626 }
627
628 /* nghttp2 guarantees that :status is received, and we store it to
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700629 stream->status_code. Fuzzing has proven this can still be reached
630 without status code having been set. */
631 if(stream->status_code == -1)
632 return NGHTTP2_ERR_CALLBACK_FAILURE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700633
634 /* Only final status code signals the end of header */
635 if(stream->status_code / 100 != 1) {
636 stream->bodystarted = TRUE;
637 stream->status_code = -1;
638 }
639
640 Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
641
642 left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
643 ncopy = MIN(stream->len, left);
644
645 memcpy(&stream->mem[stream->memlen],
646 stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
647 ncopy);
648 stream->nread_header_recvbuf += ncopy;
649
Elliott Hughescac39802018-04-27 16:19:43 -0700650 H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700651 ncopy, stream_id, stream->mem));
652
653 stream->len -= ncopy;
654 stream->memlen += ncopy;
655
656 data_s->state.drain++;
Alex Deymod15eaac2016-06-28 14:49:26 -0700657 httpc->drain_total++;
658 {
659 /* get the pointer from userp again since it was re-assigned above */
660 struct connectdata *conn_s = (struct connectdata *)userp;
661
662 /* if we receive data for another handle, wake that up */
663 if(conn_s->data != data_s)
Elliott Hughes82be86d2017-09-20 17:00:17 -0700664 Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
Alex Deymod15eaac2016-06-28 14:49:26 -0700665 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700666 break;
667 case NGHTTP2_PUSH_PROMISE:
Alex Deymod15eaac2016-06-28 14:49:26 -0700668 rv = push_promise(data_s, conn, &frame->push_promise);
669 if(rv) { /* deny! */
670 rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
671 frame->push_promise.promised_stream_id,
672 NGHTTP2_CANCEL);
673 if(nghttp2_is_fatal(rv)) {
674 return rv;
675 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700676 }
677 break;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700678 default:
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700679 H2BUGF(infof(data_s, "Got frame type %x for stream %u!\n",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700680 frame->hd.type, stream_id));
681 break;
682 }
683 return 0;
684}
685
686static int on_invalid_frame_recv(nghttp2_session *session,
687 const nghttp2_frame *frame,
688 int lib_error_code, void *userp)
689{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700690 struct Curl_easy *data_s = NULL;
Alex Deymod15eaac2016-06-28 14:49:26 -0700691 (void)userp;
Elliott Hughescac39802018-04-27 16:19:43 -0700692#if !defined(DEBUG_HTTP2) || defined(CURL_DISABLE_VERBOSE_STRINGS)
Elliott Hughes82be86d2017-09-20 17:00:17 -0700693 (void)lib_error_code;
694#endif
Alex Deymod15eaac2016-06-28 14:49:26 -0700695
696 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
697 if(data_s) {
Elliott Hughescac39802018-04-27 16:19:43 -0700698 H2BUGF(infof(data_s,
Alex Deymod15eaac2016-06-28 14:49:26 -0700699 "on_invalid_frame_recv() was called, error=%d:%s\n",
700 lib_error_code, nghttp2_strerror(lib_error_code)));
701 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700702 return 0;
703}
704
705static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
706 int32_t stream_id,
707 const uint8_t *data, size_t len, void *userp)
708{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700709 struct HTTP *stream;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700710 struct Curl_easy *data_s;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700711 size_t nread;
Alex Deymod15eaac2016-06-28 14:49:26 -0700712 struct connectdata *conn = (struct connectdata *)userp;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700713 (void)session;
714 (void)flags;
715 (void)data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700716
717 DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
718
719 /* get the stream from the hash based on Stream ID */
Alex Deymod15eaac2016-06-28 14:49:26 -0700720 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
721 if(!data_s)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700722 /* Receiving a Stream ID not in the hash should not happen, this is an
723 internal error more than anything else! */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700724 return NGHTTP2_ERR_CALLBACK_FAILURE;
Alex Deymod15eaac2016-06-28 14:49:26 -0700725
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700726 stream = data_s->req.protop;
Alex Deymod15eaac2016-06-28 14:49:26 -0700727 if(!stream)
728 return NGHTTP2_ERR_CALLBACK_FAILURE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700729
730 nread = MIN(stream->len, len);
731 memcpy(&stream->mem[stream->memlen], data, nread);
732
733 stream->len -= nread;
734 stream->memlen += nread;
735
736 data_s->state.drain++;
Alex Deymod15eaac2016-06-28 14:49:26 -0700737 conn->proto.httpc.drain_total++;
738
739 /* if we receive data for another handle, wake that up */
740 if(conn->data != data_s)
Elliott Hughes82be86d2017-09-20 17:00:17 -0700741 Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700742
Elliott Hughescac39802018-04-27 16:19:43 -0700743 H2BUGF(infof(data_s, "%zu data received for stream %u "
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700744 "(%zu left in buffer %p, total %zu)\n",
745 nread, stream_id,
746 stream->len, stream->mem,
747 stream->memlen));
748
749 if(nread < len) {
750 stream->pausedata = data + nread;
751 stream->pauselen = len - nread;
Elliott Hughescac39802018-04-27 16:19:43 -0700752 H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700753 ", stream %u\n",
754 len - nread, stream_id));
Alex Deymod15eaac2016-06-28 14:49:26 -0700755 data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
756
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700757 return NGHTTP2_ERR_PAUSE;
758 }
Alex Deymod15eaac2016-06-28 14:49:26 -0700759
760 /* pause execution of nghttp2 if we received data for another handle
761 in order to process them first. */
762 if(conn->data != data_s) {
763 data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
764
765 return NGHTTP2_ERR_PAUSE;
766 }
767
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700768 return 0;
769}
770
771static int before_frame_send(nghttp2_session *session,
772 const nghttp2_frame *frame,
773 void *userp)
774{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700775 struct Curl_easy *data_s;
Alex Deymod15eaac2016-06-28 14:49:26 -0700776 (void)userp;
777
778 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
779 if(data_s) {
Elliott Hughescac39802018-04-27 16:19:43 -0700780 H2BUGF(infof(data_s, "before_frame_send() was called\n"));
Alex Deymod15eaac2016-06-28 14:49:26 -0700781 }
782
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700783 return 0;
784}
785static int on_frame_send(nghttp2_session *session,
786 const nghttp2_frame *frame,
787 void *userp)
788{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700789 struct Curl_easy *data_s;
Alex Deymod15eaac2016-06-28 14:49:26 -0700790 (void)userp;
791
792 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
793 if(data_s) {
Elliott Hughescac39802018-04-27 16:19:43 -0700794 H2BUGF(infof(data_s, "on_frame_send() was called, length = %zd\n",
Alex Deymod15eaac2016-06-28 14:49:26 -0700795 frame->hd.length));
796 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700797 return 0;
798}
799static int on_frame_not_send(nghttp2_session *session,
800 const nghttp2_frame *frame,
801 int lib_error_code, void *userp)
802{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700803 struct Curl_easy *data_s;
Alex Deymod15eaac2016-06-28 14:49:26 -0700804 (void)userp;
Elliott Hughescac39802018-04-27 16:19:43 -0700805#if !defined(DEBUG_HTTP2) || defined(CURL_DISABLE_VERBOSE_STRINGS)
Elliott Hughes82be86d2017-09-20 17:00:17 -0700806 (void)lib_error_code;
807#endif
Alex Deymod15eaac2016-06-28 14:49:26 -0700808
809 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
810 if(data_s) {
Elliott Hughescac39802018-04-27 16:19:43 -0700811 H2BUGF(infof(data_s,
Alex Deymod15eaac2016-06-28 14:49:26 -0700812 "on_frame_not_send() was called, lib_error_code = %d\n",
813 lib_error_code));
814 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700815 return 0;
816}
817static int on_stream_close(nghttp2_session *session, int32_t stream_id,
818 uint32_t error_code, void *userp)
819{
Alex Deymoe3149cc2016-10-05 11:18:42 -0700820 struct Curl_easy *data_s;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700821 struct HTTP *stream;
Alex Deymod15eaac2016-06-28 14:49:26 -0700822 struct connectdata *conn = (struct connectdata *)userp;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700823 (void)session;
824 (void)stream_id;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700825
826 if(stream_id) {
Elliott Hughescac39802018-04-27 16:19:43 -0700827 struct http_conn *httpc;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700828 /* get the stream from the hash based on Stream ID, stream ID zero is for
829 connection-oriented stuff */
Alex Deymod15eaac2016-06-28 14:49:26 -0700830 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700831 if(!data_s) {
832 /* We could get stream ID not in the hash. For example, if we
Alex Deymod15eaac2016-06-28 14:49:26 -0700833 decided to reject stream (e.g., PUSH_PROMISE). */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700834 return 0;
835 }
Elliott Hughescac39802018-04-27 16:19:43 -0700836 H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
Alex Deymod15eaac2016-06-28 14:49:26 -0700837 Curl_http2_strerror(error_code), error_code, stream_id));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700838 stream = data_s->req.protop;
Alex Deymod15eaac2016-06-28 14:49:26 -0700839 if(!stream)
840 return NGHTTP2_ERR_CALLBACK_FAILURE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700841
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700842 stream->closed = TRUE;
Alex Deymod15eaac2016-06-28 14:49:26 -0700843 data_s->state.drain++;
Elliott Hughescac39802018-04-27 16:19:43 -0700844 httpc = &conn->proto.httpc;
845 httpc->drain_total++;
846 httpc->error_code = error_code;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700847
848 /* remove the entry from the hash as the stream is now gone */
Alex Deymod15eaac2016-06-28 14:49:26 -0700849 nghttp2_session_set_stream_user_data(session, stream_id, 0);
Elliott Hughescac39802018-04-27 16:19:43 -0700850 H2BUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700851 }
852 return 0;
853}
854
855static int on_begin_headers(nghttp2_session *session,
856 const nghttp2_frame *frame, void *userp)
857{
Alex Deymod15eaac2016-06-28 14:49:26 -0700858 struct HTTP *stream;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700859 struct Curl_easy *data_s = NULL;
Alex Deymod15eaac2016-06-28 14:49:26 -0700860 (void)userp;
861
862 data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
863 if(!data_s) {
864 return 0;
865 }
866
Elliott Hughescac39802018-04-27 16:19:43 -0700867 H2BUGF(infof(data_s, "on_begin_headers() was called\n"));
Alex Deymod15eaac2016-06-28 14:49:26 -0700868
869 if(frame->hd.type != NGHTTP2_HEADERS) {
870 return 0;
871 }
872
873 stream = data_s->req.protop;
874 if(!stream || !stream->bodystarted) {
875 return 0;
876 }
877
Alex Deymod15eaac2016-06-28 14:49:26 -0700878 if(!stream->trailer_recvbuf) {
Elliott Hughes1ef06ba2018-05-30 15:43:58 -0700879 stream->trailer_recvbuf = Curl_add_buffer_init();
880 if(!stream->trailer_recvbuf) {
881 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
882 }
Alex Deymod15eaac2016-06-28 14:49:26 -0700883 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700884 return 0;
885}
886
887/* Decode HTTP status code. Returns -1 if no valid status code was
888 decoded. */
889static int decode_status_code(const uint8_t *value, size_t len)
890{
891 int i;
892 int res;
893
894 if(len != 3) {
895 return -1;
896 }
897
898 res = 0;
899
900 for(i = 0; i < 3; ++i) {
901 char c = value[i];
902
903 if(c < '0' || c > '9') {
904 return -1;
905 }
906
907 res *= 10;
908 res += c - '0';
909 }
910
911 return res;
912}
913
914/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
915static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
916 const uint8_t *name, size_t namelen,
917 const uint8_t *value, size_t valuelen,
918 uint8_t flags,
919 void *userp)
920{
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700921 struct HTTP *stream;
Alex Deymoe3149cc2016-10-05 11:18:42 -0700922 struct Curl_easy *data_s;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700923 int32_t stream_id = frame->hd.stream_id;
Alex Deymod15eaac2016-06-28 14:49:26 -0700924 struct connectdata *conn = (struct connectdata *)userp;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700925 (void)flags;
926
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700927 DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
928
929 /* get the stream from the hash based on Stream ID */
Alex Deymod15eaac2016-06-28 14:49:26 -0700930 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
931 if(!data_s)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700932 /* Receiving a Stream ID not in the hash should not happen, this is an
933 internal error more than anything else! */
Alex Deymod15eaac2016-06-28 14:49:26 -0700934 return NGHTTP2_ERR_CALLBACK_FAILURE;
935
936 stream = data_s->req.protop;
937 if(!stream) {
938 failf(data_s, "Internal NULL stream! 5\n");
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700939 return NGHTTP2_ERR_CALLBACK_FAILURE;
940 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700941
Alex Deymod15eaac2016-06-28 14:49:26 -0700942 /* Store received PUSH_PROMISE headers to be used when the subsequent
943 PUSH_PROMISE callback comes */
944 if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
945 char *h;
946
947 if(!stream->push_headers) {
948 stream->push_headers_alloc = 10;
949 stream->push_headers = malloc(stream->push_headers_alloc *
950 sizeof(char *));
951 stream->push_headers_used = 0;
952 }
953 else if(stream->push_headers_used ==
954 stream->push_headers_alloc) {
955 char **headp;
956 stream->push_headers_alloc *= 2;
Elliott Hughescee03382017-06-23 12:17:18 -0700957 headp = Curl_saferealloc(stream->push_headers,
958 stream->push_headers_alloc * sizeof(char *));
Alex Deymod15eaac2016-06-28 14:49:26 -0700959 if(!headp) {
Alex Deymod15eaac2016-06-28 14:49:26 -0700960 stream->push_headers = NULL;
961 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
962 }
963 stream->push_headers = headp;
964 }
965 h = aprintf("%s:%s", name, value);
966 if(h)
967 stream->push_headers[stream->push_headers_used++] = h;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700968 return 0;
Alex Deymod15eaac2016-06-28 14:49:26 -0700969 }
970
971 if(stream->bodystarted) {
972 /* This is trailer fields. */
Elliott Hughes0128fe42018-02-27 14:57:55 -0800973 /* 4 is for ": " and "\r\n". */
974 uint32_t n = (uint32_t)(namelen + valuelen + 4);
Alex Deymod15eaac2016-06-28 14:49:26 -0700975
Elliott Hughescac39802018-04-27 16:19:43 -0700976 H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
Alex Deymod15eaac2016-06-28 14:49:26 -0700977 value));
978
979 Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n));
980 Curl_add_buffer(stream->trailer_recvbuf, name, namelen);
981 Curl_add_buffer(stream->trailer_recvbuf, ": ", 2);
982 Curl_add_buffer(stream->trailer_recvbuf, value, valuelen);
983 Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3);
984
985 return 0;
986 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700987
988 if(namelen == sizeof(":status") - 1 &&
989 memcmp(":status", name, namelen) == 0) {
990 /* nghttp2 guarantees :status is received first and only once, and
991 value is 3 digits status code, and decode_status_code always
992 succeeds. */
993 stream->status_code = decode_status_code(value, valuelen);
994 DEBUGASSERT(stream->status_code != -1);
995
Alex Deymod15eaac2016-06-28 14:49:26 -0700996 Curl_add_buffer(stream->header_recvbuf, "HTTP/2 ", 7);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -0700997 Curl_add_buffer(stream->header_recvbuf, value, valuelen);
Alex Deymod15eaac2016-06-28 14:49:26 -0700998 /* the space character after the status code is mandatory */
999 Curl_add_buffer(stream->header_recvbuf, " \r\n", 3);
1000 /* if we receive data for another handle, wake that up */
1001 if(conn->data != data_s)
Elliott Hughes82be86d2017-09-20 17:00:17 -07001002 Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001003
Elliott Hughescac39802018-04-27 16:19:43 -07001004 H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
Alex Deymod15eaac2016-06-28 14:49:26 -07001005 stream->status_code, data_s));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001006 return 0;
1007 }
1008
1009 /* nghttp2 guarantees that namelen > 0, and :status was already
1010 received, and this is not pseudo-header field . */
1011 /* convert to a HTTP1-style header */
1012 Curl_add_buffer(stream->header_recvbuf, name, namelen);
Alex Deymod15eaac2016-06-28 14:49:26 -07001013 Curl_add_buffer(stream->header_recvbuf, ": ", 2);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001014 Curl_add_buffer(stream->header_recvbuf, value, valuelen);
1015 Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
Alex Deymod15eaac2016-06-28 14:49:26 -07001016 /* if we receive data for another handle, wake that up */
1017 if(conn->data != data_s)
Elliott Hughes82be86d2017-09-20 17:00:17 -07001018 Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001019
Elliott Hughescac39802018-04-27 16:19:43 -07001020 H2BUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001021 value));
1022
1023 return 0; /* 0 is successful */
1024}
1025
1026static ssize_t data_source_read_callback(nghttp2_session *session,
1027 int32_t stream_id,
1028 uint8_t *buf, size_t length,
1029 uint32_t *data_flags,
1030 nghttp2_data_source *source,
1031 void *userp)
1032{
Alex Deymoe3149cc2016-10-05 11:18:42 -07001033 struct Curl_easy *data_s;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001034 struct HTTP *stream = NULL;
1035 size_t nread;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001036 (void)source;
Alex Deymod15eaac2016-06-28 14:49:26 -07001037 (void)userp;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001038
1039 if(stream_id) {
1040 /* get the stream from the hash based on Stream ID, stream ID zero is for
1041 connection-oriented stuff */
Alex Deymod15eaac2016-06-28 14:49:26 -07001042 data_s = nghttp2_session_get_stream_user_data(session, stream_id);
1043 if(!data_s)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001044 /* Receiving a Stream ID not in the hash should not happen, this is an
1045 internal error more than anything else! */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001046 return NGHTTP2_ERR_CALLBACK_FAILURE;
Alex Deymod15eaac2016-06-28 14:49:26 -07001047
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001048 stream = data_s->req.protop;
Alex Deymod15eaac2016-06-28 14:49:26 -07001049 if(!stream)
1050 return NGHTTP2_ERR_CALLBACK_FAILURE;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001051 }
Alex Deymod15eaac2016-06-28 14:49:26 -07001052 else
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001053 return NGHTTP2_ERR_INVALID_ARGUMENT;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001054
1055 nread = MIN(stream->upload_len, length);
1056 if(nread > 0) {
1057 memcpy(buf, stream->upload_mem, nread);
1058 stream->upload_mem += nread;
1059 stream->upload_len -= nread;
Elliott Hughescee03382017-06-23 12:17:18 -07001060 if(data_s->state.infilesize != -1)
1061 stream->upload_left -= nread;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001062 }
1063
1064 if(stream->upload_left == 0)
Elliott Hughescee03382017-06-23 12:17:18 -07001065 *data_flags = NGHTTP2_DATA_FLAG_EOF;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001066 else if(nread == 0)
1067 return NGHTTP2_ERR_DEFERRED;
1068
Elliott Hughescac39802018-04-27 16:19:43 -07001069 H2BUGF(infof(data_s, "data_source_read_callback: "
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001070 "returns %zu bytes stream %u\n",
1071 nread, stream_id));
1072
1073 return nread;
1074}
1075
Alex Deymod15eaac2016-06-28 14:49:26 -07001076#ifdef NGHTTP2_HAS_ERROR_CALLBACK
1077static int error_callback(nghttp2_session *session,
1078 const char *msg,
1079 size_t len,
1080 void *userp)
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001081{
Alex Deymod15eaac2016-06-28 14:49:26 -07001082 struct connectdata *conn = (struct connectdata *)userp;
1083 (void)session;
1084 infof(conn->data, "http2 error: %.*s\n", len, msg);
1085 return 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001086}
Alex Deymod15eaac2016-06-28 14:49:26 -07001087#endif
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001088
Elliott Hughes82be86d2017-09-20 17:00:17 -07001089static void populate_settings(struct connectdata *conn,
1090 struct http_conn *httpc)
1091{
1092 nghttp2_settings_entry *iv = httpc->local_settings;
1093
1094 iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
1095 iv[0].value = 100;
1096
1097 iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
1098 iv[1].value = HTTP2_HUGE_WINDOW_SIZE;
1099
1100 iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
1101 iv[2].value = conn->data->multi->push_cb != NULL;
1102
1103 httpc->local_settings_num = 3;
1104}
1105
Elliott Hughescee03382017-06-23 12:17:18 -07001106void Curl_http2_done(struct connectdata *conn, bool premature)
1107{
1108 struct Curl_easy *data = conn->data;
1109 struct HTTP *http = data->req.protop;
1110 struct http_conn *httpc = &conn->proto.httpc;
1111
1112 if(http->header_recvbuf) {
Elliott Hughescee03382017-06-23 12:17:18 -07001113 Curl_add_buffer_free(http->header_recvbuf);
1114 http->header_recvbuf = NULL; /* clear the pointer */
1115 Curl_add_buffer_free(http->trailer_recvbuf);
1116 http->trailer_recvbuf = NULL; /* clear the pointer */
1117 if(http->push_headers) {
1118 /* if they weren't used and then freed before */
1119 for(; http->push_headers_used > 0; --http->push_headers_used) {
1120 free(http->push_headers[http->push_headers_used - 1]);
1121 }
1122 free(http->push_headers);
1123 http->push_headers = NULL;
1124 }
1125 }
1126
1127 if(premature) {
1128 /* RST_STREAM */
1129 nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, http->stream_id,
1130 NGHTTP2_STREAM_CLOSED);
1131 if(http->stream_id == httpc->pause_stream_id) {
1132 infof(data, "stopped the pause stream!\n");
1133 httpc->pause_stream_id = 0;
1134 }
1135 }
1136 if(http->stream_id) {
1137 nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0);
1138 http->stream_id = 0;
1139 }
1140}
1141
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001142/*
1143 * Initialize nghttp2 for a Curl connection
1144 */
1145CURLcode Curl_http2_init(struct connectdata *conn)
1146{
1147 if(!conn->proto.httpc.h2) {
1148 int rc;
1149 nghttp2_session_callbacks *callbacks;
1150
1151 conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
1152 if(conn->proto.httpc.inbuf == NULL)
1153 return CURLE_OUT_OF_MEMORY;
1154
1155 rc = nghttp2_session_callbacks_new(&callbacks);
1156
1157 if(rc) {
1158 failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
1159 return CURLE_OUT_OF_MEMORY; /* most likely at least */
1160 }
1161
1162 /* nghttp2_send_callback */
1163 nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
1164 /* nghttp2_on_frame_recv_callback */
1165 nghttp2_session_callbacks_set_on_frame_recv_callback
1166 (callbacks, on_frame_recv);
1167 /* nghttp2_on_invalid_frame_recv_callback */
1168 nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
1169 (callbacks, on_invalid_frame_recv);
1170 /* nghttp2_on_data_chunk_recv_callback */
1171 nghttp2_session_callbacks_set_on_data_chunk_recv_callback
1172 (callbacks, on_data_chunk_recv);
1173 /* nghttp2_before_frame_send_callback */
1174 nghttp2_session_callbacks_set_before_frame_send_callback
1175 (callbacks, before_frame_send);
1176 /* nghttp2_on_frame_send_callback */
1177 nghttp2_session_callbacks_set_on_frame_send_callback
1178 (callbacks, on_frame_send);
1179 /* nghttp2_on_frame_not_send_callback */
1180 nghttp2_session_callbacks_set_on_frame_not_send_callback
1181 (callbacks, on_frame_not_send);
1182 /* nghttp2_on_stream_close_callback */
1183 nghttp2_session_callbacks_set_on_stream_close_callback
1184 (callbacks, on_stream_close);
1185 /* nghttp2_on_begin_headers_callback */
1186 nghttp2_session_callbacks_set_on_begin_headers_callback
1187 (callbacks, on_begin_headers);
1188 /* nghttp2_on_header_callback */
1189 nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
1190
Alex Deymod15eaac2016-06-28 14:49:26 -07001191 nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
1192
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001193 /* The nghttp2 session is not yet setup, do it */
1194 rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
1195
1196 nghttp2_session_callbacks_del(callbacks);
1197
1198 if(rc) {
1199 failf(conn->data, "Couldn't initialize nghttp2!");
1200 return CURLE_OUT_OF_MEMORY; /* most likely at least */
1201 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001202 }
1203 return CURLE_OK;
1204}
1205
1206/*
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001207 * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
1208 */
1209CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
1210 struct connectdata *conn)
1211{
1212 CURLcode result;
1213 ssize_t binlen;
1214 char *base64;
1215 size_t blen;
1216 struct SingleRequest *k = &conn->data->req;
1217 uint8_t *binsettings = conn->proto.httpc.binsettings;
Elliott Hughes82be86d2017-09-20 17:00:17 -07001218 struct http_conn *httpc = &conn->proto.httpc;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001219
Elliott Hughes82be86d2017-09-20 17:00:17 -07001220 populate_settings(conn, httpc);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001221
1222 /* this returns number of bytes it wrote */
1223 binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
Elliott Hughes82be86d2017-09-20 17:00:17 -07001224 httpc->local_settings,
1225 httpc->local_settings_num);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001226 if(!binlen) {
1227 failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
Alex Deymo486467e2017-12-19 19:04:07 +01001228 Curl_add_buffer_free(req);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001229 return CURLE_FAILED_INIT;
1230 }
1231 conn->proto.httpc.binlen = binlen;
1232
1233 result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
1234 &base64, &blen);
Alex Deymo486467e2017-12-19 19:04:07 +01001235 if(result) {
1236 Curl_add_buffer_free(req);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001237 return result;
Alex Deymo486467e2017-12-19 19:04:07 +01001238 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001239
1240 result = Curl_add_bufferf(req,
1241 "Connection: Upgrade, HTTP2-Settings\r\n"
1242 "Upgrade: %s\r\n"
1243 "HTTP2-Settings: %s\r\n",
1244 NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
1245 free(base64);
1246
1247 k->upgr101 = UPGR101_REQUESTED;
1248
1249 return result;
1250}
1251
Alex Deymod15eaac2016-06-28 14:49:26 -07001252/*
1253 * Returns nonzero if current HTTP/2 session should be closed.
1254 */
Elliott Hughescee03382017-06-23 12:17:18 -07001255static int should_close_session(struct http_conn *httpc)
1256{
Alex Deymod15eaac2016-06-28 14:49:26 -07001257 return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) &&
Elliott Hughescee03382017-06-23 12:17:18 -07001258 !nghttp2_session_want_write(httpc->h2);
Alex Deymod15eaac2016-06-28 14:49:26 -07001259}
1260
Alex Deymod15eaac2016-06-28 14:49:26 -07001261/*
1262 * h2_process_pending_input() processes pending input left in
1263 * httpc->inbuf. Then, call h2_session_send() to send pending data.
1264 * This function returns 0 if it succeeds, or -1 and error code will
1265 * be assigned to *err.
1266 */
Elliott Hughescac39802018-04-27 16:19:43 -07001267static int h2_process_pending_input(struct connectdata *conn,
Alex Deymod15eaac2016-06-28 14:49:26 -07001268 struct http_conn *httpc,
Elliott Hughescee03382017-06-23 12:17:18 -07001269 CURLcode *err)
1270{
Alex Deymod15eaac2016-06-28 14:49:26 -07001271 ssize_t nread;
1272 char *inbuf;
1273 ssize_t rv;
Elliott Hughescac39802018-04-27 16:19:43 -07001274 struct Curl_easy *data = conn->data;
Alex Deymod15eaac2016-06-28 14:49:26 -07001275
1276 nread = httpc->inbuflen - httpc->nread_inbuf;
1277 inbuf = httpc->inbuf + httpc->nread_inbuf;
1278
1279 rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
1280 if(rv < 0) {
1281 failf(data,
1282 "h2_process_pending_input: nghttp2_session_mem_recv() returned "
1283 "%d:%s\n", rv, nghttp2_strerror((int)rv));
1284 *err = CURLE_RECV_ERROR;
1285 return -1;
1286 }
1287
1288 if(nread == rv) {
Elliott Hughescac39802018-04-27 16:19:43 -07001289 H2BUGF(infof(data,
Alex Deymod15eaac2016-06-28 14:49:26 -07001290 "h2_process_pending_input: All data in connection buffer "
1291 "processed\n"));
1292 httpc->inbuflen = 0;
1293 httpc->nread_inbuf = 0;
1294 }
1295 else {
1296 httpc->nread_inbuf += rv;
Elliott Hughescac39802018-04-27 16:19:43 -07001297 H2BUGF(infof(data,
Alex Deymod15eaac2016-06-28 14:49:26 -07001298 "h2_process_pending_input: %zu bytes left in connection "
1299 "buffer\n",
1300 httpc->inbuflen - httpc->nread_inbuf));
1301 }
1302
1303 rv = h2_session_send(data, httpc->h2);
1304 if(rv != 0) {
1305 *err = CURLE_SEND_ERROR;
1306 return -1;
1307 }
1308
1309 if(should_close_session(httpc)) {
Elliott Hughescac39802018-04-27 16:19:43 -07001310 H2BUGF(infof(data,
Alex Deymod15eaac2016-06-28 14:49:26 -07001311 "h2_process_pending_input: nothing to do in this session\n"));
Elliott Hughescac39802018-04-27 16:19:43 -07001312 if(httpc->error_code)
1313 *err = CURLE_HTTP2;
1314 else {
1315 /* not an error per se, but should still close the connection */
1316 connclose(conn, "GOAWAY received");
1317 *err = CURLE_OK;
1318 }
Alex Deymod15eaac2016-06-28 14:49:26 -07001319 return -1;
1320 }
1321
1322 return 0;
1323}
1324
Elliott Hughescee03382017-06-23 12:17:18 -07001325/*
1326 * Called from transfer.c:done_sending when we stop uploading.
1327 */
1328CURLcode Curl_http2_done_sending(struct connectdata *conn)
1329{
1330 CURLcode result = CURLE_OK;
1331
1332 if((conn->handler == &Curl_handler_http2_ssl) ||
1333 (conn->handler == &Curl_handler_http2)) {
1334 /* make sure this is only attempted for HTTP/2 transfers */
1335
1336 struct HTTP *stream = conn->data->req.protop;
1337
1338 if(stream->upload_left) {
1339 /* If the stream still thinks there's data left to upload. */
1340 struct http_conn *httpc = &conn->proto.httpc;
1341 nghttp2_session *h2 = httpc->h2;
1342
1343 stream->upload_left = 0; /* DONE! */
1344
1345 /* resume sending here to trigger the callback to get called again so
1346 that it can signal EOF to nghttp2 */
1347 (void)nghttp2_session_resume_data(h2, stream->stream_id);
1348
Elliott Hughescac39802018-04-27 16:19:43 -07001349 (void)h2_process_pending_input(conn, httpc, &result);
Elliott Hughescee03382017-06-23 12:17:18 -07001350 }
1351 }
1352 return result;
1353}
1354
1355
Alex Deymod15eaac2016-06-28 14:49:26 -07001356static ssize_t http2_handle_stream_close(struct connectdata *conn,
Alex Deymoe3149cc2016-10-05 11:18:42 -07001357 struct Curl_easy *data,
Elliott Hughescee03382017-06-23 12:17:18 -07001358 struct HTTP *stream, CURLcode *err)
1359{
Alex Deymod15eaac2016-06-28 14:49:26 -07001360 char *trailer_pos, *trailer_end;
1361 CURLcode result;
1362 struct http_conn *httpc = &conn->proto.httpc;
1363
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001364 if(httpc->pause_stream_id == stream->stream_id) {
1365 httpc->pause_stream_id = 0;
1366 }
Alex Deymod15eaac2016-06-28 14:49:26 -07001367
1368 DEBUGASSERT(httpc->drain_total >= data->state.drain);
1369 httpc->drain_total -= data->state.drain;
1370 data->state.drain = 0;
1371
1372 if(httpc->pause_stream_id == 0) {
Elliott Hughescac39802018-04-27 16:19:43 -07001373 if(h2_process_pending_input(conn, httpc, err) != 0) {
Alex Deymod15eaac2016-06-28 14:49:26 -07001374 return -1;
1375 }
1376 }
1377
1378 DEBUGASSERT(data->state.drain == 0);
1379
Elliott Hughescee03382017-06-23 12:17:18 -07001380 /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001381 stream->closed = FALSE;
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001382 if(httpc->error_code == NGHTTP2_REFUSED_STREAM) {
1383 H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!\n",
1384 stream->stream_id));
1385 connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */
1386 data->state.refused_stream = TRUE;
1387 *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
1388 return -1;
1389 }
1390 else if(httpc->error_code != NGHTTP2_NO_ERROR) {
Alex Deymod15eaac2016-06-28 14:49:26 -07001391 failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)",
Elliott Hughescac39802018-04-27 16:19:43 -07001392 stream->stream_id, Curl_http2_strerror(httpc->error_code),
1393 httpc->error_code);
Alex Deymod15eaac2016-06-28 14:49:26 -07001394 *err = CURLE_HTTP2_STREAM;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001395 return -1;
1396 }
Alex Deymod15eaac2016-06-28 14:49:26 -07001397
1398 if(!stream->bodystarted) {
1399 failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001400 " all response header fields, treated as error",
Alex Deymod15eaac2016-06-28 14:49:26 -07001401 stream->stream_id);
1402 *err = CURLE_HTTP2_STREAM;
1403 return -1;
1404 }
1405
1406 if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) {
1407 trailer_pos = stream->trailer_recvbuf->buffer;
1408 trailer_end = trailer_pos + stream->trailer_recvbuf->size_used;
1409
1410 for(; trailer_pos < trailer_end;) {
1411 uint32_t n;
1412 memcpy(&n, trailer_pos, sizeof(n));
1413 trailer_pos += sizeof(n);
1414
1415 result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n);
1416 if(result) {
1417 *err = result;
1418 return -1;
1419 }
1420
1421 trailer_pos += n + 1;
1422 }
1423 }
1424
Elliott Hughescee03382017-06-23 12:17:18 -07001425 stream->close_handled = TRUE;
1426
Elliott Hughescac39802018-04-27 16:19:43 -07001427 H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001428 return 0;
1429}
1430
1431/*
Alex Deymod15eaac2016-06-28 14:49:26 -07001432 * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
1433 * and dependency to the peer. It also stores the updated values in the state
1434 * struct.
1435 */
1436
Alex Deymoe3149cc2016-10-05 11:18:42 -07001437static void h2_pri_spec(struct Curl_easy *data,
Alex Deymod15eaac2016-06-28 14:49:26 -07001438 nghttp2_priority_spec *pri_spec)
1439{
1440 struct HTTP *depstream = (data->set.stream_depends_on?
1441 data->set.stream_depends_on->req.protop:NULL);
1442 int32_t depstream_id = depstream? depstream->stream_id:0;
1443 nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
1444 data->set.stream_depends_e);
1445 data->state.stream_weight = data->set.stream_weight;
1446 data->state.stream_depends_e = data->set.stream_depends_e;
1447 data->state.stream_depends_on = data->set.stream_depends_on;
1448}
1449
1450/*
1451 * h2_session_send() checks if there's been an update in the priority /
1452 * dependency settings and if so it submits a PRIORITY frame with the updated
1453 * info.
1454 */
Alex Deymoe3149cc2016-10-05 11:18:42 -07001455static int h2_session_send(struct Curl_easy *data,
Alex Deymod15eaac2016-06-28 14:49:26 -07001456 nghttp2_session *h2)
1457{
1458 struct HTTP *stream = data->req.protop;
1459 if((data->set.stream_weight != data->state.stream_weight) ||
1460 (data->set.stream_depends_e != data->state.stream_depends_e) ||
1461 (data->set.stream_depends_on != data->state.stream_depends_on) ) {
1462 /* send new weight and/or dependency */
1463 nghttp2_priority_spec pri_spec;
1464 int rv;
1465
1466 h2_pri_spec(data, &pri_spec);
1467
Elliott Hughescac39802018-04-27 16:19:43 -07001468 H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
Alex Deymod15eaac2016-06-28 14:49:26 -07001469 stream->stream_id, data));
1470 rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
1471 &pri_spec);
1472 if(rv)
1473 return rv;
1474 }
1475
1476 return nghttp2_session_send(h2);
1477}
1478
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001479static ssize_t http2_recv(struct connectdata *conn, int sockindex,
1480 char *mem, size_t len, CURLcode *err)
1481{
1482 CURLcode result = CURLE_OK;
1483 ssize_t rv;
1484 ssize_t nread;
1485 struct http_conn *httpc = &conn->proto.httpc;
Alex Deymoe3149cc2016-10-05 11:18:42 -07001486 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001487 struct HTTP *stream = data->req.protop;
1488
1489 (void)sockindex; /* we always do HTTP2 on sockindex 0 */
1490
Alex Deymod15eaac2016-06-28 14:49:26 -07001491 if(should_close_session(httpc)) {
Elliott Hughescac39802018-04-27 16:19:43 -07001492 H2BUGF(infof(data,
Alex Deymod15eaac2016-06-28 14:49:26 -07001493 "http2_recv: nothing to do in this session\n"));
1494 *err = CURLE_HTTP2;
1495 return -1;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001496 }
1497
1498 /* Nullify here because we call nghttp2_session_send() and they
1499 might refer to the old buffer. */
1500 stream->upload_mem = NULL;
1501 stream->upload_len = 0;
1502
1503 /*
Alex Deymoe3149cc2016-10-05 11:18:42 -07001504 * At this point 'stream' is just in the Curl_easy the connection
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001505 * identifies as its owner at this time.
1506 */
1507
1508 if(stream->bodystarted &&
1509 stream->nread_header_recvbuf < stream->header_recvbuf->size_used) {
1510 /* If there is body data pending for this stream to return, do that */
1511 size_t left =
1512 stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
1513 size_t ncopy = MIN(len, left);
1514 memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
1515 ncopy);
1516 stream->nread_header_recvbuf += ncopy;
1517
Elliott Hughescac39802018-04-27 16:19:43 -07001518 H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
Alex Deymod15eaac2016-06-28 14:49:26 -07001519 (int)ncopy));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001520 return ncopy;
1521 }
1522
Elliott Hughescac39802018-04-27 16:19:43 -07001523 H2BUGF(infof(data, "http2_recv: easy %p (stream %u)\n",
Alex Deymod15eaac2016-06-28 14:49:26 -07001524 data, stream->stream_id));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001525
1526 if((data->state.drain) && stream->memlen) {
Elliott Hughescac39802018-04-27 16:19:43 -07001527 H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001528 stream->memlen, stream->stream_id,
1529 stream->mem, mem));
1530 if(mem != stream->mem) {
1531 /* if we didn't get the same buffer this time, we must move the data to
1532 the beginning */
1533 memmove(mem, stream->mem, stream->memlen);
1534 stream->len = len - stream->memlen;
1535 stream->mem = mem;
1536 }
Alex Deymod15eaac2016-06-28 14:49:26 -07001537 if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) {
1538 /* We have paused nghttp2, but we have no pause data (see
1539 on_data_chunk_recv). */
1540 httpc->pause_stream_id = 0;
Elliott Hughescac39802018-04-27 16:19:43 -07001541 if(h2_process_pending_input(conn, httpc, &result) != 0) {
Alex Deymod15eaac2016-06-28 14:49:26 -07001542 *err = result;
1543 return -1;
1544 }
1545 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001546 }
1547 else if(stream->pausedata) {
Alex Deymod15eaac2016-06-28 14:49:26 -07001548 DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001549 nread = MIN(len, stream->pauselen);
1550 memcpy(mem, stream->pausedata, nread);
1551
1552 stream->pausedata += nread;
1553 stream->pauselen -= nread;
1554
1555 infof(data, "%zu data bytes written\n", nread);
1556 if(stream->pauselen == 0) {
Elliott Hughescac39802018-04-27 16:19:43 -07001557 H2BUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
Elliott Hughes82be86d2017-09-20 17:00:17 -07001558 DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001559 httpc->pause_stream_id = 0;
1560
1561 stream->pausedata = NULL;
1562 stream->pauselen = 0;
Alex Deymod15eaac2016-06-28 14:49:26 -07001563
1564 /* When NGHTTP2_ERR_PAUSE is returned from
1565 data_source_read_callback, we might not process DATA frame
1566 fully. Calling nghttp2_session_mem_recv() again will
1567 continue to process DATA frame, but if there is no incoming
1568 frames, then we have to call it again with 0-length data.
1569 Without this, on_stream_close callback will not be called,
1570 and stream could be hanged. */
Elliott Hughescac39802018-04-27 16:19:43 -07001571 if(h2_process_pending_input(conn, httpc, &result) != 0) {
Alex Deymod15eaac2016-06-28 14:49:26 -07001572 *err = result;
1573 return -1;
1574 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001575 }
Elliott Hughescac39802018-04-27 16:19:43 -07001576 H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
Alex Deymod15eaac2016-06-28 14:49:26 -07001577 nread, stream->stream_id));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001578 return nread;
1579 }
1580 else if(httpc->pause_stream_id) {
1581 /* If a stream paused nghttp2_session_mem_recv previously, and has
1582 not processed all data, it still refers to the buffer in
1583 nghttp2_session. If we call nghttp2_session_mem_recv(), we may
1584 overwrite that buffer. To avoid that situation, just return
1585 here with CURLE_AGAIN. This could be busy loop since data in
1586 socket is not read. But it seems that usually streams are
1587 notified with its drain property, and socket is read again
1588 quickly. */
Elliott Hughescac39802018-04-27 16:19:43 -07001589 H2BUGF(infof(data, "stream %x is paused, pause id: %x\n",
Elliott Hughescee03382017-06-23 12:17:18 -07001590 stream->stream_id, httpc->pause_stream_id));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001591 *err = CURLE_AGAIN;
1592 return -1;
1593 }
1594 else {
1595 char *inbuf;
1596 /* remember where to store incoming data for this stream and how big the
1597 buffer is */
1598 stream->mem = mem;
1599 stream->len = len;
1600 stream->memlen = 0;
1601
1602 if(httpc->inbuflen == 0) {
1603 nread = ((Curl_recv *)httpc->recv_underlying)(
1604 conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
1605
Alex Deymod15eaac2016-06-28 14:49:26 -07001606 if(nread == -1) {
1607 if(result != CURLE_AGAIN)
1608 failf(data, "Failed receiving HTTP2 data");
1609 else if(stream->closed)
1610 /* received when the stream was already closed! */
1611 return http2_handle_stream_close(conn, data, stream, err);
1612
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001613 *err = result;
1614 return -1;
1615 }
1616
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001617 if(nread == 0) {
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001618 H2BUGF(infof(data, "end of stream\n"));
1619 *err = CURLE_OK;
1620 return 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001621 }
1622
Elliott Hughescac39802018-04-27 16:19:43 -07001623 H2BUGF(infof(data, "nread=%zd\n", nread));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001624
1625 httpc->inbuflen = nread;
1626 inbuf = httpc->inbuf;
1627 }
1628 else {
1629 nread = httpc->inbuflen - httpc->nread_inbuf;
1630 inbuf = httpc->inbuf + httpc->nread_inbuf;
1631
Elliott Hughescac39802018-04-27 16:19:43 -07001632 H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001633 nread));
1634 }
1635 rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
1636
1637 if(nghttp2_is_fatal((int)rv)) {
1638 failf(data, "nghttp2_session_mem_recv() returned %d:%s\n",
1639 rv, nghttp2_strerror((int)rv));
1640 *err = CURLE_RECV_ERROR;
Alex Deymo486467e2017-12-19 19:04:07 +01001641 return -1;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001642 }
Elliott Hughescac39802018-04-27 16:19:43 -07001643 H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001644 if(nread == rv) {
Elliott Hughescac39802018-04-27 16:19:43 -07001645 H2BUGF(infof(data, "All data in connection buffer processed\n"));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001646 httpc->inbuflen = 0;
1647 httpc->nread_inbuf = 0;
1648 }
1649 else {
1650 httpc->nread_inbuf += rv;
Elliott Hughescac39802018-04-27 16:19:43 -07001651 H2BUGF(infof(data, "%zu bytes left in connection buffer\n",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001652 httpc->inbuflen - httpc->nread_inbuf));
1653 }
1654 /* Always send pending frames in nghttp2 session, because
1655 nghttp2_session_mem_recv() may queue new frame */
Alex Deymod15eaac2016-06-28 14:49:26 -07001656 rv = h2_session_send(data, httpc->h2);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001657 if(rv != 0) {
1658 *err = CURLE_SEND_ERROR;
Alex Deymo486467e2017-12-19 19:04:07 +01001659 return -1;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001660 }
Alex Deymod15eaac2016-06-28 14:49:26 -07001661
1662 if(should_close_session(httpc)) {
Elliott Hughescac39802018-04-27 16:19:43 -07001663 H2BUGF(infof(data, "http2_recv: nothing to do in this session\n"));
Alex Deymod15eaac2016-06-28 14:49:26 -07001664 *err = CURLE_HTTP2;
1665 return -1;
1666 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001667 }
1668 if(stream->memlen) {
1669 ssize_t retlen = stream->memlen;
Elliott Hughescac39802018-04-27 16:19:43 -07001670 H2BUGF(infof(data, "http2_recv: returns %zd for stream %u\n",
Alex Deymod15eaac2016-06-28 14:49:26 -07001671 retlen, stream->stream_id));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001672 stream->memlen = 0;
1673
1674 if(httpc->pause_stream_id == stream->stream_id) {
1675 /* data for this stream is returned now, but this stream caused a pause
1676 already so we need it called again asap */
Elliott Hughescac39802018-04-27 16:19:43 -07001677 H2BUGF(infof(data, "Data returned for PAUSED stream %u\n",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001678 stream->stream_id));
1679 }
Alex Deymod15eaac2016-06-28 14:49:26 -07001680 else if(!stream->closed) {
1681 DEBUGASSERT(httpc->drain_total >= data->state.drain);
1682 httpc->drain_total -= data->state.drain;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001683 data->state.drain = 0; /* this stream is hereby drained */
Alex Deymod15eaac2016-06-28 14:49:26 -07001684 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001685
1686 return retlen;
1687 }
1688 /* If stream is closed, return 0 to signal the http routine to close
1689 the connection */
1690 if(stream->closed) {
Alex Deymod15eaac2016-06-28 14:49:26 -07001691 return http2_handle_stream_close(conn, data, stream, err);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001692 }
1693 *err = CURLE_AGAIN;
Elliott Hughescac39802018-04-27 16:19:43 -07001694 H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001695 stream->stream_id));
1696 return -1;
1697}
1698
1699/* Index where :authority header field will appear in request header
1700 field list. */
1701#define AUTHORITY_DST_IDX 3
1702
Alex Deymod15eaac2016-06-28 14:49:26 -07001703#define HEADER_OVERFLOW(x) \
1704 (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen)
1705
Elliott Hughescee03382017-06-23 12:17:18 -07001706/*
1707 * Check header memory for the token "trailers".
1708 * Parse the tokens as separated by comma and surrounded by whitespace.
1709 * Returns TRUE if found or FALSE if not.
1710 */
1711static bool contains_trailers(const char *p, size_t len)
1712{
1713 const char *end = p + len;
1714 for(;;) {
1715 for(; p != end && (*p == ' ' || *p == '\t'); ++p)
1716 ;
1717 if(p == end || (size_t)(end - p) < sizeof("trailers") - 1)
1718 return FALSE;
1719 if(strncasecompare("trailers", p, sizeof("trailers") - 1)) {
1720 p += sizeof("trailers") - 1;
1721 for(; p != end && (*p == ' ' || *p == '\t'); ++p)
1722 ;
1723 if(p == end || *p == ',')
1724 return TRUE;
1725 }
1726 /* skip to next token */
1727 for(; p != end && *p != ','; ++p)
1728 ;
1729 if(p == end)
1730 return FALSE;
1731 ++p;
1732 }
1733}
1734
1735typedef enum {
1736 /* Send header to server */
1737 HEADERINST_FORWARD,
1738 /* Don't send header to server */
1739 HEADERINST_IGNORE,
1740 /* Discard header, and replace it with "te: trailers" */
1741 HEADERINST_TE_TRAILERS
1742} header_instruction;
1743
1744/* Decides how to treat given header field. */
1745static header_instruction inspect_header(const char *name, size_t namelen,
1746 const char *value, size_t valuelen) {
1747 switch(namelen) {
1748 case 2:
1749 if(!strncasecompare("te", name, namelen))
1750 return HEADERINST_FORWARD;
1751
1752 return contains_trailers(value, valuelen) ?
1753 HEADERINST_TE_TRAILERS : HEADERINST_IGNORE;
1754 case 7:
1755 return strncasecompare("upgrade", name, namelen) ?
1756 HEADERINST_IGNORE : HEADERINST_FORWARD;
1757 case 10:
1758 return (strncasecompare("connection", name, namelen) ||
1759 strncasecompare("keep-alive", name, namelen)) ?
1760 HEADERINST_IGNORE : HEADERINST_FORWARD;
1761 case 16:
1762 return strncasecompare("proxy-connection", name, namelen) ?
1763 HEADERINST_IGNORE : HEADERINST_FORWARD;
1764 case 17:
1765 return strncasecompare("transfer-encoding", name, namelen) ?
1766 HEADERINST_IGNORE : HEADERINST_FORWARD;
1767 default:
1768 return HEADERINST_FORWARD;
1769 }
1770}
1771
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001772static ssize_t http2_send(struct connectdata *conn, int sockindex,
1773 const void *mem, size_t len, CURLcode *err)
1774{
1775 /*
1776 * BIG TODO: Currently, we send request in this function, but this
1777 * function is also used to send request body. It would be nice to
1778 * add dedicated function for request.
1779 */
1780 int rv;
1781 struct http_conn *httpc = &conn->proto.httpc;
1782 struct HTTP *stream = conn->data->req.protop;
Alex Deymod15eaac2016-06-28 14:49:26 -07001783 nghttp2_nv *nva = NULL;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001784 size_t nheader;
1785 size_t i;
1786 size_t authority_idx;
Elliott Hughescee03382017-06-23 12:17:18 -07001787 char *hdbuf = (char *)mem;
Alex Deymod15eaac2016-06-28 14:49:26 -07001788 char *end, *line_end;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001789 nghttp2_data_provider data_prd;
1790 int32_t stream_id;
1791 nghttp2_session *h2 = httpc->h2;
Alex Deymod15eaac2016-06-28 14:49:26 -07001792 nghttp2_priority_spec pri_spec;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001793
1794 (void)sockindex;
1795
Elliott Hughescac39802018-04-27 16:19:43 -07001796 H2BUGF(infof(conn->data, "http2_send len=%zu\n", len));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001797
1798 if(stream->stream_id != -1) {
Elliott Hughescee03382017-06-23 12:17:18 -07001799 if(stream->close_handled) {
1800 infof(conn->data, "stream %d closed\n", stream->stream_id);
1801 *err = CURLE_HTTP2_STREAM;
1802 return -1;
1803 }
1804 else if(stream->closed) {
1805 return http2_handle_stream_close(conn, conn->data, stream, err);
1806 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001807 /* If stream_id != -1, we have dispatched request HEADERS, and now
1808 are going to send or sending request body in DATA frame */
1809 stream->upload_mem = mem;
1810 stream->upload_len = len;
1811 nghttp2_session_resume_data(h2, stream->stream_id);
Alex Deymod15eaac2016-06-28 14:49:26 -07001812 rv = h2_session_send(conn->data, h2);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001813 if(nghttp2_is_fatal(rv)) {
1814 *err = CURLE_SEND_ERROR;
1815 return -1;
1816 }
1817 len -= stream->upload_len;
1818
1819 /* Nullify here because we call nghttp2_session_send() and they
1820 might refer to the old buffer. */
1821 stream->upload_mem = NULL;
1822 stream->upload_len = 0;
1823
Alex Deymod15eaac2016-06-28 14:49:26 -07001824 if(should_close_session(httpc)) {
Elliott Hughescac39802018-04-27 16:19:43 -07001825 H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
Alex Deymod15eaac2016-06-28 14:49:26 -07001826 *err = CURLE_HTTP2;
1827 return -1;
1828 }
1829
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001830 if(stream->upload_left) {
1831 /* we are sure that we have more data to send here. Calling the
1832 following API will make nghttp2_session_want_write() return
1833 nonzero if remote window allows it, which then libcurl checks
1834 socket is writable or not. See http2_perform_getsock(). */
1835 nghttp2_session_resume_data(h2, stream->stream_id);
1836 }
1837
Elliott Hughescac39802018-04-27 16:19:43 -07001838 H2BUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len,
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001839 stream->stream_id));
1840 return len;
1841 }
1842
1843 /* Calculate number of headers contained in [mem, mem + len) */
1844 /* Here, we assume the curl http code generate *correct* HTTP header
1845 field block */
1846 nheader = 0;
Alex Deymod15eaac2016-06-28 14:49:26 -07001847 for(i = 1; i < len; ++i) {
1848 if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001849 ++nheader;
Alex Deymod15eaac2016-06-28 14:49:26 -07001850 ++i;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001851 }
1852 }
Alex Deymod15eaac2016-06-28 14:49:26 -07001853 if(nheader < 2)
1854 goto fail;
1855
1856 /* We counted additional 2 \r\n in the first and last line. We need 3
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001857 new headers: :method, :path and :scheme. Therefore we need one
1858 more space. */
1859 nheader += 1;
1860 nva = malloc(sizeof(nghttp2_nv) * nheader);
1861 if(nva == NULL) {
1862 *err = CURLE_OUT_OF_MEMORY;
1863 return -1;
1864 }
Alex Deymod15eaac2016-06-28 14:49:26 -07001865
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001866 /* Extract :method, :path from request line
1867 We do line endings with CRLF so checking for CR is enough */
1868 line_end = memchr(hdbuf, '\r', len);
1869 if(!line_end)
1870 goto fail;
Alex Deymod15eaac2016-06-28 14:49:26 -07001871
1872 /* Method does not contain spaces */
1873 end = memchr(hdbuf, ' ', line_end - hdbuf);
1874 if(!end || end == hdbuf)
1875 goto fail;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001876 nva[0].name = (unsigned char *)":method";
Alex Deymod15eaac2016-06-28 14:49:26 -07001877 nva[0].namelen = strlen((char *)nva[0].name);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001878 nva[0].value = (unsigned char *)hdbuf;
Alex Deymod15eaac2016-06-28 14:49:26 -07001879 nva[0].valuelen = (size_t)(end - hdbuf);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001880 nva[0].flags = NGHTTP2_NV_FLAG_NONE;
Alex Deymod15eaac2016-06-28 14:49:26 -07001881 if(HEADER_OVERFLOW(nva[0])) {
1882 failf(conn->data, "Failed sending HTTP request: Header overflow");
1883 goto fail;
1884 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001885
1886 hdbuf = end + 1;
1887
Alex Deymod15eaac2016-06-28 14:49:26 -07001888 /* Path may contain spaces so scan backwards */
1889 end = NULL;
1890 for(i = (size_t)(line_end - hdbuf); i; --i) {
1891 if(hdbuf[i - 1] == ' ') {
1892 end = &hdbuf[i - 1];
1893 break;
1894 }
1895 }
1896 if(!end || end == hdbuf)
1897 goto fail;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001898 nva[1].name = (unsigned char *)":path";
Alex Deymod15eaac2016-06-28 14:49:26 -07001899 nva[1].namelen = strlen((char *)nva[1].name);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001900 nva[1].value = (unsigned char *)hdbuf;
Alex Deymod15eaac2016-06-28 14:49:26 -07001901 nva[1].valuelen = (size_t)(end - hdbuf);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001902 nva[1].flags = NGHTTP2_NV_FLAG_NONE;
Alex Deymod15eaac2016-06-28 14:49:26 -07001903 if(HEADER_OVERFLOW(nva[1])) {
1904 failf(conn->data, "Failed sending HTTP request: Header overflow");
1905 goto fail;
1906 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001907
1908 nva[2].name = (unsigned char *)":scheme";
Alex Deymod15eaac2016-06-28 14:49:26 -07001909 nva[2].namelen = strlen((char *)nva[2].name);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001910 if(conn->handler->flags & PROTOPT_SSL)
1911 nva[2].value = (unsigned char *)"https";
1912 else
1913 nva[2].value = (unsigned char *)"http";
Alex Deymod15eaac2016-06-28 14:49:26 -07001914 nva[2].valuelen = strlen((char *)nva[2].value);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001915 nva[2].flags = NGHTTP2_NV_FLAG_NONE;
Alex Deymod15eaac2016-06-28 14:49:26 -07001916 if(HEADER_OVERFLOW(nva[2])) {
1917 failf(conn->data, "Failed sending HTTP request: Header overflow");
1918 goto fail;
1919 }
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001920
1921 authority_idx = 0;
Alex Deymod15eaac2016-06-28 14:49:26 -07001922 i = 3;
1923 while(i < nheader) {
1924 size_t hlen;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001925
Alex Deymod15eaac2016-06-28 14:49:26 -07001926 hdbuf = line_end + 2;
1927
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07001928 /* check for next CR, but only within the piece of data left in the given
1929 buffer */
1930 line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
1931 if(!line_end || (line_end == hdbuf))
Alex Deymod15eaac2016-06-28 14:49:26 -07001932 goto fail;
1933
1934 /* header continuation lines are not supported */
1935 if(*hdbuf == ' ' || *hdbuf == '\t')
1936 goto fail;
1937
1938 for(end = hdbuf; end < line_end && *end != ':'; ++end)
1939 ;
1940 if(end == hdbuf || end == line_end)
1941 goto fail;
1942 hlen = end - hdbuf;
1943
Elliott Hughescee03382017-06-23 12:17:18 -07001944 if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001945 authority_idx = i;
1946 nva[i].name = (unsigned char *)":authority";
Alex Deymod15eaac2016-06-28 14:49:26 -07001947 nva[i].namelen = strlen((char *)nva[i].name);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001948 }
1949 else {
1950 nva[i].name = (unsigned char *)hdbuf;
Alex Deymod15eaac2016-06-28 14:49:26 -07001951 nva[i].namelen = (size_t)(end - hdbuf);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001952 }
1953 hdbuf = end + 1;
Alex Deymod15eaac2016-06-28 14:49:26 -07001954 while(*hdbuf == ' ' || *hdbuf == '\t')
1955 ++hdbuf;
1956 end = line_end;
Elliott Hughescee03382017-06-23 12:17:18 -07001957
1958 switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
1959 end - hdbuf)) {
1960 case HEADERINST_IGNORE:
1961 /* skip header fields prohibited by HTTP/2 specification. */
1962 --nheader;
1963 continue;
1964 case HEADERINST_TE_TRAILERS:
1965 nva[i].value = (uint8_t*)"trailers";
1966 nva[i].valuelen = sizeof("trailers") - 1;
1967 break;
1968 default:
Alex Deymod15eaac2016-06-28 14:49:26 -07001969 nva[i].value = (unsigned char *)hdbuf;
1970 nva[i].valuelen = (size_t)(end - hdbuf);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001971 }
Elliott Hughescee03382017-06-23 12:17:18 -07001972
1973 nva[i].flags = NGHTTP2_NV_FLAG_NONE;
1974 if(HEADER_OVERFLOW(nva[i])) {
1975 failf(conn->data, "Failed sending HTTP request: Header overflow");
1976 goto fail;
1977 }
1978 ++i;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07001979 }
1980
1981 /* :authority must come before non-pseudo header fields */
1982 if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
1983 nghttp2_nv authority = nva[authority_idx];
1984 for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
1985 nva[i] = nva[i - 1];
1986 }
1987 nva[i] = authority;
1988 }
1989
Alex Deymod15eaac2016-06-28 14:49:26 -07001990 /* Warn stream may be rejected if cumulative length of headers is too large.
1991 It appears nghttp2 will not send a header frame larger than 64KB. */
Elliott Hughes82be86d2017-09-20 17:00:17 -07001992#define MAX_ACC 60000 /* <64KB to account for some overhead */
Alex Deymod15eaac2016-06-28 14:49:26 -07001993 {
1994 size_t acc = 0;
Alex Deymod15eaac2016-06-28 14:49:26 -07001995
1996 for(i = 0; i < nheader; ++i) {
Elliott Hughes82be86d2017-09-20 17:00:17 -07001997 acc += nva[i].namelen + nva[i].valuelen;
Elliott Hughescee03382017-06-23 12:17:18 -07001998
Elliott Hughescac39802018-04-27 16:19:43 -07001999 H2BUGF(infof(conn->data, "h2 header: %.*s:%.*s\n",
Elliott Hughescee03382017-06-23 12:17:18 -07002000 nva[i].namelen, nva[i].name,
2001 nva[i].valuelen, nva[i].value));
Alex Deymod15eaac2016-06-28 14:49:26 -07002002 }
2003
Elliott Hughes82be86d2017-09-20 17:00:17 -07002004 if(acc > MAX_ACC) {
Alex Deymod15eaac2016-06-28 14:49:26 -07002005 infof(conn->data, "http2_send: Warning: The cumulative length of all "
Elliott Hughes82be86d2017-09-20 17:00:17 -07002006 "headers exceeds %zu bytes and that could cause the "
2007 "stream to be rejected.\n", MAX_ACC);
Alex Deymod15eaac2016-06-28 14:49:26 -07002008 }
2009 }
2010
2011 h2_pri_spec(conn->data, &pri_spec);
2012
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002013 switch(conn->data->set.httpreq) {
2014 case HTTPREQ_POST:
2015 case HTTPREQ_POST_FORM:
Alex Deymo486467e2017-12-19 19:04:07 +01002016 case HTTPREQ_POST_MIME:
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002017 case HTTPREQ_PUT:
Elliott Hughescee03382017-06-23 12:17:18 -07002018 if(conn->data->state.infilesize != -1)
2019 stream->upload_left = conn->data->state.infilesize;
2020 else
2021 /* data sending without specifying the data amount up front */
2022 stream->upload_left = -1; /* unknown, but not zero */
2023
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002024 data_prd.read_callback = data_source_read_callback;
2025 data_prd.source.ptr = NULL;
Alex Deymod15eaac2016-06-28 14:49:26 -07002026 stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
2027 &data_prd, conn->data);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002028 break;
2029 default:
Alex Deymod15eaac2016-06-28 14:49:26 -07002030 stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
2031 NULL, conn->data);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002032 }
2033
Alex Deymod15eaac2016-06-28 14:49:26 -07002034 Curl_safefree(nva);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002035
2036 if(stream_id < 0) {
Elliott Hughescac39802018-04-27 16:19:43 -07002037 H2BUGF(infof(conn->data, "http2_send() send error\n"));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002038 *err = CURLE_SEND_ERROR;
2039 return -1;
2040 }
2041
2042 infof(conn->data, "Using Stream ID: %x (easy handle %p)\n",
2043 stream_id, conn->data);
2044 stream->stream_id = stream_id;
2045
Alex Deymod15eaac2016-06-28 14:49:26 -07002046 /* this does not call h2_session_send() since there can not have been any
2047 * priority upodate since the nghttp2_submit_request() call above */
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002048 rv = nghttp2_session_send(h2);
2049
2050 if(rv != 0) {
2051 *err = CURLE_SEND_ERROR;
2052 return -1;
2053 }
2054
Alex Deymod15eaac2016-06-28 14:49:26 -07002055 if(should_close_session(httpc)) {
Elliott Hughescac39802018-04-27 16:19:43 -07002056 H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
Alex Deymod15eaac2016-06-28 14:49:26 -07002057 *err = CURLE_HTTP2;
2058 return -1;
2059 }
2060
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002061 if(stream->stream_id != -1) {
2062 /* If whole HEADERS frame was sent off to the underlying socket,
2063 the nghttp2 library calls data_source_read_callback. But only
2064 it found that no data available, so it deferred the DATA
2065 transmission. Which means that nghttp2_session_want_write()
2066 returns 0 on http2_perform_getsock(), which results that no
2067 writable socket check is performed. To workaround this, we
2068 issue nghttp2_session_resume_data() here to bring back DATA
2069 transmission from deferred state. */
2070 nghttp2_session_resume_data(h2, stream->stream_id);
2071 }
2072
2073 return len;
Alex Deymod15eaac2016-06-28 14:49:26 -07002074
2075fail:
2076 free(nva);
2077 *err = CURLE_SEND_ERROR;
2078 return -1;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002079}
2080
2081CURLcode Curl_http2_setup(struct connectdata *conn)
2082{
2083 CURLcode result;
2084 struct http_conn *httpc = &conn->proto.httpc;
2085 struct HTTP *stream = conn->data->req.protop;
2086
2087 stream->stream_id = -1;
2088
2089 if(!stream->header_recvbuf)
2090 stream->header_recvbuf = Curl_add_buffer_init();
2091
2092 if((conn->handler == &Curl_handler_http2_ssl) ||
2093 (conn->handler == &Curl_handler_http2))
2094 return CURLE_OK; /* already done */
2095
2096 if(conn->handler->flags & PROTOPT_SSL)
2097 conn->handler = &Curl_handler_http2_ssl;
2098 else
2099 conn->handler = &Curl_handler_http2;
2100
2101 result = Curl_http2_init(conn);
2102 if(result)
2103 return result;
2104
2105 infof(conn->data, "Using HTTP2, server supports multi-use\n");
2106 stream->upload_left = 0;
2107 stream->upload_mem = NULL;
2108 stream->upload_len = 0;
2109
2110 httpc->inbuflen = 0;
2111 httpc->nread_inbuf = 0;
2112
2113 httpc->pause_stream_id = 0;
Alex Deymod15eaac2016-06-28 14:49:26 -07002114 httpc->drain_total = 0;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002115
2116 conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
2117 conn->httpversion = 20;
2118 conn->bundle->multiuse = BUNDLE_MULTIPLEX;
2119
2120 infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
2121 Curl_multi_connchanged(conn->data->multi);
2122
2123 return CURLE_OK;
2124}
2125
2126CURLcode Curl_http2_switched(struct connectdata *conn,
2127 const char *mem, size_t nread)
2128{
2129 CURLcode result;
2130 struct http_conn *httpc = &conn->proto.httpc;
2131 int rv;
2132 ssize_t nproc;
Alex Deymoe3149cc2016-10-05 11:18:42 -07002133 struct Curl_easy *data = conn->data;
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002134 struct HTTP *stream = conn->data->req.protop;
2135
2136 result = Curl_http2_setup(conn);
2137 if(result)
2138 return result;
2139
Elliott Hughes1ef06ba2018-05-30 15:43:58 -07002140 httpc->recv_underlying = conn->recv[FIRSTSOCKET];
2141 httpc->send_underlying = conn->send[FIRSTSOCKET];
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002142 conn->recv[FIRSTSOCKET] = http2_recv;
2143 conn->send[FIRSTSOCKET] = http2_send;
2144
2145 if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
2146 /* stream 1 is opened implicitly on upgrade */
2147 stream->stream_id = 1;
2148 /* queue SETTINGS frame (again) */
2149 rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
2150 httpc->binlen, NULL);
2151 if(rv != 0) {
2152 failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
2153 nghttp2_strerror(rv), rv);
2154 return CURLE_HTTP2;
2155 }
2156
Alex Deymod15eaac2016-06-28 14:49:26 -07002157 nghttp2_session_set_stream_user_data(httpc->h2,
2158 stream->stream_id,
2159 conn->data);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002160 }
2161 else {
Elliott Hughes82be86d2017-09-20 17:00:17 -07002162 populate_settings(conn, httpc);
2163
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002164 /* stream ID is unknown at this point */
2165 stream->stream_id = -1;
Elliott Hughes82be86d2017-09-20 17:00:17 -07002166 rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE,
2167 httpc->local_settings,
2168 httpc->local_settings_num);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002169 if(rv != 0) {
2170 failf(data, "nghttp2_submit_settings() failed: %s(%d)",
2171 nghttp2_strerror(rv), rv);
2172 return CURLE_HTTP2;
2173 }
2174 }
2175
Elliott Hughes82be86d2017-09-20 17:00:17 -07002176#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
Elliott Hughescee03382017-06-23 12:17:18 -07002177 rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0,
2178 HTTP2_HUGE_WINDOW_SIZE);
2179 if(rv != 0) {
2180 failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
2181 nghttp2_strerror(rv), rv);
2182 return CURLE_HTTP2;
2183 }
Elliott Hughes82be86d2017-09-20 17:00:17 -07002184#endif
Elliott Hughescee03382017-06-23 12:17:18 -07002185
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002186 /* we are going to copy mem to httpc->inbuf. This is required since
2187 mem is part of buffer pointed by stream->mem, and callbacks
2188 called by nghttp2_session_mem_recv() will write stream specific
2189 data into stream->mem, overwriting data already there. */
2190 if(H2_BUFSIZE < nread) {
2191 failf(data, "connection buffer size is too small to store data following "
2192 "HTTP Upgrade response header: buflen=%zu, datalen=%zu",
2193 H2_BUFSIZE, nread);
2194 return CURLE_HTTP2;
2195 }
2196
2197 infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer"
2198 " after upgrade: len=%zu\n",
2199 nread);
2200
Elliott Hughescee03382017-06-23 12:17:18 -07002201 if(nread)
2202 memcpy(httpc->inbuf, mem, nread);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002203 httpc->inbuflen = nread;
2204
2205 nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf,
2206 httpc->inbuflen);
2207
2208 if(nghttp2_is_fatal((int)nproc)) {
2209 failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
2210 nghttp2_strerror((int)nproc), (int)nproc);
2211 return CURLE_HTTP2;
2212 }
2213
Elliott Hughescac39802018-04-27 16:19:43 -07002214 H2BUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002215
2216 if((ssize_t)nread == nproc) {
2217 httpc->inbuflen = 0;
2218 httpc->nread_inbuf = 0;
2219 }
2220 else {
2221 httpc->nread_inbuf += nproc;
2222 }
2223
2224 /* Try to send some frames since we may read SETTINGS already. */
Alex Deymod15eaac2016-06-28 14:49:26 -07002225 rv = h2_session_send(data, httpc->h2);
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002226
2227 if(rv != 0) {
2228 failf(data, "nghttp2_session_send() failed: %s(%d)",
2229 nghttp2_strerror(rv), rv);
2230 return CURLE_HTTP2;
2231 }
2232
Alex Deymod15eaac2016-06-28 14:49:26 -07002233 if(should_close_session(httpc)) {
Elliott Hughescac39802018-04-27 16:19:43 -07002234 H2BUGF(infof(data,
Alex Deymod15eaac2016-06-28 14:49:26 -07002235 "nghttp2_session_send(): nothing to do in this session\n"));
2236 return CURLE_HTTP2;
2237 }
2238
Bertrand SIMONNETe6cd7382015-07-01 15:39:44 -07002239 return CURLE_OK;
2240}
2241
Elliott Hughes82be86d2017-09-20 17:00:17 -07002242CURLcode Curl_http2_add_child(struct Curl_easy *parent,
2243 struct Curl_easy *child,
2244 bool exclusive)
2245{
2246 if(parent) {
2247 struct Curl_http2_dep **tail;
2248 struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep));
2249 if(!dep)
2250 return CURLE_OUT_OF_MEMORY;
2251 dep->data = child;
2252
2253 if(parent->set.stream_dependents && exclusive) {
2254 struct Curl_http2_dep *node = parent->set.stream_dependents;
2255 while(node) {
2256 node->data->set.stream_depends_on = child;
2257 node = node->next;
2258 }
2259
2260 tail = &child->set.stream_dependents;
2261 while(*tail)
2262 tail = &(*tail)->next;
2263
2264 DEBUGASSERT(!*tail);
2265 *tail = parent->set.stream_dependents;
2266 parent->set.stream_dependents = 0;
2267 }
2268
2269 tail = &parent->set.stream_dependents;
2270 while(*tail) {
2271 (*tail)->data->set.stream_depends_e = FALSE;
2272 tail = &(*tail)->next;
2273 }
2274
2275 DEBUGASSERT(!*tail);
2276 *tail = dep;
2277 }
2278
2279 child->set.stream_depends_on = parent;
2280 child->set.stream_depends_e = exclusive;
2281 return CURLE_OK;
2282}
2283
2284void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child)
2285{
2286 struct Curl_http2_dep *last = 0;
2287 struct Curl_http2_dep *data = parent->set.stream_dependents;
2288 DEBUGASSERT(child->set.stream_depends_on == parent);
2289
2290 while(data && data->data != child) {
2291 last = data;
2292 data = data->next;
2293 }
2294
2295 DEBUGASSERT(data);
2296
2297 if(data) {
2298 if(last) {
2299 last->next = data->next;
2300 }
2301 else {
2302 parent->set.stream_dependents = data->next;
2303 }
2304 free(data);
2305 }
2306
2307 child->set.stream_depends_on = 0;
2308 child->set.stream_depends_e = FALSE;
2309}
2310
2311void Curl_http2_cleanup_dependencies(struct Curl_easy *data)
2312{
2313 while(data->set.stream_dependents) {
2314 struct Curl_easy *tmp = data->set.stream_dependents->data;
2315 Curl_http2_remove_child(data, tmp);
2316 if(data->set.stream_depends_on)
2317 Curl_http2_add_child(data->set.stream_depends_on, tmp, FALSE);
2318 }
2319
2320 if(data->set.stream_depends_on)
2321 Curl_http2_remove_child(data->set.stream_depends_on, data);
2322}
2323
Alex Deymod15eaac2016-06-28 14:49:26 -07002324#else /* !USE_NGHTTP2 */
2325
2326/* Satisfy external references even if http2 is not compiled in. */
2327
2328#define CURL_DISABLE_TYPECHECK
2329#include <curl/curl.h>
2330
2331char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
2332{
2333 (void) h;
2334 (void) num;
2335 return NULL;
2336}
2337
2338char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
2339{
2340 (void) h;
2341 (void) header;
2342 return NULL;
2343}
2344
2345#endif /* USE_NGHTTP2 */