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