Update to 7.44.0
[platform/upstream/curl.git] / lib / http2.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2015, 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 http://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 "curl_printf.h"
27 #include <nghttp2/nghttp2.h>
28 #include "urldata.h"
29 #include "http2.h"
30 #include "http.h"
31 #include "sendf.h"
32 #include "curl_base64.h"
33 #include "rawstr.h"
34 #include "multiif.h"
35 #include "conncache.h"
36 #include "url.h"
37
38 /* The last #include files should be: */
39 #include "curl_memory.h"
40 #include "memdebug.h"
41
42 #define MIN(x,y) ((x)<(y)?(x):(y))
43
44 #if (NGHTTP2_VERSION_NUM < 0x000600)
45 #error too old nghttp2 version, upgrade!
46 #endif
47
48 static int http2_perform_getsock(const struct connectdata *conn,
49                                  curl_socket_t *sock, /* points to
50                                                          numsocks
51                                                          number of
52                                                          sockets */
53                                  int numsocks)
54 {
55   const struct http_conn *c = &conn->proto.httpc;
56   int bitmap = GETSOCK_BLANK;
57   (void)numsocks;
58
59   /* TODO We should check underlying socket state if it is SSL socket
60      because of renegotiation. */
61   sock[0] = conn->sock[FIRSTSOCKET];
62
63   if(nghttp2_session_want_read(c->h2))
64     bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
65
66   if(nghttp2_session_want_write(c->h2))
67     bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
68
69   return bitmap;
70 }
71
72 static int http2_getsock(struct connectdata *conn,
73                          curl_socket_t *sock, /* points to numsocks
74                                                  number of sockets */
75                          int numsocks)
76 {
77   return http2_perform_getsock(conn, sock, numsocks);
78 }
79
80 static CURLcode http2_disconnect(struct connectdata *conn,
81                                  bool dead_connection)
82 {
83   struct HTTP *http = conn->data->req.protop;
84   struct http_conn *c = &conn->proto.httpc;
85   (void)dead_connection;
86
87   DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n"));
88
89   nghttp2_session_del(c->h2);
90   Curl_safefree(c->inbuf);
91
92   if(http) {
93     Curl_add_buffer_free(http->header_recvbuf);
94     http->header_recvbuf = NULL; /* clear the pointer */
95     for(; http->push_headers_used > 0; --http->push_headers_used) {
96       free(http->push_headers[http->push_headers_used - 1]);
97     }
98     free(http->push_headers);
99     http->push_headers = NULL;
100   }
101
102   DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
103
104   return CURLE_OK;
105 }
106
107 /* called from Curl_http_setup_conn */
108 void Curl_http2_setup_req(struct SessionHandle *data)
109 {
110   struct HTTP *http = data->req.protop;
111
112   http->nread_header_recvbuf = 0;
113   http->bodystarted = FALSE;
114   http->status_code = -1;
115   http->pausedata = NULL;
116   http->pauselen = 0;
117   http->error_code = NGHTTP2_NO_ERROR;
118   http->closed = FALSE;
119   http->mem = data->state.buffer;
120   http->len = BUFSIZE;
121   http->memlen = 0;
122 }
123
124 /* called from Curl_http_setup_conn */
125 void Curl_http2_setup_conn(struct connectdata *conn)
126 {
127   conn->proto.httpc.settings.max_concurrent_streams =
128     DEFAULT_MAX_CONCURRENT_STREAMS;
129 }
130
131 /*
132  * HTTP2 handler interface. This isn't added to the general list of protocols
133  * but will be used at run-time when the protocol is dynamically switched from
134  * HTTP to HTTP2.
135  */
136 const struct Curl_handler Curl_handler_http2 = {
137   "HTTP2",                              /* scheme */
138   ZERO_NULL,                            /* setup_connection */
139   Curl_http,                            /* do_it */
140   Curl_http_done,                       /* done */
141   ZERO_NULL,                            /* do_more */
142   ZERO_NULL,                            /* connect_it */
143   ZERO_NULL,                            /* connecting */
144   ZERO_NULL,                            /* doing */
145   http2_getsock,                        /* proto_getsock */
146   http2_getsock,                        /* doing_getsock */
147   ZERO_NULL,                            /* domore_getsock */
148   http2_perform_getsock,                /* perform_getsock */
149   http2_disconnect,                     /* disconnect */
150   ZERO_NULL,                            /* readwrite */
151   PORT_HTTP,                            /* defport */
152   CURLPROTO_HTTP,                       /* protocol */
153   PROTOPT_NONE                          /* flags */
154 };
155
156 const struct Curl_handler Curl_handler_http2_ssl = {
157   "HTTP2",                              /* scheme */
158   ZERO_NULL,                            /* setup_connection */
159   Curl_http,                            /* do_it */
160   Curl_http_done,                       /* done */
161   ZERO_NULL,                            /* do_more */
162   ZERO_NULL,                            /* connect_it */
163   ZERO_NULL,                            /* connecting */
164   ZERO_NULL,                            /* doing */
165   http2_getsock,                        /* proto_getsock */
166   http2_getsock,                        /* doing_getsock */
167   ZERO_NULL,                            /* domore_getsock */
168   http2_perform_getsock,                /* perform_getsock */
169   http2_disconnect,                     /* disconnect */
170   ZERO_NULL,                            /* readwrite */
171   PORT_HTTP,                            /* defport */
172   CURLPROTO_HTTPS,                      /* protocol */
173   PROTOPT_SSL                           /* flags */
174 };
175
176 /*
177  * Store nghttp2 version info in this buffer, Prefix with a space.  Return
178  * total length written.
179  */
180 int Curl_http2_ver(char *p, size_t len)
181 {
182   nghttp2_info *h2 = nghttp2_version(0);
183   return snprintf(p, len, " nghttp2/%s", h2->version_str);
184 }
185
186 /*
187  * The implementation of nghttp2_send_callback type. Here we write |data| with
188  * size |length| to the network and return the number of bytes actually
189  * written. See the documentation of nghttp2_send_callback for the details.
190  */
191 static ssize_t send_callback(nghttp2_session *h2,
192                              const uint8_t *data, size_t length, int flags,
193                              void *userp)
194 {
195   struct connectdata *conn = (struct connectdata *)userp;
196   struct http_conn *c = &conn->proto.httpc;
197   ssize_t written;
198   CURLcode result = CURLE_OK;
199
200   (void)h2;
201   (void)flags;
202
203   written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET,
204                                              data, length, &result);
205
206   if(result == CURLE_AGAIN) {
207     return NGHTTP2_ERR_WOULDBLOCK;
208   }
209
210   if(written == -1) {
211     failf(conn->data, "Failed sending HTTP2 data");
212     return NGHTTP2_ERR_CALLBACK_FAILURE;
213   }
214
215   if(!written)
216     return NGHTTP2_ERR_WOULDBLOCK;
217
218   return written;
219 }
220
221
222 /* We pass a pointer to this struct in the push callback, but the contents of
223    the struct are hidden from the user. */
224 struct curl_pushheaders {
225   struct SessionHandle *data;
226   const nghttp2_push_promise *frame;
227 };
228
229 /*
230  * push header access function. Only to be used from within the push callback
231  */
232 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
233 {
234   /* Verify that we got a good easy handle in the push header struct, mostly to
235      detect rubbish input fast(er). */
236   if(!h || !GOOD_EASY_HANDLE(h->data))
237     return NULL;
238   else {
239     struct HTTP *stream = h->data->req.protop;
240     if(num < stream->push_headers_used)
241       return stream->push_headers[num];
242   }
243   return NULL;
244 }
245
246 /*
247  * push header access function. Only to be used from within the push callback
248  */
249 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
250 {
251   /* Verify that we got a good easy handle in the push header struct,
252      mostly to detect rubbish input fast(er). Also empty header name
253      is just a rubbish too. We have to allow ":" at the beginning of
254      the header, but header == ":" must be rejected. If we have ':' in
255      the middle of header, it could be matched in middle of the value,
256      this is because we do prefix match.*/
257   if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] ||
258      Curl_raw_equal(header, ":") || strchr(header + 1, ':'))
259     return NULL;
260   else {
261     struct HTTP *stream = h->data->req.protop;
262     size_t len = strlen(header);
263     size_t i;
264     for(i=0; i<stream->push_headers_used; i++) {
265       if(!strncmp(header, stream->push_headers[i], len)) {
266         /* sub-match, make sure that it us followed by a colon */
267         if(stream->push_headers[i][len] != ':')
268           continue;
269         return &stream->push_headers[i][len+1];
270       }
271     }
272   }
273   return NULL;
274 }
275
276 static CURL *duphandle(struct SessionHandle *data)
277 {
278   struct SessionHandle *second = curl_easy_duphandle(data);
279   if(second) {
280     /* setup the request struct */
281     struct HTTP *http = calloc(1, sizeof(struct HTTP));
282     if(!http) {
283       (void)Curl_close(second);
284       second = NULL;
285     }
286     else {
287       second->req.protop = http;
288       http->header_recvbuf = Curl_add_buffer_init();
289       if(!http->header_recvbuf) {
290         free(http);
291         (void)Curl_close(second);
292         second = NULL;
293       }
294       else
295         Curl_http2_setup_req(second);
296     }
297   }
298   return second;
299 }
300
301
302 static int push_promise(struct SessionHandle *data,
303                         struct connectdata *conn,
304                         const nghttp2_push_promise *frame)
305 {
306   int rv;
307   DEBUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
308                frame->promised_stream_id));
309   if(data->multi->push_cb) {
310     struct HTTP *stream;
311     struct curl_pushheaders heads;
312     CURLMcode rc;
313     struct http_conn *httpc;
314     size_t i;
315     /* clone the parent */
316     CURL *newhandle = duphandle(data);
317     if(!newhandle) {
318       infof(data, "failed to duplicate handle\n");
319       rv = 1; /* FAIL HARD */
320       goto fail;
321     }
322
323     heads.data = data;
324     heads.frame = frame;
325     /* ask the application */
326     DEBUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
327
328     stream = data->req.protop;
329     if(!stream) {
330       failf(data, "Internal NULL stream!\n");
331       rv = 1;
332       goto fail;
333     }
334
335     rv = data->multi->push_cb(data, newhandle,
336                               stream->push_headers_used, &heads,
337                               data->multi->push_userp);
338
339     /* free the headers again */
340     for(i=0; i<stream->push_headers_used; i++)
341       free(stream->push_headers[i]);
342     free(stream->push_headers);
343     stream->push_headers = NULL;
344
345     if(rv) {
346       /* denied, kill off the new handle again */
347       (void)Curl_close(newhandle);
348       goto fail;
349     }
350
351     /* approved, add to the multi handle and immediately switch to PERFORM
352        state with the given connection !*/
353     rc = Curl_multi_add_perform(data->multi, newhandle, conn);
354     if(rc) {
355       infof(data, "failed to add handle to multi\n");
356       Curl_close(newhandle);
357       rv = 1;
358       goto fail;
359     }
360
361     httpc = &conn->proto.httpc;
362     nghttp2_session_set_stream_user_data(httpc->h2,
363                                          frame->promised_stream_id, newhandle);
364   }
365   else {
366     DEBUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
367     rv = 1;
368   }
369   fail:
370   return rv;
371 }
372
373 static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
374                          void *userp)
375 {
376   struct connectdata *conn = NULL;
377   struct http_conn *httpc = NULL;
378   struct SessionHandle *data_s = NULL;
379   struct HTTP *stream = NULL;
380   static int lastStream = -1;
381   int rv;
382   size_t left, ncopy;
383   int32_t stream_id = frame->hd.stream_id;
384
385   (void)userp;
386
387   if(!stream_id) {
388     /* stream ID zero is for connection-oriented stuff */
389     return 0;
390   }
391   data_s = nghttp2_session_get_stream_user_data(session,
392                                                 frame->hd.stream_id);
393   if(lastStream != frame->hd.stream_id) {
394     lastStream = frame->hd.stream_id;
395   }
396   if(!data_s) {
397     DEBUGF(infof(conn->data,
398                  "No SessionHandle associated with stream: %x\n",
399                  stream_id));
400     return 0;
401   }
402
403   stream = data_s->req.protop;
404   if(!stream)
405     return NGHTTP2_ERR_CALLBACK_FAILURE;
406
407   DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
408                frame->hd.type, stream_id));
409
410   conn = data_s->easy_conn;
411   assert(conn);
412   assert(conn->data == data_s);
413   httpc = &conn->proto.httpc;
414   switch(frame->hd.type) {
415   case NGHTTP2_DATA:
416     /* If body started on this stream, then receiving DATA is illegal. */
417     if(!stream->bodystarted) {
418       rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
419                                      stream_id, NGHTTP2_PROTOCOL_ERROR);
420
421       if(nghttp2_is_fatal(rv)) {
422         return NGHTTP2_ERR_CALLBACK_FAILURE;
423       }
424     }
425     break;
426   case NGHTTP2_HEADERS:
427     if(frame->headers.cat == NGHTTP2_HCAT_REQUEST)
428       break;
429
430     if(stream->bodystarted) {
431       /* Only valid HEADERS after body started is trailer HEADERS.  We
432          ignores trailer HEADERS for now.  nghttp2 guarantees that it
433          has END_STREAM flag set. */
434       break;
435     }
436
437     /* nghttp2 guarantees that :status is received, and we store it to
438        stream->status_code */
439     DEBUGASSERT(stream->status_code != -1);
440
441     /* Only final status code signals the end of header */
442     if(stream->status_code / 100 != 1) {
443       stream->bodystarted = TRUE;
444       stream->status_code = -1;
445     }
446
447     Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
448
449     left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
450     ncopy = MIN(stream->len, left);
451
452     memcpy(&stream->mem[stream->memlen],
453            stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
454            ncopy);
455     stream->nread_header_recvbuf += ncopy;
456
457     DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
458                  ncopy, stream_id, stream->mem));
459
460     stream->len -= ncopy;
461     stream->memlen += ncopy;
462
463     data_s->state.drain++;
464     Curl_expire(data_s, 1);
465     break;
466   case NGHTTP2_PUSH_PROMISE:
467     rv = push_promise(data_s, conn, &frame->push_promise);
468     if(rv) { /* deny! */
469       rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
470                                      frame->push_promise.promised_stream_id,
471                                      NGHTTP2_CANCEL);
472       if(nghttp2_is_fatal(rv)) {
473         return rv;
474       }
475     }
476     break;
477   case NGHTTP2_SETTINGS:
478   {
479     uint32_t max_conn = httpc->settings.max_concurrent_streams;
480     DEBUGF(infof(conn->data, "Got SETTINGS for stream %u!\n", stream_id));
481     httpc->settings.max_concurrent_streams =
482       nghttp2_session_get_remote_settings(
483         session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
484     httpc->settings.enable_push =
485       nghttp2_session_get_remote_settings(
486         session, NGHTTP2_SETTINGS_ENABLE_PUSH);
487     DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
488                  httpc->settings.max_concurrent_streams));
489     DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
490                  httpc->settings.enable_push?"TRUE":"false"));
491     if(max_conn != httpc->settings.max_concurrent_streams) {
492       /* only signal change if the value actually changed */
493       infof(conn->data,
494             "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
495       Curl_multi_connchanged(conn->data->multi);
496     }
497   }
498   break;
499   default:
500     DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n",
501                  frame->hd.type, stream_id));
502     break;
503   }
504   return 0;
505 }
506
507 static int on_invalid_frame_recv(nghttp2_session *session,
508                                  const nghttp2_frame *frame,
509                                  int lib_error_code, void *userp)
510 {
511   struct SessionHandle *data_s = NULL;
512   (void)userp;
513
514   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
515   if(data_s) {
516     DEBUGF(infof(data_s,
517                  "on_invalid_frame_recv() was called, error=%d:%s\n",
518                  lib_error_code, nghttp2_strerror(lib_error_code)));
519   }
520   return 0;
521 }
522
523 static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
524                               int32_t stream_id,
525                               const uint8_t *data, size_t len, void *userp)
526 {
527   struct HTTP *stream;
528   struct SessionHandle *data_s;
529   size_t nread;
530   (void)session;
531   (void)flags;
532   (void)data;
533   (void)userp;
534
535   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
536
537   /* get the stream from the hash based on Stream ID */
538   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
539   if(!data_s)
540     /* Receiving a Stream ID not in the hash should not happen, this is an
541        internal error more than anything else! */
542     return NGHTTP2_ERR_CALLBACK_FAILURE;
543
544   stream = data_s->req.protop;
545   if(!stream)
546     return NGHTTP2_ERR_CALLBACK_FAILURE;
547
548   nread = MIN(stream->len, len);
549   memcpy(&stream->mem[stream->memlen], data, nread);
550
551   stream->len -= nread;
552   stream->memlen += nread;
553
554   data_s->state.drain++;
555   Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for
556                              immediately? */
557
558   DEBUGF(infof(data_s, "%zu data received for stream %u "
559                "(%zu left in buffer %p, total %zu)\n",
560                nread, stream_id,
561                stream->len, stream->mem,
562                stream->memlen));
563
564   if(nread < len) {
565     stream->pausedata = data + nread;
566     stream->pauselen = len - nread;
567     DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
568                  ", stream %u\n",
569                  len - nread, stream_id));
570     data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
571     return NGHTTP2_ERR_PAUSE;
572   }
573   return 0;
574 }
575
576 static int before_frame_send(nghttp2_session *session,
577                              const nghttp2_frame *frame,
578                              void *userp)
579 {
580   struct SessionHandle *data_s;
581   (void)userp;
582
583   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
584   if(data_s) {
585     DEBUGF(infof(data_s, "before_frame_send() was called\n"));
586   }
587
588   return 0;
589 }
590 static int on_frame_send(nghttp2_session *session,
591                          const nghttp2_frame *frame,
592                          void *userp)
593 {
594   struct SessionHandle *data_s;
595   (void)userp;
596
597   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
598   if(data_s) {
599     DEBUGF(infof(data_s, "on_frame_send() was called, length = %zd\n",
600                  frame->hd.length));
601   }
602   return 0;
603 }
604 static int on_frame_not_send(nghttp2_session *session,
605                              const nghttp2_frame *frame,
606                              int lib_error_code, void *userp)
607 {
608   struct SessionHandle *data_s;
609   (void)userp;
610
611   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
612   if(data_s) {
613     DEBUGF(infof(data_s,
614                  "on_frame_not_send() was called, lib_error_code = %d\n",
615                  lib_error_code));
616   }
617   return 0;
618 }
619 static int on_stream_close(nghttp2_session *session, int32_t stream_id,
620                            uint32_t error_code, void *userp)
621 {
622   struct SessionHandle *data_s;
623   struct HTTP *stream;
624   (void)session;
625   (void)stream_id;
626   (void)userp;
627
628   if(stream_id) {
629     /* get the stream from the hash based on Stream ID, stream ID zero is for
630        connection-oriented stuff */
631     data_s = nghttp2_session_get_stream_user_data(session, stream_id);
632     if(!data_s) {
633       /* We could get stream ID not in the hash.  For example, if we
634          decided to reject stream (e.g., PUSH_PROMISE). */
635       return 0;
636     }
637     DEBUGF(infof(data_s, "on_stream_close(), error_code = %d, stream %u\n",
638                  error_code, stream_id));
639     stream = data_s->req.protop;
640     if(!stream)
641       return NGHTTP2_ERR_CALLBACK_FAILURE;
642
643     stream->error_code = error_code;
644     stream->closed = TRUE;
645
646     /* remove the entry from the hash as the stream is now gone */
647     nghttp2_session_set_stream_user_data(session, stream_id, 0);
648     DEBUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
649   }
650   return 0;
651 }
652
653 static int on_begin_headers(nghttp2_session *session,
654                             const nghttp2_frame *frame, void *userp)
655 {
656   struct SessionHandle *data_s = NULL;
657   (void)userp;
658
659   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
660   if(data_s) {
661     DEBUGF(infof(data_s, "on_begin_headers() was called\n"));
662   }
663   return 0;
664 }
665
666 /* Decode HTTP status code.  Returns -1 if no valid status code was
667    decoded. */
668 static int decode_status_code(const uint8_t *value, size_t len)
669 {
670   int i;
671   int res;
672
673   if(len != 3) {
674     return -1;
675   }
676
677   res = 0;
678
679   for(i = 0; i < 3; ++i) {
680     char c = value[i];
681
682     if(c < '0' || c > '9') {
683       return -1;
684     }
685
686     res *= 10;
687     res += c - '0';
688   }
689
690   return res;
691 }
692
693 /* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
694 static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
695                      const uint8_t *name, size_t namelen,
696                      const uint8_t *value, size_t valuelen,
697                      uint8_t flags,
698                      void *userp)
699 {
700   struct HTTP *stream;
701   struct SessionHandle *data_s;
702   int32_t stream_id = frame->hd.stream_id;
703
704   (void)flags;
705   (void)userp;
706
707   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
708
709   /* get the stream from the hash based on Stream ID */
710   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
711   if(!data_s)
712     /* Receiving a Stream ID not in the hash should not happen, this is an
713        internal error more than anything else! */
714     return NGHTTP2_ERR_CALLBACK_FAILURE;
715
716   stream = data_s->req.protop;
717   if(!stream) {
718     failf(data_s, "Internal NULL stream! 5\n");
719     return NGHTTP2_ERR_CALLBACK_FAILURE;
720   }
721
722   if(stream->bodystarted)
723     /* Ignore trailer or HEADERS not mapped to HTTP semantics.  The
724        consequence is handled in on_frame_recv(). */
725     return 0;
726
727   /* Store received PUSH_PROMISE headers to be used when the subsequent
728      PUSH_PROMISE callback comes */
729   if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
730     char *h;
731
732     if(!stream->push_headers) {
733       stream->push_headers_alloc = 10;
734       stream->push_headers = malloc(stream->push_headers_alloc *
735                                     sizeof(char *));
736       stream->push_headers_used = 0;
737     }
738     else if(stream->push_headers_used ==
739             stream->push_headers_alloc) {
740       char **headp;
741       stream->push_headers_alloc *= 2;
742       headp = realloc(stream->push_headers,
743                       stream->push_headers_alloc * sizeof(char *));
744       if(!headp) {
745         free(stream->push_headers);
746         stream->push_headers = NULL;
747         return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
748       }
749       stream->push_headers = headp;
750     }
751     h = aprintf("%s:%s", name, value);
752     if(h)
753       stream->push_headers[stream->push_headers_used++] = h;
754     return 0;
755   }
756
757   if(namelen == sizeof(":status") - 1 &&
758      memcmp(":status", name, namelen) == 0) {
759     /* nghttp2 guarantees :status is received first and only once, and
760        value is 3 digits status code, and decode_status_code always
761        succeeds. */
762     stream->status_code = decode_status_code(value, valuelen);
763     DEBUGASSERT(stream->status_code != -1);
764
765     Curl_add_buffer(stream->header_recvbuf, "HTTP/2.0 ", 9);
766     Curl_add_buffer(stream->header_recvbuf, value, valuelen);
767     Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
768     data_s->state.drain++;
769     Curl_expire(data_s, 1);
770
771     DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d\n",
772                  stream->status_code));
773     return 0;
774   }
775
776   /* nghttp2 guarantees that namelen > 0, and :status was already
777      received, and this is not pseudo-header field . */
778   /* convert to a HTTP1-style header */
779   Curl_add_buffer(stream->header_recvbuf, name, namelen);
780   Curl_add_buffer(stream->header_recvbuf, ":", 1);
781   Curl_add_buffer(stream->header_recvbuf, value, valuelen);
782   Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
783   data_s->state.drain++;
784   Curl_expire(data_s, 1);
785
786   DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
787                value));
788
789   return 0; /* 0 is successful */
790 }
791
792 static ssize_t data_source_read_callback(nghttp2_session *session,
793                                          int32_t stream_id,
794                                          uint8_t *buf, size_t length,
795                                          uint32_t *data_flags,
796                                          nghttp2_data_source *source,
797                                          void *userp)
798 {
799   struct SessionHandle *data_s;
800   struct HTTP *stream = NULL;
801   size_t nread;
802   (void)source;
803   (void)userp;
804
805   if(stream_id) {
806     /* get the stream from the hash based on Stream ID, stream ID zero is for
807        connection-oriented stuff */
808     data_s = nghttp2_session_get_stream_user_data(session, stream_id);
809     if(!data_s)
810       /* Receiving a Stream ID not in the hash should not happen, this is an
811          internal error more than anything else! */
812       return NGHTTP2_ERR_CALLBACK_FAILURE;
813
814     stream = data_s->req.protop;
815     if(!stream)
816       return NGHTTP2_ERR_CALLBACK_FAILURE;
817   }
818   else
819     return NGHTTP2_ERR_INVALID_ARGUMENT;
820
821   nread = MIN(stream->upload_len, length);
822   if(nread > 0) {
823     memcpy(buf, stream->upload_mem, nread);
824     stream->upload_mem += nread;
825     stream->upload_len -= nread;
826     stream->upload_left -= nread;
827   }
828
829   if(stream->upload_left == 0)
830     *data_flags = 1;
831   else if(nread == 0)
832     return NGHTTP2_ERR_DEFERRED;
833
834   DEBUGF(infof(data_s, "data_source_read_callback: "
835                "returns %zu bytes stream %u\n",
836                nread, stream_id));
837
838   return nread;
839 }
840
841 /*
842  * The HTTP2 settings we send in the Upgrade request
843  */
844 static nghttp2_settings_entry settings[] = {
845   { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 },
846   { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, NGHTTP2_INITIAL_WINDOW_SIZE },
847 };
848
849 #define H2_BUFSIZE 32768
850
851 /*
852  * Initialize nghttp2 for a Curl connection
853  */
854 CURLcode Curl_http2_init(struct connectdata *conn)
855 {
856   if(!conn->proto.httpc.h2) {
857     int rc;
858     nghttp2_session_callbacks *callbacks;
859
860     conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
861     if(conn->proto.httpc.inbuf == NULL)
862       return CURLE_OUT_OF_MEMORY;
863
864     rc = nghttp2_session_callbacks_new(&callbacks);
865
866     if(rc) {
867       failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
868       return CURLE_OUT_OF_MEMORY; /* most likely at least */
869     }
870
871     /* nghttp2_send_callback */
872     nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
873     /* nghttp2_on_frame_recv_callback */
874     nghttp2_session_callbacks_set_on_frame_recv_callback
875       (callbacks, on_frame_recv);
876     /* nghttp2_on_invalid_frame_recv_callback */
877     nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
878       (callbacks, on_invalid_frame_recv);
879     /* nghttp2_on_data_chunk_recv_callback */
880     nghttp2_session_callbacks_set_on_data_chunk_recv_callback
881       (callbacks, on_data_chunk_recv);
882     /* nghttp2_before_frame_send_callback */
883     nghttp2_session_callbacks_set_before_frame_send_callback
884       (callbacks, before_frame_send);
885     /* nghttp2_on_frame_send_callback */
886     nghttp2_session_callbacks_set_on_frame_send_callback
887       (callbacks, on_frame_send);
888     /* nghttp2_on_frame_not_send_callback */
889     nghttp2_session_callbacks_set_on_frame_not_send_callback
890       (callbacks, on_frame_not_send);
891     /* nghttp2_on_stream_close_callback */
892     nghttp2_session_callbacks_set_on_stream_close_callback
893       (callbacks, on_stream_close);
894     /* nghttp2_on_begin_headers_callback */
895     nghttp2_session_callbacks_set_on_begin_headers_callback
896       (callbacks, on_begin_headers);
897     /* nghttp2_on_header_callback */
898     nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
899
900     /* The nghttp2 session is not yet setup, do it */
901     rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
902
903     nghttp2_session_callbacks_del(callbacks);
904
905     if(rc) {
906       failf(conn->data, "Couldn't initialize nghttp2!");
907       return CURLE_OUT_OF_MEMORY; /* most likely at least */
908     }
909
910     if(rc) {
911       failf(conn->data, "Couldn't init stream hash!");
912       return CURLE_OUT_OF_MEMORY; /* most likely at least */
913     }
914   }
915   return CURLE_OK;
916 }
917
918 /*
919  * Send a request using http2
920  */
921 CURLcode Curl_http2_send_request(struct connectdata *conn)
922 {
923   (void)conn;
924   return CURLE_OK;
925 }
926
927 /*
928  * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
929  */
930 CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
931                                     struct connectdata *conn)
932 {
933   CURLcode result;
934   ssize_t binlen;
935   char *base64;
936   size_t blen;
937   struct SingleRequest *k = &conn->data->req;
938   uint8_t *binsettings = conn->proto.httpc.binsettings;
939
940   /* As long as we have a fixed set of settings, we don't have to dynamically
941    * figure out the base64 strings since it'll always be the same. However,
942    * the settings will likely not be fixed every time in the future.
943    */
944
945   /* this returns number of bytes it wrote */
946   binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
947                                          settings,
948                                          sizeof(settings)/sizeof(settings[0]));
949   if(!binlen) {
950     failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
951     return CURLE_FAILED_INIT;
952   }
953   conn->proto.httpc.binlen = binlen;
954
955   result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
956                                  &base64, &blen);
957   if(result)
958     return result;
959
960   result = Curl_add_bufferf(req,
961                             "Connection: Upgrade, HTTP2-Settings\r\n"
962                             "Upgrade: %s\r\n"
963                             "HTTP2-Settings: %s\r\n",
964                             NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
965   free(base64);
966
967   k->upgr101 = UPGR101_REQUESTED;
968
969   return result;
970 }
971
972 static ssize_t http2_handle_stream_close(struct http_conn *httpc,
973                                          struct SessionHandle *data,
974                                          struct HTTP *stream, CURLcode *err) {
975   if(httpc->pause_stream_id == stream->stream_id) {
976     httpc->pause_stream_id = 0;
977   }
978   /* Reset to FALSE to prevent infinite loop in readwrite_data
979    function. */
980   stream->closed = FALSE;
981   if(stream->error_code != NGHTTP2_NO_ERROR) {
982     failf(data, "HTTP/2 stream %u was not closed cleanly: error_code = %d",
983           stream->stream_id, stream->error_code);
984     *err = CURLE_HTTP2;
985     return -1;
986   }
987   DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
988   return 0;
989 }
990
991 /*
992  * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
993  * a regular CURLcode value.
994  */
995 static ssize_t http2_recv(struct connectdata *conn, int sockindex,
996                           char *mem, size_t len, CURLcode *err)
997 {
998   CURLcode result = CURLE_OK;
999   ssize_t rv;
1000   ssize_t nread;
1001   struct http_conn *httpc = &conn->proto.httpc;
1002   struct SessionHandle *data = conn->data;
1003   struct HTTP *stream = data->req.protop;
1004
1005   (void)sockindex; /* we always do HTTP2 on sockindex 0 */
1006
1007   /* If stream is closed, return 0 to signal the http routine to close
1008      the connection.  We need to handle stream closure here,
1009      otherwise, we may be going to read from underlying connection,
1010      and gets EAGAIN, and we will get stuck there. */
1011   if(stream->memlen == 0 && stream->closed) {
1012     return http2_handle_stream_close(httpc, data, stream, err);
1013   }
1014
1015   /* Nullify here because we call nghttp2_session_send() and they
1016      might refer to the old buffer. */
1017   stream->upload_mem = NULL;
1018   stream->upload_len = 0;
1019
1020   /*
1021    * At this point 'stream' is just in the SessionHandle the connection
1022    * identifies as its owner at this time.
1023    */
1024
1025   if(stream->bodystarted &&
1026      stream->nread_header_recvbuf < stream->header_recvbuf->size_used) {
1027     /* If there is body data pending for this stream to return, do that */
1028     size_t left =
1029       stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
1030     size_t ncopy = MIN(len, left);
1031     memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
1032            ncopy);
1033     stream->nread_header_recvbuf += ncopy;
1034
1035     infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
1036           (int)ncopy);
1037     return ncopy;
1038   }
1039
1040   infof(data, "http2_recv: %d bytes buffer at %p (stream %u)\n",
1041         len, mem, stream->stream_id);
1042
1043   if((data->state.drain) && stream->memlen) {
1044     DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
1045                  stream->memlen, stream->stream_id,
1046                  stream->mem, mem));
1047     if(mem != stream->mem) {
1048       /* if we didn't get the same buffer this time, we must move the data to
1049          the beginning */
1050       memmove(mem, stream->mem, stream->memlen);
1051       stream->len = len - stream->memlen;
1052       stream->mem = mem;
1053     }
1054   }
1055   else if(stream->pausedata) {
1056     nread = MIN(len, stream->pauselen);
1057     memcpy(mem, stream->pausedata, nread);
1058
1059     stream->pausedata += nread;
1060     stream->pauselen -= nread;
1061
1062     infof(data, "%zu data bytes written\n", nread);
1063     if(stream->pauselen == 0) {
1064       DEBUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
1065       assert(httpc->pause_stream_id == stream->stream_id);
1066       httpc->pause_stream_id = 0;
1067
1068       stream->pausedata = NULL;
1069       stream->pauselen = 0;
1070     }
1071     infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
1072           nread, stream->stream_id);
1073     return nread;
1074   }
1075   else if(httpc->pause_stream_id) {
1076     /* If a stream paused nghttp2_session_mem_recv previously, and has
1077        not processed all data, it still refers to the buffer in
1078        nghttp2_session.  If we call nghttp2_session_mem_recv(), we may
1079        overwrite that buffer.  To avoid that situation, just return
1080        here with CURLE_AGAIN.  This could be busy loop since data in
1081        socket is not read.  But it seems that usually streams are
1082        notified with its drain property, and socket is read again
1083        quickly. */
1084     *err = CURLE_AGAIN;
1085     return -1;
1086   }
1087   else {
1088     char *inbuf;
1089     /* remember where to store incoming data for this stream and how big the
1090        buffer is */
1091     stream->mem = mem;
1092     stream->len = len;
1093     stream->memlen = 0;
1094
1095     if(httpc->inbuflen == 0) {
1096       nread = ((Curl_recv *)httpc->recv_underlying)(
1097           conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
1098
1099       if(result == CURLE_AGAIN) {
1100         *err = result;
1101         return -1;
1102       }
1103
1104       if(nread == -1) {
1105         failf(data, "Failed receiving HTTP2 data");
1106         *err = result;
1107         return 0;
1108       }
1109
1110       if(nread == 0) {
1111         failf(data, "Unexpected EOF");
1112         *err = CURLE_RECV_ERROR;
1113         return -1;
1114       }
1115
1116       DEBUGF(infof(data, "nread=%zd\n", nread));
1117
1118       httpc->inbuflen = nread;
1119       inbuf = httpc->inbuf;
1120     }
1121     else {
1122       nread = httpc->inbuflen - httpc->nread_inbuf;
1123       inbuf = httpc->inbuf + httpc->nread_inbuf;
1124
1125       DEBUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
1126                    nread));
1127     }
1128     rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
1129
1130     if(nghttp2_is_fatal((int)rv)) {
1131       failf(data, "nghttp2_session_mem_recv() returned %d:%s\n",
1132             rv, nghttp2_strerror((int)rv));
1133       *err = CURLE_RECV_ERROR;
1134       return 0;
1135     }
1136     DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
1137     if(nread == rv) {
1138       DEBUGF(infof(data, "All data in connection buffer processed\n"));
1139       httpc->inbuflen = 0;
1140       httpc->nread_inbuf = 0;
1141     }
1142     else {
1143       httpc->nread_inbuf += rv;
1144       DEBUGF(infof(data, "%zu bytes left in connection buffer\n",
1145                    httpc->inbuflen - httpc->nread_inbuf));
1146     }
1147     /* Always send pending frames in nghttp2 session, because
1148        nghttp2_session_mem_recv() may queue new frame */
1149     rv = nghttp2_session_send(httpc->h2);
1150     if(rv != 0) {
1151       *err = CURLE_SEND_ERROR;
1152       return 0;
1153     }
1154   }
1155   if(stream->memlen) {
1156     ssize_t retlen = stream->memlen;
1157     infof(data, "http2_recv: returns %zd for stream %u\n",
1158           retlen, stream->stream_id);
1159     stream->memlen = 0;
1160
1161     if(httpc->pause_stream_id == stream->stream_id) {
1162       /* data for this stream is returned now, but this stream caused a pause
1163          already so we need it called again asap */
1164       DEBUGF(infof(data, "Data returned for PAUSED stream %u\n",
1165                    stream->stream_id));
1166     }
1167     else
1168       data->state.drain = 0; /* this stream is hereby drained */
1169
1170     return retlen;
1171   }
1172   /* If stream is closed, return 0 to signal the http routine to close
1173      the connection */
1174   if(stream->closed) {
1175     return http2_handle_stream_close(httpc, data, stream, err);
1176   }
1177   *err = CURLE_AGAIN;
1178   DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
1179                stream->stream_id));
1180   return -1;
1181 }
1182
1183 /* Index where :authority header field will appear in request header
1184    field list. */
1185 #define AUTHORITY_DST_IDX 3
1186
1187 /* return number of received (decrypted) bytes */
1188 static ssize_t http2_send(struct connectdata *conn, int sockindex,
1189                           const void *mem, size_t len, CURLcode *err)
1190 {
1191   /*
1192    * BIG TODO: Currently, we send request in this function, but this
1193    * function is also used to send request body. It would be nice to
1194    * add dedicated function for request.
1195    */
1196   int rv;
1197   struct http_conn *httpc = &conn->proto.httpc;
1198   struct HTTP *stream = conn->data->req.protop;
1199   nghttp2_nv *nva;
1200   size_t nheader;
1201   size_t i;
1202   size_t authority_idx;
1203   char *hdbuf = (char*)mem;
1204   char *end;
1205   nghttp2_data_provider data_prd;
1206   int32_t stream_id;
1207   nghttp2_session *h2 = httpc->h2;
1208
1209   (void)sockindex;
1210
1211   DEBUGF(infof(conn->data, "http2_send len=%zu\n", len));
1212
1213   if(stream->stream_id != -1) {
1214     /* If stream_id != -1, we have dispatched request HEADERS, and now
1215        are going to send or sending request body in DATA frame */
1216     stream->upload_mem = mem;
1217     stream->upload_len = len;
1218     nghttp2_session_resume_data(h2, stream->stream_id);
1219     rv = nghttp2_session_send(h2);
1220     if(nghttp2_is_fatal(rv)) {
1221       *err = CURLE_SEND_ERROR;
1222       return -1;
1223     }
1224     len -= stream->upload_len;
1225
1226     /* Nullify here because we call nghttp2_session_send() and they
1227        might refer to the old buffer. */
1228     stream->upload_mem = NULL;
1229     stream->upload_len = 0;
1230
1231     if(stream->upload_left) {
1232       /* we are sure that we have more data to send here.  Calling the
1233          following API will make nghttp2_session_want_write() return
1234          nonzero if remote window allows it, which then libcurl checks
1235          socket is writable or not.  See http2_perform_getsock(). */
1236       nghttp2_session_resume_data(h2, stream->stream_id);
1237     }
1238
1239     DEBUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len,
1240                  stream->stream_id));
1241     return len;
1242   }
1243
1244   /* Calculate number of headers contained in [mem, mem + len) */
1245   /* Here, we assume the curl http code generate *correct* HTTP header
1246      field block */
1247   nheader = 0;
1248   for(i = 0; i < len; ++i) {
1249     if(hdbuf[i] == 0x0a) {
1250       ++nheader;
1251     }
1252   }
1253   /* We counted additional 2 \n in the first and last line. We need 3
1254      new headers: :method, :path and :scheme. Therefore we need one
1255      more space. */
1256   nheader += 1;
1257   nva = malloc(sizeof(nghttp2_nv) * nheader);
1258   if(nva == NULL) {
1259     *err = CURLE_OUT_OF_MEMORY;
1260     return -1;
1261   }
1262   /* Extract :method, :path from request line */
1263   end = strchr(hdbuf, ' ');
1264   if(!end)
1265     goto fail;
1266   nva[0].name = (unsigned char *)":method";
1267   nva[0].namelen = (uint16_t)strlen((char *)nva[0].name);
1268   nva[0].value = (unsigned char *)hdbuf;
1269   nva[0].valuelen = (uint16_t)(end - hdbuf);
1270   nva[0].flags = NGHTTP2_NV_FLAG_NONE;
1271
1272   hdbuf = end + 1;
1273
1274   end = strchr(hdbuf, ' ');
1275   if(!end)
1276     goto fail;
1277   nva[1].name = (unsigned char *)":path";
1278   nva[1].namelen = (uint16_t)strlen((char *)nva[1].name);
1279   nva[1].value = (unsigned char *)hdbuf;
1280   nva[1].valuelen = (uint16_t)(end - hdbuf);
1281   nva[1].flags = NGHTTP2_NV_FLAG_NONE;
1282
1283   nva[2].name = (unsigned char *)":scheme";
1284   nva[2].namelen = (uint16_t)strlen((char *)nva[2].name);
1285   if(conn->handler->flags & PROTOPT_SSL)
1286     nva[2].value = (unsigned char *)"https";
1287   else
1288     nva[2].value = (unsigned char *)"http";
1289   nva[2].valuelen = (uint16_t)strlen((char *)nva[2].value);
1290   nva[2].flags = NGHTTP2_NV_FLAG_NONE;
1291
1292   hdbuf = strchr(hdbuf, 0x0a);
1293   if(!hdbuf)
1294     goto fail;
1295   ++hdbuf;
1296
1297   authority_idx = 0;
1298
1299   for(i = 3; i < nheader; ++i) {
1300     end = strchr(hdbuf, ':');
1301     if(!end)
1302       goto fail;
1303     if(end - hdbuf == 4 && Curl_raw_nequal("host", hdbuf, 4)) {
1304       authority_idx = i;
1305       nva[i].name = (unsigned char *)":authority";
1306       nva[i].namelen = (uint16_t)strlen((char *)nva[i].name);
1307     }
1308     else {
1309       nva[i].name = (unsigned char *)hdbuf;
1310       nva[i].namelen = (uint16_t)(end - hdbuf);
1311     }
1312     hdbuf = end + 1;
1313     for(; *hdbuf == ' '; ++hdbuf);
1314     end = strchr(hdbuf, 0x0d);
1315     if(!end)
1316       goto fail;
1317     nva[i].value = (unsigned char *)hdbuf;
1318     nva[i].valuelen = (uint16_t)(end - hdbuf);
1319     nva[i].flags = NGHTTP2_NV_FLAG_NONE;
1320
1321     hdbuf = end + 2;
1322     /* Inspect Content-Length header field and retrieve the request
1323        entity length so that we can set END_STREAM to the last DATA
1324        frame. */
1325     if(nva[i].namelen == 14 &&
1326        Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) {
1327       size_t j;
1328       stream->upload_left = 0;
1329       for(j = 0; j < nva[i].valuelen; ++j) {
1330         stream->upload_left *= 10;
1331         stream->upload_left += nva[i].value[j] - '0';
1332       }
1333       DEBUGF(infof(conn->data,
1334                    "request content-length=%"
1335                    CURL_FORMAT_CURL_OFF_T
1336                    "\n", stream->upload_left));
1337     }
1338   }
1339
1340   /* :authority must come before non-pseudo header fields */
1341   if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
1342     nghttp2_nv authority = nva[authority_idx];
1343     for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
1344       nva[i] = nva[i - 1];
1345     }
1346     nva[i] = authority;
1347   }
1348
1349   switch(conn->data->set.httpreq) {
1350   case HTTPREQ_POST:
1351   case HTTPREQ_POST_FORM:
1352   case HTTPREQ_PUT:
1353     data_prd.read_callback = data_source_read_callback;
1354     data_prd.source.ptr = NULL;
1355     stream_id = nghttp2_submit_request(h2, NULL, nva, nheader,
1356                                        &data_prd, conn->data);
1357     break;
1358   default:
1359     stream_id = nghttp2_submit_request(h2, NULL, nva, nheader,
1360                                        NULL, conn->data);
1361   }
1362
1363   Curl_safefree(nva);
1364
1365   if(stream_id < 0) {
1366     DEBUGF(infof(conn->data, "http2_send() send error\n"));
1367     *err = CURLE_SEND_ERROR;
1368     return -1;
1369   }
1370
1371   infof(conn->data, "Using Stream ID: %x (easy handle %p)\n",
1372         stream_id, conn->data);
1373   stream->stream_id = stream_id;
1374
1375   rv = nghttp2_session_send(h2);
1376
1377   if(rv != 0) {
1378     *err = CURLE_SEND_ERROR;
1379     return -1;
1380   }
1381
1382   if(stream->stream_id != -1) {
1383     /* If whole HEADERS frame was sent off to the underlying socket,
1384        the nghttp2 library calls data_source_read_callback. But only
1385        it found that no data available, so it deferred the DATA
1386        transmission. Which means that nghttp2_session_want_write()
1387        returns 0 on http2_perform_getsock(), which results that no
1388        writable socket check is performed. To workaround this, we
1389        issue nghttp2_session_resume_data() here to bring back DATA
1390        transmission from deferred state. */
1391     nghttp2_session_resume_data(h2, stream->stream_id);
1392   }
1393
1394   return len;
1395
1396   fail:
1397   free(nva);
1398   *err = CURLE_SEND_ERROR;
1399   return -1;
1400 }
1401
1402 CURLcode Curl_http2_setup(struct connectdata *conn)
1403 {
1404   CURLcode result;
1405   struct http_conn *httpc = &conn->proto.httpc;
1406   struct HTTP *stream = conn->data->req.protop;
1407
1408   stream->stream_id = -1;
1409
1410   if(!stream->header_recvbuf)
1411     stream->header_recvbuf = Curl_add_buffer_init();
1412
1413   if((conn->handler == &Curl_handler_http2_ssl) ||
1414      (conn->handler == &Curl_handler_http2))
1415     return CURLE_OK; /* already done */
1416
1417   if(conn->handler->flags & PROTOPT_SSL)
1418     conn->handler = &Curl_handler_http2_ssl;
1419   else
1420     conn->handler = &Curl_handler_http2;
1421
1422   result = Curl_http2_init(conn);
1423   if(result)
1424     return result;
1425
1426   infof(conn->data, "Using HTTP2, server supports multi-use\n");
1427   stream->upload_left = 0;
1428   stream->upload_mem = NULL;
1429   stream->upload_len = 0;
1430
1431   httpc->inbuflen = 0;
1432   httpc->nread_inbuf = 0;
1433
1434   httpc->pause_stream_id = 0;
1435
1436   conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
1437   conn->httpversion = 20;
1438   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
1439
1440   infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
1441   Curl_multi_connchanged(conn->data->multi);
1442
1443   return CURLE_OK;
1444 }
1445
1446 CURLcode Curl_http2_switched(struct connectdata *conn,
1447                              const char *mem, size_t nread)
1448 {
1449   CURLcode result;
1450   struct http_conn *httpc = &conn->proto.httpc;
1451   int rv;
1452   ssize_t nproc;
1453   struct SessionHandle *data = conn->data;
1454   struct HTTP *stream = conn->data->req.protop;
1455
1456   result = Curl_http2_setup(conn);
1457   if(result)
1458     return result;
1459
1460   httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
1461   httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
1462   conn->recv[FIRSTSOCKET] = http2_recv;
1463   conn->send[FIRSTSOCKET] = http2_send;
1464
1465   if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
1466     /* stream 1 is opened implicitly on upgrade */
1467     stream->stream_id = 1;
1468     /* queue SETTINGS frame (again) */
1469     rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
1470                                  httpc->binlen, NULL);
1471     if(rv != 0) {
1472       failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
1473             nghttp2_strerror(rv), rv);
1474       return CURLE_HTTP2;
1475     }
1476
1477     nghttp2_session_set_stream_user_data(httpc->h2,
1478                                          stream->stream_id,
1479                                          conn->data);
1480   }
1481   else {
1482     /* stream ID is unknown at this point */
1483     stream->stream_id = -1;
1484     rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0);
1485     if(rv != 0) {
1486       failf(data, "nghttp2_submit_settings() failed: %s(%d)",
1487             nghttp2_strerror(rv), rv);
1488       return CURLE_HTTP2;
1489     }
1490   }
1491
1492   /* we are going to copy mem to httpc->inbuf.  This is required since
1493      mem is part of buffer pointed by stream->mem, and callbacks
1494      called by nghttp2_session_mem_recv() will write stream specific
1495      data into stream->mem, overwriting data already there. */
1496   if(H2_BUFSIZE < nread) {
1497     failf(data, "connection buffer size is too small to store data following "
1498                 "HTTP Upgrade response header: buflen=%zu, datalen=%zu",
1499           H2_BUFSIZE, nread);
1500     return CURLE_HTTP2;
1501   }
1502
1503   infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer"
1504                     " after upgrade: len=%zu\n",
1505         nread);
1506
1507   memcpy(httpc->inbuf, mem, nread);
1508   httpc->inbuflen = nread;
1509
1510   nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf,
1511                                    httpc->inbuflen);
1512
1513   if(nghttp2_is_fatal((int)nproc)) {
1514     failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
1515           nghttp2_strerror((int)nproc), (int)nproc);
1516     return CURLE_HTTP2;
1517   }
1518
1519   DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));
1520
1521   if((ssize_t)nread == nproc) {
1522     httpc->inbuflen = 0;
1523     httpc->nread_inbuf = 0;
1524   }
1525   else {
1526     httpc->nread_inbuf += nproc;
1527   }
1528
1529   /* Try to send some frames since we may read SETTINGS already. */
1530   rv = nghttp2_session_send(httpc->h2);
1531
1532   if(rv != 0) {
1533     failf(data, "nghttp2_session_send() failed: %s(%d)",
1534           nghttp2_strerror(rv), rv);
1535     return CURLE_HTTP2;
1536   }
1537
1538   return CURLE_OK;
1539 }
1540
1541 #else /* !USE_NGHTTP2 */
1542
1543 /* Satisfy external references even if http2 is not compiled in. */
1544
1545 #define CURL_DISABLE_TYPECHECK
1546 #include <curl/curl.h>
1547
1548 char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
1549 {
1550   (void) h;
1551   (void) num;
1552   return NULL;
1553 }
1554
1555 char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
1556 {
1557   (void) h;
1558   (void) header;
1559   return NULL;
1560 }
1561
1562 #endif /* USE_NGHTTP2 */