1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#ifdef USE_NGHTTP2
26#define _MPRINTF_REPLACE
27#include <curl/mprintf.h>
28
29#include <nghttp2/nghttp2.h>
30#include "urldata.h"
31#include "http2.h"
32#include "http.h"
33#include "sendf.h"
34#include "curl_base64.h"
35#include "curl_memory.h"
36#include "rawstr.h"
37#include "multiif.h"
38
39/* include memdebug.h last */
40#include "memdebug.h"
41
42#if (NGHTTP2_VERSION_NUM < 0x000300)
43#error too old nghttp2 version, upgrade!
44#endif
45
46static int http2_perform_getsock(const struct connectdata *conn,
47                                 curl_socket_t *sock, /* points to
48                                                         numsocks
49                                                         number of
50                                                         sockets */
51                                 int numsocks)
52{
53  const struct http_conn *httpc = &conn->proto.httpc;
54  int bitmap = GETSOCK_BLANK;
55  (void)numsocks;
56
57  /* TODO We should check underlying socket state if it is SSL socket
58     because of renegotiation. */
59  sock[0] = conn->sock[FIRSTSOCKET];
60
61  if(nghttp2_session_want_read(httpc->h2))
62    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
63
64  if(nghttp2_session_want_write(httpc->h2))
65    bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
66
67  return bitmap;
68}
69
70static int http2_getsock(struct connectdata *conn,
71                         curl_socket_t *sock, /* points to numsocks
72                                                 number of sockets */
73                         int numsocks)
74{
75  return http2_perform_getsock(conn, sock, numsocks);
76}
77
78static CURLcode http2_disconnect(struct connectdata *conn,
79                                 bool dead_connection)
80{
81  struct http_conn *httpc = &conn->proto.httpc;
82  (void)dead_connection;
83
84  infof(conn->data, "HTTP/2 DISCONNECT starts now\n");
85
86  nghttp2_session_del(httpc->h2);
87
88  Curl_safefree(httpc->header_recvbuf->buffer);
89  Curl_safefree(httpc->header_recvbuf);
90
91  Curl_safefree(httpc->inbuf);
92
93  infof(conn->data, "HTTP/2 DISCONNECT done\n");
94
95  return CURLE_OK;
96}
97
98/*
99 * HTTP2 handler interface. This isn't added to the general list of protocols
100 * but will be used at run-time when the protocol is dynamically switched from
101 * HTTP to HTTP2.
102 */
103const struct Curl_handler Curl_handler_http2 = {
104  "HTTP2",                              /* scheme */
105  ZERO_NULL,                            /* setup_connection */
106  Curl_http,                            /* do_it */
107  ZERO_NULL,                            /* done */
108  ZERO_NULL,                            /* do_more */
109  ZERO_NULL,                            /* connect_it */
110  ZERO_NULL,                            /* connecting */
111  ZERO_NULL,                            /* doing */
112  http2_getsock,                        /* proto_getsock */
113  http2_getsock,                        /* doing_getsock */
114  ZERO_NULL,                            /* domore_getsock */
115  http2_perform_getsock,                /* perform_getsock */
116  http2_disconnect,                     /* disconnect */
117  ZERO_NULL,                            /* readwrite */
118  PORT_HTTP,                            /* defport */
119  CURLPROTO_HTTP,                       /* protocol */
120  PROTOPT_NONE                          /* flags */
121};
122
123const struct Curl_handler Curl_handler_http2_ssl = {
124  "HTTP2",                              /* scheme */
125  ZERO_NULL,                            /* setup_connection */
126  Curl_http,                            /* do_it */
127  ZERO_NULL,                            /* done */
128  ZERO_NULL,                            /* do_more */
129  ZERO_NULL,                            /* connect_it */
130  ZERO_NULL,                            /* connecting */
131  ZERO_NULL,                            /* doing */
132  http2_getsock,                        /* proto_getsock */
133  http2_getsock,                        /* doing_getsock */
134  ZERO_NULL,                            /* domore_getsock */
135  http2_perform_getsock,                /* perform_getsock */
136  http2_disconnect,                     /* disconnect */
137  ZERO_NULL,                            /* readwrite */
138  PORT_HTTP,                            /* defport */
139  CURLPROTO_HTTPS,                      /* protocol */
140  PROTOPT_SSL                           /* flags */
141};
142
143/*
144 * Store nghttp2 version info in this buffer, Prefix with a space.  Return
145 * total length written.
146 */
147int Curl_http2_ver(char *p, size_t len)
148{
149  nghttp2_info *h2 = nghttp2_version(0);
150  return snprintf(p, len, " nghttp2/%s", h2->version_str);
151}
152
153/*
154 * The implementation of nghttp2_send_callback type. Here we write |data| with
155 * size |length| to the network and return the number of bytes actually
156 * written. See the documentation of nghttp2_send_callback for the details.
157 */
158static ssize_t send_callback(nghttp2_session *h2,
159                             const uint8_t *data, size_t length, int flags,
160                             void *userp)
161{
162  struct connectdata *conn = (struct connectdata *)userp;
163  struct http_conn *httpc = &conn->proto.httpc;
164  ssize_t written;
165  CURLcode rc;
166  (void)h2;
167  (void)flags;
168
169  rc = 0;
170  written = ((Curl_send*)httpc->send_underlying)(conn, FIRSTSOCKET,
171                                                 data, length, &rc);
172
173  if(rc == CURLE_AGAIN) {
174    return NGHTTP2_ERR_WOULDBLOCK;
175  }
176
177  if(written == -1) {
178    failf(conn->data, "Failed sending HTTP2 data");
179    return NGHTTP2_ERR_CALLBACK_FAILURE;
180  }
181
182  if(!written)
183    return NGHTTP2_ERR_WOULDBLOCK;
184
185  return written;
186}
187
188static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
189                         void *userp)
190{
191  struct connectdata *conn = (struct connectdata *)userp;
192  struct http_conn *c = &conn->proto.httpc;
193  int rv;
194  (void)session;
195  (void)frame;
196  infof(conn->data, "on_frame_recv() was called with header %x\n",
197        frame->hd.type);
198  switch(frame->hd.type) {
199  case NGHTTP2_HEADERS:
200    if(frame->headers.cat != NGHTTP2_HCAT_RESPONSE)
201      break;
202    c->bodystarted = TRUE;
203    Curl_add_buffer(c->header_recvbuf, "\r\n", 2);
204    c->nread_header_recvbuf = c->len < c->header_recvbuf->size_used ?
205      c->len : c->header_recvbuf->size_used;
206
207    memcpy(c->mem, c->header_recvbuf->buffer, c->nread_header_recvbuf);
208
209    c->mem += c->nread_header_recvbuf;
210    c->len -= c->nread_header_recvbuf;
211    break;
212  case NGHTTP2_PUSH_PROMISE:
213    rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
214                                   frame->hd.stream_id, NGHTTP2_CANCEL);
215    if(nghttp2_is_fatal(rv)) {
216      return rv;
217    }
218    break;
219  }
220  return 0;
221}
222
223static int on_invalid_frame_recv(nghttp2_session *session,
224                                 const nghttp2_frame *frame,
225                                 nghttp2_error_code error_code, void *userp)
226{
227  struct connectdata *conn = (struct connectdata *)userp;
228  (void)session;
229  (void)frame;
230  infof(conn->data, "on_invalid_frame_recv() was called, error_code = %d\n",
231        error_code);
232  return 0;
233}
234
235static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
236                              int32_t stream_id,
237                              const uint8_t *data, size_t len, void *userp)
238{
239  struct connectdata *conn = (struct connectdata *)userp;
240  struct http_conn *c = &conn->proto.httpc;
241  size_t nread;
242  (void)session;
243  (void)flags;
244  (void)data;
245  infof(conn->data, "on_data_chunk_recv() "
246        "len = %u, stream = %x\n", len, stream_id);
247
248  if(stream_id != c->stream_id) {
249    return 0;
250  }
251
252  nread = c->len < len ? c->len : len;
253  memcpy(c->mem, data, nread);
254
255  c->mem += nread;
256  c->len -= nread;
257
258  infof(conn->data, "%zu data written\n", nread);
259
260  if(nread < len) {
261    c->data = data + nread;
262    c->datalen = len - nread;
263    return NGHTTP2_ERR_PAUSE;
264  }
265  return 0;
266}
267
268static int before_frame_send(nghttp2_session *session,
269                             const nghttp2_frame *frame,
270                             void *userp)
271{
272  struct connectdata *conn = (struct connectdata *)userp;
273  (void)session;
274  (void)frame;
275  infof(conn->data, "before_frame_send() was called\n");
276  return 0;
277}
278static int on_frame_send(nghttp2_session *session,
279                         const nghttp2_frame *frame,
280                         void *userp)
281{
282  struct connectdata *conn = (struct connectdata *)userp;
283  (void)session;
284  (void)frame;
285  infof(conn->data, "on_frame_send() was called\n");
286  return 0;
287}
288static int on_frame_not_send(nghttp2_session *session,
289                             const nghttp2_frame *frame,
290                             int lib_error_code, void *userp)
291{
292  struct connectdata *conn = (struct connectdata *)userp;
293  (void)session;
294  (void)frame;
295  infof(conn->data, "on_frame_not_send() was called, lib_error_code = %d\n",
296        lib_error_code);
297  return 0;
298}
299static int on_stream_close(nghttp2_session *session, int32_t stream_id,
300                           nghttp2_error_code error_code, void *userp)
301{
302  struct connectdata *conn = (struct connectdata *)userp;
303  struct http_conn *c = &conn->proto.httpc;
304  (void)session;
305  (void)stream_id;
306  infof(conn->data, "on_stream_close() was called, error_code = %d\n",
307        error_code);
308
309  if(stream_id != c->stream_id) {
310    return 0;
311  }
312
313  c->closed = TRUE;
314
315  return 0;
316}
317
318static int on_unknown_frame_recv(nghttp2_session *session,
319                                 const uint8_t *head, size_t headlen,
320                                 const uint8_t *payload, size_t payloadlen,
321                                 void *userp)
322{
323  struct connectdata *conn = (struct connectdata *)userp;
324  (void)session;
325  (void)head;
326  (void)headlen;
327  (void)payload;
328  (void)payloadlen;
329  infof(conn->data, "on_unknown_frame_recv() was called\n");
330  return 0;
331}
332static int on_begin_headers(nghttp2_session *session,
333                            const nghttp2_frame *frame, void *userp)
334{
335  struct connectdata *conn = (struct connectdata *)userp;
336  (void)session;
337  (void)frame;
338  infof(conn->data, "on_begin_headers() was called\n");
339  return 0;
340}
341
342static const char STATUS[] = ":status";
343
344/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
345static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
346                     const uint8_t *name, size_t namelen,
347                     const uint8_t *value, size_t valuelen,
348                     uint8_t flags,
349                     void *userp)
350{
351  struct connectdata *conn = (struct connectdata *)userp;
352  struct http_conn *c = &conn->proto.httpc;
353  (void)session;
354  (void)frame;
355  (void)flags;
356
357  if(frame->hd.stream_id != c->stream_id) {
358    return 0;
359  }
360
361  if(namelen == sizeof(":status") - 1 &&
362     memcmp(STATUS, name, namelen) == 0) {
363    snprintf(c->header_recvbuf->buffer, 13, "HTTP/2.0 %s", value);
364    c->header_recvbuf->buffer[12] = '\r';
365    return 0;
366  }
367  else {
368    /* convert to a HTTP1-style header */
369    infof(conn->data, "got header\n");
370    Curl_add_buffer(c->header_recvbuf, name, namelen);
371    Curl_add_buffer(c->header_recvbuf, ":", 1);
372    Curl_add_buffer(c->header_recvbuf, value, valuelen);
373    Curl_add_buffer(c->header_recvbuf, "\r\n", 2);
374  }
375
376  return 0; /* 0 is successful */
377}
378
379/*
380 * This is all callbacks nghttp2 calls
381 */
382static const nghttp2_session_callbacks callbacks = {
383  send_callback,         /* nghttp2_send_callback */
384  NULL,                  /* nghttp2_recv_callback */
385  on_frame_recv,         /* nghttp2_on_frame_recv_callback */
386  on_invalid_frame_recv, /* nghttp2_on_invalid_frame_recv_callback */
387  on_data_chunk_recv,    /* nghttp2_on_data_chunk_recv_callback */
388  before_frame_send,     /* nghttp2_before_frame_send_callback */
389  on_frame_send,         /* nghttp2_on_frame_send_callback */
390  on_frame_not_send,     /* nghttp2_on_frame_not_send_callback */
391  on_stream_close,       /* nghttp2_on_stream_close_callback */
392  on_unknown_frame_recv, /* nghttp2_on_unknown_frame_recv_callback */
393  on_begin_headers,      /* nghttp2_on_begin_headers_callback */
394  on_header              /* nghttp2_on_header_callback */
395#if NGHTTP2_VERSION_NUM >= 0x000400
396  , NULL                 /* nghttp2_select_padding_callback */
397#endif
398};
399
400static ssize_t data_source_read_callback(nghttp2_session *session,
401                                         int32_t stream_id,
402                                         uint8_t *buf, size_t length,
403                                         uint32_t *data_flags,
404                                         nghttp2_data_source *source,
405                                         void *userp)
406{
407  struct connectdata *conn = (struct connectdata *)userp;
408  struct http_conn *c = &conn->proto.httpc;
409  size_t nread;
410  (void)session;
411  (void)stream_id;
412  (void)source;
413
414  nread = c->upload_len < length ? c->upload_len : length;
415  if(nread > 0) {
416    memcpy(buf, c->upload_mem, nread);
417    c->upload_mem += nread;
418    c->upload_len -= nread;
419    c->upload_left -= nread;
420  }
421
422  if(c->upload_left == 0)
423    *data_flags = 1;
424  else if(nread == 0)
425    return NGHTTP2_ERR_DEFERRED;
426
427  return nread;
428}
429
430/*
431 * The HTTP2 settings we send in the Upgrade request
432 */
433static nghttp2_settings_entry settings[] = {
434  { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 },
435  { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, NGHTTP2_INITIAL_WINDOW_SIZE },
436};
437
438#define H2_BUFSIZE 4096
439
440/*
441 * Initialize nghttp2 for a Curl connection
442 */
443CURLcode Curl_http2_init(struct connectdata *conn)
444{
445  if(!conn->proto.httpc.h2) {
446    int rc;
447    conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
448    if(conn->proto.httpc.inbuf == NULL)
449      return CURLE_OUT_OF_MEMORY;
450
451    /* The nghttp2 session is not yet setup, do it */
452    rc = nghttp2_session_client_new(&conn->proto.httpc.h2,
453                                    &callbacks, conn);
454    if(rc) {
455      failf(conn->data, "Couldn't initialize nghttp2!");
456      return CURLE_OUT_OF_MEMORY; /* most likely at least */
457    }
458  }
459  return CURLE_OK;
460}
461
462/*
463 * Send a request using http2
464 */
465CURLcode Curl_http2_send_request(struct connectdata *conn)
466{
467  (void)conn;
468  return CURLE_OK;
469}
470
471/*
472 * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
473 */
474CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
475                                    struct connectdata *conn)
476{
477  CURLcode result;
478  ssize_t binlen;
479  char *base64;
480  size_t blen;
481  struct SingleRequest *k = &conn->data->req;
482  uint8_t *binsettings = conn->proto.httpc.binsettings;
483
484  result = Curl_http2_init(conn);
485  if(result)
486    return result;
487
488  result = Curl_http2_setup(conn);
489  if(result)
490    return result;
491
492  /* As long as we have a fixed set of settings, we don't have to dynamically
493   * figure out the base64 strings since it'll always be the same. However,
494   * the settings will likely not be fixed every time in the future.
495   */
496
497  /* this returns number of bytes it wrote */
498  binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
499                                         settings,
500                                         sizeof(settings)/sizeof(settings[0]));
501  if(!binlen) {
502    failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
503    return CURLE_FAILED_INIT;
504  }
505  conn->proto.httpc.binlen = binlen;
506
507  result = Curl_base64_encode(conn->data, (const char *)binsettings, binlen,
508                              &base64, &blen);
509  if(result)
510    return result;
511
512  result = Curl_add_bufferf(req,
513                            "Connection: Upgrade, HTTP2-Settings\r\n"
514                            "Upgrade: %s\r\n"
515                            "HTTP2-Settings: %s\r\n",
516                            NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
517  Curl_safefree(base64);
518
519  k->upgr101 = UPGR101_REQUESTED;
520
521  return result;
522}
523
524/*
525 * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
526 * a regular CURLcode value.
527 */
528static ssize_t http2_recv(struct connectdata *conn, int sockindex,
529                          char *mem, size_t len, CURLcode *err)
530{
531  CURLcode rc;
532  ssize_t rv;
533  ssize_t nread;
534  struct http_conn *httpc = &conn->proto.httpc;
535
536  (void)sockindex; /* we always do HTTP2 on sockindex 0 */
537
538  if(httpc->closed) {
539    return 0;
540  }
541
542  /* Nullify here because we call nghttp2_session_send() and they
543     might refer to the old buffer. */
544  httpc->upload_mem = NULL;
545  httpc->upload_len = 0;
546
547  if(httpc->bodystarted &&
548     httpc->nread_header_recvbuf < httpc->header_recvbuf->size_used) {
549    size_t left =
550      httpc->header_recvbuf->size_used - httpc->nread_header_recvbuf;
551    size_t ncopy = len < left ? len : left;
552    memcpy(mem, httpc->header_recvbuf->buffer + httpc->nread_header_recvbuf,
553           ncopy);
554    httpc->nread_header_recvbuf += ncopy;
555    return ncopy;
556  }
557
558  if(httpc->data) {
559    nread = len < httpc->datalen ? len : httpc->datalen;
560    memcpy(mem, httpc->data, nread);
561
562    httpc->data += nread;
563    httpc->datalen -= nread;
564
565    infof(conn->data, "%zu data written\n", nread);
566    if(httpc->datalen == 0) {
567      httpc->data = NULL;
568      httpc->datalen = 0;
569    }
570    return nread;
571  }
572
573  conn->proto.httpc.mem = mem;
574  conn->proto.httpc.len = len;
575
576  infof(conn->data, "http2_recv: %d bytes buffer\n",
577        conn->proto.httpc.len);
578
579  rc = 0;
580  nread = ((Curl_recv*)httpc->recv_underlying)(conn, FIRSTSOCKET,
581                                               httpc->inbuf, H2_BUFSIZE, &rc);
582
583  if(rc == CURLE_AGAIN) {
584    *err = rc;
585    return -1;
586  }
587
588  if(nread == -1) {
589    failf(conn->data, "Failed receiving HTTP2 data");
590    *err = rc;
591    return 0;
592  }
593
594  infof(conn->data, "nread=%zd\n", nread);
595  rv = nghttp2_session_mem_recv(httpc->h2,
596                                (const uint8_t *)httpc->inbuf, nread);
597
598  if(nghttp2_is_fatal((int)rv)) {
599    failf(conn->data, "nghttp2_session_mem_recv() returned %d:%s\n",
600          rv, nghttp2_strerror((int)rv));
601    *err = CURLE_RECV_ERROR;
602    return 0;
603  }
604  infof(conn->data, "nghttp2_session_mem_recv() returns %zd\n", rv);
605  /* Always send pending frames in nghttp2 session, because
606     nghttp2_session_mem_recv() may queue new frame */
607  rv = nghttp2_session_send(httpc->h2);
608  if(rv != 0) {
609    *err = CURLE_SEND_ERROR;
610    return 0;
611  }
612  if(len != httpc->len) {
613    return len - conn->proto.httpc.len;
614  }
615  /* If stream is closed, return 0 to signal the http routine to close
616     the connection */
617  if(httpc->closed) {
618    return 0;
619  }
620  *err = CURLE_AGAIN;
621  return -1;
622}
623
624/* return number of received (decrypted) bytes */
625static ssize_t http2_send(struct connectdata *conn, int sockindex,
626                          const void *mem, size_t len, CURLcode *err)
627{
628  /*
629   * BIG TODO: Currently, we send request in this function, but this
630   * function is also used to send request body. It would be nice to
631   * add dedicated function for request.
632   */
633  int rv;
634  struct http_conn *httpc = &conn->proto.httpc;
635  nghttp2_nv *nva;
636  size_t nheader;
637  size_t i;
638  char *hdbuf = (char*)mem;
639  char *end;
640  nghttp2_data_provider data_prd;
641  int32_t stream_id;
642
643  (void)sockindex;
644
645  infof(conn->data, "http2_send len=%zu\n", len);
646
647  if(httpc->stream_id != -1) {
648    /* If stream_id != -1, we have dispatched request HEADERS, and now
649       are going to send or sending request body in DATA frame */
650    httpc->upload_mem = mem;
651    httpc->upload_len = len;
652    nghttp2_session_resume_data(httpc->h2, httpc->stream_id);
653    rv = nghttp2_session_send(httpc->h2);
654    if(nghttp2_is_fatal(rv)) {
655      *err = CURLE_SEND_ERROR;
656      return -1;
657    }
658    return len - httpc->upload_len;
659  }
660
661  /* Calculate number of headers contained in [mem, mem + len) */
662  /* Here, we assume the curl http code generate *correct* HTTP header
663     field block */
664  nheader = 0;
665  for(i = 0; i < len; ++i) {
666    if(hdbuf[i] == 0x0a) {
667      ++nheader;
668    }
669  }
670  /* We counted additional 2 \n in the first and last line. We need 3
671     new headers: :method, :path and :scheme. Therefore we need one
672     more space. */
673  nheader += 1;
674  nva = malloc(sizeof(nghttp2_nv) * nheader);
675  if(nva == NULL) {
676    *err = CURLE_OUT_OF_MEMORY;
677    return -1;
678  }
679  /* Extract :method, :path from request line */
680  end = strchr(hdbuf, ' ');
681  nva[0].name = (unsigned char *)":method";
682  nva[0].namelen = (uint16_t)strlen((char *)nva[0].name);
683  nva[0].value = (unsigned char *)hdbuf;
684  nva[0].valuelen = (uint16_t)(end - hdbuf);
685  nva[0].flags = NGHTTP2_NV_FLAG_NONE;
686
687  hdbuf = end + 1;
688
689  end = strchr(hdbuf, ' ');
690  nva[1].name = (unsigned char *)":path";
691  nva[1].namelen = (uint16_t)strlen((char *)nva[1].name);
692  nva[1].value = (unsigned char *)hdbuf;
693  nva[1].valuelen = (uint16_t)(end - hdbuf);
694  nva[1].flags = NGHTTP2_NV_FLAG_NONE;
695
696  nva[2].name = (unsigned char *)":scheme";
697  nva[2].namelen = (uint16_t)strlen((char *)nva[2].name);
698  if(conn->handler->flags & PROTOPT_SSL)
699    nva[2].value = (unsigned char *)"https";
700  else
701    nva[2].value = (unsigned char *)"http";
702  nva[2].valuelen = (uint16_t)strlen((char *)nva[2].value);
703  nva[2].flags = NGHTTP2_NV_FLAG_NONE;
704
705  hdbuf = strchr(hdbuf, 0x0a);
706  ++hdbuf;
707
708  for(i = 3; i < nheader; ++i) {
709    end = strchr(hdbuf, ':');
710    assert(end);
711    if(end - hdbuf == 4 && Curl_raw_nequal("host", hdbuf, 4)) {
712      nva[i].name = (unsigned char *)":authority";
713      nva[i].namelen = (uint16_t)strlen((char *)nva[i].name);
714    }
715    else {
716      nva[i].name = (unsigned char *)hdbuf;
717      nva[i].namelen = (uint16_t)(end - hdbuf);
718    }
719    hdbuf = end + 1;
720    for(; *hdbuf == ' '; ++hdbuf);
721    end = strchr(hdbuf, 0x0d);
722    assert(end);
723    nva[i].value = (unsigned char *)hdbuf;
724    nva[i].valuelen = (uint16_t)(end - hdbuf);
725    nva[i].flags = NGHTTP2_NV_FLAG_NONE;
726
727    hdbuf = end + 2;
728    /* Inspect Content-Length header field and retrieve the request
729       entity length so that we can set END_STREAM to the last DATA
730       frame. */
731    if(nva[i].namelen == 14 &&
732       Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) {
733      size_t j;
734      for(j = 0; j < nva[i].valuelen; ++j) {
735        httpc->upload_left *= 10;
736        httpc->upload_left += nva[i].value[j] - '0';
737      }
738      infof(conn->data, "request content-length=%zu\n", httpc->upload_left);
739    }
740  }
741
742  switch(conn->data->set.httpreq) {
743  case HTTPREQ_POST:
744  case HTTPREQ_POST_FORM:
745  case HTTPREQ_PUT:
746    data_prd.read_callback = data_source_read_callback;
747    data_prd.source.ptr = NULL;
748    stream_id = nghttp2_submit_request(httpc->h2, NULL, nva, nheader,
749                                       &data_prd, NULL);
750    break;
751  default:
752    stream_id = nghttp2_submit_request(httpc->h2, NULL, nva, nheader,
753                                       NULL, NULL);
754  }
755
756  Curl_safefree(nva);
757
758  if(stream_id < 0) {
759    *err = CURLE_SEND_ERROR;
760    return -1;
761  }
762
763  httpc->stream_id = stream_id;
764
765  rv = nghttp2_session_send(httpc->h2);
766
767  if(rv != 0) {
768    *err = CURLE_SEND_ERROR;
769    return -1;
770  }
771
772  if(httpc->stream_id != -1) {
773    /* If whole HEADERS frame was sent off to the underlying socket,
774       the nghttp2 library calls data_source_read_callback. But only
775       it found that no data available, so it deferred the DATA
776       transmission. Which means that nghttp2_session_want_write()
777       returns 0 on http2_perform_getsock(), which results that no
778       writable socket check is performed. To workaround this, we
779       issue nghttp2_session_resume_data() here to bring back DATA
780       transmission from deferred state. */
781    nghttp2_session_resume_data(httpc->h2, httpc->stream_id);
782  }
783
784  return len;
785}
786
787CURLcode Curl_http2_setup(struct connectdata *conn)
788{
789  struct http_conn *httpc = &conn->proto.httpc;
790  if(conn->handler->flags & PROTOPT_SSL)
791    conn->handler = &Curl_handler_http2_ssl;
792  else
793    conn->handler = &Curl_handler_http2;
794
795  infof(conn->data, "Using HTTP2\n");
796  httpc->bodystarted = FALSE;
797  httpc->closed = FALSE;
798  httpc->header_recvbuf = Curl_add_buffer_init();
799  httpc->nread_header_recvbuf = 0;
800  httpc->data = NULL;
801  httpc->datalen = 0;
802  httpc->upload_left = 0;
803  httpc->upload_mem = NULL;
804  httpc->upload_len = 0;
805  httpc->stream_id = -1;
806
807  conn->httpversion = 20;
808
809  /* Put place holder for status line */
810  return Curl_add_buffer(httpc->header_recvbuf, "HTTP/2.0 200\r\n", 14);
811}
812
813int Curl_http2_switched(struct connectdata *conn)
814{
815  /* TODO: May get CURLE_AGAIN */
816  CURLcode rc;
817  struct http_conn *httpc = &conn->proto.httpc;
818  int rv;
819
820  httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
821  httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
822  conn->recv[FIRSTSOCKET] = http2_recv;
823  conn->send[FIRSTSOCKET] = http2_send;
824
825  rv = (int) ((Curl_send*)httpc->send_underlying)
826    (conn, FIRSTSOCKET,
827     NGHTTP2_CLIENT_CONNECTION_PREFACE,
828     NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN,
829     &rc);
830  assert(rv == 24);
831  if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
832    /* stream 1 is opened implicitly on upgrade */
833    httpc->stream_id = 1;
834    /* queue SETTINGS frame (again) */
835    rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
836                                 httpc->binlen, NULL);
837    if(rv != 0) {
838      failf(conn->data, "nghttp2_session_upgrade() failed: %s(%d)",
839            nghttp2_strerror(rv), rv);
840      return -1;
841    }
842  }
843  else {
844    /* stream ID is unknown at this point */
845    httpc->stream_id = -1;
846    rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0);
847    if(rv != 0) {
848      failf(conn->data, "nghttp2_submit_settings() failed: %s(%d)",
849            nghttp2_strerror(rv), rv);
850      return -1;
851    }
852  }
853  return 0;
854}
855
856#endif
857