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