Imported Upstream version 1.0.0
[platform/upstream/nghttp2.git] / src / nghttp.cc
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2013 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "nghttp.h"
26
27 #include <sys/stat.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif // HAVE_UNISTD_H
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif // HAVE_FCNTL_H
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif // HAVE_NETINET_IN_H
37 #include <netinet/tcp.h>
38 #include <getopt.h>
39
40 #include <cassert>
41 #include <cstdio>
42 #include <cerrno>
43 #include <cstdlib>
44 #include <cstring>
45 #include <iostream>
46 #include <iomanip>
47 #include <sstream>
48 #include <tuple>
49
50 #include <openssl/err.h>
51 #include <openssl/conf.h>
52
53 #ifdef HAVE_JANSSON
54 #include <jansson.h>
55 #endif // HAVE_JANSSON
56
57 #include "app_helper.h"
58 #include "HtmlParser.h"
59 #include "util.h"
60 #include "base64.h"
61 #include "ssl.h"
62 #include "template.h"
63
64 #ifndef O_BINARY
65 #define O_BINARY (0)
66 #endif // O_BINARY
67
68 namespace nghttp2 {
69
70 // The anchor stream nodes when --no-dep is not used.  The stream ID =
71 // 1 is excluded since it is used as first stream in upgrade case.  We
72 // follows the same dependency anchor nodes as Firefox does.
73 struct Anchor {
74   int32_t stream_id;
75   // stream ID this anchor depends on
76   int32_t dep_stream_id;
77   // .. with this weight.
78   int32_t weight;
79 };
80
81 // This is index into anchors.  Firefox uses ANCHOR_FOLLOWERS for html
82 // file.
83 enum {
84   ANCHOR_LEADERS,
85   ANCHOR_UNBLOCKED,
86   ANCHOR_BACKGROUND,
87   ANCHOR_SPECULATIVE,
88   ANCHOR_FOLLOWERS,
89 };
90
91 namespace {
92 auto anchors = std::array<Anchor, 5>{{
93     {3, 0, 201}, {5, 0, 101}, {7, 0, 1}, {9, 7, 1}, {11, 3, 1},
94 }};
95 } // namespace
96
97 Config::Config()
98     : output_upper_thres(1024 * 1024), padding(0),
99       peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS),
100       header_table_size(-1), weight(NGHTTP2_DEFAULT_WEIGHT), multiply(1),
101       timeout(0.), window_bits(-1), connection_window_bits(-1), verbose(0),
102       null_out(false), remote_name(false), get_assets(false), stat(false),
103       upgrade(false), continuation(false), no_content_length(false),
104       no_dep(false), hexdump(false), no_push(false) {
105   nghttp2_option_new(&http2_option);
106   nghttp2_option_set_peer_max_concurrent_streams(http2_option,
107                                                  peer_max_concurrent_streams);
108 }
109
110 Config::~Config() { nghttp2_option_del(http2_option); }
111
112 namespace {
113 Config config;
114 } // namespace
115
116 namespace {
117 void print_protocol_nego_error() {
118   std::cerr << "[ERROR] HTTP/2 protocol was not selected."
119             << " (nghttp2 expects " << NGHTTP2_PROTO_VERSION_ID << ")"
120             << std::endl;
121 }
122 } // namespace
123
124 namespace {
125 std::string strip_fragment(const char *raw_uri) {
126   const char *end;
127   for (end = raw_uri; *end && *end != '#'; ++end)
128     ;
129   size_t len = end - raw_uri;
130   return std::string(raw_uri, len);
131 }
132 } // namespace
133
134 Request::Request(const std::string &uri, const http_parser_url &u,
135                  const nghttp2_data_provider *data_prd, int64_t data_length,
136                  const nghttp2_priority_spec &pri_spec, int level)
137     : uri(uri), u(u), pri_spec(pri_spec), data_length(data_length),
138       data_offset(0), response_len(0), inflater(nullptr), html_parser(nullptr),
139       data_prd(data_prd), stream_id(-1), status(0), level(level),
140       expect_final_response(false) {
141   http2::init_hdidx(res_hdidx);
142   http2::init_hdidx(req_hdidx);
143 }
144
145 Request::~Request() {
146   nghttp2_gzip_inflate_del(inflater);
147   delete html_parser;
148 }
149
150 void Request::init_inflater() {
151   int rv;
152   rv = nghttp2_gzip_inflate_new(&inflater);
153   assert(rv == 0);
154 }
155
156 void Request::init_html_parser() { html_parser = new HtmlParser(uri); }
157
158 int Request::update_html_parser(const uint8_t *data, size_t len, int fin) {
159   if (!html_parser) {
160     return 0;
161   }
162   return html_parser->parse_chunk(reinterpret_cast<const char *>(data), len,
163                                   fin);
164 }
165
166 std::string Request::make_reqpath() const {
167   std::string path = util::has_uri_field(u, UF_PATH)
168                          ? util::get_uri_field(uri.c_str(), u, UF_PATH)
169                          : "/";
170   if (util::has_uri_field(u, UF_QUERY)) {
171     path += "?";
172     path.append(uri.c_str() + u.field_data[UF_QUERY].off,
173                 u.field_data[UF_QUERY].len);
174   }
175   return path;
176 }
177
178 namespace {
179 nghttp2_priority_spec resolve_dep(int res_type) {
180   nghttp2_priority_spec pri_spec;
181
182   if (config.no_dep) {
183     nghttp2_priority_spec_default_init(&pri_spec);
184
185     return pri_spec;
186   }
187
188   int32_t anchor_id;
189   int32_t weight;
190   switch (res_type) {
191   case REQ_CSS:
192   case REQ_JS:
193     anchor_id = anchors[ANCHOR_LEADERS].stream_id;
194     weight = 2;
195     break;
196   case REQ_UNBLOCK_JS:
197     anchor_id = anchors[ANCHOR_UNBLOCKED].stream_id;
198     weight = 2;
199     break;
200   case REQ_IMG:
201     anchor_id = anchors[ANCHOR_FOLLOWERS].stream_id;
202     weight = 12;
203     break;
204   default:
205     anchor_id = anchors[ANCHOR_FOLLOWERS].stream_id;
206     weight = 2;
207   }
208
209   nghttp2_priority_spec_init(&pri_spec, anchor_id, weight, 0);
210   return pri_spec;
211 }
212 } // namespace
213
214 bool Request::is_ipv6_literal_addr() const {
215   if (util::has_uri_field(u, UF_HOST)) {
216     return memchr(uri.c_str() + u.field_data[UF_HOST].off, ':',
217                   u.field_data[UF_HOST].len);
218   } else {
219     return false;
220   }
221 }
222
223 bool Request::response_pseudo_header_allowed(int16_t token) const {
224   if (!res_nva.empty() && res_nva.back().name.c_str()[0] != ':') {
225     return false;
226   }
227   switch (token) {
228   case http2::HD__STATUS:
229     return res_hdidx[token] == -1;
230   default:
231     return false;
232   }
233 }
234
235 bool Request::push_request_pseudo_header_allowed(int16_t token) const {
236   if (!req_nva.empty() && req_nva.back().name.c_str()[0] != ':') {
237     return false;
238   }
239   switch (token) {
240   case http2::HD__AUTHORITY:
241   case http2::HD__METHOD:
242   case http2::HD__PATH:
243   case http2::HD__SCHEME:
244     return req_hdidx[token] == -1;
245   default:
246     return false;
247   }
248 }
249
250 Headers::value_type *Request::get_res_header(int16_t token) {
251   auto idx = res_hdidx[token];
252   if (idx == -1) {
253     return nullptr;
254   }
255   return &res_nva[idx];
256 }
257
258 Headers::value_type *Request::get_req_header(int16_t token) {
259   auto idx = req_hdidx[token];
260   if (idx == -1) {
261     return nullptr;
262   }
263   return &req_nva[idx];
264 }
265
266 void Request::record_request_start_time() {
267   timing.state = RequestState::ON_REQUEST;
268   timing.request_start_time = get_time();
269 }
270
271 void Request::record_response_start_time() {
272   timing.state = RequestState::ON_RESPONSE;
273   timing.response_start_time = get_time();
274 }
275
276 void Request::record_response_end_time() {
277   timing.state = RequestState::ON_COMPLETE;
278   timing.response_end_time = get_time();
279 }
280
281 namespace {
282 int htp_msg_begincb(http_parser *htp) {
283   if (config.verbose) {
284     print_timer();
285     std::cout << " HTTP Upgrade response" << std::endl;
286   }
287   return 0;
288 }
289 } // namespace
290
291 namespace {
292 int htp_statuscb(http_parser *htp, const char *at, size_t length) {
293   auto client = static_cast<HttpClient *>(htp->data);
294   client->upgrade_response_status_code = htp->status_code;
295   return 0;
296 }
297 } // namespace
298
299 namespace {
300 int htp_msg_completecb(http_parser *htp) {
301   auto client = static_cast<HttpClient *>(htp->data);
302   client->upgrade_response_complete = true;
303   return 0;
304 }
305 } // namespace
306
307 namespace {
308 http_parser_settings htp_hooks = {
309     htp_msg_begincb,   // http_cb      on_message_begin;
310     nullptr,           // http_data_cb on_url;
311     htp_statuscb,      // http_data_cb on_status;
312     nullptr,           // http_data_cb on_header_field;
313     nullptr,           // http_data_cb on_header_value;
314     nullptr,           // http_cb      on_headers_complete;
315     nullptr,           // http_data_cb on_body;
316     htp_msg_completecb // http_cb      on_message_complete;
317 };
318 } // namespace
319
320 namespace {
321 int submit_request(HttpClient *client, const Headers &headers, Request *req) {
322   auto path = req->make_reqpath();
323   auto scheme = util::get_uri_field(req->uri.c_str(), req->u, UF_SCHEMA);
324   auto build_headers = Headers{{":method", req->data_prd ? "POST" : "GET"},
325                                {":path", path},
326                                {":scheme", scheme},
327                                {":authority", client->hostport},
328                                {"accept", "*/*"},
329                                {"accept-encoding", "gzip, deflate"},
330                                {"user-agent", "nghttp2/" NGHTTP2_VERSION}};
331   if (config.continuation) {
332     for (size_t i = 0; i < 6; ++i) {
333       build_headers.emplace_back("continuation-test-" + util::utos(i + 1),
334                                  std::string(4096, '-'));
335     }
336   }
337   auto num_initial_headers = build_headers.size();
338   if (!config.no_content_length && req->data_prd) {
339     build_headers.emplace_back("content-length", util::utos(req->data_length));
340   }
341   for (auto &kv : headers) {
342     size_t i;
343     for (i = 0; i < num_initial_headers; ++i) {
344       if (kv.name == build_headers[i].name) {
345         build_headers[i].value = kv.value;
346         break;
347       }
348     }
349     if (i < num_initial_headers) {
350       continue;
351     }
352
353     build_headers.emplace_back(kv.name, kv.value, kv.no_index);
354   }
355
356   auto nva = std::vector<nghttp2_nv>();
357   nva.reserve(build_headers.size());
358
359   for (auto &kv : build_headers) {
360     nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index));
361   }
362
363   std::string trailer_names;
364   if (!config.trailer.empty()) {
365     trailer_names = config.trailer[0].name;
366     for (size_t i = 1; i < config.trailer.size(); ++i) {
367       trailer_names += ", ";
368       trailer_names += config.trailer[i].name;
369     }
370     nva.push_back(http2::make_nv_ls("trailer", trailer_names));
371   }
372
373   auto stream_id =
374       nghttp2_submit_request(client->session, &req->pri_spec, nva.data(),
375                              nva.size(), req->data_prd, req);
376   if (stream_id < 0) {
377     std::cerr << "[ERROR] nghttp2_submit_request() returned error: "
378               << nghttp2_strerror(stream_id) << std::endl;
379     return -1;
380   }
381
382   req->stream_id = stream_id;
383   client->request_done(req);
384
385   req->req_nva = std::move(build_headers);
386
387   return 0;
388 }
389 } // namespace
390
391 namespace {
392 void readcb(struct ev_loop *loop, ev_io *w, int revents) {
393   auto client = static_cast<HttpClient *>(w->data);
394   if (client->do_read() != 0) {
395     client->disconnect();
396   }
397 }
398 } // namespace
399
400 namespace {
401 void writecb(struct ev_loop *loop, ev_io *w, int revents) {
402   auto client = static_cast<HttpClient *>(w->data);
403   auto rv = client->do_write();
404   if (rv == HttpClient::ERR_CONNECT_FAIL) {
405     client->connect_fail();
406     return;
407   }
408   if (rv != 0) {
409     client->disconnect();
410   }
411 }
412 } // namespace
413
414 namespace {
415 void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
416   auto client = static_cast<HttpClient *>(w->data);
417   std::cerr << "[ERROR] Timeout" << std::endl;
418   client->disconnect();
419 }
420 } // namespace
421
422 namespace {
423 void settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
424   auto client = static_cast<HttpClient *>(w->data);
425   ev_timer_stop(loop, w);
426
427   nghttp2_session_terminate_session(client->session, NGHTTP2_SETTINGS_TIMEOUT);
428
429   client->signal_write();
430 }
431 } // namespace
432
433 HttpClient::HttpClient(const nghttp2_session_callbacks *callbacks,
434                        struct ev_loop *loop, SSL_CTX *ssl_ctx)
435     : session(nullptr), callbacks(callbacks), loop(loop), ssl_ctx(ssl_ctx),
436       ssl(nullptr), addrs(nullptr), next_addr(nullptr), cur_addr(nullptr),
437       complete(0), success(0), settings_payloadlen(0), state(ClientState::IDLE),
438       upgrade_response_status_code(0), fd(-1),
439       upgrade_response_complete(false) {
440   ev_io_init(&wev, writecb, 0, EV_WRITE);
441   ev_io_init(&rev, readcb, 0, EV_READ);
442
443   wev.data = this;
444   rev.data = this;
445
446   ev_timer_init(&wt, timeoutcb, 0., config.timeout);
447   ev_timer_init(&rt, timeoutcb, 0., config.timeout);
448
449   wt.data = this;
450   rt.data = this;
451
452   ev_timer_init(&settings_timer, settings_timeout_cb, 0., 10.);
453
454   settings_timer.data = this;
455 }
456
457 HttpClient::~HttpClient() {
458   disconnect();
459
460   if (addrs) {
461     freeaddrinfo(addrs);
462     addrs = nullptr;
463     next_addr = nullptr;
464   }
465 }
466
467 bool HttpClient::need_upgrade() const {
468   return config.upgrade && scheme == "http";
469 }
470
471 int HttpClient::resolve_host(const std::string &host, uint16_t port) {
472   int rv;
473   addrinfo hints;
474   this->host = host;
475   memset(&hints, 0, sizeof(hints));
476   hints.ai_family = AF_UNSPEC;
477   hints.ai_socktype = SOCK_STREAM;
478   hints.ai_protocol = 0;
479   hints.ai_flags = AI_ADDRCONFIG;
480   rv = getaddrinfo(host.c_str(), util::utos(port).c_str(), &hints, &addrs);
481   if (rv != 0) {
482     std::cerr << "[ERROR] getaddrinfo() failed: " << gai_strerror(rv)
483               << std::endl;
484     return -1;
485   }
486   if (addrs == nullptr) {
487     std::cerr << "[ERROR] No address returned" << std::endl;
488     return -1;
489   }
490   next_addr = addrs;
491   return 0;
492 }
493
494 int HttpClient::initiate_connection() {
495   int rv;
496
497   cur_addr = nullptr;
498   while (next_addr) {
499     cur_addr = next_addr;
500     next_addr = next_addr->ai_next;
501     fd = util::create_nonblock_socket(cur_addr->ai_family);
502     if (fd == -1) {
503       continue;
504     }
505
506     if (ssl_ctx) {
507       // We are establishing TLS connection.
508       ssl = SSL_new(ssl_ctx);
509       if (!ssl) {
510         std::cerr << "[ERROR] SSL_new() failed: "
511                   << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
512         return -1;
513       }
514
515       SSL_set_fd(ssl, fd);
516       SSL_set_connect_state(ssl);
517
518       // If the user overrode the :authority or host header, use that
519       // value for the SNI extension
520       const char *host_string = nullptr;
521       auto i = std::find_if(std::begin(config.headers),
522                             std::end(config.headers), [](const Header &nv) {
523         return ":authority" == nv.name || "host" == nv.name;
524       });
525       if (i != std::end(config.headers)) {
526         host_string = (*i).value.c_str();
527       } else {
528         host_string = host.c_str();
529       }
530
531       if (!util::numeric_host(host_string)) {
532         SSL_set_tlsext_host_name(ssl, host_string);
533       }
534     }
535
536     rv = connect(fd, cur_addr->ai_addr, cur_addr->ai_addrlen);
537
538     if (rv != 0 && errno != EINPROGRESS) {
539       if (ssl) {
540         SSL_free(ssl);
541         ssl = nullptr;
542       }
543       close(fd);
544       fd = -1;
545       continue;
546     }
547     break;
548   }
549
550   if (fd == -1) {
551     return -1;
552   }
553
554   writefn = &HttpClient::connected;
555
556   if (need_upgrade()) {
557     on_readfn = &HttpClient::on_upgrade_read;
558     on_writefn = &HttpClient::on_upgrade_connect;
559   } else {
560     on_readfn = &HttpClient::on_read;
561     on_writefn = &HttpClient::on_write;
562   }
563
564   ev_io_set(&rev, fd, EV_READ);
565   ev_io_set(&wev, fd, EV_WRITE);
566
567   ev_io_start(loop, &wev);
568
569   ev_timer_again(loop, &wt);
570
571   return 0;
572 }
573
574 void HttpClient::disconnect() {
575   state = ClientState::IDLE;
576
577   ev_timer_stop(loop, &settings_timer);
578
579   ev_timer_stop(loop, &rt);
580   ev_timer_stop(loop, &wt);
581
582   ev_io_stop(loop, &rev);
583   ev_io_stop(loop, &wev);
584
585   nghttp2_session_del(session);
586   session = nullptr;
587
588   if (ssl) {
589     SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
590     ERR_clear_error();
591     SSL_shutdown(ssl);
592     SSL_free(ssl);
593     ssl = nullptr;
594   }
595
596   if (fd != -1) {
597     shutdown(fd, SHUT_WR);
598     close(fd);
599     fd = -1;
600   }
601 }
602
603 int HttpClient::read_clear() {
604   ev_timer_again(loop, &rt);
605
606   std::array<uint8_t, 8192> buf;
607
608   for (;;) {
609     ssize_t nread;
610     while ((nread = read(fd, buf.data(), buf.size())) == -1 && errno == EINTR)
611       ;
612     if (nread == -1) {
613       if (errno == EAGAIN || errno == EWOULDBLOCK) {
614         return 0;
615       }
616       return -1;
617     }
618
619     if (nread == 0) {
620       return -1;
621     }
622
623     if (on_readfn(*this, buf.data(), nread) != 0) {
624       return -1;
625     }
626   }
627
628   return 0;
629 }
630
631 int HttpClient::write_clear() {
632   ev_timer_again(loop, &rt);
633
634   for (;;) {
635     if (wb.rleft() > 0) {
636       ssize_t nwrite;
637       while ((nwrite = write(fd, wb.pos, wb.rleft())) == -1 && errno == EINTR)
638         ;
639       if (nwrite == -1) {
640         if (errno == EAGAIN || errno == EWOULDBLOCK) {
641           ev_io_start(loop, &wev);
642           ev_timer_again(loop, &wt);
643           return 0;
644         }
645         return -1;
646       }
647       wb.drain(nwrite);
648       continue;
649     }
650     wb.reset();
651     if (on_writefn(*this) != 0) {
652       return -1;
653     }
654     if (wb.rleft() == 0) {
655       break;
656     }
657   }
658
659   ev_io_stop(loop, &wev);
660   ev_timer_stop(loop, &wt);
661
662   return 0;
663 }
664
665 int HttpClient::noop() { return 0; }
666
667 void HttpClient::connect_fail() {
668   if (state == ClientState::IDLE) {
669     std::cerr << "[ERROR] Could not connect to the address "
670               << util::numeric_name(cur_addr->ai_addr, cur_addr->ai_addrlen)
671               << std::endl;
672   }
673   auto cur_state = state;
674   disconnect();
675   if (cur_state == ClientState::IDLE) {
676     if (initiate_connection() == 0) {
677       std::cerr << "Trying next address "
678                 << util::numeric_name(cur_addr->ai_addr, cur_addr->ai_addrlen)
679                 << std::endl;
680     }
681   }
682 }
683
684 int HttpClient::connected() {
685   if (!util::check_socket_connected(fd)) {
686     return ERR_CONNECT_FAIL;
687   }
688
689   if (config.verbose) {
690     print_timer();
691     std::cout << " Connected" << std::endl;
692   }
693
694   state = ClientState::CONNECTED;
695
696   ev_io_start(loop, &rev);
697   ev_io_stop(loop, &wev);
698
699   ev_timer_again(loop, &rt);
700   ev_timer_stop(loop, &wt);
701
702   if (ssl) {
703     readfn = &HttpClient::tls_handshake;
704     writefn = &HttpClient::tls_handshake;
705
706     return do_write();
707   }
708
709   readfn = &HttpClient::read_clear;
710   writefn = &HttpClient::write_clear;
711
712   if (need_upgrade()) {
713     htp = make_unique<http_parser>();
714     http_parser_init(htp.get(), HTTP_RESPONSE);
715     htp->data = this;
716
717     return do_write();
718   }
719
720   if (connection_made() != 0) {
721     return -1;
722   }
723
724   return 0;
725 }
726
727 namespace {
728 size_t populate_settings(nghttp2_settings_entry *iv) {
729   size_t niv = 2;
730
731   iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
732   iv[0].value = 100;
733
734   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
735   if (config.window_bits != -1) {
736     iv[1].value = (1 << config.window_bits) - 1;
737   } else {
738     iv[1].value = NGHTTP2_INITIAL_WINDOW_SIZE;
739   }
740
741   if (config.header_table_size >= 0) {
742     iv[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
743     iv[niv].value = config.header_table_size;
744     ++niv;
745   }
746
747   if (config.no_push) {
748     iv[niv].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
749     iv[niv].value = 0;
750     ++niv;
751   }
752
753   return niv;
754 }
755 } // namespace
756
757 int HttpClient::on_upgrade_connect() {
758   ssize_t rv;
759   record_connect_end_time();
760   assert(!reqvec.empty());
761   std::array<nghttp2_settings_entry, 16> iv;
762   size_t niv = populate_settings(iv.data());
763   assert(settings_payload.size() >= 8 * niv);
764   rv = nghttp2_pack_settings_payload(settings_payload.data(),
765                                      settings_payload.size(), iv.data(), niv);
766   if (rv < 0) {
767     return -1;
768   }
769   settings_payloadlen = rv;
770   auto token68 =
771       base64::encode(std::begin(settings_payload),
772                      std::begin(settings_payload) + settings_payloadlen);
773   util::to_token68(token68);
774   std::string req;
775   if (reqvec[0]->data_prd) {
776     // If the request contains upload data, use OPTIONS * to upgrade
777     req = "OPTIONS *";
778   } else {
779     req = "GET ";
780     req += reqvec[0]->make_reqpath();
781   }
782
783   auto headers = Headers{{"Host", hostport},
784                          {"Connection", "Upgrade, HTTP2-Settings"},
785                          {"Upgrade", NGHTTP2_CLEARTEXT_PROTO_VERSION_ID},
786                          {"HTTP2-Settings", token68},
787                          {"Accept", "*/*"},
788                          {"User-Agent", "nghttp2/" NGHTTP2_VERSION}};
789   auto initial_headerslen = headers.size();
790
791   for (auto &kv : config.headers) {
792     size_t i;
793     for (i = 0; i < initial_headerslen; ++i) {
794       if (util::strieq(kv.name, headers[i].name)) {
795         headers[i].value = kv.value;
796         break;
797       }
798     }
799     if (i < initial_headerslen) {
800       continue;
801     }
802     if (kv.name.size() != 0 && kv.name[0] != ':') {
803       headers.emplace_back(kv.name, kv.value, kv.no_index);
804     }
805   }
806
807   req += " HTTP/1.1\r\n";
808
809   for (auto &kv : headers) {
810     req += kv.name;
811     req += ": ";
812     req += kv.value;
813     req += "\r\n";
814   }
815   req += "\r\n";
816
817   wb.write(req.c_str(), req.size());
818
819   if (config.verbose) {
820     print_timer();
821     std::cout << " HTTP Upgrade request\n" << req << std::endl;
822   }
823
824   // record request time if this is GET request
825   if (!reqvec[0]->data_prd) {
826     reqvec[0]->record_request_start_time();
827   }
828
829   on_writefn = &HttpClient::noop;
830
831   signal_write();
832
833   return 0;
834 }
835
836 int HttpClient::on_upgrade_read(const uint8_t *data, size_t len) {
837   int rv;
838
839   auto nread = http_parser_execute(htp.get(), &htp_hooks,
840                                    reinterpret_cast<const char *>(data), len);
841
842   if (config.verbose) {
843     std::cout.write(reinterpret_cast<const char *>(data), nread);
844   }
845
846   auto htperr = HTTP_PARSER_ERRNO(htp.get());
847
848   if (htperr != HPE_OK) {
849     std::cerr << "[ERROR] Failed to parse HTTP Upgrade response header: "
850               << "(" << http_errno_name(htperr) << ") "
851               << http_errno_description(htperr) << std::endl;
852     return -1;
853   }
854
855   if (!upgrade_response_complete) {
856     return 0;
857   }
858
859   if (config.verbose) {
860     std::cout << std::endl;
861   }
862
863   if (upgrade_response_status_code != 101) {
864     std::cerr << "[ERROR] HTTP Upgrade failed" << std::endl;
865
866     return -1;
867   }
868
869   if (config.verbose) {
870     print_timer();
871     std::cout << " HTTP Upgrade success" << std::endl;
872   }
873
874   on_readfn = &HttpClient::on_read;
875   on_writefn = &HttpClient::on_write;
876
877   rv = connection_made();
878   if (rv != 0) {
879     return rv;
880   }
881
882   // Read remaining data in the buffer because it is not notified
883   // callback anymore.
884   rv = on_readfn(*this, data + nread, len - nread);
885   if (rv != 0) {
886     return rv;
887   }
888
889   return 0;
890 }
891
892 int HttpClient::do_read() { return readfn(*this); }
893 int HttpClient::do_write() { return writefn(*this); }
894
895 int HttpClient::connection_made() {
896   int rv;
897
898   if (!need_upgrade()) {
899     record_connect_end_time();
900   }
901
902   if (ssl) {
903     // Check NPN or ALPN result
904     const unsigned char *next_proto = nullptr;
905     unsigned int next_proto_len;
906     SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
907     for (int i = 0; i < 2; ++i) {
908       if (next_proto) {
909         if (config.verbose) {
910           std::cout << "The negotiated protocol: ";
911           std::cout.write(reinterpret_cast<const char *>(next_proto),
912                           next_proto_len);
913           std::cout << std::endl;
914         }
915         if (!util::check_h2_is_selected(next_proto, next_proto_len)) {
916           next_proto = nullptr;
917         }
918         break;
919       }
920 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
921       SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len);
922 #else  // OPENSSL_VERSION_NUMBER < 0x10002000L
923       break;
924 #endif // OPENSSL_VERSION_NUMBER < 0x10002000L
925     }
926     if (!next_proto) {
927       print_protocol_nego_error();
928       return -1;
929     }
930   }
931
932   rv = nghttp2_session_client_new2(&session, callbacks, this,
933                                    config.http2_option);
934
935   if (rv != 0) {
936     return -1;
937   }
938   if (need_upgrade()) {
939     // Adjust stream user-data depending on the existence of upload
940     // data
941     Request *stream_user_data = nullptr;
942     if (!reqvec[0]->data_prd) {
943       stream_user_data = reqvec[0].get();
944     }
945     rv = nghttp2_session_upgrade(session, settings_payload.data(),
946                                  settings_payloadlen, stream_user_data);
947     if (rv != 0) {
948       std::cerr << "[ERROR] nghttp2_session_upgrade() returned error: "
949                 << nghttp2_strerror(rv) << std::endl;
950       return -1;
951     }
952     if (stream_user_data) {
953       stream_user_data->stream_id = 1;
954       request_done(stream_user_data);
955     }
956   }
957   // If upgrade succeeds, the SETTINGS value sent with
958   // HTTP2-Settings header field has already been submitted to
959   // session object.
960   if (!need_upgrade()) {
961     std::array<nghttp2_settings_entry, 16> iv;
962     auto niv = populate_settings(iv.data());
963     rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv.data(), niv);
964     if (rv != 0) {
965       return -1;
966     }
967   }
968   if (!config.no_dep) {
969     // Create anchor stream nodes
970     nghttp2_priority_spec pri_spec;
971
972     for (auto &anchor : anchors) {
973       nghttp2_priority_spec_init(&pri_spec, anchor.dep_stream_id, anchor.weight,
974                                  0);
975       rv = nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, anchor.stream_id,
976                                    &pri_spec);
977       if (rv != 0) {
978         return -1;
979       }
980     }
981
982     rv = nghttp2_session_set_next_stream_id(
983         session, anchors[ANCHOR_FOLLOWERS].stream_id + 2);
984     if (rv != 0) {
985       return -1;
986     }
987
988     if (need_upgrade()) {
989       // Amend the priority because we cannot send priority in
990       // HTTP/1.1 Upgrade.
991       auto &anchor = anchors[ANCHOR_FOLLOWERS];
992       nghttp2_priority_spec_init(&pri_spec, anchor.stream_id, config.weight, 0);
993
994       rv = nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 1, &pri_spec);
995       if (rv != 0) {
996         return -1;
997       }
998     }
999   } else if (need_upgrade() && config.weight != NGHTTP2_DEFAULT_WEIGHT) {
1000     // Amend the priority because we cannot send priority in
1001     // HTTP/1.1 Upgrade.
1002     nghttp2_priority_spec pri_spec;
1003
1004     nghttp2_priority_spec_init(&pri_spec, 0, config.weight, 0);
1005
1006     rv = nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 1, &pri_spec);
1007     if (rv != 0) {
1008       return -1;
1009     }
1010   }
1011
1012   ev_timer_again(loop, &settings_timer);
1013
1014   if (config.connection_window_bits != -1) {
1015     int32_t wininc = (1 << config.connection_window_bits) - 1 -
1016                      NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
1017     rv = nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0, wininc);
1018     if (rv != 0) {
1019       return -1;
1020     }
1021   }
1022   // Adjust first request depending on the existence of the upload
1023   // data
1024   for (auto i = std::begin(reqvec) + (need_upgrade() && !reqvec[0]->data_prd);
1025        i != std::end(reqvec); ++i) {
1026     if (submit_request(this, config.headers, (*i).get()) != 0) {
1027       return -1;
1028     }
1029   }
1030
1031   signal_write();
1032
1033   return 0;
1034 }
1035
1036 int HttpClient::on_read(const uint8_t *data, size_t len) {
1037   if (config.hexdump) {
1038     util::hexdump(stdout, data, len);
1039   }
1040
1041   auto rv = nghttp2_session_mem_recv(session, data, len);
1042   if (rv < 0) {
1043     std::cerr << "[ERROR] nghttp2_session_mem_recv() returned error: "
1044               << nghttp2_strerror(rv) << std::endl;
1045     return -1;
1046   }
1047
1048   assert(static_cast<size_t>(rv) == len);
1049
1050   if (nghttp2_session_want_read(session) == 0 &&
1051       nghttp2_session_want_write(session) == 0 && wb.rleft() == 0) {
1052     return -1;
1053   }
1054
1055   signal_write();
1056
1057   return 0;
1058 }
1059
1060 int HttpClient::on_write() {
1061   auto rv = nghttp2_session_send(session);
1062   if (rv != 0) {
1063     std::cerr << "[ERROR] nghttp2_session_send() returned error: "
1064               << nghttp2_strerror(rv) << std::endl;
1065     return -1;
1066   }
1067
1068   if (nghttp2_session_want_read(session) == 0 &&
1069       nghttp2_session_want_write(session) == 0 && wb.rleft() == 0) {
1070     return -1;
1071   }
1072
1073   return 0;
1074 }
1075
1076 int HttpClient::tls_handshake() {
1077   ev_timer_again(loop, &rt);
1078
1079   ERR_clear_error();
1080
1081   auto rv = SSL_do_handshake(ssl);
1082
1083   if (rv == 0) {
1084     return -1;
1085   }
1086
1087   if (rv < 0) {
1088     auto err = SSL_get_error(ssl, rv);
1089     switch (err) {
1090     case SSL_ERROR_WANT_READ:
1091       ev_io_stop(loop, &wev);
1092       ev_timer_stop(loop, &wt);
1093       return 0;
1094     case SSL_ERROR_WANT_WRITE:
1095       ev_io_start(loop, &wev);
1096       ev_timer_again(loop, &wt);
1097       return 0;
1098     default:
1099       return -1;
1100     }
1101   }
1102
1103   ev_io_stop(loop, &wev);
1104   ev_timer_stop(loop, &wt);
1105
1106   readfn = &HttpClient::read_tls;
1107   writefn = &HttpClient::write_tls;
1108
1109   if (connection_made() != 0) {
1110     return -1;
1111   }
1112
1113   return 0;
1114 }
1115
1116 int HttpClient::read_tls() {
1117   ev_timer_again(loop, &rt);
1118
1119   ERR_clear_error();
1120
1121   std::array<uint8_t, 8192> buf;
1122   for (;;) {
1123     auto rv = SSL_read(ssl, buf.data(), buf.size());
1124
1125     if (rv == 0) {
1126       return -1;
1127     }
1128
1129     if (rv < 0) {
1130       auto err = SSL_get_error(ssl, rv);
1131       switch (err) {
1132       case SSL_ERROR_WANT_READ:
1133         return 0;
1134       case SSL_ERROR_WANT_WRITE:
1135         // renegotiation started
1136         return -1;
1137       default:
1138         return -1;
1139       }
1140     }
1141
1142     if (on_readfn(*this, buf.data(), rv) != 0) {
1143       return -1;
1144     }
1145   }
1146 }
1147
1148 int HttpClient::write_tls() {
1149   ev_timer_again(loop, &rt);
1150
1151   ERR_clear_error();
1152
1153   for (;;) {
1154     if (wb.rleft() > 0) {
1155       auto rv = SSL_write(ssl, wb.pos, wb.rleft());
1156
1157       if (rv == 0) {
1158         return -1;
1159       }
1160
1161       if (rv < 0) {
1162         auto err = SSL_get_error(ssl, rv);
1163         switch (err) {
1164         case SSL_ERROR_WANT_READ:
1165           // renegotiation started
1166           return -1;
1167         case SSL_ERROR_WANT_WRITE:
1168           ev_io_start(loop, &wev);
1169           ev_timer_again(loop, &wt);
1170           return 0;
1171         default:
1172           return -1;
1173         }
1174       }
1175
1176       wb.drain(rv);
1177
1178       continue;
1179     }
1180     wb.reset();
1181     if (on_writefn(*this) != 0) {
1182       return -1;
1183     }
1184     if (wb.rleft() == 0) {
1185       break;
1186     }
1187   }
1188
1189   ev_io_stop(loop, &wev);
1190   ev_timer_stop(loop, &wt);
1191
1192   return 0;
1193 }
1194
1195 void HttpClient::signal_write() { ev_io_start(loop, &wev); }
1196
1197 bool HttpClient::all_requests_processed() const {
1198   return complete == reqvec.size();
1199 }
1200
1201 void HttpClient::update_hostport() {
1202   if (reqvec.empty()) {
1203     return;
1204   }
1205   scheme = util::get_uri_field(reqvec[0]->uri.c_str(), reqvec[0]->u, UF_SCHEMA);
1206   std::stringstream ss;
1207   if (reqvec[0]->is_ipv6_literal_addr()) {
1208     ss << "[";
1209     util::write_uri_field(ss, reqvec[0]->uri.c_str(), reqvec[0]->u, UF_HOST);
1210     ss << "]";
1211   } else {
1212     util::write_uri_field(ss, reqvec[0]->uri.c_str(), reqvec[0]->u, UF_HOST);
1213   }
1214   if (util::has_uri_field(reqvec[0]->u, UF_PORT) &&
1215       reqvec[0]->u.port !=
1216           util::get_default_port(reqvec[0]->uri.c_str(), reqvec[0]->u)) {
1217     ss << ":" << reqvec[0]->u.port;
1218   }
1219   hostport = ss.str();
1220 }
1221
1222 bool HttpClient::add_request(const std::string &uri,
1223                              const nghttp2_data_provider *data_prd,
1224                              int64_t data_length,
1225                              const nghttp2_priority_spec &pri_spec, int level) {
1226   http_parser_url u;
1227   memset(&u, 0, sizeof(u));
1228   if (http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) != 0) {
1229     return false;
1230   }
1231   if (path_cache.count(uri)) {
1232     return false;
1233   }
1234
1235   if (config.multiply == 1) {
1236     path_cache.insert(uri);
1237   }
1238
1239   reqvec.push_back(
1240       make_unique<Request>(uri, u, data_prd, data_length, pri_spec, level));
1241   return true;
1242 }
1243
1244 void HttpClient::record_start_time() {
1245   timing.system_start_time = std::chrono::system_clock::now();
1246   timing.start_time = get_time();
1247 }
1248
1249 void HttpClient::record_domain_lookup_end_time() {
1250   timing.domain_lookup_end_time = get_time();
1251 }
1252
1253 void HttpClient::record_connect_end_time() {
1254   timing.connect_end_time = get_time();
1255 }
1256
1257 void HttpClient::request_done(Request *req) {
1258   if (req->stream_id % 2 == 0) {
1259     return;
1260   }
1261 }
1262
1263 #ifdef HAVE_JANSSON
1264 void HttpClient::output_har(FILE *outfile) {
1265   static auto PAGE_ID = "page_0";
1266
1267   auto root = json_object();
1268   auto log = json_object();
1269   json_object_set_new(root, "log", log);
1270   json_object_set_new(log, "version", json_string("1.2"));
1271
1272   auto creator = json_object();
1273   json_object_set_new(log, "creator", creator);
1274
1275   json_object_set_new(creator, "name", json_string("nghttp"));
1276   json_object_set_new(creator, "version", json_string(NGHTTP2_VERSION));
1277
1278   auto pages = json_array();
1279   json_object_set_new(log, "pages", pages);
1280
1281   auto page = json_object();
1282   json_array_append_new(pages, page);
1283
1284   json_object_set_new(
1285       page, "startedDateTime",
1286       json_string(util::format_iso8601(timing.system_start_time).c_str()));
1287   json_object_set_new(page, "id", json_string(PAGE_ID));
1288   json_object_set_new(page, "title", json_string(""));
1289
1290   json_object_set_new(page, "pageTimings", json_object());
1291
1292   auto entries = json_array();
1293   json_object_set_new(log, "entries", entries);
1294
1295   auto dns_delta =
1296       std::chrono::duration_cast<std::chrono::microseconds>(
1297           timing.domain_lookup_end_time - timing.start_time).count() /
1298       1000.0;
1299   auto connect_delta =
1300       std::chrono::duration_cast<std::chrono::microseconds>(
1301           timing.connect_end_time - timing.domain_lookup_end_time).count() /
1302       1000.0;
1303
1304   for (size_t i = 0; i < reqvec.size(); ++i) {
1305     auto &req = reqvec[i];
1306
1307     if (req->timing.state != RequestState::ON_COMPLETE) {
1308       continue;
1309     }
1310
1311     auto entry = json_object();
1312     json_array_append_new(entries, entry);
1313
1314     auto &req_timing = req->timing;
1315     auto request_time =
1316         (i == 0) ? timing.system_start_time
1317                  : timing.system_start_time +
1318                        std::chrono::duration_cast<
1319                            std::chrono::system_clock::duration>(
1320                            req_timing.request_start_time - timing.start_time);
1321
1322     auto wait_delta = std::chrono::duration_cast<std::chrono::microseconds>(
1323                           req_timing.response_start_time -
1324                           req_timing.request_start_time).count() /
1325                       1000.0;
1326     auto receive_delta = std::chrono::duration_cast<std::chrono::microseconds>(
1327                              req_timing.response_end_time -
1328                              req_timing.response_start_time).count() /
1329                          1000.0;
1330
1331     auto time_sum =
1332         std::chrono::duration_cast<std::chrono::microseconds>(
1333             (i == 0) ? (req_timing.response_end_time - timing.start_time)
1334                      : (req_timing.response_end_time -
1335                         req_timing.request_start_time)).count() /
1336         1000.0;
1337
1338     json_object_set_new(
1339         entry, "startedDateTime",
1340         json_string(util::format_iso8601(request_time).c_str()));
1341     json_object_set_new(entry, "time", json_real(time_sum));
1342
1343     auto request = json_object();
1344     json_object_set_new(entry, "request", request);
1345
1346     auto method_ptr = http2::get_header(req->req_nva, ":method");
1347
1348     const char *method = "GET";
1349     if (method_ptr) {
1350       method = (*method_ptr).value.c_str();
1351     }
1352
1353     auto req_headers = json_array();
1354     json_object_set_new(request, "headers", req_headers);
1355
1356     for (auto &nv : req->req_nva) {
1357       auto hd = json_object();
1358       json_array_append_new(req_headers, hd);
1359
1360       json_object_set_new(hd, "name", json_string(nv.name.c_str()));
1361       json_object_set_new(hd, "value", json_string(nv.value.c_str()));
1362     }
1363
1364     json_object_set_new(request, "method", json_string(method));
1365     json_object_set_new(request, "url", json_string(req->uri.c_str()));
1366     json_object_set_new(request, "httpVersion", json_string("HTTP/2.0"));
1367     json_object_set_new(request, "cookies", json_array());
1368     json_object_set_new(request, "queryString", json_array());
1369     json_object_set_new(request, "headersSize", json_integer(-1));
1370     json_object_set_new(request, "bodySize", json_integer(-1));
1371
1372     auto response = json_object();
1373     json_object_set_new(entry, "response", response);
1374
1375     auto res_headers = json_array();
1376     json_object_set_new(response, "headers", res_headers);
1377
1378     for (auto &nv : req->res_nva) {
1379       auto hd = json_object();
1380       json_array_append_new(res_headers, hd);
1381
1382       json_object_set_new(hd, "name", json_string(nv.name.c_str()));
1383       json_object_set_new(hd, "value", json_string(nv.value.c_str()));
1384     }
1385
1386     json_object_set_new(response, "status", json_integer(req->status));
1387     json_object_set_new(response, "statusText", json_string(""));
1388     json_object_set_new(response, "httpVersion", json_string("HTTP/2.0"));
1389     json_object_set_new(response, "cookies", json_array());
1390
1391     auto content = json_object();
1392     json_object_set_new(response, "content", content);
1393
1394     json_object_set_new(content, "size", json_integer(req->response_len));
1395
1396     auto content_type_ptr = http2::get_header(req->res_nva, "content-type");
1397
1398     const char *content_type = "";
1399     if (content_type_ptr) {
1400       content_type = content_type_ptr->value.c_str();
1401     }
1402
1403     json_object_set_new(content, "mimeType", json_string(content_type));
1404
1405     json_object_set_new(response, "redirectURL", json_string(""));
1406     json_object_set_new(response, "headersSize", json_integer(-1));
1407     json_object_set_new(response, "bodySize", json_integer(-1));
1408
1409     json_object_set_new(entry, "cache", json_object());
1410
1411     auto timings = json_object();
1412     json_object_set_new(entry, "timings", timings);
1413
1414     auto dns_timing = (i == 0) ? dns_delta : 0;
1415     auto connect_timing = (i == 0) ? connect_delta : 0;
1416
1417     json_object_set_new(timings, "dns", json_real(dns_timing));
1418     json_object_set_new(timings, "connect", json_real(connect_timing));
1419
1420     json_object_set_new(timings, "blocked", json_real(0.0));
1421     json_object_set_new(timings, "send", json_real(0.0));
1422     json_object_set_new(timings, "wait", json_real(wait_delta));
1423     json_object_set_new(timings, "receive", json_real(receive_delta));
1424
1425     json_object_set_new(entry, "pageref", json_string(PAGE_ID));
1426   }
1427
1428   json_dumpf(root, outfile, JSON_PRESERVE_ORDER | JSON_INDENT(2));
1429   json_decref(root);
1430 }
1431 #endif // HAVE_JANSSON
1432
1433 namespace {
1434 void update_html_parser(HttpClient *client, Request *req, const uint8_t *data,
1435                         size_t len, int fin) {
1436   if (!req->html_parser) {
1437     return;
1438   }
1439   req->update_html_parser(data, len, fin);
1440
1441   for (auto &p : req->html_parser->get_links()) {
1442     auto uri = strip_fragment(p.first.c_str());
1443     auto res_type = p.second;
1444
1445     http_parser_url u;
1446     memset(&u, 0, sizeof(u));
1447     if (http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) == 0 &&
1448         util::fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_SCHEMA) &&
1449         util::fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_HOST) &&
1450         util::porteq(uri.c_str(), u, req->uri.c_str(), req->u)) {
1451       // No POST data for assets
1452       auto pri_spec = resolve_dep(res_type);
1453
1454       if (client->add_request(uri, nullptr, 0, pri_spec, req->level + 1)) {
1455
1456         submit_request(client, config.headers, client->reqvec.back().get());
1457       }
1458     }
1459   }
1460   req->html_parser->clear_links();
1461 }
1462 } // namespace
1463
1464 namespace {
1465 HttpClient *get_client(void *user_data) {
1466   return static_cast<HttpClient *>(user_data);
1467 }
1468 } // namespace
1469
1470 namespace {
1471 int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
1472                                 int32_t stream_id, const uint8_t *data,
1473                                 size_t len, void *user_data) {
1474   auto client = get_client(user_data);
1475   auto req = static_cast<Request *>(
1476       nghttp2_session_get_stream_user_data(session, stream_id));
1477
1478   if (!req) {
1479     return 0;
1480   }
1481
1482   if (config.verbose >= 2) {
1483     verbose_on_data_chunk_recv_callback(session, flags, stream_id, data, len,
1484                                         user_data);
1485   }
1486
1487   req->response_len += len;
1488
1489   if (req->inflater) {
1490     while (len > 0) {
1491       const size_t MAX_OUTLEN = 4096;
1492       std::array<uint8_t, MAX_OUTLEN> out;
1493       size_t outlen = MAX_OUTLEN;
1494       size_t tlen = len;
1495       int rv =
1496           nghttp2_gzip_inflate(req->inflater, out.data(), &outlen, data, &tlen);
1497       if (rv != 0) {
1498         nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, stream_id,
1499                                   NGHTTP2_INTERNAL_ERROR);
1500         break;
1501       }
1502
1503       if (!config.null_out) {
1504         std::cout.write(reinterpret_cast<const char *>(out.data()), outlen);
1505       }
1506
1507       update_html_parser(client, req, out.data(), outlen, 0);
1508       data += tlen;
1509       len -= tlen;
1510     }
1511
1512     return 0;
1513   }
1514
1515   if (!config.null_out) {
1516     std::cout.write(reinterpret_cast<const char *>(data), len);
1517   }
1518
1519   update_html_parser(client, req, data, len, 0);
1520
1521   return 0;
1522 }
1523 } // namespace
1524
1525 namespace {
1526 ssize_t select_padding_callback(nghttp2_session *session,
1527                                 const nghttp2_frame *frame, size_t max_payload,
1528                                 void *user_data) {
1529   return std::min(max_payload, frame->hd.length + config.padding);
1530 }
1531 } // namespace
1532
1533 namespace {
1534 void check_response_header(nghttp2_session *session, Request *req) {
1535   bool gzip = false;
1536
1537   req->expect_final_response = false;
1538
1539   auto status_hd = req->get_res_header(http2::HD__STATUS);
1540
1541   if (!status_hd) {
1542     nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, req->stream_id,
1543                               NGHTTP2_PROTOCOL_ERROR);
1544     return;
1545   }
1546
1547   auto status = http2::parse_http_status_code(status_hd->value);
1548   if (status == -1) {
1549     nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, req->stream_id,
1550                               NGHTTP2_PROTOCOL_ERROR);
1551     return;
1552   }
1553
1554   req->status = status;
1555
1556   for (auto &nv : req->res_nva) {
1557     if ("content-encoding" == nv.name) {
1558       gzip = util::strieq_l("gzip", nv.value) ||
1559              util::strieq_l("deflate", nv.value);
1560       continue;
1561     }
1562   }
1563
1564   if (req->status / 100 == 1) {
1565     req->expect_final_response = true;
1566     req->status = 0;
1567     req->res_nva.clear();
1568     http2::init_hdidx(req->res_hdidx);
1569     return;
1570   }
1571
1572   if (gzip) {
1573     if (!req->inflater) {
1574       req->init_inflater();
1575     }
1576   }
1577   if (config.get_assets && req->level == 0) {
1578     if (!req->html_parser) {
1579       req->init_html_parser();
1580     }
1581   }
1582 }
1583 } // namespace
1584
1585 namespace {
1586 int on_begin_headers_callback(nghttp2_session *session,
1587                               const nghttp2_frame *frame, void *user_data) {
1588   auto client = get_client(user_data);
1589   switch (frame->hd.type) {
1590   case NGHTTP2_HEADERS: {
1591     auto req = static_cast<Request *>(
1592         nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1593     if (!req) {
1594       break;
1595     }
1596
1597     switch (frame->headers.cat) {
1598     case NGHTTP2_HCAT_RESPONSE:
1599     case NGHTTP2_HCAT_PUSH_RESPONSE:
1600       req->record_response_start_time();
1601       break;
1602     default:
1603       break;
1604     }
1605
1606     break;
1607   }
1608   case NGHTTP2_PUSH_PROMISE: {
1609     auto stream_id = frame->push_promise.promised_stream_id;
1610     http_parser_url u;
1611     memset(&u, 0, sizeof(u));
1612     // TODO Set pri and level
1613     nghttp2_priority_spec pri_spec;
1614
1615     nghttp2_priority_spec_default_init(&pri_spec);
1616
1617     auto req = make_unique<Request>("", u, nullptr, 0, pri_spec);
1618     req->stream_id = stream_id;
1619
1620     nghttp2_session_set_stream_user_data(session, stream_id, req.get());
1621
1622     client->request_done(req.get());
1623     req->record_request_start_time();
1624     client->reqvec.push_back(std::move(req));
1625
1626     break;
1627   }
1628   }
1629   return 0;
1630 }
1631 } // namespace
1632
1633 namespace {
1634 int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
1635                        const uint8_t *name, size_t namelen,
1636                        const uint8_t *value, size_t valuelen, uint8_t flags,
1637                        void *user_data) {
1638   if (config.verbose) {
1639     verbose_on_header_callback(session, frame, name, namelen, value, valuelen,
1640                                flags, user_data);
1641   }
1642
1643   switch (frame->hd.type) {
1644   case NGHTTP2_HEADERS: {
1645     auto req = static_cast<Request *>(
1646         nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1647
1648     if (!req) {
1649       break;
1650     }
1651
1652     /* ignore trailer header */
1653     if (frame->headers.cat == NGHTTP2_HCAT_HEADERS &&
1654         !req->expect_final_response) {
1655       break;
1656     }
1657
1658     auto token = http2::lookup_token(name, namelen);
1659
1660     http2::index_header(req->res_hdidx, token, req->res_nva.size());
1661     http2::add_header(req->res_nva, name, namelen, value, valuelen,
1662                       flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
1663     break;
1664   }
1665   case NGHTTP2_PUSH_PROMISE: {
1666     auto req = static_cast<Request *>(nghttp2_session_get_stream_user_data(
1667         session, frame->push_promise.promised_stream_id));
1668
1669     if (!req) {
1670       break;
1671     }
1672
1673     auto token = http2::lookup_token(name, namelen);
1674
1675     http2::index_header(req->req_hdidx, token, req->req_nva.size());
1676     http2::add_header(req->req_nva, name, namelen, value, valuelen,
1677                       flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
1678     break;
1679   }
1680   }
1681   return 0;
1682 }
1683 } // namespace
1684
1685 namespace {
1686 int on_frame_recv_callback2(nghttp2_session *session,
1687                             const nghttp2_frame *frame, void *user_data) {
1688   int rv = 0;
1689
1690   if (config.verbose) {
1691     verbose_on_frame_recv_callback(session, frame, user_data);
1692   }
1693
1694   auto client = get_client(user_data);
1695   switch (frame->hd.type) {
1696   case NGHTTP2_DATA: {
1697     auto req = static_cast<Request *>(
1698         nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1699     if (!req) {
1700       return 0;
1701       ;
1702     }
1703
1704     if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
1705       req->record_response_end_time();
1706       ++client->success;
1707     }
1708
1709     break;
1710   }
1711   case NGHTTP2_HEADERS: {
1712     auto req = static_cast<Request *>(
1713         nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1714     // If this is the HTTP Upgrade with OPTIONS method to avoid POST,
1715     // req is nullptr.
1716     if (!req) {
1717       return 0;
1718       ;
1719     }
1720
1721     switch (frame->headers.cat) {
1722     case NGHTTP2_HCAT_RESPONSE:
1723     case NGHTTP2_HCAT_PUSH_RESPONSE:
1724       check_response_header(session, req);
1725       break;
1726     case NGHTTP2_HCAT_HEADERS:
1727       if (req->expect_final_response) {
1728         check_response_header(session, req);
1729         break;
1730       }
1731       if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
1732         nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
1733                                   frame->hd.stream_id, NGHTTP2_PROTOCOL_ERROR);
1734         return 0;
1735       }
1736       break;
1737     default:
1738       assert(0);
1739     }
1740
1741     if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
1742       req->record_response_end_time();
1743       ++client->success;
1744     }
1745
1746     break;
1747   }
1748   case NGHTTP2_SETTINGS:
1749     if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
1750       break;
1751     }
1752     ev_timer_stop(client->loop, &client->settings_timer);
1753     break;
1754   case NGHTTP2_PUSH_PROMISE: {
1755     auto req = static_cast<Request *>(nghttp2_session_get_stream_user_data(
1756         session, frame->push_promise.promised_stream_id));
1757     if (!req) {
1758       break;
1759     }
1760     auto scheme = req->get_req_header(http2::HD__SCHEME);
1761     auto authority = req->get_req_header(http2::HD__AUTHORITY);
1762     auto path = req->get_req_header(http2::HD__PATH);
1763
1764     if (!authority) {
1765       authority = req->get_req_header(http2::HD_HOST);
1766     }
1767
1768     // libnghttp2 guarantees :scheme, :method, :path and (:authority |
1769     // host) exist and non-empty.
1770     if (path->value[0] != '/') {
1771       nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
1772                                 frame->push_promise.promised_stream_id,
1773                                 NGHTTP2_PROTOCOL_ERROR);
1774       break;
1775     }
1776     std::string uri = scheme->value;
1777     uri += "://";
1778     uri += authority->value;
1779     uri += path->value;
1780     http_parser_url u;
1781     memset(&u, 0, sizeof(u));
1782     if (http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) != 0) {
1783       nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
1784                                 frame->push_promise.promised_stream_id,
1785                                 NGHTTP2_PROTOCOL_ERROR);
1786       break;
1787     }
1788     req->uri = uri;
1789     req->u = u;
1790
1791     if (client->path_cache.count(uri)) {
1792       nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
1793                                 frame->push_promise.promised_stream_id,
1794                                 NGHTTP2_CANCEL);
1795       break;
1796     }
1797
1798     if (config.multiply == 1) {
1799       client->path_cache.insert(uri);
1800     }
1801
1802     break;
1803   }
1804   }
1805   return rv;
1806 }
1807 } // namespace
1808
1809 namespace {
1810 int before_frame_send_callback(nghttp2_session *session,
1811                                const nghttp2_frame *frame, void *user_data) {
1812   if (frame->hd.type != NGHTTP2_HEADERS ||
1813       frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
1814     return 0;
1815   }
1816   auto req = static_cast<Request *>(
1817       nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1818   assert(req);
1819   req->record_request_start_time();
1820   return 0;
1821 }
1822
1823 } // namespace
1824
1825 namespace {
1826 int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
1827                              uint32_t error_code, void *user_data) {
1828   auto client = get_client(user_data);
1829   auto req = static_cast<Request *>(
1830       nghttp2_session_get_stream_user_data(session, stream_id));
1831
1832   if (!req) {
1833     return 0;
1834   }
1835
1836   update_html_parser(client, req, nullptr, 0, 1);
1837   ++client->complete;
1838
1839   if (client->all_requests_processed()) {
1840     nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
1841   }
1842
1843   return 0;
1844 }
1845 } // namespace
1846
1847 struct RequestResult {
1848   std::chrono::microseconds time;
1849 };
1850
1851 namespace {
1852 void print_stats(const HttpClient &client) {
1853   std::cout << "***** Statistics *****" << std::endl;
1854
1855   std::vector<Request *> reqs;
1856   reqs.reserve(client.reqvec.size());
1857   for (const auto &req : client.reqvec) {
1858     if (req->timing.state == RequestState::ON_COMPLETE) {
1859       reqs.push_back(req.get());
1860     }
1861   }
1862
1863   std::sort(std::begin(reqs), std::end(reqs),
1864             [](const Request *lhs, const Request *rhs) {
1865     const auto &ltiming = lhs->timing;
1866     const auto &rtiming = rhs->timing;
1867     return ltiming.response_end_time < rtiming.response_end_time ||
1868            (ltiming.response_end_time == rtiming.response_end_time &&
1869             ltiming.request_start_time < rtiming.request_start_time);
1870   });
1871
1872   std::cout << R"(
1873 Request timing:
1874   responseEnd: the  time  when  last  byte of  response  was  received
1875                relative to connectEnd
1876  requestStart: the time  just before  first byte  of request  was sent
1877                relative  to connectEnd.   If  '*' is  shown, this  was
1878                pushed by server.
1879       process: responseEnd - requestStart
1880          code: HTTP status code
1881          size: number  of  bytes  received as  response  body  without
1882                inflation.
1883           URI: request URI
1884
1885 see http://www.w3.org/TR/resource-timing/#processing-model
1886
1887 sorted by 'complete'
1888
1889 id  responseEnd requestStart  process code size request path)" << std::endl;
1890
1891   const auto &base = client.timing.connect_end_time;
1892   for (const auto &req : reqs) {
1893     auto response_end = std::chrono::duration_cast<std::chrono::microseconds>(
1894         req->timing.response_end_time - base);
1895     auto request_start = std::chrono::duration_cast<std::chrono::microseconds>(
1896         req->timing.request_start_time - base);
1897     auto total = std::chrono::duration_cast<std::chrono::microseconds>(
1898         req->timing.response_end_time - req->timing.request_start_time);
1899     auto pushed = req->stream_id % 2 == 0;
1900
1901     std::cout << std::setw(3) << req->stream_id << " " << std::setw(11)
1902               << ("+" + util::format_duration(response_end)) << " "
1903               << (pushed ? "*" : " ") << std::setw(11)
1904               << ("+" + util::format_duration(request_start)) << " "
1905               << std::setw(8) << util::format_duration(total) << " "
1906               << std::setw(4) << req->status << " " << std::setw(4)
1907               << util::utos_with_unit(req->response_len) << " "
1908               << req->make_reqpath() << std::endl;
1909   }
1910 }
1911 } // namespace
1912
1913 namespace {
1914 int client_select_next_proto_cb(SSL *ssl, unsigned char **out,
1915                                 unsigned char *outlen, const unsigned char *in,
1916                                 unsigned int inlen, void *arg) {
1917   if (config.verbose) {
1918     print_timer();
1919     std::cout << "[NPN] server offers:" << std::endl;
1920   }
1921   for (unsigned int i = 0; i < inlen; i += in [i] + 1) {
1922     if (config.verbose) {
1923       std::cout << "          * ";
1924       std::cout.write(reinterpret_cast<const char *>(&in[i + 1]), in[i]);
1925       std::cout << std::endl;
1926     }
1927   }
1928   if (!util::select_h2(const_cast<const unsigned char **>(out), outlen, in,
1929                        inlen)) {
1930     print_protocol_nego_error();
1931     return SSL_TLSEXT_ERR_NOACK;
1932   }
1933   return SSL_TLSEXT_ERR_OK;
1934 }
1935 } // namespace
1936
1937 namespace {
1938 // Recommended general purpose "Intermediate compatibility" cipher by
1939 // mozilla.
1940 //
1941 // https://wiki.mozilla.org/Security/Server_Side_TLS
1942 const char *const CIPHER_LIST =
1943     "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-"
1944     "AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:"
1945     "DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-"
1946     "AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-"
1947     "AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-"
1948     "AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:"
1949     "DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-"
1950     "SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-"
1951     "SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!"
1952     "aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
1953 } // namespace
1954
1955 namespace {
1956 int communicate(
1957     const std::string &scheme, const std::string &host, uint16_t port,
1958     std::vector<std::tuple<std::string, nghttp2_data_provider *, int64_t>>
1959         requests, const nghttp2_session_callbacks *callbacks) {
1960   int result = 0;
1961   auto loop = EV_DEFAULT;
1962   SSL_CTX *ssl_ctx = nullptr;
1963   if (scheme == "https") {
1964     ssl_ctx = SSL_CTX_new(SSLv23_client_method());
1965     if (!ssl_ctx) {
1966       std::cerr << "[ERROR] Failed to create SSL_CTX: "
1967                 << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
1968       result = -1;
1969       goto fin;
1970     }
1971     SSL_CTX_set_options(ssl_ctx,
1972                         SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
1973                             SSL_OP_NO_COMPRESSION |
1974                             SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
1975     SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
1976     SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
1977     if (SSL_CTX_set_cipher_list(ssl_ctx, CIPHER_LIST) == 0) {
1978       std::cerr << "[ERROR] " << ERR_error_string(ERR_get_error(), nullptr)
1979                 << std::endl;
1980       result = -1;
1981       goto fin;
1982     }
1983     if (!config.keyfile.empty()) {
1984       if (SSL_CTX_use_PrivateKey_file(ssl_ctx, config.keyfile.c_str(),
1985                                       SSL_FILETYPE_PEM) != 1) {
1986         std::cerr << "[ERROR] " << ERR_error_string(ERR_get_error(), nullptr)
1987                   << std::endl;
1988         result = -1;
1989         goto fin;
1990       }
1991     }
1992     if (!config.certfile.empty()) {
1993       if (SSL_CTX_use_certificate_chain_file(ssl_ctx,
1994                                              config.certfile.c_str()) != 1) {
1995         std::cerr << "[ERROR] " << ERR_error_string(ERR_get_error(), nullptr)
1996                   << std::endl;
1997         result = -1;
1998         goto fin;
1999       }
2000     }
2001     SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
2002                                      nullptr);
2003
2004 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
2005     auto proto_list = util::get_default_alpn();
2006
2007     SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
2008 #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
2009   }
2010   {
2011     HttpClient client{callbacks, loop, ssl_ctx};
2012
2013     nghttp2_priority_spec pri_spec;
2014     int32_t dep_stream_id = 0;
2015
2016     if (!config.no_dep) {
2017       dep_stream_id = anchors[ANCHOR_FOLLOWERS].stream_id;
2018     }
2019
2020     nghttp2_priority_spec_init(&pri_spec, dep_stream_id, config.weight, 0);
2021
2022     for (auto req : requests) {
2023       for (int i = 0; i < config.multiply; ++i) {
2024         client.add_request(std::get<0>(req), std::get<1>(req), std::get<2>(req),
2025                            pri_spec);
2026       }
2027     }
2028     client.update_hostport();
2029
2030     client.record_start_time();
2031
2032     if (client.resolve_host(host, port) != 0) {
2033       goto fin;
2034     }
2035
2036     client.record_domain_lookup_end_time();
2037
2038     if (client.initiate_connection() != 0) {
2039       goto fin;
2040     }
2041     ev_run(loop, 0);
2042
2043 #ifdef HAVE_JANSSON
2044     if (!config.harfile.empty()) {
2045       FILE *outfile;
2046       if (config.harfile == "-") {
2047         outfile = stdout;
2048       } else {
2049         outfile = fopen(config.harfile.c_str(), "wb");
2050       }
2051
2052       if (outfile) {
2053         client.output_har(outfile);
2054
2055         if (outfile != stdout) {
2056           fclose(outfile);
2057         }
2058       } else {
2059         std::cerr << "Cannot open file " << config.harfile << ". "
2060                   << "har file could not be created." << std::endl;
2061       }
2062     }
2063 #endif // HAVE_JANSSON
2064
2065     if (client.success != client.reqvec.size()) {
2066       std::cerr << "Some requests were not processed. total="
2067                 << client.reqvec.size() << ", processed=" << client.success
2068                 << std::endl;
2069     }
2070     if (config.stat) {
2071       print_stats(client);
2072     }
2073   }
2074 fin:
2075   if (ssl_ctx) {
2076     SSL_CTX_free(ssl_ctx);
2077   }
2078   return result;
2079 }
2080 } // namespace
2081
2082 namespace {
2083 ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
2084                            uint8_t *buf, size_t length, uint32_t *data_flags,
2085                            nghttp2_data_source *source, void *user_data) {
2086   int rv;
2087   auto req = static_cast<Request *>(
2088       nghttp2_session_get_stream_user_data(session, stream_id));
2089   assert(req);
2090   int fd = source->fd;
2091   ssize_t nread;
2092
2093   while ((nread = pread(fd, buf, length, req->data_offset)) == -1 &&
2094          errno == EINTR)
2095     ;
2096
2097   if (nread == -1) {
2098     return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
2099   }
2100
2101   if (nread == 0) {
2102     *data_flags |= NGHTTP2_DATA_FLAG_EOF;
2103     if (!config.trailer.empty()) {
2104       std::vector<nghttp2_nv> nva;
2105       nva.reserve(config.trailer.size());
2106       for (auto &kv : config.trailer) {
2107         nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index));
2108       }
2109       rv = nghttp2_submit_trailer(session, stream_id, nva.data(), nva.size());
2110       if (rv != 0) {
2111         if (nghttp2_is_fatal(rv)) {
2112           return NGHTTP2_ERR_CALLBACK_FAILURE;
2113         }
2114       } else {
2115         *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
2116       }
2117     }
2118   } else {
2119     req->data_offset += nread;
2120   }
2121
2122   return nread;
2123 }
2124 } // namespace
2125
2126 namespace {
2127 ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
2128                       size_t length, int flags, void *user_data) {
2129   auto client = static_cast<HttpClient *>(user_data);
2130   auto &wb = client->wb;
2131
2132   if (wb.wleft() == 0) {
2133     return NGHTTP2_ERR_WOULDBLOCK;
2134   }
2135
2136   return wb.write(data, length);
2137 }
2138 } // namespace
2139
2140 namespace {
2141 int run(char **uris, int n) {
2142   nghttp2_session_callbacks *callbacks;
2143
2144   nghttp2_session_callbacks_new(&callbacks);
2145   auto cbsdel = defer(nghttp2_session_callbacks_del, callbacks);
2146
2147   nghttp2_session_callbacks_set_on_stream_close_callback(
2148       callbacks, on_stream_close_callback);
2149
2150   nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
2151                                                        on_frame_recv_callback2);
2152
2153   if (config.verbose) {
2154     nghttp2_session_callbacks_set_on_frame_send_callback(
2155         callbacks, verbose_on_frame_send_callback);
2156
2157     nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
2158         callbacks, verbose_on_invalid_frame_recv_callback);
2159   }
2160
2161   nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
2162       callbacks, on_data_chunk_recv_callback);
2163
2164   nghttp2_session_callbacks_set_on_begin_headers_callback(
2165       callbacks, on_begin_headers_callback);
2166
2167   nghttp2_session_callbacks_set_on_header_callback(callbacks,
2168                                                    on_header_callback);
2169
2170   nghttp2_session_callbacks_set_before_frame_send_callback(
2171       callbacks, before_frame_send_callback);
2172
2173   nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
2174
2175   if (config.padding) {
2176     nghttp2_session_callbacks_set_select_padding_callback(
2177         callbacks, select_padding_callback);
2178   }
2179
2180   std::string prev_scheme;
2181   std::string prev_host;
2182   uint16_t prev_port = 0;
2183   int failures = 0;
2184   int data_fd = -1;
2185   nghttp2_data_provider data_prd;
2186   struct stat data_stat;
2187
2188   if (!config.datafile.empty()) {
2189     if (config.datafile == "-") {
2190       if (fstat(0, &data_stat) == 0 &&
2191           (data_stat.st_mode & S_IFMT) == S_IFREG) {
2192         // use STDIN if it is a regular file
2193         data_fd = 0;
2194       } else {
2195         // copy the contents of STDIN to a temporary file
2196         char tempfn[] = "/tmp/nghttp.temp.XXXXXX";
2197         data_fd = mkstemp(tempfn);
2198         if (data_fd == -1) {
2199           std::cerr << "[ERROR] Could not create a temporary file in /tmp"
2200                     << std::endl;
2201           return 1;
2202         }
2203         if (unlink(tempfn) != 0) {
2204           std::cerr << "[WARNING] failed to unlink temporary file:" << tempfn
2205                     << std::endl;
2206         }
2207         while (1) {
2208           std::array<char, 1024> buf;
2209           ssize_t rret, wret;
2210           while ((rret = read(0, buf.data(), buf.size())) == -1 &&
2211                  errno == EINTR)
2212             ;
2213           if (rret == 0)
2214             break;
2215           if (rret == -1) {
2216             std::cerr << "[ERROR] I/O error while reading from STDIN"
2217                       << std::endl;
2218             return 1;
2219           }
2220           while ((wret = write(data_fd, buf.data(), rret)) == -1 &&
2221                  errno == EINTR)
2222             ;
2223           if (wret != rret) {
2224             std::cerr << "[ERROR] I/O error while writing to temporary file"
2225                       << std::endl;
2226             return 1;
2227           }
2228         }
2229         if (fstat(data_fd, &data_stat) == -1) {
2230           close(data_fd);
2231           std::cerr << "[ERROR] Could not stat temporary file" << std::endl;
2232           return 1;
2233         }
2234       }
2235     } else {
2236       data_fd = open(config.datafile.c_str(), O_RDONLY | O_BINARY);
2237       if (data_fd == -1) {
2238         std::cerr << "[ERROR] Could not open file " << config.datafile
2239                   << std::endl;
2240         return 1;
2241       }
2242       if (fstat(data_fd, &data_stat) == -1) {
2243         close(data_fd);
2244         std::cerr << "[ERROR] Could not stat file " << config.datafile
2245                   << std::endl;
2246         return 1;
2247       }
2248     }
2249     data_prd.source.fd = data_fd;
2250     data_prd.read_callback = file_read_callback;
2251   }
2252   std::vector<std::tuple<std::string, nghttp2_data_provider *, int64_t>>
2253       requests;
2254   for (int i = 0; i < n; ++i) {
2255     http_parser_url u;
2256     memset(&u, 0, sizeof(u));
2257     auto uri = strip_fragment(uris[i]);
2258     if (http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) == 0 &&
2259         util::has_uri_field(u, UF_SCHEMA)) {
2260       uint16_t port = util::has_uri_field(u, UF_PORT)
2261                           ? u.port
2262                           : util::get_default_port(uri.c_str(), u);
2263       if (!util::fieldeq(uri.c_str(), u, UF_SCHEMA, prev_scheme.c_str()) ||
2264           !util::fieldeq(uri.c_str(), u, UF_HOST, prev_host.c_str()) ||
2265           port != prev_port) {
2266         if (!requests.empty()) {
2267           if (communicate(prev_scheme, prev_host, prev_port,
2268                           std::move(requests), callbacks) != 0) {
2269             ++failures;
2270           }
2271           requests.clear();
2272         }
2273         prev_scheme = util::get_uri_field(uri.c_str(), u, UF_SCHEMA);
2274         prev_host = util::get_uri_field(uri.c_str(), u, UF_HOST);
2275         prev_port = port;
2276       }
2277       requests.emplace_back(uri, data_fd == -1 ? nullptr : &data_prd,
2278                             data_stat.st_size);
2279     }
2280   }
2281   if (!requests.empty()) {
2282     if (communicate(prev_scheme, prev_host, prev_port, std::move(requests),
2283                     callbacks) != 0) {
2284       ++failures;
2285     }
2286   }
2287   return failures;
2288 }
2289 } // namespace
2290
2291 namespace {
2292 void print_version(std::ostream &out) {
2293   out << "nghttp nghttp2/" NGHTTP2_VERSION << std::endl;
2294 }
2295 } // namespace
2296
2297 namespace {
2298 void print_usage(std::ostream &out) {
2299   out << R"(Usage: nghttp [OPTIONS]... <URI>...
2300 HTTP/2 experimental client)" << std::endl;
2301 }
2302 } // namespace
2303
2304 namespace {
2305 void print_help(std::ostream &out) {
2306   print_usage(out);
2307   out << R"(
2308   <URI>       Specify URI to access.
2309 Options:
2310   -v, --verbose
2311               Print   debug   information   such  as   reception   and
2312               transmission of frames and name/value pairs.  Specifying
2313               this option multiple times increases verbosity.
2314   -n, --null-out
2315               Discard downloaded data.
2316   -O, --remote-name
2317               Save  download  data  in  the  current  directory.   The
2318               filename is  dereived from URI.   If URI ends  with '/',
2319               'index.html'  is used  as a  filename.  Not  implemented
2320               yet.
2321   -t, --timeout=<DURATION>
2322               Timeout each request after <DURATION>.  Set 0 to disable
2323               timeout.
2324   -w, --window-bits=<N>
2325               Sets the stream level initial window size to 2**<N>-1.
2326   -W, --connection-window-bits=<N>
2327               Sets  the  connection  level   initial  window  size  to
2328               2**<N>-1.
2329   -a, --get-assets
2330               Download assets  such as stylesheets, images  and script
2331               files linked  from the downloaded resource.   Only links
2332               whose  origins are  the same  with the  linking resource
2333               will be downloaded.   nghttp prioritizes resources using
2334               HTTP/2 dependency  based priority.  The  priority order,
2335               from highest to lowest,  is html itself, css, javascript
2336               and images.
2337   -s, --stat  Print statistics.
2338   -H, --header=<HEADER>
2339               Add a header to the requests.  Example: -H':method: PUT'
2340   --trailer=<HEADER>
2341               Add a trailer header to the requests.  <HEADER> must not
2342               include pseudo header field  (header field name starting
2343               with ':').  To  send trailer, one must use  -d option to
2344               send request body.  Example: --trailer 'foo: bar'.
2345   --cert=<CERT>
2346               Use  the specified  client certificate  file.  The  file
2347               must be in PEM format.
2348   --key=<KEY> Use the  client private key  file.  The file must  be in
2349               PEM format.
2350   -d, --data=<FILE>
2351               Post FILE to server. If '-'  is given, data will be read
2352               from stdin.
2353   -m, --multiply=<N>
2354               Request each URI <N> times.  By default, same URI is not
2355               requested twice.  This option disables it too.
2356   -u, --upgrade
2357               Perform HTTP Upgrade for HTTP/2.  This option is ignored
2358               if the request URI has https scheme.  If -d is used, the
2359               HTTP upgrade request is performed with OPTIONS method.
2360   -p, --weight=<WEIGHT>
2361               Sets priority group weight.  The valid value range is
2362               [)" << NGHTTP2_MIN_WEIGHT << ", " << NGHTTP2_MAX_WEIGHT
2363       << R"(], inclusive.
2364               Default: )" << NGHTTP2_DEFAULT_WEIGHT << R"(
2365   -M, --peer-max-concurrent-streams=<N>
2366               Use  <N>  as  SETTINGS_MAX_CONCURRENT_STREAMS  value  of
2367               remote endpoint as if it  is received in SETTINGS frame.
2368               The default is large enough as it is seen as unlimited.
2369   -c, --header-table-size=<SIZE>
2370               Specify decoder header table size.
2371   -b, --padding=<N>
2372               Add at  most <N>  bytes to a  frame payload  as padding.
2373               Specify 0 to disable padding.
2374   -r, --har=<FILE>
2375               Output HTTP  transactions <FILE> in HAR  format.  If '-'
2376               is given, data is written to stdout.
2377   --color     Force colored log output.
2378   --continuation
2379               Send large header to test CONTINUATION.
2380   --no-content-length
2381               Don't send content-length header field.
2382   --no-dep    Don't send dependency based priority hint to server.
2383   --hexdump   Display the  incoming traffic in  hexadecimal (Canonical
2384               hex+ASCII display).  If SSL/TLS  is used, decrypted data
2385               are used.
2386   --no-push   Disable server push.
2387   --version   Display version information and exit.
2388   -h, --help  Display this help and exit.
2389
2390 --
2391
2392   The <SIZE> argument is an integer and an optional unit (e.g., 10K is
2393   10 * 1024).  Units are K, M and G (powers of 1024).
2394
2395   The <DURATION> argument is an integer and an optional unit (e.g., 1s
2396   is 1 second and 500ms is 500 milliseconds).  Units are h, m, s or ms
2397   (hours, minutes, seconds and milliseconds, respectively).  If a unit
2398   is omitted, a second is used as unit.)" << std::endl;
2399 }
2400 } // namespace
2401
2402 int main(int argc, char **argv) {
2403   bool color = false;
2404   while (1) {
2405     static int flag = 0;
2406     static option long_options[] = {
2407         {"verbose", no_argument, nullptr, 'v'},
2408         {"null-out", no_argument, nullptr, 'n'},
2409         {"remote-name", no_argument, nullptr, 'O'},
2410         {"timeout", required_argument, nullptr, 't'},
2411         {"window-bits", required_argument, nullptr, 'w'},
2412         {"connection-window-bits", required_argument, nullptr, 'W'},
2413         {"get-assets", no_argument, nullptr, 'a'},
2414         {"stat", no_argument, nullptr, 's'},
2415         {"help", no_argument, nullptr, 'h'},
2416         {"header", required_argument, nullptr, 'H'},
2417         {"data", required_argument, nullptr, 'd'},
2418         {"multiply", required_argument, nullptr, 'm'},
2419         {"upgrade", no_argument, nullptr, 'u'},
2420         {"weight", required_argument, nullptr, 'p'},
2421         {"peer-max-concurrent-streams", required_argument, nullptr, 'M'},
2422         {"header-table-size", required_argument, nullptr, 'c'},
2423         {"padding", required_argument, nullptr, 'b'},
2424         {"har", required_argument, nullptr, 'r'},
2425         {"cert", required_argument, &flag, 1},
2426         {"key", required_argument, &flag, 2},
2427         {"color", no_argument, &flag, 3},
2428         {"continuation", no_argument, &flag, 4},
2429         {"version", no_argument, &flag, 5},
2430         {"no-content-length", no_argument, &flag, 6},
2431         {"no-dep", no_argument, &flag, 7},
2432         {"trailer", required_argument, &flag, 9},
2433         {"hexdump", no_argument, &flag, 10},
2434         {"no-push", no_argument, &flag, 11},
2435         {nullptr, 0, nullptr, 0}};
2436     int option_index = 0;
2437     int c = getopt_long(argc, argv, "M:Oab:c:d:gm:np:r:hH:vst:uw:W:",
2438                         long_options, &option_index);
2439     if (c == -1) {
2440       break;
2441     }
2442     switch (c) {
2443     case 'M':
2444       // peer-max-concurrent-streams option
2445       config.peer_max_concurrent_streams = strtoul(optarg, nullptr, 10);
2446       break;
2447     case 'O':
2448       config.remote_name = true;
2449       break;
2450     case 'h':
2451       print_help(std::cout);
2452       exit(EXIT_SUCCESS);
2453     case 'b':
2454       config.padding = strtol(optarg, nullptr, 10);
2455       break;
2456     case 'n':
2457       config.null_out = true;
2458       break;
2459     case 'p': {
2460       errno = 0;
2461       auto n = strtoul(optarg, nullptr, 10);
2462       if (errno == 0 && NGHTTP2_MIN_WEIGHT <= n && n <= NGHTTP2_MAX_WEIGHT) {
2463         config.weight = n;
2464       } else {
2465         std::cerr << "-p: specify the integer in the range ["
2466                   << NGHTTP2_MIN_WEIGHT << ", " << NGHTTP2_MAX_WEIGHT
2467                   << "], inclusive" << std::endl;
2468         exit(EXIT_FAILURE);
2469       }
2470       break;
2471     }
2472     case 'r':
2473 #ifdef HAVE_JANSSON
2474       config.harfile = optarg;
2475 #else  // !HAVE_JANSSON
2476       std::cerr << "[WARNING]: -r, --har option is ignored because\n"
2477                 << "the binary was not compiled with libjansson." << std::endl;
2478 #endif // !HAVE_JANSSON
2479       break;
2480     case 'v':
2481       ++config.verbose;
2482       break;
2483     case 't':
2484       config.timeout = util::parse_duration_with_unit(optarg);
2485       if (config.timeout == std::numeric_limits<double>::infinity()) {
2486         std::cerr << "-t: bad timeout value: " << optarg << std::endl;
2487         exit(EXIT_FAILURE);
2488       }
2489       break;
2490     case 'u':
2491       config.upgrade = true;
2492       break;
2493     case 'w':
2494     case 'W': {
2495       errno = 0;
2496       char *endptr = nullptr;
2497       unsigned long int n = strtoul(optarg, &endptr, 10);
2498       if (errno == 0 && *endptr == '\0' && n < 31) {
2499         if (c == 'w') {
2500           config.window_bits = n;
2501         } else {
2502           config.connection_window_bits = n;
2503         }
2504       } else {
2505         std::cerr << "-" << static_cast<char>(c)
2506                   << ": specify the integer in the range [0, 30], inclusive"
2507                   << std::endl;
2508         exit(EXIT_FAILURE);
2509       }
2510       break;
2511     }
2512     case 'H': {
2513       char *header = optarg;
2514       // Skip first possible ':' in the header name
2515       char *value = strchr(optarg + 1, ':');
2516       if (!value || (header[0] == ':' && header + 1 == value)) {
2517         std::cerr << "-H: invalid header: " << optarg << std::endl;
2518         exit(EXIT_FAILURE);
2519       }
2520       *value = 0;
2521       value++;
2522       while (isspace(*value)) {
2523         value++;
2524       }
2525       if (*value == 0) {
2526         // This could also be a valid case for suppressing a header
2527         // similar to curl
2528         std::cerr << "-H: invalid header - value missing: " << optarg
2529                   << std::endl;
2530         exit(EXIT_FAILURE);
2531       }
2532       config.headers.emplace_back(header, value, false);
2533       util::inp_strlower(config.headers.back().name);
2534       break;
2535     }
2536     case 'a':
2537 #ifdef HAVE_LIBXML2
2538       config.get_assets = true;
2539 #else  // !HAVE_LIBXML2
2540       std::cerr << "[WARNING]: -a, --get-assets option is ignored because\n"
2541                 << "the binary was not compiled with libxml2." << std::endl;
2542 #endif // !HAVE_LIBXML2
2543       break;
2544     case 's':
2545       config.stat = true;
2546       break;
2547     case 'd':
2548       config.datafile = optarg;
2549       break;
2550     case 'm':
2551       config.multiply = strtoul(optarg, nullptr, 10);
2552       break;
2553     case 'c':
2554       errno = 0;
2555       config.header_table_size = util::parse_uint_with_unit(optarg);
2556       if (config.header_table_size == -1) {
2557         std::cerr << "-c: Bad option value: " << optarg << std::endl;
2558         exit(EXIT_FAILURE);
2559       }
2560       break;
2561     case '?':
2562       util::show_candidates(argv[optind - 1], long_options);
2563       exit(EXIT_FAILURE);
2564     case 0:
2565       switch (flag) {
2566       case 1:
2567         // cert option
2568         config.certfile = optarg;
2569         break;
2570       case 2:
2571         // key option
2572         config.keyfile = optarg;
2573         break;
2574       case 3:
2575         // color option
2576         color = true;
2577         break;
2578       case 4:
2579         // continuation option
2580         config.continuation = true;
2581         break;
2582       case 5:
2583         // version option
2584         print_version(std::cout);
2585         exit(EXIT_SUCCESS);
2586       case 6:
2587         // no-content-length option
2588         config.no_content_length = true;
2589         break;
2590       case 7:
2591         // no-dep option
2592         config.no_dep = true;
2593         break;
2594       case 9: {
2595         // trailer option
2596         auto header = optarg;
2597         auto value = strchr(optarg, ':');
2598         if (!value) {
2599           std::cerr << "--trailer: invalid header: " << optarg << std::endl;
2600           exit(EXIT_FAILURE);
2601         }
2602         *value = 0;
2603         value++;
2604         while (isspace(*value)) {
2605           value++;
2606         }
2607         if (*value == 0) {
2608           // This could also be a valid case for suppressing a header
2609           // similar to curl
2610           std::cerr << "--trailer: invalid header - value missing: " << optarg
2611                     << std::endl;
2612           exit(EXIT_FAILURE);
2613         }
2614         config.trailer.emplace_back(header, value, false);
2615         util::inp_strlower(config.trailer.back().name);
2616         break;
2617       }
2618       case 10:
2619         // hexdump option
2620         config.hexdump = true;
2621         break;
2622       case 11:
2623         // no-push option
2624         config.no_push = true;
2625         break;
2626       }
2627       break;
2628     default:
2629       break;
2630     }
2631   }
2632
2633   set_color_output(color || isatty(fileno(stdout)));
2634
2635   nghttp2_option_set_peer_max_concurrent_streams(
2636       config.http2_option, config.peer_max_concurrent_streams);
2637
2638   struct sigaction act;
2639   memset(&act, 0, sizeof(struct sigaction));
2640   act.sa_handler = SIG_IGN;
2641   sigaction(SIGPIPE, &act, nullptr);
2642   OPENSSL_config(nullptr);
2643   OpenSSL_add_all_algorithms();
2644   SSL_load_error_strings();
2645   SSL_library_init();
2646   reset_timer();
2647   return run(argv + optind, argc - optind);
2648 }
2649
2650 } // namespace nghttp2
2651
2652 int main(int argc, char **argv) { return nghttp2::main(argc, argv); }