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