1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#ifdef USE_NGHTTP2
26#include <nghttp2/nghttp2.h>
27#include "urldata.h"
28#include "http2.h"
29#include "http.h"
30#include "sendf.h"
31#include "curl_base64.h"
32#include "rawstr.h"
33#include "multiif.h"
34#include "conncache.h"
35#include "url.h"
36#include "connect.h"
37#include "strtoofft.h"
38
39/* The last 3 #include files should be in this order */
40#include "curl_printf.h"
41#include "curl_memory.h"
42#include "memdebug.h"
43
44#define MIN(x,y) ((x)<(y)?(x):(y))
45
46#if (NGHTTP2_VERSION_NUM < 0x010000)
47#error too old nghttp2 version, upgrade!
48#endif
49
50#if (NGHTTP2_VERSION_NUM > 0x010800)
51#define NGHTTP2_HAS_HTTP2_STRERROR 1
52#endif
53
54#if (NGHTTP2_VERSION_NUM >= 0x010900)
55/* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or
56   later */
57#define NGHTTP2_HAS_ERROR_CALLBACK 1
58#else
59#define nghttp2_session_callbacks_set_error_callback(x,y)
60#endif
61
62/*
63 * Curl_http2_init_state() is called when the easy handle is created and
64 * allows for HTTP/2 specific init of state.
65 */
66void Curl_http2_init_state(struct UrlState *state)
67{
68  state->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
69}
70
71/*
72 * Curl_http2_init_userset() is called when the easy handle is created and
73 * allows for HTTP/2 specific user-set fields.
74 */
75void Curl_http2_init_userset(struct UserDefined *set)
76{
77  set->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
78}
79
80static int http2_perform_getsock(const struct connectdata *conn,
81                                 curl_socket_t *sock, /* points to
82                                                         numsocks
83                                                         number of
84                                                         sockets */
85                                 int numsocks)
86{
87  const struct http_conn *c = &conn->proto.httpc;
88  int bitmap = GETSOCK_BLANK;
89  (void)numsocks;
90
91  /* TODO We should check underlying socket state if it is SSL socket
92     because of renegotiation. */
93  sock[0] = conn->sock[FIRSTSOCKET];
94
95  if(nghttp2_session_want_read(c->h2))
96    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
97
98  if(nghttp2_session_want_write(c->h2))
99    bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
100
101  return bitmap;
102}
103
104static int http2_getsock(struct connectdata *conn,
105                         curl_socket_t *sock, /* points to numsocks
106                                                 number of sockets */
107                         int numsocks)
108{
109  return http2_perform_getsock(conn, sock, numsocks);
110}
111
112static CURLcode http2_disconnect(struct connectdata *conn,
113                                 bool dead_connection)
114{
115  struct HTTP *http = conn->data->req.protop;
116  struct http_conn *c = &conn->proto.httpc;
117  (void)dead_connection;
118
119  DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n"));
120
121  nghttp2_session_del(c->h2);
122  Curl_safefree(c->inbuf);
123
124  if(http) {
125    Curl_add_buffer_free(http->header_recvbuf);
126    http->header_recvbuf = NULL; /* clear the pointer */
127    Curl_add_buffer_free(http->trailer_recvbuf);
128    http->trailer_recvbuf = NULL; /* clear the pointer */
129    for(; http->push_headers_used > 0; --http->push_headers_used) {
130      free(http->push_headers[http->push_headers_used - 1]);
131    }
132    free(http->push_headers);
133    http->push_headers = NULL;
134  }
135
136  DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
137
138  return CURLE_OK;
139}
140
141/* called from Curl_http_setup_conn */
142void Curl_http2_setup_req(struct Curl_easy *data)
143{
144  struct HTTP *http = data->req.protop;
145
146  http->nread_header_recvbuf = 0;
147  http->bodystarted = FALSE;
148  http->status_code = -1;
149  http->pausedata = NULL;
150  http->pauselen = 0;
151  http->error_code = NGHTTP2_NO_ERROR;
152  http->closed = FALSE;
153  http->mem = data->state.buffer;
154  http->len = BUFSIZE;
155  http->memlen = 0;
156}
157
158/* called from Curl_http_setup_conn */
159void Curl_http2_setup_conn(struct connectdata *conn)
160{
161  conn->proto.httpc.settings.max_concurrent_streams =
162    DEFAULT_MAX_CONCURRENT_STREAMS;
163}
164
165/*
166 * HTTP2 handler interface. This isn't added to the general list of protocols
167 * but will be used at run-time when the protocol is dynamically switched from
168 * HTTP to HTTP2.
169 */
170const struct Curl_handler Curl_handler_http2 = {
171  "HTTP",                               /* scheme */
172  ZERO_NULL,                            /* setup_connection */
173  Curl_http,                            /* do_it */
174  Curl_http_done,                       /* done */
175  ZERO_NULL,                            /* do_more */
176  ZERO_NULL,                            /* connect_it */
177  ZERO_NULL,                            /* connecting */
178  ZERO_NULL,                            /* doing */
179  http2_getsock,                        /* proto_getsock */
180  http2_getsock,                        /* doing_getsock */
181  ZERO_NULL,                            /* domore_getsock */
182  http2_perform_getsock,                /* perform_getsock */
183  http2_disconnect,                     /* disconnect */
184  ZERO_NULL,                            /* readwrite */
185  PORT_HTTP,                            /* defport */
186  CURLPROTO_HTTP,                       /* protocol */
187  PROTOPT_NONE                          /* flags */
188};
189
190const struct Curl_handler Curl_handler_http2_ssl = {
191  "HTTPS",                              /* scheme */
192  ZERO_NULL,                            /* setup_connection */
193  Curl_http,                            /* do_it */
194  Curl_http_done,                       /* done */
195  ZERO_NULL,                            /* do_more */
196  ZERO_NULL,                            /* connect_it */
197  ZERO_NULL,                            /* connecting */
198  ZERO_NULL,                            /* doing */
199  http2_getsock,                        /* proto_getsock */
200  http2_getsock,                        /* doing_getsock */
201  ZERO_NULL,                            /* domore_getsock */
202  http2_perform_getsock,                /* perform_getsock */
203  http2_disconnect,                     /* disconnect */
204  ZERO_NULL,                            /* readwrite */
205  PORT_HTTP,                            /* defport */
206  CURLPROTO_HTTPS,                      /* protocol */
207  PROTOPT_SSL                           /* flags */
208};
209
210/*
211 * Store nghttp2 version info in this buffer, Prefix with a space.  Return
212 * total length written.
213 */
214int Curl_http2_ver(char *p, size_t len)
215{
216  nghttp2_info *h2 = nghttp2_version(0);
217  return snprintf(p, len, " nghttp2/%s", h2->version_str);
218}
219
220/* HTTP/2 error code to name based on the Error Code Registry.
221https://tools.ietf.org/html/rfc7540#page-77
222nghttp2_error_code enums are identical.
223*/
224const char *Curl_http2_strerror(uint32_t err) {
225#ifndef NGHTTP2_HAS_HTTP2_STRERROR
226  const char *str[] = {
227    "NO_ERROR",             /* 0x0 */
228    "PROTOCOL_ERROR",       /* 0x1 */
229    "INTERNAL_ERROR",       /* 0x2 */
230    "FLOW_CONTROL_ERROR",   /* 0x3 */
231    "SETTINGS_TIMEOUT",     /* 0x4 */
232    "STREAM_CLOSED",        /* 0x5 */
233    "FRAME_SIZE_ERROR",     /* 0x6 */
234    "REFUSED_STREAM",       /* 0x7 */
235    "CANCEL",               /* 0x8 */
236    "COMPRESSION_ERROR",    /* 0x9 */
237    "CONNECT_ERROR",        /* 0xA */
238    "ENHANCE_YOUR_CALM",    /* 0xB */
239    "INADEQUATE_SECURITY",  /* 0xC */
240    "HTTP_1_1_REQUIRED"     /* 0xD */
241  };
242  return (err < sizeof str / sizeof str[0]) ? str[err] : "unknown";
243#else
244  return nghttp2_http2_strerror(err);
245#endif
246}
247
248/*
249 * The implementation of nghttp2_send_callback type. Here we write |data| with
250 * size |length| to the network and return the number of bytes actually
251 * written. See the documentation of nghttp2_send_callback for the details.
252 */
253static ssize_t send_callback(nghttp2_session *h2,
254                             const uint8_t *data, size_t length, int flags,
255                             void *userp)
256{
257  struct connectdata *conn = (struct connectdata *)userp;
258  struct http_conn *c = &conn->proto.httpc;
259  ssize_t written;
260  CURLcode result = CURLE_OK;
261
262  (void)h2;
263  (void)flags;
264
265  written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET,
266                                             data, length, &result);
267
268  if(result == CURLE_AGAIN) {
269    return NGHTTP2_ERR_WOULDBLOCK;
270  }
271
272  if(written == -1) {
273    failf(conn->data, "Failed sending HTTP2 data");
274    return NGHTTP2_ERR_CALLBACK_FAILURE;
275  }
276
277  if(!written)
278    return NGHTTP2_ERR_WOULDBLOCK;
279
280  return written;
281}
282
283
284/* We pass a pointer to this struct in the push callback, but the contents of
285   the struct are hidden from the user. */
286struct curl_pushheaders {
287  struct Curl_easy *data;
288  const nghttp2_push_promise *frame;
289};
290
291/*
292 * push header access function. Only to be used from within the push callback
293 */
294char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
295{
296  /* Verify that we got a good easy handle in the push header struct, mostly to
297     detect rubbish input fast(er). */
298  if(!h || !GOOD_EASY_HANDLE(h->data))
299    return NULL;
300  else {
301    struct HTTP *stream = h->data->req.protop;
302    if(num < stream->push_headers_used)
303      return stream->push_headers[num];
304  }
305  return NULL;
306}
307
308/*
309 * push header access function. Only to be used from within the push callback
310 */
311char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
312{
313  /* Verify that we got a good easy handle in the push header struct,
314     mostly to detect rubbish input fast(er). Also empty header name
315     is just a rubbish too. We have to allow ":" at the beginning of
316     the header, but header == ":" must be rejected. If we have ':' in
317     the middle of header, it could be matched in middle of the value,
318     this is because we do prefix match.*/
319  if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] ||
320     Curl_raw_equal(header, ":") || strchr(header + 1, ':'))
321    return NULL;
322  else {
323    struct HTTP *stream = h->data->req.protop;
324    size_t len = strlen(header);
325    size_t i;
326    for(i=0; i<stream->push_headers_used; i++) {
327      if(!strncmp(header, stream->push_headers[i], len)) {
328        /* sub-match, make sure that it is followed by a colon */
329        if(stream->push_headers[i][len] != ':')
330          continue;
331        return &stream->push_headers[i][len+1];
332      }
333    }
334  }
335  return NULL;
336}
337
338static struct Curl_easy *duphandle(struct Curl_easy *data)
339{
340  struct Curl_easy *second = curl_easy_duphandle(data);
341  if(second) {
342    /* setup the request struct */
343    struct HTTP *http = calloc(1, sizeof(struct HTTP));
344    if(!http) {
345      (void)Curl_close(second);
346      second = NULL;
347    }
348    else {
349      second->req.protop = http;
350      http->header_recvbuf = Curl_add_buffer_init();
351      if(!http->header_recvbuf) {
352        free(http);
353        (void)Curl_close(second);
354        second = NULL;
355      }
356      else {
357        Curl_http2_setup_req(second);
358        second->state.stream_weight = data->state.stream_weight;
359      }
360    }
361  }
362  return second;
363}
364
365
366static int push_promise(struct Curl_easy *data,
367                        struct connectdata *conn,
368                        const nghttp2_push_promise *frame)
369{
370  int rv;
371  DEBUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
372               frame->promised_stream_id));
373  if(data->multi->push_cb) {
374    struct HTTP *stream;
375    struct HTTP *newstream;
376    struct curl_pushheaders heads;
377    CURLMcode rc;
378    struct http_conn *httpc;
379    size_t i;
380    /* clone the parent */
381    struct Curl_easy *newhandle = duphandle(data);
382    if(!newhandle) {
383      infof(data, "failed to duplicate handle\n");
384      rv = 1; /* FAIL HARD */
385      goto fail;
386    }
387
388    heads.data = data;
389    heads.frame = frame;
390    /* ask the application */
391    DEBUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
392
393    stream = data->req.protop;
394    if(!stream) {
395      failf(data, "Internal NULL stream!\n");
396      rv = 1;
397      goto fail;
398    }
399
400    rv = data->multi->push_cb(data, newhandle,
401                              stream->push_headers_used, &heads,
402                              data->multi->push_userp);
403
404    /* free the headers again */
405    for(i=0; i<stream->push_headers_used; i++)
406      free(stream->push_headers[i]);
407    free(stream->push_headers);
408    stream->push_headers = NULL;
409
410    if(rv) {
411      /* denied, kill off the new handle again */
412      (void)Curl_close(newhandle);
413      goto fail;
414    }
415
416    newstream = newhandle->req.protop;
417    newstream->stream_id = frame->promised_stream_id;
418    newhandle->req.maxdownload = -1;
419    newhandle->req.size = -1;
420
421    /* approved, add to the multi handle and immediately switch to PERFORM
422       state with the given connection !*/
423    rc = Curl_multi_add_perform(data->multi, newhandle, conn);
424    if(rc) {
425      infof(data, "failed to add handle to multi\n");
426      Curl_close(newhandle);
427      rv = 1;
428      goto fail;
429    }
430
431    httpc = &conn->proto.httpc;
432    nghttp2_session_set_stream_user_data(httpc->h2,
433                                         frame->promised_stream_id, newhandle);
434  }
435  else {
436    DEBUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
437    rv = 1;
438  }
439  fail:
440  return rv;
441}
442
443static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
444                         void *userp)
445{
446  struct connectdata *conn = (struct connectdata *)userp;
447  struct http_conn *httpc = &conn->proto.httpc;
448  struct Curl_easy *data_s = NULL;
449  struct HTTP *stream = NULL;
450  static int lastStream = -1;
451  int rv;
452  size_t left, ncopy;
453  int32_t stream_id = frame->hd.stream_id;
454
455  if(!stream_id) {
456    /* stream ID zero is for connection-oriented stuff */
457    if(frame->hd.type == NGHTTP2_SETTINGS) {
458      uint32_t max_conn = httpc->settings.max_concurrent_streams;
459      DEBUGF(infof(conn->data, "Got SETTINGS\n"));
460      httpc->settings.max_concurrent_streams =
461        nghttp2_session_get_remote_settings(
462          session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
463      httpc->settings.enable_push =
464        nghttp2_session_get_remote_settings(
465          session, NGHTTP2_SETTINGS_ENABLE_PUSH);
466      DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
467                   httpc->settings.max_concurrent_streams));
468      DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
469                   httpc->settings.enable_push?"TRUE":"false"));
470      if(max_conn != httpc->settings.max_concurrent_streams) {
471        /* only signal change if the value actually changed */
472        infof(conn->data,
473              "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
474        Curl_multi_connchanged(conn->data->multi);
475      }
476    }
477    return 0;
478  }
479  data_s = nghttp2_session_get_stream_user_data(session, stream_id);
480  if(lastStream != stream_id) {
481    lastStream = stream_id;
482  }
483  if(!data_s) {
484    DEBUGF(infof(conn->data,
485                 "No Curl_easy associated with stream: %x\n",
486                 stream_id));
487    return 0;
488  }
489
490  stream = data_s->req.protop;
491  if(!stream)
492    return NGHTTP2_ERR_CALLBACK_FAILURE;
493
494  DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
495               frame->hd.type, stream_id));
496
497  switch(frame->hd.type) {
498  case NGHTTP2_DATA:
499    /* If body started on this stream, then receiving DATA is illegal. */
500    if(!stream->bodystarted) {
501      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
502                                     stream_id, NGHTTP2_PROTOCOL_ERROR);
503
504      if(nghttp2_is_fatal(rv)) {
505        return NGHTTP2_ERR_CALLBACK_FAILURE;
506      }
507    }
508    break;
509  case NGHTTP2_HEADERS:
510    if(stream->bodystarted) {
511      /* Only valid HEADERS after body started is trailer HEADERS.  We
512         buffer them in on_header callback. */
513      break;
514    }
515
516    /* nghttp2 guarantees that :status is received, and we store it to
517       stream->status_code */
518    DEBUGASSERT(stream->status_code != -1);
519
520    /* Only final status code signals the end of header */
521    if(stream->status_code / 100 != 1) {
522      stream->bodystarted = TRUE;
523      stream->status_code = -1;
524    }
525
526    Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
527
528    left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
529    ncopy = MIN(stream->len, left);
530
531    memcpy(&stream->mem[stream->memlen],
532           stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
533           ncopy);
534    stream->nread_header_recvbuf += ncopy;
535
536    DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
537                 ncopy, stream_id, stream->mem));
538
539    stream->len -= ncopy;
540    stream->memlen += ncopy;
541
542    data_s->state.drain++;
543    httpc->drain_total++;
544    {
545      /* get the pointer from userp again since it was re-assigned above */
546      struct connectdata *conn_s = (struct connectdata *)userp;
547
548      /* if we receive data for another handle, wake that up */
549      if(conn_s->data != data_s)
550        Curl_expire(data_s, 1);
551    }
552    break;
553  case NGHTTP2_PUSH_PROMISE:
554    rv = push_promise(data_s, conn, &frame->push_promise);
555    if(rv) { /* deny! */
556      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
557                                     frame->push_promise.promised_stream_id,
558                                     NGHTTP2_CANCEL);
559      if(nghttp2_is_fatal(rv)) {
560        return rv;
561      }
562    }
563    break;
564  default:
565    DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n",
566                 frame->hd.type, stream_id));
567    break;
568  }
569  return 0;
570}
571
572static int on_invalid_frame_recv(nghttp2_session *session,
573                                 const nghttp2_frame *frame,
574                                 int lib_error_code, void *userp)
575{
576  struct Curl_easy *data_s = NULL;
577  (void)userp;
578
579  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
580  if(data_s) {
581    DEBUGF(infof(data_s,
582                 "on_invalid_frame_recv() was called, error=%d:%s\n",
583                 lib_error_code, nghttp2_strerror(lib_error_code)));
584  }
585  return 0;
586}
587
588static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
589                              int32_t stream_id,
590                              const uint8_t *data, size_t len, void *userp)
591{
592  struct HTTP *stream;
593  struct Curl_easy *data_s;
594  size_t nread;
595  struct connectdata *conn = (struct connectdata *)userp;
596  (void)session;
597  (void)flags;
598  (void)data;
599
600  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
601
602  /* get the stream from the hash based on Stream ID */
603  data_s = nghttp2_session_get_stream_user_data(session, stream_id);
604  if(!data_s)
605    /* Receiving a Stream ID not in the hash should not happen, this is an
606       internal error more than anything else! */
607    return NGHTTP2_ERR_CALLBACK_FAILURE;
608
609  stream = data_s->req.protop;
610  if(!stream)
611    return NGHTTP2_ERR_CALLBACK_FAILURE;
612
613  nread = MIN(stream->len, len);
614  memcpy(&stream->mem[stream->memlen], data, nread);
615
616  stream->len -= nread;
617  stream->memlen += nread;
618
619  data_s->state.drain++;
620  conn->proto.httpc.drain_total++;
621
622  /* if we receive data for another handle, wake that up */
623  if(conn->data != data_s)
624    Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for
625                               immediately? */
626
627  DEBUGF(infof(data_s, "%zu data received for stream %u "
628               "(%zu left in buffer %p, total %zu)\n",
629               nread, stream_id,
630               stream->len, stream->mem,
631               stream->memlen));
632
633  if(nread < len) {
634    stream->pausedata = data + nread;
635    stream->pauselen = len - nread;
636    DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
637                 ", stream %u\n",
638                 len - nread, stream_id));
639    data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
640
641    return NGHTTP2_ERR_PAUSE;
642  }
643
644  /* pause execution of nghttp2 if we received data for another handle
645     in order to process them first. */
646  if(conn->data != data_s) {
647    data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
648
649    return NGHTTP2_ERR_PAUSE;
650  }
651
652  return 0;
653}
654
655static int before_frame_send(nghttp2_session *session,
656                             const nghttp2_frame *frame,
657                             void *userp)
658{
659  struct Curl_easy *data_s;
660  (void)userp;
661
662  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
663  if(data_s) {
664    DEBUGF(infof(data_s, "before_frame_send() was called\n"));
665  }
666
667  return 0;
668}
669static int on_frame_send(nghttp2_session *session,
670                         const nghttp2_frame *frame,
671                         void *userp)
672{
673  struct Curl_easy *data_s;
674  (void)userp;
675
676  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
677  if(data_s) {
678    DEBUGF(infof(data_s, "on_frame_send() was called, length = %zd\n",
679                 frame->hd.length));
680  }
681  return 0;
682}
683static int on_frame_not_send(nghttp2_session *session,
684                             const nghttp2_frame *frame,
685                             int lib_error_code, void *userp)
686{
687  struct Curl_easy *data_s;
688  (void)userp;
689
690  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
691  if(data_s) {
692    DEBUGF(infof(data_s,
693                 "on_frame_not_send() was called, lib_error_code = %d\n",
694                 lib_error_code));
695  }
696  return 0;
697}
698static int on_stream_close(nghttp2_session *session, int32_t stream_id,
699                           uint32_t error_code, void *userp)
700{
701  struct Curl_easy *data_s;
702  struct HTTP *stream;
703  struct connectdata *conn = (struct connectdata *)userp;
704  (void)session;
705  (void)stream_id;
706
707  if(stream_id) {
708    /* get the stream from the hash based on Stream ID, stream ID zero is for
709       connection-oriented stuff */
710    data_s = nghttp2_session_get_stream_user_data(session, stream_id);
711    if(!data_s) {
712      /* We could get stream ID not in the hash.  For example, if we
713         decided to reject stream (e.g., PUSH_PROMISE). */
714      return 0;
715    }
716    DEBUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
717                 Curl_http2_strerror(error_code), error_code, stream_id));
718    stream = data_s->req.protop;
719    if(!stream)
720      return NGHTTP2_ERR_CALLBACK_FAILURE;
721
722    stream->error_code = error_code;
723    stream->closed = TRUE;
724    data_s->state.drain++;
725    conn->proto.httpc.drain_total++;
726
727    /* remove the entry from the hash as the stream is now gone */
728    nghttp2_session_set_stream_user_data(session, stream_id, 0);
729    DEBUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
730  }
731  return 0;
732}
733
734static int on_begin_headers(nghttp2_session *session,
735                            const nghttp2_frame *frame, void *userp)
736{
737  struct HTTP *stream;
738  struct Curl_easy *data_s = NULL;
739  (void)userp;
740
741  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
742  if(!data_s) {
743    return 0;
744  }
745
746  DEBUGF(infof(data_s, "on_begin_headers() was called\n"));
747
748  if(frame->hd.type != NGHTTP2_HEADERS) {
749    return 0;
750  }
751
752  stream = data_s->req.protop;
753  if(!stream || !stream->bodystarted) {
754    return 0;
755  }
756
757  /* This is trailer HEADERS started.  Allocate buffer for them. */
758  DEBUGF(infof(data_s, "trailer field started\n"));
759
760  assert(stream->trailer_recvbuf == NULL);
761
762  stream->trailer_recvbuf = Curl_add_buffer_init();
763  if(!stream->trailer_recvbuf) {
764    return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
765  }
766
767  return 0;
768}
769
770/* Decode HTTP status code.  Returns -1 if no valid status code was
771   decoded. */
772static int decode_status_code(const uint8_t *value, size_t len)
773{
774  int i;
775  int res;
776
777  if(len != 3) {
778    return -1;
779  }
780
781  res = 0;
782
783  for(i = 0; i < 3; ++i) {
784    char c = value[i];
785
786    if(c < '0' || c > '9') {
787      return -1;
788    }
789
790    res *= 10;
791    res += c - '0';
792  }
793
794  return res;
795}
796
797/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
798static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
799                     const uint8_t *name, size_t namelen,
800                     const uint8_t *value, size_t valuelen,
801                     uint8_t flags,
802                     void *userp)
803{
804  struct HTTP *stream;
805  struct Curl_easy *data_s;
806  int32_t stream_id = frame->hd.stream_id;
807  struct connectdata *conn = (struct connectdata *)userp;
808  (void)flags;
809
810  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
811
812  /* get the stream from the hash based on Stream ID */
813  data_s = nghttp2_session_get_stream_user_data(session, stream_id);
814  if(!data_s)
815    /* Receiving a Stream ID not in the hash should not happen, this is an
816       internal error more than anything else! */
817    return NGHTTP2_ERR_CALLBACK_FAILURE;
818
819  stream = data_s->req.protop;
820  if(!stream) {
821    failf(data_s, "Internal NULL stream! 5\n");
822    return NGHTTP2_ERR_CALLBACK_FAILURE;
823  }
824
825  /* Store received PUSH_PROMISE headers to be used when the subsequent
826     PUSH_PROMISE callback comes */
827  if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
828    char *h;
829
830    if(!stream->push_headers) {
831      stream->push_headers_alloc = 10;
832      stream->push_headers = malloc(stream->push_headers_alloc *
833                                    sizeof(char *));
834      stream->push_headers_used = 0;
835    }
836    else if(stream->push_headers_used ==
837            stream->push_headers_alloc) {
838      char **headp;
839      stream->push_headers_alloc *= 2;
840      headp = realloc(stream->push_headers,
841                      stream->push_headers_alloc * sizeof(char *));
842      if(!headp) {
843        free(stream->push_headers);
844        stream->push_headers = NULL;
845        return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
846      }
847      stream->push_headers = headp;
848    }
849    h = aprintf("%s:%s", name, value);
850    if(h)
851      stream->push_headers[stream->push_headers_used++] = h;
852    return 0;
853  }
854
855  if(stream->bodystarted) {
856    /* This is trailer fields. */
857    /* 3 is for ":" and "\r\n". */
858    uint32_t n = (uint32_t)(namelen + valuelen + 3);
859
860    DEBUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
861                 value));
862
863    Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n));
864    Curl_add_buffer(stream->trailer_recvbuf, name, namelen);
865    Curl_add_buffer(stream->trailer_recvbuf, ": ", 2);
866    Curl_add_buffer(stream->trailer_recvbuf, value, valuelen);
867    Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3);
868
869    return 0;
870  }
871
872  if(namelen == sizeof(":status") - 1 &&
873     memcmp(":status", name, namelen) == 0) {
874    /* nghttp2 guarantees :status is received first and only once, and
875       value is 3 digits status code, and decode_status_code always
876       succeeds. */
877    stream->status_code = decode_status_code(value, valuelen);
878    DEBUGASSERT(stream->status_code != -1);
879
880    Curl_add_buffer(stream->header_recvbuf, "HTTP/2 ", 7);
881    Curl_add_buffer(stream->header_recvbuf, value, valuelen);
882    /* the space character after the status code is mandatory */
883    Curl_add_buffer(stream->header_recvbuf, " \r\n", 3);
884    /* if we receive data for another handle, wake that up */
885    if(conn->data != data_s)
886      Curl_expire(data_s, 1);
887
888    DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
889                 stream->status_code, data_s));
890    return 0;
891  }
892
893  /* nghttp2 guarantees that namelen > 0, and :status was already
894     received, and this is not pseudo-header field . */
895  /* convert to a HTTP1-style header */
896  Curl_add_buffer(stream->header_recvbuf, name, namelen);
897  Curl_add_buffer(stream->header_recvbuf, ": ", 2);
898  Curl_add_buffer(stream->header_recvbuf, value, valuelen);
899  Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
900  /* if we receive data for another handle, wake that up */
901  if(conn->data != data_s)
902    Curl_expire(data_s, 1);
903
904  DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
905               value));
906
907  return 0; /* 0 is successful */
908}
909
910static ssize_t data_source_read_callback(nghttp2_session *session,
911                                         int32_t stream_id,
912                                         uint8_t *buf, size_t length,
913                                         uint32_t *data_flags,
914                                         nghttp2_data_source *source,
915                                         void *userp)
916{
917  struct Curl_easy *data_s;
918  struct HTTP *stream = NULL;
919  size_t nread;
920  (void)source;
921  (void)userp;
922
923  if(stream_id) {
924    /* get the stream from the hash based on Stream ID, stream ID zero is for
925       connection-oriented stuff */
926    data_s = nghttp2_session_get_stream_user_data(session, stream_id);
927    if(!data_s)
928      /* Receiving a Stream ID not in the hash should not happen, this is an
929         internal error more than anything else! */
930      return NGHTTP2_ERR_CALLBACK_FAILURE;
931
932    stream = data_s->req.protop;
933    if(!stream)
934      return NGHTTP2_ERR_CALLBACK_FAILURE;
935  }
936  else
937    return NGHTTP2_ERR_INVALID_ARGUMENT;
938
939  nread = MIN(stream->upload_len, length);
940  if(nread > 0) {
941    memcpy(buf, stream->upload_mem, nread);
942    stream->upload_mem += nread;
943    stream->upload_len -= nread;
944    stream->upload_left -= nread;
945  }
946
947  if(stream->upload_left == 0)
948    *data_flags = 1;
949  else if(nread == 0)
950    return NGHTTP2_ERR_DEFERRED;
951
952  DEBUGF(infof(data_s, "data_source_read_callback: "
953               "returns %zu bytes stream %u\n",
954               nread, stream_id));
955
956  return nread;
957}
958
959/*
960 * The HTTP2 settings we send in the Upgrade request
961 */
962static nghttp2_settings_entry settings[] = {
963  { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 },
964  { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, NGHTTP2_INITIAL_WINDOW_SIZE },
965};
966
967#define H2_BUFSIZE 32768
968
969#ifdef NGHTTP2_HAS_ERROR_CALLBACK
970static int error_callback(nghttp2_session *session,
971                          const char *msg,
972                          size_t len,
973                          void *userp)
974{
975  struct connectdata *conn = (struct connectdata *)userp;
976  (void)session;
977  infof(conn->data, "http2 error: %.*s\n", len, msg);
978  return 0;
979}
980#endif
981
982/*
983 * Initialize nghttp2 for a Curl connection
984 */
985CURLcode Curl_http2_init(struct connectdata *conn)
986{
987  if(!conn->proto.httpc.h2) {
988    int rc;
989    nghttp2_session_callbacks *callbacks;
990
991    conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
992    if(conn->proto.httpc.inbuf == NULL)
993      return CURLE_OUT_OF_MEMORY;
994
995    rc = nghttp2_session_callbacks_new(&callbacks);
996
997    if(rc) {
998      failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
999      return CURLE_OUT_OF_MEMORY; /* most likely at least */
1000    }
1001
1002    /* nghttp2_send_callback */
1003    nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
1004    /* nghttp2_on_frame_recv_callback */
1005    nghttp2_session_callbacks_set_on_frame_recv_callback
1006      (callbacks, on_frame_recv);
1007    /* nghttp2_on_invalid_frame_recv_callback */
1008    nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
1009      (callbacks, on_invalid_frame_recv);
1010    /* nghttp2_on_data_chunk_recv_callback */
1011    nghttp2_session_callbacks_set_on_data_chunk_recv_callback
1012      (callbacks, on_data_chunk_recv);
1013    /* nghttp2_before_frame_send_callback */
1014    nghttp2_session_callbacks_set_before_frame_send_callback
1015      (callbacks, before_frame_send);
1016    /* nghttp2_on_frame_send_callback */
1017    nghttp2_session_callbacks_set_on_frame_send_callback
1018      (callbacks, on_frame_send);
1019    /* nghttp2_on_frame_not_send_callback */
1020    nghttp2_session_callbacks_set_on_frame_not_send_callback
1021      (callbacks, on_frame_not_send);
1022    /* nghttp2_on_stream_close_callback */
1023    nghttp2_session_callbacks_set_on_stream_close_callback
1024      (callbacks, on_stream_close);
1025    /* nghttp2_on_begin_headers_callback */
1026    nghttp2_session_callbacks_set_on_begin_headers_callback
1027      (callbacks, on_begin_headers);
1028    /* nghttp2_on_header_callback */
1029    nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
1030
1031    nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
1032
1033    /* The nghttp2 session is not yet setup, do it */
1034    rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
1035
1036    nghttp2_session_callbacks_del(callbacks);
1037
1038    if(rc) {
1039      failf(conn->data, "Couldn't initialize nghttp2!");
1040      return CURLE_OUT_OF_MEMORY; /* most likely at least */
1041    }
1042  }
1043  return CURLE_OK;
1044}
1045
1046/*
1047 * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
1048 */
1049CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
1050                                    struct connectdata *conn)
1051{
1052  CURLcode result;
1053  ssize_t binlen;
1054  char *base64;
1055  size_t blen;
1056  struct SingleRequest *k = &conn->data->req;
1057  uint8_t *binsettings = conn->proto.httpc.binsettings;
1058
1059  /* As long as we have a fixed set of settings, we don't have to dynamically
1060   * figure out the base64 strings since it'll always be the same. However,
1061   * the settings will likely not be fixed every time in the future.
1062   */
1063
1064  /* this returns number of bytes it wrote */
1065  binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
1066                                         settings,
1067                                         sizeof(settings)/sizeof(settings[0]));
1068  if(!binlen) {
1069    failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
1070    return CURLE_FAILED_INIT;
1071  }
1072  conn->proto.httpc.binlen = binlen;
1073
1074  result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
1075                                 &base64, &blen);
1076  if(result)
1077    return result;
1078
1079  result = Curl_add_bufferf(req,
1080                            "Connection: Upgrade, HTTP2-Settings\r\n"
1081                            "Upgrade: %s\r\n"
1082                            "HTTP2-Settings: %s\r\n",
1083                            NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
1084  free(base64);
1085
1086  k->upgr101 = UPGR101_REQUESTED;
1087
1088  return result;
1089}
1090
1091/*
1092 * Returns nonzero if current HTTP/2 session should be closed.
1093 */
1094static int should_close_session(struct http_conn *httpc) {
1095  return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) &&
1096         !nghttp2_session_want_write(httpc->h2);
1097}
1098
1099static int h2_session_send(struct Curl_easy *data,
1100                           nghttp2_session *h2);
1101
1102/*
1103 * h2_process_pending_input() processes pending input left in
1104 * httpc->inbuf.  Then, call h2_session_send() to send pending data.
1105 * This function returns 0 if it succeeds, or -1 and error code will
1106 * be assigned to *err.
1107 */
1108static int h2_process_pending_input(struct Curl_easy *data,
1109                                    struct http_conn *httpc,
1110                                    CURLcode *err) {
1111  ssize_t nread;
1112  char *inbuf;
1113  ssize_t rv;
1114
1115  nread = httpc->inbuflen - httpc->nread_inbuf;
1116  inbuf = httpc->inbuf + httpc->nread_inbuf;
1117
1118  rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
1119  if(rv < 0) {
1120    failf(data,
1121          "h2_process_pending_input: nghttp2_session_mem_recv() returned "
1122          "%d:%s\n", rv, nghttp2_strerror((int)rv));
1123    *err = CURLE_RECV_ERROR;
1124    return -1;
1125  }
1126
1127  if(nread == rv) {
1128    DEBUGF(infof(data,
1129                 "h2_process_pending_input: All data in connection buffer "
1130                 "processed\n"));
1131    httpc->inbuflen = 0;
1132    httpc->nread_inbuf = 0;
1133  }
1134  else {
1135    httpc->nread_inbuf += rv;
1136    DEBUGF(infof(data,
1137                 "h2_process_pending_input: %zu bytes left in connection "
1138                 "buffer\n",
1139                 httpc->inbuflen - httpc->nread_inbuf));
1140  }
1141
1142  rv = h2_session_send(data, httpc->h2);
1143  if(rv != 0) {
1144    *err = CURLE_SEND_ERROR;
1145    return -1;
1146  }
1147
1148  if(should_close_session(httpc)) {
1149    DEBUGF(infof(data,
1150                 "h2_process_pending_input: nothing to do in this session\n"));
1151    *err = CURLE_HTTP2;
1152    return -1;
1153  }
1154
1155  return 0;
1156}
1157
1158static ssize_t http2_handle_stream_close(struct connectdata *conn,
1159                                         struct Curl_easy *data,
1160                                         struct HTTP *stream, CURLcode *err) {
1161  char *trailer_pos, *trailer_end;
1162  CURLcode result;
1163  struct http_conn *httpc = &conn->proto.httpc;
1164
1165  if(httpc->pause_stream_id == stream->stream_id) {
1166    httpc->pause_stream_id = 0;
1167  }
1168
1169  DEBUGASSERT(httpc->drain_total >= data->state.drain);
1170  httpc->drain_total -= data->state.drain;
1171  data->state.drain = 0;
1172
1173  if(httpc->pause_stream_id == 0) {
1174    if(h2_process_pending_input(data, httpc, err) != 0) {
1175      return -1;
1176    }
1177  }
1178
1179  DEBUGASSERT(data->state.drain == 0);
1180
1181  /* Reset to FALSE to prevent infinite loop in readwrite_data
1182   function. */
1183  stream->closed = FALSE;
1184  if(stream->error_code != NGHTTP2_NO_ERROR) {
1185    failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)",
1186          stream->stream_id, Curl_http2_strerror(stream->error_code),
1187          stream->error_code);
1188    *err = CURLE_HTTP2_STREAM;
1189    return -1;
1190  }
1191
1192  if(!stream->bodystarted) {
1193    failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
1194          " all response header fields, teated as error",
1195          stream->stream_id);
1196    *err = CURLE_HTTP2_STREAM;
1197    return -1;
1198  }
1199
1200  if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) {
1201    trailer_pos = stream->trailer_recvbuf->buffer;
1202    trailer_end = trailer_pos + stream->trailer_recvbuf->size_used;
1203
1204    for(; trailer_pos < trailer_end;) {
1205      uint32_t n;
1206      memcpy(&n, trailer_pos, sizeof(n));
1207      trailer_pos += sizeof(n);
1208
1209      result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n);
1210      if(result) {
1211        *err = result;
1212        return -1;
1213      }
1214
1215      trailer_pos += n + 1;
1216    }
1217  }
1218
1219  DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
1220  return 0;
1221}
1222
1223/*
1224 * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
1225 * and dependency to the peer. It also stores the updated values in the state
1226 * struct.
1227 */
1228
1229static void h2_pri_spec(struct Curl_easy *data,
1230                        nghttp2_priority_spec *pri_spec)
1231{
1232  struct HTTP *depstream = (data->set.stream_depends_on?
1233                            data->set.stream_depends_on->req.protop:NULL);
1234  int32_t depstream_id = depstream? depstream->stream_id:0;
1235  nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
1236                             data->set.stream_depends_e);
1237  data->state.stream_weight = data->set.stream_weight;
1238  data->state.stream_depends_e = data->set.stream_depends_e;
1239  data->state.stream_depends_on = data->set.stream_depends_on;
1240}
1241
1242/*
1243 * h2_session_send() checks if there's been an update in the priority /
1244 * dependency settings and if so it submits a PRIORITY frame with the updated
1245 * info.
1246 */
1247static int h2_session_send(struct Curl_easy *data,
1248                           nghttp2_session *h2)
1249{
1250  struct HTTP *stream = data->req.protop;
1251  if((data->set.stream_weight != data->state.stream_weight) ||
1252     (data->set.stream_depends_e != data->state.stream_depends_e) ||
1253     (data->set.stream_depends_on != data->state.stream_depends_on) ) {
1254    /* send new weight and/or dependency */
1255    nghttp2_priority_spec pri_spec;
1256    int rv;
1257
1258    h2_pri_spec(data, &pri_spec);
1259
1260    DEBUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
1261                 stream->stream_id, data));
1262    rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
1263                                 &pri_spec);
1264    if(rv)
1265      return rv;
1266  }
1267
1268  return nghttp2_session_send(h2);
1269}
1270
1271/*
1272 * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
1273 * a regular CURLcode value.
1274 */
1275static ssize_t http2_recv(struct connectdata *conn, int sockindex,
1276                          char *mem, size_t len, CURLcode *err)
1277{
1278  CURLcode result = CURLE_OK;
1279  ssize_t rv;
1280  ssize_t nread;
1281  struct http_conn *httpc = &conn->proto.httpc;
1282  struct Curl_easy *data = conn->data;
1283  struct HTTP *stream = data->req.protop;
1284
1285  (void)sockindex; /* we always do HTTP2 on sockindex 0 */
1286
1287  if(should_close_session(httpc)) {
1288    DEBUGF(infof(data,
1289                 "http2_recv: nothing to do in this session\n"));
1290    *err = CURLE_HTTP2;
1291    return -1;
1292  }
1293
1294  /* Nullify here because we call nghttp2_session_send() and they
1295     might refer to the old buffer. */
1296  stream->upload_mem = NULL;
1297  stream->upload_len = 0;
1298
1299  /*
1300   * At this point 'stream' is just in the Curl_easy the connection
1301   * identifies as its owner at this time.
1302   */
1303
1304  if(stream->bodystarted &&
1305     stream->nread_header_recvbuf < stream->header_recvbuf->size_used) {
1306    /* If there is body data pending for this stream to return, do that */
1307    size_t left =
1308      stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
1309    size_t ncopy = MIN(len, left);
1310    memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
1311           ncopy);
1312    stream->nread_header_recvbuf += ncopy;
1313
1314    DEBUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
1315                 (int)ncopy));
1316    return ncopy;
1317  }
1318
1319  DEBUGF(infof(data, "http2_recv: easy %p (stream %u)\n",
1320               data, stream->stream_id));
1321
1322  if((data->state.drain) && stream->memlen) {
1323    DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
1324                 stream->memlen, stream->stream_id,
1325                 stream->mem, mem));
1326    if(mem != stream->mem) {
1327      /* if we didn't get the same buffer this time, we must move the data to
1328         the beginning */
1329      memmove(mem, stream->mem, stream->memlen);
1330      stream->len = len - stream->memlen;
1331      stream->mem = mem;
1332    }
1333    if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) {
1334      /* We have paused nghttp2, but we have no pause data (see
1335         on_data_chunk_recv). */
1336      httpc->pause_stream_id = 0;
1337      if(h2_process_pending_input(data, httpc, &result) != 0) {
1338        *err = result;
1339        return -1;
1340      }
1341    }
1342  }
1343  else if(stream->pausedata) {
1344    DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
1345    nread = MIN(len, stream->pauselen);
1346    memcpy(mem, stream->pausedata, nread);
1347
1348    stream->pausedata += nread;
1349    stream->pauselen -= nread;
1350
1351    infof(data, "%zu data bytes written\n", nread);
1352    if(stream->pauselen == 0) {
1353      DEBUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
1354      assert(httpc->pause_stream_id == stream->stream_id);
1355      httpc->pause_stream_id = 0;
1356
1357      stream->pausedata = NULL;
1358      stream->pauselen = 0;
1359
1360      /* When NGHTTP2_ERR_PAUSE is returned from
1361         data_source_read_callback, we might not process DATA frame
1362         fully.  Calling nghttp2_session_mem_recv() again will
1363         continue to process DATA frame, but if there is no incoming
1364         frames, then we have to call it again with 0-length data.
1365         Without this, on_stream_close callback will not be called,
1366         and stream could be hanged. */
1367      if(h2_process_pending_input(data, httpc, &result) != 0) {
1368        *err = result;
1369        return -1;
1370      }
1371    }
1372    DEBUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
1373                 nread, stream->stream_id));
1374    return nread;
1375  }
1376  else if(httpc->pause_stream_id) {
1377    /* If a stream paused nghttp2_session_mem_recv previously, and has
1378       not processed all data, it still refers to the buffer in
1379       nghttp2_session.  If we call nghttp2_session_mem_recv(), we may
1380       overwrite that buffer.  To avoid that situation, just return
1381       here with CURLE_AGAIN.  This could be busy loop since data in
1382       socket is not read.  But it seems that usually streams are
1383       notified with its drain property, and socket is read again
1384       quickly. */
1385    *err = CURLE_AGAIN;
1386    return -1;
1387  }
1388  else {
1389    char *inbuf;
1390    /* remember where to store incoming data for this stream and how big the
1391       buffer is */
1392    stream->mem = mem;
1393    stream->len = len;
1394    stream->memlen = 0;
1395
1396    if(httpc->inbuflen == 0) {
1397      nread = ((Curl_recv *)httpc->recv_underlying)(
1398          conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
1399
1400      if(nread == -1) {
1401        if(result != CURLE_AGAIN)
1402          failf(data, "Failed receiving HTTP2 data");
1403        else if(stream->closed)
1404          /* received when the stream was already closed! */
1405          return http2_handle_stream_close(conn, data, stream, err);
1406
1407        *err = result;
1408        return -1;
1409      }
1410
1411      if(nread == 0) {
1412        failf(data, "Unexpected EOF");
1413        *err = CURLE_RECV_ERROR;
1414        return -1;
1415      }
1416
1417      DEBUGF(infof(data, "nread=%zd\n", nread));
1418
1419      httpc->inbuflen = nread;
1420      inbuf = httpc->inbuf;
1421    }
1422    else {
1423      nread = httpc->inbuflen - httpc->nread_inbuf;
1424      inbuf = httpc->inbuf + httpc->nread_inbuf;
1425
1426      DEBUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
1427                   nread));
1428    }
1429    rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
1430
1431    if(nghttp2_is_fatal((int)rv)) {
1432      failf(data, "nghttp2_session_mem_recv() returned %d:%s\n",
1433            rv, nghttp2_strerror((int)rv));
1434      *err = CURLE_RECV_ERROR;
1435      return 0;
1436    }
1437    DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
1438    if(nread == rv) {
1439      DEBUGF(infof(data, "All data in connection buffer processed\n"));
1440      httpc->inbuflen = 0;
1441      httpc->nread_inbuf = 0;
1442    }
1443    else {
1444      httpc->nread_inbuf += rv;
1445      DEBUGF(infof(data, "%zu bytes left in connection buffer\n",
1446                   httpc->inbuflen - httpc->nread_inbuf));
1447    }
1448    /* Always send pending frames in nghttp2 session, because
1449       nghttp2_session_mem_recv() may queue new frame */
1450    rv = h2_session_send(data, httpc->h2);
1451    if(rv != 0) {
1452      *err = CURLE_SEND_ERROR;
1453      return 0;
1454    }
1455
1456    if(should_close_session(httpc)) {
1457      DEBUGF(infof(data, "http2_recv: nothing to do in this session\n"));
1458      *err = CURLE_HTTP2;
1459      return -1;
1460    }
1461  }
1462  if(stream->memlen) {
1463    ssize_t retlen = stream->memlen;
1464    DEBUGF(infof(data, "http2_recv: returns %zd for stream %u\n",
1465                 retlen, stream->stream_id));
1466    stream->memlen = 0;
1467
1468    if(httpc->pause_stream_id == stream->stream_id) {
1469      /* data for this stream is returned now, but this stream caused a pause
1470         already so we need it called again asap */
1471      DEBUGF(infof(data, "Data returned for PAUSED stream %u\n",
1472                   stream->stream_id));
1473    }
1474    else if(!stream->closed) {
1475      DEBUGASSERT(httpc->drain_total >= data->state.drain);
1476      httpc->drain_total -= data->state.drain;
1477      data->state.drain = 0; /* this stream is hereby drained */
1478    }
1479
1480    return retlen;
1481  }
1482  /* If stream is closed, return 0 to signal the http routine to close
1483     the connection */
1484  if(stream->closed) {
1485    return http2_handle_stream_close(conn, data, stream, err);
1486  }
1487  *err = CURLE_AGAIN;
1488  DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
1489               stream->stream_id));
1490  return -1;
1491}
1492
1493/* Index where :authority header field will appear in request header
1494   field list. */
1495#define AUTHORITY_DST_IDX 3
1496
1497#define HEADER_OVERFLOW(x) \
1498  (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen)
1499
1500/* return number of received (decrypted) bytes */
1501static ssize_t http2_send(struct connectdata *conn, int sockindex,
1502                          const void *mem, size_t len, CURLcode *err)
1503{
1504  /*
1505   * BIG TODO: Currently, we send request in this function, but this
1506   * function is also used to send request body. It would be nice to
1507   * add dedicated function for request.
1508   */
1509  int rv;
1510  struct http_conn *httpc = &conn->proto.httpc;
1511  struct HTTP *stream = conn->data->req.protop;
1512  nghttp2_nv *nva = NULL;
1513  size_t nheader;
1514  size_t i;
1515  size_t authority_idx;
1516  char *hdbuf = (char*)mem;
1517  char *end, *line_end;
1518  nghttp2_data_provider data_prd;
1519  int32_t stream_id;
1520  nghttp2_session *h2 = httpc->h2;
1521  nghttp2_priority_spec pri_spec;
1522
1523  (void)sockindex;
1524
1525  DEBUGF(infof(conn->data, "http2_send len=%zu\n", len));
1526
1527  if(stream->stream_id != -1) {
1528    /* If stream_id != -1, we have dispatched request HEADERS, and now
1529       are going to send or sending request body in DATA frame */
1530    stream->upload_mem = mem;
1531    stream->upload_len = len;
1532    nghttp2_session_resume_data(h2, stream->stream_id);
1533    rv = h2_session_send(conn->data, h2);
1534    if(nghttp2_is_fatal(rv)) {
1535      *err = CURLE_SEND_ERROR;
1536      return -1;
1537    }
1538    len -= stream->upload_len;
1539
1540    /* Nullify here because we call nghttp2_session_send() and they
1541       might refer to the old buffer. */
1542    stream->upload_mem = NULL;
1543    stream->upload_len = 0;
1544
1545    if(should_close_session(httpc)) {
1546      DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
1547      *err = CURLE_HTTP2;
1548      return -1;
1549    }
1550
1551    if(stream->upload_left) {
1552      /* we are sure that we have more data to send here.  Calling the
1553         following API will make nghttp2_session_want_write() return
1554         nonzero if remote window allows it, which then libcurl checks
1555         socket is writable or not.  See http2_perform_getsock(). */
1556      nghttp2_session_resume_data(h2, stream->stream_id);
1557    }
1558
1559    DEBUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len,
1560                 stream->stream_id));
1561    return len;
1562  }
1563
1564  /* Calculate number of headers contained in [mem, mem + len) */
1565  /* Here, we assume the curl http code generate *correct* HTTP header
1566     field block */
1567  nheader = 0;
1568  for(i = 1; i < len; ++i) {
1569    if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
1570      ++nheader;
1571      ++i;
1572    }
1573  }
1574  if(nheader < 2)
1575    goto fail;
1576
1577  /* We counted additional 2 \r\n in the first and last line. We need 3
1578     new headers: :method, :path and :scheme. Therefore we need one
1579     more space. */
1580  nheader += 1;
1581  nva = malloc(sizeof(nghttp2_nv) * nheader);
1582  if(nva == NULL) {
1583    *err = CURLE_OUT_OF_MEMORY;
1584    return -1;
1585  }
1586
1587  /* Extract :method, :path from request line */
1588  line_end = strstr(hdbuf, "\r\n");
1589
1590  /* Method does not contain spaces */
1591  end = memchr(hdbuf, ' ', line_end - hdbuf);
1592  if(!end || end == hdbuf)
1593    goto fail;
1594  nva[0].name = (unsigned char *)":method";
1595  nva[0].namelen = strlen((char *)nva[0].name);
1596  nva[0].value = (unsigned char *)hdbuf;
1597  nva[0].valuelen = (size_t)(end - hdbuf);
1598  nva[0].flags = NGHTTP2_NV_FLAG_NONE;
1599  if(HEADER_OVERFLOW(nva[0])) {
1600    failf(conn->data, "Failed sending HTTP request: Header overflow");
1601    goto fail;
1602  }
1603
1604  hdbuf = end + 1;
1605
1606  /* Path may contain spaces so scan backwards */
1607  end = NULL;
1608  for(i = (size_t)(line_end - hdbuf); i; --i) {
1609    if(hdbuf[i - 1] == ' ') {
1610      end = &hdbuf[i - 1];
1611      break;
1612    }
1613  }
1614  if(!end || end == hdbuf)
1615    goto fail;
1616  nva[1].name = (unsigned char *)":path";
1617  nva[1].namelen = strlen((char *)nva[1].name);
1618  nva[1].value = (unsigned char *)hdbuf;
1619  nva[1].valuelen = (size_t)(end - hdbuf);
1620  nva[1].flags = NGHTTP2_NV_FLAG_NONE;
1621  if(HEADER_OVERFLOW(nva[1])) {
1622    failf(conn->data, "Failed sending HTTP request: Header overflow");
1623    goto fail;
1624  }
1625
1626  hdbuf = end + 1;
1627
1628  end = line_end;
1629  nva[2].name = (unsigned char *)":scheme";
1630  nva[2].namelen = strlen((char *)nva[2].name);
1631  if(conn->handler->flags & PROTOPT_SSL)
1632    nva[2].value = (unsigned char *)"https";
1633  else
1634    nva[2].value = (unsigned char *)"http";
1635  nva[2].valuelen = strlen((char *)nva[2].value);
1636  nva[2].flags = NGHTTP2_NV_FLAG_NONE;
1637  if(HEADER_OVERFLOW(nva[2])) {
1638    failf(conn->data, "Failed sending HTTP request: Header overflow");
1639    goto fail;
1640  }
1641
1642  authority_idx = 0;
1643  i = 3;
1644  while(i < nheader) {
1645    size_t hlen;
1646    int skip = 0;
1647
1648    hdbuf = line_end + 2;
1649
1650    line_end = strstr(hdbuf, "\r\n");
1651    if(line_end == hdbuf)
1652      goto fail;
1653
1654    /* header continuation lines are not supported */
1655    if(*hdbuf == ' ' || *hdbuf == '\t')
1656      goto fail;
1657
1658    for(end = hdbuf; end < line_end && *end != ':'; ++end)
1659      ;
1660    if(end == hdbuf || end == line_end)
1661      goto fail;
1662    hlen = end - hdbuf;
1663
1664    if(hlen == 10 && Curl_raw_nequal("connection", hdbuf, 10)) {
1665      /* skip Connection: headers! */
1666      skip = 1;
1667      --nheader;
1668    }
1669    else if(hlen == 4 && Curl_raw_nequal("host", hdbuf, 4)) {
1670      authority_idx = i;
1671      nva[i].name = (unsigned char *)":authority";
1672      nva[i].namelen = strlen((char *)nva[i].name);
1673    }
1674    else {
1675      nva[i].name = (unsigned char *)hdbuf;
1676      nva[i].namelen = (size_t)(end - hdbuf);
1677    }
1678    hdbuf = end + 1;
1679    while(*hdbuf == ' ' || *hdbuf == '\t')
1680      ++hdbuf;
1681    end = line_end;
1682    if(!skip) {
1683      nva[i].value = (unsigned char *)hdbuf;
1684      nva[i].valuelen = (size_t)(end - hdbuf);
1685      nva[i].flags = NGHTTP2_NV_FLAG_NONE;
1686      if(HEADER_OVERFLOW(nva[i])) {
1687        failf(conn->data, "Failed sending HTTP request: Header overflow");
1688        goto fail;
1689      }
1690      /* Inspect Content-Length header field and retrieve the request
1691         entity length so that we can set END_STREAM to the last DATA
1692         frame. */
1693      if(nva[i].namelen == 14 &&
1694         Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) {
1695        size_t j;
1696        stream->upload_left = 0;
1697        if(!nva[i].valuelen)
1698          goto fail;
1699        for(j = 0; j < nva[i].valuelen; ++j) {
1700          if(nva[i].value[j] < '0' || nva[i].value[j] > '9')
1701            goto fail;
1702          if(stream->upload_left >= CURL_OFF_T_MAX / 10)
1703            goto fail;
1704          stream->upload_left *= 10;
1705          stream->upload_left += nva[i].value[j] - '0';
1706        }
1707        DEBUGF(infof(conn->data,
1708                     "request content-length=%"
1709                     CURL_FORMAT_CURL_OFF_T
1710                     "\n", stream->upload_left));
1711      }
1712      ++i;
1713    }
1714  }
1715
1716  /* :authority must come before non-pseudo header fields */
1717  if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
1718    nghttp2_nv authority = nva[authority_idx];
1719    for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
1720      nva[i] = nva[i - 1];
1721    }
1722    nva[i] = authority;
1723  }
1724
1725  /* Warn stream may be rejected if cumulative length of headers is too large.
1726     It appears nghttp2 will not send a header frame larger than 64KB. */
1727  {
1728    size_t acc = 0;
1729    const size_t max_acc = 60000;  /* <64KB to account for some overhead */
1730
1731    for(i = 0; i < nheader; ++i) {
1732      if(nva[i].namelen > max_acc - acc)
1733        break;
1734      acc += nva[i].namelen;
1735
1736      if(nva[i].valuelen > max_acc - acc)
1737        break;
1738      acc += nva[i].valuelen;
1739    }
1740
1741    if(i != nheader) {
1742      infof(conn->data, "http2_send: Warning: The cumulative length of all "
1743                        "headers exceeds %zu bytes and that could cause the "
1744                        "stream to be rejected.\n", max_acc);
1745    }
1746  }
1747
1748  h2_pri_spec(conn->data, &pri_spec);
1749
1750  switch(conn->data->set.httpreq) {
1751  case HTTPREQ_POST:
1752  case HTTPREQ_POST_FORM:
1753  case HTTPREQ_PUT:
1754    data_prd.read_callback = data_source_read_callback;
1755    data_prd.source.ptr = NULL;
1756    stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
1757                                       &data_prd, conn->data);
1758    break;
1759  default:
1760    stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
1761                                       NULL, conn->data);
1762  }
1763
1764  Curl_safefree(nva);
1765
1766  if(stream_id < 0) {
1767    DEBUGF(infof(conn->data, "http2_send() send error\n"));
1768    *err = CURLE_SEND_ERROR;
1769    return -1;
1770  }
1771
1772  infof(conn->data, "Using Stream ID: %x (easy handle %p)\n",
1773        stream_id, conn->data);
1774  stream->stream_id = stream_id;
1775
1776  /* this does not call h2_session_send() since there can not have been any
1777   * priority upodate since the nghttp2_submit_request() call above */
1778  rv = nghttp2_session_send(h2);
1779
1780  if(rv != 0) {
1781    *err = CURLE_SEND_ERROR;
1782    return -1;
1783  }
1784
1785  if(should_close_session(httpc)) {
1786    DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
1787    *err = CURLE_HTTP2;
1788    return -1;
1789  }
1790
1791  if(stream->stream_id != -1) {
1792    /* If whole HEADERS frame was sent off to the underlying socket,
1793       the nghttp2 library calls data_source_read_callback. But only
1794       it found that no data available, so it deferred the DATA
1795       transmission. Which means that nghttp2_session_want_write()
1796       returns 0 on http2_perform_getsock(), which results that no
1797       writable socket check is performed. To workaround this, we
1798       issue nghttp2_session_resume_data() here to bring back DATA
1799       transmission from deferred state. */
1800    nghttp2_session_resume_data(h2, stream->stream_id);
1801  }
1802
1803  return len;
1804
1805fail:
1806  free(nva);
1807  *err = CURLE_SEND_ERROR;
1808  return -1;
1809}
1810
1811CURLcode Curl_http2_setup(struct connectdata *conn)
1812{
1813  CURLcode result;
1814  struct http_conn *httpc = &conn->proto.httpc;
1815  struct HTTP *stream = conn->data->req.protop;
1816
1817  stream->stream_id = -1;
1818
1819  if(!stream->header_recvbuf)
1820    stream->header_recvbuf = Curl_add_buffer_init();
1821
1822  if((conn->handler == &Curl_handler_http2_ssl) ||
1823     (conn->handler == &Curl_handler_http2))
1824    return CURLE_OK; /* already done */
1825
1826  if(conn->handler->flags & PROTOPT_SSL)
1827    conn->handler = &Curl_handler_http2_ssl;
1828  else
1829    conn->handler = &Curl_handler_http2;
1830
1831  result = Curl_http2_init(conn);
1832  if(result)
1833    return result;
1834
1835  infof(conn->data, "Using HTTP2, server supports multi-use\n");
1836  stream->upload_left = 0;
1837  stream->upload_mem = NULL;
1838  stream->upload_len = 0;
1839
1840  httpc->inbuflen = 0;
1841  httpc->nread_inbuf = 0;
1842
1843  httpc->pause_stream_id = 0;
1844  httpc->drain_total = 0;
1845
1846  conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
1847  conn->httpversion = 20;
1848  conn->bundle->multiuse = BUNDLE_MULTIPLEX;
1849
1850  infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
1851  Curl_multi_connchanged(conn->data->multi);
1852
1853  /* switch on TCP_NODELAY as we need to send off packets without delay for
1854     maximum throughput */
1855  Curl_tcpnodelay(conn, conn->sock[FIRSTSOCKET]);
1856
1857  return CURLE_OK;
1858}
1859
1860CURLcode Curl_http2_switched(struct connectdata *conn,
1861                             const char *mem, size_t nread)
1862{
1863  CURLcode result;
1864  struct http_conn *httpc = &conn->proto.httpc;
1865  int rv;
1866  ssize_t nproc;
1867  struct Curl_easy *data = conn->data;
1868  struct HTTP *stream = conn->data->req.protop;
1869
1870  result = Curl_http2_setup(conn);
1871  if(result)
1872    return result;
1873
1874  httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
1875  httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
1876  conn->recv[FIRSTSOCKET] = http2_recv;
1877  conn->send[FIRSTSOCKET] = http2_send;
1878
1879  if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
1880    /* stream 1 is opened implicitly on upgrade */
1881    stream->stream_id = 1;
1882    /* queue SETTINGS frame (again) */
1883    rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
1884                                 httpc->binlen, NULL);
1885    if(rv != 0) {
1886      failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
1887            nghttp2_strerror(rv), rv);
1888      return CURLE_HTTP2;
1889    }
1890
1891    nghttp2_session_set_stream_user_data(httpc->h2,
1892                                         stream->stream_id,
1893                                         conn->data);
1894  }
1895  else {
1896    /* stream ID is unknown at this point */
1897    stream->stream_id = -1;
1898    rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0);
1899    if(rv != 0) {
1900      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
1901            nghttp2_strerror(rv), rv);
1902      return CURLE_HTTP2;
1903    }
1904  }
1905
1906  /* we are going to copy mem to httpc->inbuf.  This is required since
1907     mem is part of buffer pointed by stream->mem, and callbacks
1908     called by nghttp2_session_mem_recv() will write stream specific
1909     data into stream->mem, overwriting data already there. */
1910  if(H2_BUFSIZE < nread) {
1911    failf(data, "connection buffer size is too small to store data following "
1912                "HTTP Upgrade response header: buflen=%zu, datalen=%zu",
1913          H2_BUFSIZE, nread);
1914    return CURLE_HTTP2;
1915  }
1916
1917  infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer"
1918                    " after upgrade: len=%zu\n",
1919        nread);
1920
1921  memcpy(httpc->inbuf, mem, nread);
1922  httpc->inbuflen = nread;
1923
1924  nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf,
1925                                   httpc->inbuflen);
1926
1927  if(nghttp2_is_fatal((int)nproc)) {
1928    failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
1929          nghttp2_strerror((int)nproc), (int)nproc);
1930    return CURLE_HTTP2;
1931  }
1932
1933  DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));
1934
1935  if((ssize_t)nread == nproc) {
1936    httpc->inbuflen = 0;
1937    httpc->nread_inbuf = 0;
1938  }
1939  else {
1940    httpc->nread_inbuf += nproc;
1941  }
1942
1943  /* Try to send some frames since we may read SETTINGS already. */
1944  rv = h2_session_send(data, httpc->h2);
1945
1946  if(rv != 0) {
1947    failf(data, "nghttp2_session_send() failed: %s(%d)",
1948          nghttp2_strerror(rv), rv);
1949    return CURLE_HTTP2;
1950  }
1951
1952  if(should_close_session(httpc)) {
1953    DEBUGF(infof(data,
1954                 "nghttp2_session_send(): nothing to do in this session\n"));
1955    return CURLE_HTTP2;
1956  }
1957
1958  return CURLE_OK;
1959}
1960
1961#else /* !USE_NGHTTP2 */
1962
1963/* Satisfy external references even if http2 is not compiled in. */
1964
1965#define CURL_DISABLE_TYPECHECK
1966#include <curl/curl.h>
1967
1968char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
1969{
1970  (void) h;
1971  (void) num;
1972  return NULL;
1973}
1974
1975char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
1976{
1977  (void) h;
1978  (void) header;
1979  return NULL;
1980}
1981
1982#endif /* USE_NGHTTP2 */
1983