12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2013 Tatsuhiro Tsujikawa
52c593315Sopenharmony_ci *
62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the
82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
122c593315Sopenharmony_ci * the following conditions:
132c593315Sopenharmony_ci *
142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be
152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software.
162c593315Sopenharmony_ci *
172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
242c593315Sopenharmony_ci */
252c593315Sopenharmony_ci#include "HttpServer.h"
262c593315Sopenharmony_ci
272c593315Sopenharmony_ci#include <sys/stat.h>
282c593315Sopenharmony_ci#ifdef HAVE_SYS_SOCKET_H
292c593315Sopenharmony_ci#  include <sys/socket.h>
302c593315Sopenharmony_ci#endif // HAVE_SYS_SOCKET_H
312c593315Sopenharmony_ci#ifdef HAVE_NETDB_H
322c593315Sopenharmony_ci#  include <netdb.h>
332c593315Sopenharmony_ci#endif // HAVE_NETDB_H
342c593315Sopenharmony_ci#ifdef HAVE_UNISTD_H
352c593315Sopenharmony_ci#  include <unistd.h>
362c593315Sopenharmony_ci#endif // HAVE_UNISTD_H
372c593315Sopenharmony_ci#ifdef HAVE_FCNTL_H
382c593315Sopenharmony_ci#  include <fcntl.h>
392c593315Sopenharmony_ci#endif // HAVE_FCNTL_H
402c593315Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
412c593315Sopenharmony_ci#  include <netinet/in.h>
422c593315Sopenharmony_ci#endif // HAVE_NETINET_IN_H
432c593315Sopenharmony_ci#include <netinet/tcp.h>
442c593315Sopenharmony_ci#ifdef HAVE_ARPA_INET_H
452c593315Sopenharmony_ci#  include <arpa/inet.h>
462c593315Sopenharmony_ci#endif // HAVE_ARPA_INET_H
472c593315Sopenharmony_ci
482c593315Sopenharmony_ci#include <cassert>
492c593315Sopenharmony_ci#include <set>
502c593315Sopenharmony_ci#include <iostream>
512c593315Sopenharmony_ci#include <thread>
522c593315Sopenharmony_ci#include <mutex>
532c593315Sopenharmony_ci#include <deque>
542c593315Sopenharmony_ci
552c593315Sopenharmony_ci#include "ssl_compat.h"
562c593315Sopenharmony_ci
572c593315Sopenharmony_ci#include <openssl/err.h>
582c593315Sopenharmony_ci#include <openssl/dh.h>
592c593315Sopenharmony_ci#if OPENSSL_3_0_0_API
602c593315Sopenharmony_ci#  include <openssl/decoder.h>
612c593315Sopenharmony_ci#endif // OPENSSL_3_0_0_API
622c593315Sopenharmony_ci
632c593315Sopenharmony_ci#include <zlib.h>
642c593315Sopenharmony_ci
652c593315Sopenharmony_ci#include "app_helper.h"
662c593315Sopenharmony_ci#include "http2.h"
672c593315Sopenharmony_ci#include "util.h"
682c593315Sopenharmony_ci#include "tls.h"
692c593315Sopenharmony_ci#include "template.h"
702c593315Sopenharmony_ci
712c593315Sopenharmony_ci#ifndef O_BINARY
722c593315Sopenharmony_ci#  define O_BINARY (0)
732c593315Sopenharmony_ci#endif // O_BINARY
742c593315Sopenharmony_ci
752c593315Sopenharmony_ciusing namespace std::chrono_literals;
762c593315Sopenharmony_ci
772c593315Sopenharmony_cinamespace nghttp2 {
782c593315Sopenharmony_ci
792c593315Sopenharmony_cinamespace {
802c593315Sopenharmony_ci// TODO could be constexpr
812c593315Sopenharmony_ciconstexpr auto DEFAULT_HTML = StringRef::from_lit("index.html");
822c593315Sopenharmony_ciconstexpr auto NGHTTPD_SERVER =
832c593315Sopenharmony_ci    StringRef::from_lit("nghttpd nghttp2/" NGHTTP2_VERSION);
842c593315Sopenharmony_ci} // namespace
852c593315Sopenharmony_ci
862c593315Sopenharmony_cinamespace {
872c593315Sopenharmony_civoid delete_handler(Http2Handler *handler) {
882c593315Sopenharmony_ci  handler->remove_self();
892c593315Sopenharmony_ci  delete handler;
902c593315Sopenharmony_ci}
912c593315Sopenharmony_ci} // namespace
922c593315Sopenharmony_ci
932c593315Sopenharmony_cinamespace {
942c593315Sopenharmony_civoid print_session_id(int64_t id) { std::cout << "[id=" << id << "] "; }
952c593315Sopenharmony_ci} // namespace
962c593315Sopenharmony_ci
972c593315Sopenharmony_ciConfig::Config()
982c593315Sopenharmony_ci    : mime_types_file("/etc/mime.types"),
992c593315Sopenharmony_ci      stream_read_timeout(1_min),
1002c593315Sopenharmony_ci      stream_write_timeout(1_min),
1012c593315Sopenharmony_ci      data_ptr(nullptr),
1022c593315Sopenharmony_ci      padding(0),
1032c593315Sopenharmony_ci      num_worker(1),
1042c593315Sopenharmony_ci      max_concurrent_streams(100),
1052c593315Sopenharmony_ci      header_table_size(-1),
1062c593315Sopenharmony_ci      encoder_header_table_size(-1),
1072c593315Sopenharmony_ci      window_bits(-1),
1082c593315Sopenharmony_ci      connection_window_bits(-1),
1092c593315Sopenharmony_ci      port(0),
1102c593315Sopenharmony_ci      verbose(false),
1112c593315Sopenharmony_ci      daemon(false),
1122c593315Sopenharmony_ci      verify_client(false),
1132c593315Sopenharmony_ci      no_tls(false),
1142c593315Sopenharmony_ci      error_gzip(false),
1152c593315Sopenharmony_ci      early_response(false),
1162c593315Sopenharmony_ci      hexdump(false),
1172c593315Sopenharmony_ci      echo_upload(false),
1182c593315Sopenharmony_ci      no_content_length(false),
1192c593315Sopenharmony_ci      ktls(false),
1202c593315Sopenharmony_ci      no_rfc7540_pri(false) {}
1212c593315Sopenharmony_ci
1222c593315Sopenharmony_ciConfig::~Config() {}
1232c593315Sopenharmony_ci
1242c593315Sopenharmony_cinamespace {
1252c593315Sopenharmony_civoid stream_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
1262c593315Sopenharmony_ci  int rv;
1272c593315Sopenharmony_ci  auto stream = static_cast<Stream *>(w->data);
1282c593315Sopenharmony_ci  auto hd = stream->handler;
1292c593315Sopenharmony_ci  auto config = hd->get_config();
1302c593315Sopenharmony_ci
1312c593315Sopenharmony_ci  ev_timer_stop(hd->get_loop(), &stream->rtimer);
1322c593315Sopenharmony_ci  ev_timer_stop(hd->get_loop(), &stream->wtimer);
1332c593315Sopenharmony_ci
1342c593315Sopenharmony_ci  if (config->verbose) {
1352c593315Sopenharmony_ci    print_session_id(hd->session_id());
1362c593315Sopenharmony_ci    print_timer();
1372c593315Sopenharmony_ci    std::cout << " timeout stream_id=" << stream->stream_id << std::endl;
1382c593315Sopenharmony_ci  }
1392c593315Sopenharmony_ci
1402c593315Sopenharmony_ci  hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
1412c593315Sopenharmony_ci
1422c593315Sopenharmony_ci  rv = hd->on_write();
1432c593315Sopenharmony_ci  if (rv == -1) {
1442c593315Sopenharmony_ci    delete_handler(hd);
1452c593315Sopenharmony_ci  }
1462c593315Sopenharmony_ci}
1472c593315Sopenharmony_ci} // namespace
1482c593315Sopenharmony_ci
1492c593315Sopenharmony_cinamespace {
1502c593315Sopenharmony_civoid add_stream_read_timeout(Stream *stream) {
1512c593315Sopenharmony_ci  auto hd = stream->handler;
1522c593315Sopenharmony_ci  ev_timer_again(hd->get_loop(), &stream->rtimer);
1532c593315Sopenharmony_ci}
1542c593315Sopenharmony_ci} // namespace
1552c593315Sopenharmony_ci
1562c593315Sopenharmony_cinamespace {
1572c593315Sopenharmony_civoid add_stream_read_timeout_if_pending(Stream *stream) {
1582c593315Sopenharmony_ci  auto hd = stream->handler;
1592c593315Sopenharmony_ci  if (ev_is_active(&stream->rtimer)) {
1602c593315Sopenharmony_ci    ev_timer_again(hd->get_loop(), &stream->rtimer);
1612c593315Sopenharmony_ci  }
1622c593315Sopenharmony_ci}
1632c593315Sopenharmony_ci} // namespace
1642c593315Sopenharmony_ci
1652c593315Sopenharmony_cinamespace {
1662c593315Sopenharmony_civoid add_stream_write_timeout(Stream *stream) {
1672c593315Sopenharmony_ci  auto hd = stream->handler;
1682c593315Sopenharmony_ci  ev_timer_again(hd->get_loop(), &stream->wtimer);
1692c593315Sopenharmony_ci}
1702c593315Sopenharmony_ci} // namespace
1712c593315Sopenharmony_ci
1722c593315Sopenharmony_cinamespace {
1732c593315Sopenharmony_civoid remove_stream_read_timeout(Stream *stream) {
1742c593315Sopenharmony_ci  auto hd = stream->handler;
1752c593315Sopenharmony_ci  ev_timer_stop(hd->get_loop(), &stream->rtimer);
1762c593315Sopenharmony_ci}
1772c593315Sopenharmony_ci} // namespace
1782c593315Sopenharmony_ci
1792c593315Sopenharmony_cinamespace {
1802c593315Sopenharmony_civoid remove_stream_write_timeout(Stream *stream) {
1812c593315Sopenharmony_ci  auto hd = stream->handler;
1822c593315Sopenharmony_ci  ev_timer_stop(hd->get_loop(), &stream->wtimer);
1832c593315Sopenharmony_ci}
1842c593315Sopenharmony_ci} // namespace
1852c593315Sopenharmony_ci
1862c593315Sopenharmony_cinamespace {
1872c593315Sopenharmony_civoid fill_callback(nghttp2_session_callbacks *callbacks, const Config *config);
1882c593315Sopenharmony_ci} // namespace
1892c593315Sopenharmony_ci
1902c593315Sopenharmony_cinamespace {
1912c593315Sopenharmony_ciconstexpr ev_tstamp RELEASE_FD_TIMEOUT = 2.;
1922c593315Sopenharmony_ci} // namespace
1932c593315Sopenharmony_ci
1942c593315Sopenharmony_cinamespace {
1952c593315Sopenharmony_civoid release_fd_cb(struct ev_loop *loop, ev_timer *w, int revents);
1962c593315Sopenharmony_ci} // namespace
1972c593315Sopenharmony_ci
1982c593315Sopenharmony_cinamespace {
1992c593315Sopenharmony_ciconstexpr auto FILE_ENTRY_MAX_AGE = 10s;
2002c593315Sopenharmony_ci} // namespace
2012c593315Sopenharmony_ci
2022c593315Sopenharmony_cinamespace {
2032c593315Sopenharmony_ciconstexpr size_t FILE_ENTRY_EVICT_THRES = 2048;
2042c593315Sopenharmony_ci} // namespace
2052c593315Sopenharmony_ci
2062c593315Sopenharmony_cinamespace {
2072c593315Sopenharmony_cibool need_validation_file_entry(
2082c593315Sopenharmony_ci    const FileEntry *ent, const std::chrono::steady_clock::time_point &now) {
2092c593315Sopenharmony_ci  return ent->last_valid + FILE_ENTRY_MAX_AGE < now;
2102c593315Sopenharmony_ci}
2112c593315Sopenharmony_ci} // namespace
2122c593315Sopenharmony_ci
2132c593315Sopenharmony_cinamespace {
2142c593315Sopenharmony_cibool validate_file_entry(FileEntry *ent,
2152c593315Sopenharmony_ci                         const std::chrono::steady_clock::time_point &now) {
2162c593315Sopenharmony_ci  struct stat stbuf;
2172c593315Sopenharmony_ci  int rv;
2182c593315Sopenharmony_ci
2192c593315Sopenharmony_ci  rv = fstat(ent->fd, &stbuf);
2202c593315Sopenharmony_ci  if (rv != 0) {
2212c593315Sopenharmony_ci    ent->stale = true;
2222c593315Sopenharmony_ci    return false;
2232c593315Sopenharmony_ci  }
2242c593315Sopenharmony_ci
2252c593315Sopenharmony_ci  if (stbuf.st_nlink == 0 || ent->mtime != stbuf.st_mtime) {
2262c593315Sopenharmony_ci    ent->stale = true;
2272c593315Sopenharmony_ci    return false;
2282c593315Sopenharmony_ci  }
2292c593315Sopenharmony_ci
2302c593315Sopenharmony_ci  ent->mtime = stbuf.st_mtime;
2312c593315Sopenharmony_ci  ent->last_valid = now;
2322c593315Sopenharmony_ci
2332c593315Sopenharmony_ci  return true;
2342c593315Sopenharmony_ci}
2352c593315Sopenharmony_ci} // namespace
2362c593315Sopenharmony_ci
2372c593315Sopenharmony_ciclass Sessions {
2382c593315Sopenharmony_cipublic:
2392c593315Sopenharmony_ci  Sessions(HttpServer *sv, struct ev_loop *loop, const Config *config,
2402c593315Sopenharmony_ci           SSL_CTX *ssl_ctx)
2412c593315Sopenharmony_ci      : sv_(sv),
2422c593315Sopenharmony_ci        loop_(loop),
2432c593315Sopenharmony_ci        config_(config),
2442c593315Sopenharmony_ci        ssl_ctx_(ssl_ctx),
2452c593315Sopenharmony_ci        callbacks_(nullptr),
2462c593315Sopenharmony_ci        option_(nullptr),
2472c593315Sopenharmony_ci        next_session_id_(1),
2482c593315Sopenharmony_ci        tstamp_cached_(ev_now(loop)),
2492c593315Sopenharmony_ci        cached_date_(util::http_date(tstamp_cached_)) {
2502c593315Sopenharmony_ci    nghttp2_session_callbacks_new(&callbacks_);
2512c593315Sopenharmony_ci
2522c593315Sopenharmony_ci    fill_callback(callbacks_, config_);
2532c593315Sopenharmony_ci
2542c593315Sopenharmony_ci    nghttp2_option_new(&option_);
2552c593315Sopenharmony_ci
2562c593315Sopenharmony_ci    if (config_->encoder_header_table_size != -1) {
2572c593315Sopenharmony_ci      nghttp2_option_set_max_deflate_dynamic_table_size(
2582c593315Sopenharmony_ci          option_, config_->encoder_header_table_size);
2592c593315Sopenharmony_ci    }
2602c593315Sopenharmony_ci
2612c593315Sopenharmony_ci    ev_timer_init(&release_fd_timer_, release_fd_cb, 0., RELEASE_FD_TIMEOUT);
2622c593315Sopenharmony_ci    release_fd_timer_.data = this;
2632c593315Sopenharmony_ci  }
2642c593315Sopenharmony_ci  ~Sessions() {
2652c593315Sopenharmony_ci    ev_timer_stop(loop_, &release_fd_timer_);
2662c593315Sopenharmony_ci    for (auto handler : handlers_) {
2672c593315Sopenharmony_ci      delete handler;
2682c593315Sopenharmony_ci    }
2692c593315Sopenharmony_ci    nghttp2_option_del(option_);
2702c593315Sopenharmony_ci    nghttp2_session_callbacks_del(callbacks_);
2712c593315Sopenharmony_ci  }
2722c593315Sopenharmony_ci  void add_handler(Http2Handler *handler) { handlers_.insert(handler); }
2732c593315Sopenharmony_ci  void remove_handler(Http2Handler *handler) {
2742c593315Sopenharmony_ci    handlers_.erase(handler);
2752c593315Sopenharmony_ci    if (handlers_.empty() && !fd_cache_.empty()) {
2762c593315Sopenharmony_ci      ev_timer_again(loop_, &release_fd_timer_);
2772c593315Sopenharmony_ci    }
2782c593315Sopenharmony_ci  }
2792c593315Sopenharmony_ci  SSL_CTX *get_ssl_ctx() const { return ssl_ctx_; }
2802c593315Sopenharmony_ci  SSL *ssl_session_new(int fd) {
2812c593315Sopenharmony_ci    SSL *ssl = SSL_new(ssl_ctx_);
2822c593315Sopenharmony_ci    if (!ssl) {
2832c593315Sopenharmony_ci      std::cerr << "SSL_new() failed" << std::endl;
2842c593315Sopenharmony_ci      return nullptr;
2852c593315Sopenharmony_ci    }
2862c593315Sopenharmony_ci    if (SSL_set_fd(ssl, fd) == 0) {
2872c593315Sopenharmony_ci      std::cerr << "SSL_set_fd() failed" << std::endl;
2882c593315Sopenharmony_ci      SSL_free(ssl);
2892c593315Sopenharmony_ci      return nullptr;
2902c593315Sopenharmony_ci    }
2912c593315Sopenharmony_ci    return ssl;
2922c593315Sopenharmony_ci  }
2932c593315Sopenharmony_ci  const Config *get_config() const { return config_; }
2942c593315Sopenharmony_ci  struct ev_loop *get_loop() const {
2952c593315Sopenharmony_ci    return loop_;
2962c593315Sopenharmony_ci  }
2972c593315Sopenharmony_ci  int64_t get_next_session_id() {
2982c593315Sopenharmony_ci    auto session_id = next_session_id_;
2992c593315Sopenharmony_ci    if (next_session_id_ == std::numeric_limits<int64_t>::max()) {
3002c593315Sopenharmony_ci      next_session_id_ = 1;
3012c593315Sopenharmony_ci    } else {
3022c593315Sopenharmony_ci      ++next_session_id_;
3032c593315Sopenharmony_ci    }
3042c593315Sopenharmony_ci    return session_id;
3052c593315Sopenharmony_ci  }
3062c593315Sopenharmony_ci  const nghttp2_session_callbacks *get_callbacks() const { return callbacks_; }
3072c593315Sopenharmony_ci  const nghttp2_option *get_option() const { return option_; }
3082c593315Sopenharmony_ci  void accept_connection(int fd) {
3092c593315Sopenharmony_ci    util::make_socket_nodelay(fd);
3102c593315Sopenharmony_ci    SSL *ssl = nullptr;
3112c593315Sopenharmony_ci    if (ssl_ctx_) {
3122c593315Sopenharmony_ci      ssl = ssl_session_new(fd);
3132c593315Sopenharmony_ci      if (!ssl) {
3142c593315Sopenharmony_ci        close(fd);
3152c593315Sopenharmony_ci        return;
3162c593315Sopenharmony_ci      }
3172c593315Sopenharmony_ci    }
3182c593315Sopenharmony_ci    auto handler =
3192c593315Sopenharmony_ci        std::make_unique<Http2Handler>(this, fd, ssl, get_next_session_id());
3202c593315Sopenharmony_ci    if (!ssl) {
3212c593315Sopenharmony_ci      if (handler->connection_made() != 0) {
3222c593315Sopenharmony_ci        return;
3232c593315Sopenharmony_ci      }
3242c593315Sopenharmony_ci    }
3252c593315Sopenharmony_ci    add_handler(handler.release());
3262c593315Sopenharmony_ci  }
3272c593315Sopenharmony_ci  void update_cached_date() { cached_date_ = util::http_date(tstamp_cached_); }
3282c593315Sopenharmony_ci  const std::string &get_cached_date() {
3292c593315Sopenharmony_ci    auto t = ev_now(loop_);
3302c593315Sopenharmony_ci    if (t != tstamp_cached_) {
3312c593315Sopenharmony_ci      tstamp_cached_ = t;
3322c593315Sopenharmony_ci      update_cached_date();
3332c593315Sopenharmony_ci    }
3342c593315Sopenharmony_ci    return cached_date_;
3352c593315Sopenharmony_ci  }
3362c593315Sopenharmony_ci  FileEntry *get_cached_fd(const std::string &path) {
3372c593315Sopenharmony_ci    auto range = fd_cache_.equal_range(path);
3382c593315Sopenharmony_ci    if (range.first == range.second) {
3392c593315Sopenharmony_ci      return nullptr;
3402c593315Sopenharmony_ci    }
3412c593315Sopenharmony_ci
3422c593315Sopenharmony_ci    auto now = std::chrono::steady_clock::now();
3432c593315Sopenharmony_ci
3442c593315Sopenharmony_ci    for (auto it = range.first; it != range.second;) {
3452c593315Sopenharmony_ci      auto &ent = (*it).second;
3462c593315Sopenharmony_ci      if (ent->stale) {
3472c593315Sopenharmony_ci        ++it;
3482c593315Sopenharmony_ci        continue;
3492c593315Sopenharmony_ci      }
3502c593315Sopenharmony_ci      if (need_validation_file_entry(ent.get(), now) &&
3512c593315Sopenharmony_ci          !validate_file_entry(ent.get(), now)) {
3522c593315Sopenharmony_ci        if (ent->usecount == 0) {
3532c593315Sopenharmony_ci          fd_cache_lru_.remove(ent.get());
3542c593315Sopenharmony_ci          close(ent->fd);
3552c593315Sopenharmony_ci          it = fd_cache_.erase(it);
3562c593315Sopenharmony_ci          continue;
3572c593315Sopenharmony_ci        }
3582c593315Sopenharmony_ci        ++it;
3592c593315Sopenharmony_ci        continue;
3602c593315Sopenharmony_ci      }
3612c593315Sopenharmony_ci
3622c593315Sopenharmony_ci      fd_cache_lru_.remove(ent.get());
3632c593315Sopenharmony_ci      fd_cache_lru_.append(ent.get());
3642c593315Sopenharmony_ci
3652c593315Sopenharmony_ci      ++ent->usecount;
3662c593315Sopenharmony_ci      return ent.get();
3672c593315Sopenharmony_ci    }
3682c593315Sopenharmony_ci    return nullptr;
3692c593315Sopenharmony_ci  }
3702c593315Sopenharmony_ci  FileEntry *cache_fd(const std::string &path, const FileEntry &ent) {
3712c593315Sopenharmony_ci#ifdef HAVE_STD_MAP_EMPLACE
3722c593315Sopenharmony_ci    auto rv = fd_cache_.emplace(path, std::make_unique<FileEntry>(ent));
3732c593315Sopenharmony_ci#else  // !HAVE_STD_MAP_EMPLACE
3742c593315Sopenharmony_ci    // for gcc-4.7
3752c593315Sopenharmony_ci    auto rv = fd_cache_.insert(
3762c593315Sopenharmony_ci        std::make_pair(path, std::make_unique<FileEntry>(ent)));
3772c593315Sopenharmony_ci#endif // !HAVE_STD_MAP_EMPLACE
3782c593315Sopenharmony_ci    auto &res = (*rv).second;
3792c593315Sopenharmony_ci    res->it = rv;
3802c593315Sopenharmony_ci    fd_cache_lru_.append(res.get());
3812c593315Sopenharmony_ci
3822c593315Sopenharmony_ci    while (fd_cache_.size() > FILE_ENTRY_EVICT_THRES) {
3832c593315Sopenharmony_ci      auto ent = fd_cache_lru_.head;
3842c593315Sopenharmony_ci      if (ent->usecount) {
3852c593315Sopenharmony_ci        break;
3862c593315Sopenharmony_ci      }
3872c593315Sopenharmony_ci      fd_cache_lru_.remove(ent);
3882c593315Sopenharmony_ci      close(ent->fd);
3892c593315Sopenharmony_ci      fd_cache_.erase(ent->it);
3902c593315Sopenharmony_ci    }
3912c593315Sopenharmony_ci
3922c593315Sopenharmony_ci    return res.get();
3932c593315Sopenharmony_ci  }
3942c593315Sopenharmony_ci  void release_fd(FileEntry *target) {
3952c593315Sopenharmony_ci    --target->usecount;
3962c593315Sopenharmony_ci
3972c593315Sopenharmony_ci    if (target->usecount == 0 && target->stale) {
3982c593315Sopenharmony_ci      fd_cache_lru_.remove(target);
3992c593315Sopenharmony_ci      close(target->fd);
4002c593315Sopenharmony_ci      fd_cache_.erase(target->it);
4012c593315Sopenharmony_ci      return;
4022c593315Sopenharmony_ci    }
4032c593315Sopenharmony_ci
4042c593315Sopenharmony_ci    // We use timer to close file descriptor and delete the entry from
4052c593315Sopenharmony_ci    // cache.  The timer will be started when there is no handler.
4062c593315Sopenharmony_ci  }
4072c593315Sopenharmony_ci  void release_unused_fd() {
4082c593315Sopenharmony_ci    for (auto i = std::begin(fd_cache_); i != std::end(fd_cache_);) {
4092c593315Sopenharmony_ci      auto &ent = (*i).second;
4102c593315Sopenharmony_ci      if (ent->usecount != 0) {
4112c593315Sopenharmony_ci        ++i;
4122c593315Sopenharmony_ci        continue;
4132c593315Sopenharmony_ci      }
4142c593315Sopenharmony_ci
4152c593315Sopenharmony_ci      fd_cache_lru_.remove(ent.get());
4162c593315Sopenharmony_ci      close(ent->fd);
4172c593315Sopenharmony_ci      i = fd_cache_.erase(i);
4182c593315Sopenharmony_ci    }
4192c593315Sopenharmony_ci  }
4202c593315Sopenharmony_ci  const HttpServer *get_server() const { return sv_; }
4212c593315Sopenharmony_ci  bool handlers_empty() const { return handlers_.empty(); }
4222c593315Sopenharmony_ci
4232c593315Sopenharmony_ciprivate:
4242c593315Sopenharmony_ci  std::set<Http2Handler *> handlers_;
4252c593315Sopenharmony_ci  // cache for file descriptors to read file.
4262c593315Sopenharmony_ci  std::multimap<std::string, std::unique_ptr<FileEntry>> fd_cache_;
4272c593315Sopenharmony_ci  DList<FileEntry> fd_cache_lru_;
4282c593315Sopenharmony_ci  HttpServer *sv_;
4292c593315Sopenharmony_ci  struct ev_loop *loop_;
4302c593315Sopenharmony_ci  const Config *config_;
4312c593315Sopenharmony_ci  SSL_CTX *ssl_ctx_;
4322c593315Sopenharmony_ci  nghttp2_session_callbacks *callbacks_;
4332c593315Sopenharmony_ci  nghttp2_option *option_;
4342c593315Sopenharmony_ci  ev_timer release_fd_timer_;
4352c593315Sopenharmony_ci  int64_t next_session_id_;
4362c593315Sopenharmony_ci  ev_tstamp tstamp_cached_;
4372c593315Sopenharmony_ci  std::string cached_date_;
4382c593315Sopenharmony_ci};
4392c593315Sopenharmony_ci
4402c593315Sopenharmony_cinamespace {
4412c593315Sopenharmony_civoid release_fd_cb(struct ev_loop *loop, ev_timer *w, int revents) {
4422c593315Sopenharmony_ci  auto sessions = static_cast<Sessions *>(w->data);
4432c593315Sopenharmony_ci
4442c593315Sopenharmony_ci  ev_timer_stop(loop, w);
4452c593315Sopenharmony_ci
4462c593315Sopenharmony_ci  if (!sessions->handlers_empty()) {
4472c593315Sopenharmony_ci    return;
4482c593315Sopenharmony_ci  }
4492c593315Sopenharmony_ci
4502c593315Sopenharmony_ci  sessions->release_unused_fd();
4512c593315Sopenharmony_ci}
4522c593315Sopenharmony_ci} // namespace
4532c593315Sopenharmony_ci
4542c593315Sopenharmony_ciStream::Stream(Http2Handler *handler, int32_t stream_id)
4552c593315Sopenharmony_ci    : balloc(1024, 1024),
4562c593315Sopenharmony_ci      header{},
4572c593315Sopenharmony_ci      handler(handler),
4582c593315Sopenharmony_ci      file_ent(nullptr),
4592c593315Sopenharmony_ci      body_length(0),
4602c593315Sopenharmony_ci      body_offset(0),
4612c593315Sopenharmony_ci      header_buffer_size(0),
4622c593315Sopenharmony_ci      stream_id(stream_id),
4632c593315Sopenharmony_ci      echo_upload(false) {
4642c593315Sopenharmony_ci  auto config = handler->get_config();
4652c593315Sopenharmony_ci  ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
4662c593315Sopenharmony_ci  ev_timer_init(&wtimer, stream_timeout_cb, 0., config->stream_write_timeout);
4672c593315Sopenharmony_ci  rtimer.data = this;
4682c593315Sopenharmony_ci  wtimer.data = this;
4692c593315Sopenharmony_ci}
4702c593315Sopenharmony_ci
4712c593315Sopenharmony_ciStream::~Stream() {
4722c593315Sopenharmony_ci  if (file_ent != nullptr) {
4732c593315Sopenharmony_ci    auto sessions = handler->get_sessions();
4742c593315Sopenharmony_ci    sessions->release_fd(file_ent);
4752c593315Sopenharmony_ci  }
4762c593315Sopenharmony_ci
4772c593315Sopenharmony_ci  auto &rcbuf = header.rcbuf;
4782c593315Sopenharmony_ci  nghttp2_rcbuf_decref(rcbuf.method);
4792c593315Sopenharmony_ci  nghttp2_rcbuf_decref(rcbuf.scheme);
4802c593315Sopenharmony_ci  nghttp2_rcbuf_decref(rcbuf.authority);
4812c593315Sopenharmony_ci  nghttp2_rcbuf_decref(rcbuf.host);
4822c593315Sopenharmony_ci  nghttp2_rcbuf_decref(rcbuf.path);
4832c593315Sopenharmony_ci  nghttp2_rcbuf_decref(rcbuf.ims);
4842c593315Sopenharmony_ci  nghttp2_rcbuf_decref(rcbuf.expect);
4852c593315Sopenharmony_ci
4862c593315Sopenharmony_ci  auto loop = handler->get_loop();
4872c593315Sopenharmony_ci  ev_timer_stop(loop, &rtimer);
4882c593315Sopenharmony_ci  ev_timer_stop(loop, &wtimer);
4892c593315Sopenharmony_ci}
4902c593315Sopenharmony_ci
4912c593315Sopenharmony_cinamespace {
4922c593315Sopenharmony_civoid on_session_closed(Http2Handler *hd, int64_t session_id) {
4932c593315Sopenharmony_ci  if (hd->get_config()->verbose) {
4942c593315Sopenharmony_ci    print_session_id(session_id);
4952c593315Sopenharmony_ci    print_timer();
4962c593315Sopenharmony_ci    std::cout << " closed" << std::endl;
4972c593315Sopenharmony_ci  }
4982c593315Sopenharmony_ci}
4992c593315Sopenharmony_ci} // namespace
5002c593315Sopenharmony_ci
5012c593315Sopenharmony_cinamespace {
5022c593315Sopenharmony_civoid settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
5032c593315Sopenharmony_ci  int rv;
5042c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(w->data);
5052c593315Sopenharmony_ci  hd->terminate_session(NGHTTP2_SETTINGS_TIMEOUT);
5062c593315Sopenharmony_ci  rv = hd->on_write();
5072c593315Sopenharmony_ci  if (rv == -1) {
5082c593315Sopenharmony_ci    delete_handler(hd);
5092c593315Sopenharmony_ci  }
5102c593315Sopenharmony_ci}
5112c593315Sopenharmony_ci} // namespace
5122c593315Sopenharmony_ci
5132c593315Sopenharmony_cinamespace {
5142c593315Sopenharmony_civoid readcb(struct ev_loop *loop, ev_io *w, int revents) {
5152c593315Sopenharmony_ci  int rv;
5162c593315Sopenharmony_ci  auto handler = static_cast<Http2Handler *>(w->data);
5172c593315Sopenharmony_ci
5182c593315Sopenharmony_ci  rv = handler->on_read();
5192c593315Sopenharmony_ci  if (rv == -1) {
5202c593315Sopenharmony_ci    delete_handler(handler);
5212c593315Sopenharmony_ci  }
5222c593315Sopenharmony_ci}
5232c593315Sopenharmony_ci} // namespace
5242c593315Sopenharmony_ci
5252c593315Sopenharmony_cinamespace {
5262c593315Sopenharmony_civoid writecb(struct ev_loop *loop, ev_io *w, int revents) {
5272c593315Sopenharmony_ci  int rv;
5282c593315Sopenharmony_ci  auto handler = static_cast<Http2Handler *>(w->data);
5292c593315Sopenharmony_ci
5302c593315Sopenharmony_ci  rv = handler->on_write();
5312c593315Sopenharmony_ci  if (rv == -1) {
5322c593315Sopenharmony_ci    delete_handler(handler);
5332c593315Sopenharmony_ci  }
5342c593315Sopenharmony_ci}
5352c593315Sopenharmony_ci} // namespace
5362c593315Sopenharmony_ci
5372c593315Sopenharmony_ciHttp2Handler::Http2Handler(Sessions *sessions, int fd, SSL *ssl,
5382c593315Sopenharmony_ci                           int64_t session_id)
5392c593315Sopenharmony_ci    : session_id_(session_id),
5402c593315Sopenharmony_ci      session_(nullptr),
5412c593315Sopenharmony_ci      sessions_(sessions),
5422c593315Sopenharmony_ci      ssl_(ssl),
5432c593315Sopenharmony_ci      data_pending_(nullptr),
5442c593315Sopenharmony_ci      data_pendinglen_(0),
5452c593315Sopenharmony_ci      fd_(fd) {
5462c593315Sopenharmony_ci  ev_timer_init(&settings_timerev_, settings_timeout_cb, 10., 0.);
5472c593315Sopenharmony_ci  ev_io_init(&wev_, writecb, fd, EV_WRITE);
5482c593315Sopenharmony_ci  ev_io_init(&rev_, readcb, fd, EV_READ);
5492c593315Sopenharmony_ci
5502c593315Sopenharmony_ci  settings_timerev_.data = this;
5512c593315Sopenharmony_ci  wev_.data = this;
5522c593315Sopenharmony_ci  rev_.data = this;
5532c593315Sopenharmony_ci
5542c593315Sopenharmony_ci  auto loop = sessions_->get_loop();
5552c593315Sopenharmony_ci  ev_io_start(loop, &rev_);
5562c593315Sopenharmony_ci
5572c593315Sopenharmony_ci  if (ssl) {
5582c593315Sopenharmony_ci    SSL_set_accept_state(ssl);
5592c593315Sopenharmony_ci    read_ = &Http2Handler::tls_handshake;
5602c593315Sopenharmony_ci    write_ = &Http2Handler::tls_handshake;
5612c593315Sopenharmony_ci  } else {
5622c593315Sopenharmony_ci    read_ = &Http2Handler::read_clear;
5632c593315Sopenharmony_ci    write_ = &Http2Handler::write_clear;
5642c593315Sopenharmony_ci  }
5652c593315Sopenharmony_ci}
5662c593315Sopenharmony_ci
5672c593315Sopenharmony_ciHttp2Handler::~Http2Handler() {
5682c593315Sopenharmony_ci  on_session_closed(this, session_id_);
5692c593315Sopenharmony_ci  nghttp2_session_del(session_);
5702c593315Sopenharmony_ci  if (ssl_) {
5712c593315Sopenharmony_ci    SSL_set_shutdown(ssl_, SSL_get_shutdown(ssl_) | SSL_RECEIVED_SHUTDOWN);
5722c593315Sopenharmony_ci    ERR_clear_error();
5732c593315Sopenharmony_ci    SSL_shutdown(ssl_);
5742c593315Sopenharmony_ci  }
5752c593315Sopenharmony_ci  auto loop = sessions_->get_loop();
5762c593315Sopenharmony_ci  ev_timer_stop(loop, &settings_timerev_);
5772c593315Sopenharmony_ci  ev_io_stop(loop, &rev_);
5782c593315Sopenharmony_ci  ev_io_stop(loop, &wev_);
5792c593315Sopenharmony_ci  if (ssl_) {
5802c593315Sopenharmony_ci    SSL_free(ssl_);
5812c593315Sopenharmony_ci  }
5822c593315Sopenharmony_ci  shutdown(fd_, SHUT_WR);
5832c593315Sopenharmony_ci  close(fd_);
5842c593315Sopenharmony_ci}
5852c593315Sopenharmony_ci
5862c593315Sopenharmony_civoid Http2Handler::remove_self() { sessions_->remove_handler(this); }
5872c593315Sopenharmony_ci
5882c593315Sopenharmony_cistruct ev_loop *Http2Handler::get_loop() const {
5892c593315Sopenharmony_ci  return sessions_->get_loop();
5902c593315Sopenharmony_ci}
5912c593315Sopenharmony_ci
5922c593315Sopenharmony_ciHttp2Handler::WriteBuf *Http2Handler::get_wb() { return &wb_; }
5932c593315Sopenharmony_ci
5942c593315Sopenharmony_civoid Http2Handler::start_settings_timer() {
5952c593315Sopenharmony_ci  ev_timer_start(sessions_->get_loop(), &settings_timerev_);
5962c593315Sopenharmony_ci}
5972c593315Sopenharmony_ci
5982c593315Sopenharmony_ciint Http2Handler::fill_wb() {
5992c593315Sopenharmony_ci  if (data_pending_) {
6002c593315Sopenharmony_ci    auto n = std::min(wb_.wleft(), data_pendinglen_);
6012c593315Sopenharmony_ci    wb_.write(data_pending_, n);
6022c593315Sopenharmony_ci    if (n < data_pendinglen_) {
6032c593315Sopenharmony_ci      data_pending_ += n;
6042c593315Sopenharmony_ci      data_pendinglen_ -= n;
6052c593315Sopenharmony_ci      return 0;
6062c593315Sopenharmony_ci    }
6072c593315Sopenharmony_ci
6082c593315Sopenharmony_ci    data_pending_ = nullptr;
6092c593315Sopenharmony_ci    data_pendinglen_ = 0;
6102c593315Sopenharmony_ci  }
6112c593315Sopenharmony_ci
6122c593315Sopenharmony_ci  for (;;) {
6132c593315Sopenharmony_ci    const uint8_t *data;
6142c593315Sopenharmony_ci    auto datalen = nghttp2_session_mem_send(session_, &data);
6152c593315Sopenharmony_ci
6162c593315Sopenharmony_ci    if (datalen < 0) {
6172c593315Sopenharmony_ci      std::cerr << "nghttp2_session_mem_send() returned error: "
6182c593315Sopenharmony_ci                << nghttp2_strerror(datalen) << std::endl;
6192c593315Sopenharmony_ci      return -1;
6202c593315Sopenharmony_ci    }
6212c593315Sopenharmony_ci    if (datalen == 0) {
6222c593315Sopenharmony_ci      break;
6232c593315Sopenharmony_ci    }
6242c593315Sopenharmony_ci    auto n = wb_.write(data, datalen);
6252c593315Sopenharmony_ci    if (n < static_cast<decltype(n)>(datalen)) {
6262c593315Sopenharmony_ci      data_pending_ = data + n;
6272c593315Sopenharmony_ci      data_pendinglen_ = datalen - n;
6282c593315Sopenharmony_ci      break;
6292c593315Sopenharmony_ci    }
6302c593315Sopenharmony_ci  }
6312c593315Sopenharmony_ci  return 0;
6322c593315Sopenharmony_ci}
6332c593315Sopenharmony_ci
6342c593315Sopenharmony_ciint Http2Handler::read_clear() {
6352c593315Sopenharmony_ci  int rv;
6362c593315Sopenharmony_ci  std::array<uint8_t, 8_k> buf;
6372c593315Sopenharmony_ci
6382c593315Sopenharmony_ci  ssize_t nread;
6392c593315Sopenharmony_ci  while ((nread = read(fd_, buf.data(), buf.size())) == -1 && errno == EINTR)
6402c593315Sopenharmony_ci    ;
6412c593315Sopenharmony_ci  if (nread == -1) {
6422c593315Sopenharmony_ci    if (errno == EAGAIN || errno == EWOULDBLOCK) {
6432c593315Sopenharmony_ci      return write_(*this);
6442c593315Sopenharmony_ci    }
6452c593315Sopenharmony_ci    return -1;
6462c593315Sopenharmony_ci  }
6472c593315Sopenharmony_ci  if (nread == 0) {
6482c593315Sopenharmony_ci    return -1;
6492c593315Sopenharmony_ci  }
6502c593315Sopenharmony_ci
6512c593315Sopenharmony_ci  if (get_config()->hexdump) {
6522c593315Sopenharmony_ci    util::hexdump(stdout, buf.data(), nread);
6532c593315Sopenharmony_ci  }
6542c593315Sopenharmony_ci
6552c593315Sopenharmony_ci  rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
6562c593315Sopenharmony_ci  if (rv < 0) {
6572c593315Sopenharmony_ci    if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
6582c593315Sopenharmony_ci      std::cerr << "nghttp2_session_mem_recv() returned error: "
6592c593315Sopenharmony_ci                << nghttp2_strerror(rv) << std::endl;
6602c593315Sopenharmony_ci    }
6612c593315Sopenharmony_ci    return -1;
6622c593315Sopenharmony_ci  }
6632c593315Sopenharmony_ci
6642c593315Sopenharmony_ci  return write_(*this);
6652c593315Sopenharmony_ci}
6662c593315Sopenharmony_ci
6672c593315Sopenharmony_ciint Http2Handler::write_clear() {
6682c593315Sopenharmony_ci  auto loop = sessions_->get_loop();
6692c593315Sopenharmony_ci  for (;;) {
6702c593315Sopenharmony_ci    if (wb_.rleft() > 0) {
6712c593315Sopenharmony_ci      ssize_t nwrite;
6722c593315Sopenharmony_ci      while ((nwrite = write(fd_, wb_.pos, wb_.rleft())) == -1 &&
6732c593315Sopenharmony_ci             errno == EINTR)
6742c593315Sopenharmony_ci        ;
6752c593315Sopenharmony_ci      if (nwrite == -1) {
6762c593315Sopenharmony_ci        if (errno == EAGAIN || errno == EWOULDBLOCK) {
6772c593315Sopenharmony_ci          ev_io_start(loop, &wev_);
6782c593315Sopenharmony_ci          return 0;
6792c593315Sopenharmony_ci        }
6802c593315Sopenharmony_ci        return -1;
6812c593315Sopenharmony_ci      }
6822c593315Sopenharmony_ci      wb_.drain(nwrite);
6832c593315Sopenharmony_ci      continue;
6842c593315Sopenharmony_ci    }
6852c593315Sopenharmony_ci    wb_.reset();
6862c593315Sopenharmony_ci    if (fill_wb() != 0) {
6872c593315Sopenharmony_ci      return -1;
6882c593315Sopenharmony_ci    }
6892c593315Sopenharmony_ci    if (wb_.rleft() == 0) {
6902c593315Sopenharmony_ci      break;
6912c593315Sopenharmony_ci    }
6922c593315Sopenharmony_ci  }
6932c593315Sopenharmony_ci
6942c593315Sopenharmony_ci  if (wb_.rleft() == 0) {
6952c593315Sopenharmony_ci    ev_io_stop(loop, &wev_);
6962c593315Sopenharmony_ci  } else {
6972c593315Sopenharmony_ci    ev_io_start(loop, &wev_);
6982c593315Sopenharmony_ci  }
6992c593315Sopenharmony_ci
7002c593315Sopenharmony_ci  if (nghttp2_session_want_read(session_) == 0 &&
7012c593315Sopenharmony_ci      nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) {
7022c593315Sopenharmony_ci    return -1;
7032c593315Sopenharmony_ci  }
7042c593315Sopenharmony_ci
7052c593315Sopenharmony_ci  return 0;
7062c593315Sopenharmony_ci}
7072c593315Sopenharmony_ci
7082c593315Sopenharmony_ciint Http2Handler::tls_handshake() {
7092c593315Sopenharmony_ci  ev_io_stop(sessions_->get_loop(), &wev_);
7102c593315Sopenharmony_ci
7112c593315Sopenharmony_ci  ERR_clear_error();
7122c593315Sopenharmony_ci
7132c593315Sopenharmony_ci  auto rv = SSL_do_handshake(ssl_);
7142c593315Sopenharmony_ci
7152c593315Sopenharmony_ci  if (rv <= 0) {
7162c593315Sopenharmony_ci    auto err = SSL_get_error(ssl_, rv);
7172c593315Sopenharmony_ci    switch (err) {
7182c593315Sopenharmony_ci    case SSL_ERROR_WANT_READ:
7192c593315Sopenharmony_ci      return 0;
7202c593315Sopenharmony_ci    case SSL_ERROR_WANT_WRITE:
7212c593315Sopenharmony_ci      ev_io_start(sessions_->get_loop(), &wev_);
7222c593315Sopenharmony_ci      return 0;
7232c593315Sopenharmony_ci    default:
7242c593315Sopenharmony_ci      return -1;
7252c593315Sopenharmony_ci    }
7262c593315Sopenharmony_ci  }
7272c593315Sopenharmony_ci
7282c593315Sopenharmony_ci  if (sessions_->get_config()->verbose) {
7292c593315Sopenharmony_ci    std::cerr << "SSL/TLS handshake completed" << std::endl;
7302c593315Sopenharmony_ci  }
7312c593315Sopenharmony_ci
7322c593315Sopenharmony_ci  if (verify_npn_result() != 0) {
7332c593315Sopenharmony_ci    return -1;
7342c593315Sopenharmony_ci  }
7352c593315Sopenharmony_ci
7362c593315Sopenharmony_ci  read_ = &Http2Handler::read_tls;
7372c593315Sopenharmony_ci  write_ = &Http2Handler::write_tls;
7382c593315Sopenharmony_ci
7392c593315Sopenharmony_ci  if (connection_made() != 0) {
7402c593315Sopenharmony_ci    return -1;
7412c593315Sopenharmony_ci  }
7422c593315Sopenharmony_ci
7432c593315Sopenharmony_ci  if (sessions_->get_config()->verbose) {
7442c593315Sopenharmony_ci    if (SSL_session_reused(ssl_)) {
7452c593315Sopenharmony_ci      std::cerr << "SSL/TLS session reused" << std::endl;
7462c593315Sopenharmony_ci    }
7472c593315Sopenharmony_ci  }
7482c593315Sopenharmony_ci
7492c593315Sopenharmony_ci  return 0;
7502c593315Sopenharmony_ci}
7512c593315Sopenharmony_ci
7522c593315Sopenharmony_ciint Http2Handler::read_tls() {
7532c593315Sopenharmony_ci  std::array<uint8_t, 8_k> buf;
7542c593315Sopenharmony_ci
7552c593315Sopenharmony_ci  ERR_clear_error();
7562c593315Sopenharmony_ci
7572c593315Sopenharmony_ci  auto rv = SSL_read(ssl_, buf.data(), buf.size());
7582c593315Sopenharmony_ci
7592c593315Sopenharmony_ci  if (rv <= 0) {
7602c593315Sopenharmony_ci    auto err = SSL_get_error(ssl_, rv);
7612c593315Sopenharmony_ci    switch (err) {
7622c593315Sopenharmony_ci    case SSL_ERROR_WANT_READ:
7632c593315Sopenharmony_ci      return write_(*this);
7642c593315Sopenharmony_ci    case SSL_ERROR_WANT_WRITE:
7652c593315Sopenharmony_ci      // renegotiation started
7662c593315Sopenharmony_ci      return -1;
7672c593315Sopenharmony_ci    default:
7682c593315Sopenharmony_ci      return -1;
7692c593315Sopenharmony_ci    }
7702c593315Sopenharmony_ci  }
7712c593315Sopenharmony_ci
7722c593315Sopenharmony_ci  auto nread = rv;
7732c593315Sopenharmony_ci
7742c593315Sopenharmony_ci  if (get_config()->hexdump) {
7752c593315Sopenharmony_ci    util::hexdump(stdout, buf.data(), nread);
7762c593315Sopenharmony_ci  }
7772c593315Sopenharmony_ci
7782c593315Sopenharmony_ci  rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
7792c593315Sopenharmony_ci  if (rv < 0) {
7802c593315Sopenharmony_ci    if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
7812c593315Sopenharmony_ci      std::cerr << "nghttp2_session_mem_recv() returned error: "
7822c593315Sopenharmony_ci                << nghttp2_strerror(rv) << std::endl;
7832c593315Sopenharmony_ci    }
7842c593315Sopenharmony_ci    return -1;
7852c593315Sopenharmony_ci  }
7862c593315Sopenharmony_ci
7872c593315Sopenharmony_ci  return write_(*this);
7882c593315Sopenharmony_ci}
7892c593315Sopenharmony_ci
7902c593315Sopenharmony_ciint Http2Handler::write_tls() {
7912c593315Sopenharmony_ci  auto loop = sessions_->get_loop();
7922c593315Sopenharmony_ci
7932c593315Sopenharmony_ci  ERR_clear_error();
7942c593315Sopenharmony_ci
7952c593315Sopenharmony_ci  for (;;) {
7962c593315Sopenharmony_ci    if (wb_.rleft() > 0) {
7972c593315Sopenharmony_ci      auto rv = SSL_write(ssl_, wb_.pos, wb_.rleft());
7982c593315Sopenharmony_ci
7992c593315Sopenharmony_ci      if (rv <= 0) {
8002c593315Sopenharmony_ci        auto err = SSL_get_error(ssl_, rv);
8012c593315Sopenharmony_ci        switch (err) {
8022c593315Sopenharmony_ci        case SSL_ERROR_WANT_READ:
8032c593315Sopenharmony_ci          // renegotiation started
8042c593315Sopenharmony_ci          return -1;
8052c593315Sopenharmony_ci        case SSL_ERROR_WANT_WRITE:
8062c593315Sopenharmony_ci          ev_io_start(sessions_->get_loop(), &wev_);
8072c593315Sopenharmony_ci          return 0;
8082c593315Sopenharmony_ci        default:
8092c593315Sopenharmony_ci          return -1;
8102c593315Sopenharmony_ci        }
8112c593315Sopenharmony_ci      }
8122c593315Sopenharmony_ci
8132c593315Sopenharmony_ci      wb_.drain(rv);
8142c593315Sopenharmony_ci      continue;
8152c593315Sopenharmony_ci    }
8162c593315Sopenharmony_ci    wb_.reset();
8172c593315Sopenharmony_ci    if (fill_wb() != 0) {
8182c593315Sopenharmony_ci      return -1;
8192c593315Sopenharmony_ci    }
8202c593315Sopenharmony_ci    if (wb_.rleft() == 0) {
8212c593315Sopenharmony_ci      break;
8222c593315Sopenharmony_ci    }
8232c593315Sopenharmony_ci  }
8242c593315Sopenharmony_ci
8252c593315Sopenharmony_ci  if (wb_.rleft() == 0) {
8262c593315Sopenharmony_ci    ev_io_stop(loop, &wev_);
8272c593315Sopenharmony_ci  } else {
8282c593315Sopenharmony_ci    ev_io_start(loop, &wev_);
8292c593315Sopenharmony_ci  }
8302c593315Sopenharmony_ci
8312c593315Sopenharmony_ci  if (nghttp2_session_want_read(session_) == 0 &&
8322c593315Sopenharmony_ci      nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) {
8332c593315Sopenharmony_ci    return -1;
8342c593315Sopenharmony_ci  }
8352c593315Sopenharmony_ci
8362c593315Sopenharmony_ci  return 0;
8372c593315Sopenharmony_ci}
8382c593315Sopenharmony_ci
8392c593315Sopenharmony_ciint Http2Handler::on_read() { return read_(*this); }
8402c593315Sopenharmony_ci
8412c593315Sopenharmony_ciint Http2Handler::on_write() { return write_(*this); }
8422c593315Sopenharmony_ci
8432c593315Sopenharmony_ciint Http2Handler::connection_made() {
8442c593315Sopenharmony_ci  int r;
8452c593315Sopenharmony_ci
8462c593315Sopenharmony_ci  r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
8472c593315Sopenharmony_ci                                  sessions_->get_option());
8482c593315Sopenharmony_ci
8492c593315Sopenharmony_ci  if (r != 0) {
8502c593315Sopenharmony_ci    return r;
8512c593315Sopenharmony_ci  }
8522c593315Sopenharmony_ci
8532c593315Sopenharmony_ci  auto config = sessions_->get_config();
8542c593315Sopenharmony_ci  std::array<nghttp2_settings_entry, 4> entry;
8552c593315Sopenharmony_ci  size_t niv = 1;
8562c593315Sopenharmony_ci
8572c593315Sopenharmony_ci  entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
8582c593315Sopenharmony_ci  entry[0].value = config->max_concurrent_streams;
8592c593315Sopenharmony_ci
8602c593315Sopenharmony_ci  if (config->header_table_size >= 0) {
8612c593315Sopenharmony_ci    entry[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
8622c593315Sopenharmony_ci    entry[niv].value = config->header_table_size;
8632c593315Sopenharmony_ci    ++niv;
8642c593315Sopenharmony_ci  }
8652c593315Sopenharmony_ci
8662c593315Sopenharmony_ci  if (config->window_bits != -1) {
8672c593315Sopenharmony_ci    entry[niv].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
8682c593315Sopenharmony_ci    entry[niv].value = (1 << config->window_bits) - 1;
8692c593315Sopenharmony_ci    ++niv;
8702c593315Sopenharmony_ci  }
8712c593315Sopenharmony_ci
8722c593315Sopenharmony_ci  if (config->no_rfc7540_pri) {
8732c593315Sopenharmony_ci    entry[niv].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
8742c593315Sopenharmony_ci    entry[niv].value = 1;
8752c593315Sopenharmony_ci    ++niv;
8762c593315Sopenharmony_ci  }
8772c593315Sopenharmony_ci
8782c593315Sopenharmony_ci  r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(), niv);
8792c593315Sopenharmony_ci  if (r != 0) {
8802c593315Sopenharmony_ci    return r;
8812c593315Sopenharmony_ci  }
8822c593315Sopenharmony_ci
8832c593315Sopenharmony_ci  if (config->connection_window_bits != -1) {
8842c593315Sopenharmony_ci    r = nghttp2_session_set_local_window_size(
8852c593315Sopenharmony_ci        session_, NGHTTP2_FLAG_NONE, 0,
8862c593315Sopenharmony_ci        (1 << config->connection_window_bits) - 1);
8872c593315Sopenharmony_ci    if (r != 0) {
8882c593315Sopenharmony_ci      return r;
8892c593315Sopenharmony_ci    }
8902c593315Sopenharmony_ci  }
8912c593315Sopenharmony_ci
8922c593315Sopenharmony_ci  if (ssl_ && !nghttp2::tls::check_http2_requirement(ssl_)) {
8932c593315Sopenharmony_ci    terminate_session(NGHTTP2_INADEQUATE_SECURITY);
8942c593315Sopenharmony_ci  }
8952c593315Sopenharmony_ci
8962c593315Sopenharmony_ci  return on_write();
8972c593315Sopenharmony_ci}
8982c593315Sopenharmony_ci
8992c593315Sopenharmony_ciint Http2Handler::verify_npn_result() {
9002c593315Sopenharmony_ci  const unsigned char *next_proto = nullptr;
9012c593315Sopenharmony_ci  unsigned int next_proto_len;
9022c593315Sopenharmony_ci  // Check the negotiated protocol in NPN or ALPN
9032c593315Sopenharmony_ci#ifndef OPENSSL_NO_NEXTPROTONEG
9042c593315Sopenharmony_ci  SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
9052c593315Sopenharmony_ci#endif // !OPENSSL_NO_NEXTPROTONEG
9062c593315Sopenharmony_ci  for (int i = 0; i < 2; ++i) {
9072c593315Sopenharmony_ci    if (next_proto) {
9082c593315Sopenharmony_ci      auto proto = StringRef{next_proto, next_proto_len};
9092c593315Sopenharmony_ci      if (sessions_->get_config()->verbose) {
9102c593315Sopenharmony_ci        std::cout << "The negotiated protocol: " << proto << std::endl;
9112c593315Sopenharmony_ci      }
9122c593315Sopenharmony_ci      if (util::check_h2_is_selected(proto)) {
9132c593315Sopenharmony_ci        return 0;
9142c593315Sopenharmony_ci      }
9152c593315Sopenharmony_ci      break;
9162c593315Sopenharmony_ci    } else {
9172c593315Sopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10002000L
9182c593315Sopenharmony_ci      SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
9192c593315Sopenharmony_ci#else  // OPENSSL_VERSION_NUMBER < 0x10002000L
9202c593315Sopenharmony_ci      break;
9212c593315Sopenharmony_ci#endif // OPENSSL_VERSION_NUMBER < 0x10002000L
9222c593315Sopenharmony_ci    }
9232c593315Sopenharmony_ci  }
9242c593315Sopenharmony_ci  if (sessions_->get_config()->verbose) {
9252c593315Sopenharmony_ci    std::cerr << "Client did not advertise HTTP/2 protocol."
9262c593315Sopenharmony_ci              << " (nghttp2 expects " << NGHTTP2_PROTO_VERSION_ID << ")"
9272c593315Sopenharmony_ci              << std::endl;
9282c593315Sopenharmony_ci  }
9292c593315Sopenharmony_ci  return -1;
9302c593315Sopenharmony_ci}
9312c593315Sopenharmony_ci
9322c593315Sopenharmony_ciint Http2Handler::submit_file_response(const StringRef &status, Stream *stream,
9332c593315Sopenharmony_ci                                       time_t last_modified, off_t file_length,
9342c593315Sopenharmony_ci                                       const std::string *content_type,
9352c593315Sopenharmony_ci                                       nghttp2_data_provider *data_prd) {
9362c593315Sopenharmony_ci  std::string last_modified_str;
9372c593315Sopenharmony_ci  auto nva = make_array(http2::make_nv_ls_nocopy(":status", status),
9382c593315Sopenharmony_ci                        http2::make_nv_ls_nocopy("server", NGHTTPD_SERVER),
9392c593315Sopenharmony_ci                        http2::make_nv_ll("cache-control", "max-age=3600"),
9402c593315Sopenharmony_ci                        http2::make_nv_ls("date", sessions_->get_cached_date()),
9412c593315Sopenharmony_ci                        http2::make_nv_ll("", ""), http2::make_nv_ll("", ""),
9422c593315Sopenharmony_ci                        http2::make_nv_ll("", ""), http2::make_nv_ll("", ""));
9432c593315Sopenharmony_ci  size_t nvlen = 4;
9442c593315Sopenharmony_ci  if (!get_config()->no_content_length) {
9452c593315Sopenharmony_ci    nva[nvlen++] = http2::make_nv_ls_nocopy(
9462c593315Sopenharmony_ci        "content-length",
9472c593315Sopenharmony_ci        util::make_string_ref_uint(stream->balloc, file_length));
9482c593315Sopenharmony_ci  }
9492c593315Sopenharmony_ci  if (last_modified != 0) {
9502c593315Sopenharmony_ci    last_modified_str = util::http_date(last_modified);
9512c593315Sopenharmony_ci    nva[nvlen++] = http2::make_nv_ls("last-modified", last_modified_str);
9522c593315Sopenharmony_ci  }
9532c593315Sopenharmony_ci  if (content_type) {
9542c593315Sopenharmony_ci    nva[nvlen++] = http2::make_nv_ls("content-type", *content_type);
9552c593315Sopenharmony_ci  }
9562c593315Sopenharmony_ci  auto &trailer_names = get_config()->trailer_names;
9572c593315Sopenharmony_ci  if (!trailer_names.empty()) {
9582c593315Sopenharmony_ci    nva[nvlen++] = http2::make_nv_ls_nocopy("trailer", trailer_names);
9592c593315Sopenharmony_ci  }
9602c593315Sopenharmony_ci  return nghttp2_submit_response(session_, stream->stream_id, nva.data(), nvlen,
9612c593315Sopenharmony_ci                                 data_prd);
9622c593315Sopenharmony_ci}
9632c593315Sopenharmony_ci
9642c593315Sopenharmony_ciint Http2Handler::submit_response(const StringRef &status, int32_t stream_id,
9652c593315Sopenharmony_ci                                  const HeaderRefs &headers,
9662c593315Sopenharmony_ci                                  nghttp2_data_provider *data_prd) {
9672c593315Sopenharmony_ci  auto nva = std::vector<nghttp2_nv>();
9682c593315Sopenharmony_ci  nva.reserve(4 + headers.size());
9692c593315Sopenharmony_ci  nva.push_back(http2::make_nv_ls_nocopy(":status", status));
9702c593315Sopenharmony_ci  nva.push_back(http2::make_nv_ls_nocopy("server", NGHTTPD_SERVER));
9712c593315Sopenharmony_ci  nva.push_back(http2::make_nv_ls("date", sessions_->get_cached_date()));
9722c593315Sopenharmony_ci
9732c593315Sopenharmony_ci  if (data_prd) {
9742c593315Sopenharmony_ci    auto &trailer_names = get_config()->trailer_names;
9752c593315Sopenharmony_ci    if (!trailer_names.empty()) {
9762c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ls_nocopy("trailer", trailer_names));
9772c593315Sopenharmony_ci    }
9782c593315Sopenharmony_ci  }
9792c593315Sopenharmony_ci
9802c593315Sopenharmony_ci  for (auto &nv : headers) {
9812c593315Sopenharmony_ci    nva.push_back(http2::make_nv_nocopy(nv.name, nv.value, nv.no_index));
9822c593315Sopenharmony_ci  }
9832c593315Sopenharmony_ci  int r = nghttp2_submit_response(session_, stream_id, nva.data(), nva.size(),
9842c593315Sopenharmony_ci                                  data_prd);
9852c593315Sopenharmony_ci  return r;
9862c593315Sopenharmony_ci}
9872c593315Sopenharmony_ci
9882c593315Sopenharmony_ciint Http2Handler::submit_response(const StringRef &status, int32_t stream_id,
9892c593315Sopenharmony_ci                                  nghttp2_data_provider *data_prd) {
9902c593315Sopenharmony_ci  auto nva = make_array(http2::make_nv_ls_nocopy(":status", status),
9912c593315Sopenharmony_ci                        http2::make_nv_ls_nocopy("server", NGHTTPD_SERVER),
9922c593315Sopenharmony_ci                        http2::make_nv_ls("date", sessions_->get_cached_date()),
9932c593315Sopenharmony_ci                        http2::make_nv_ll("", ""));
9942c593315Sopenharmony_ci  size_t nvlen = 3;
9952c593315Sopenharmony_ci
9962c593315Sopenharmony_ci  if (data_prd) {
9972c593315Sopenharmony_ci    auto &trailer_names = get_config()->trailer_names;
9982c593315Sopenharmony_ci    if (!trailer_names.empty()) {
9992c593315Sopenharmony_ci      nva[nvlen++] = http2::make_nv_ls_nocopy("trailer", trailer_names);
10002c593315Sopenharmony_ci    }
10012c593315Sopenharmony_ci  }
10022c593315Sopenharmony_ci
10032c593315Sopenharmony_ci  return nghttp2_submit_response(session_, stream_id, nva.data(), nvlen,
10042c593315Sopenharmony_ci                                 data_prd);
10052c593315Sopenharmony_ci}
10062c593315Sopenharmony_ci
10072c593315Sopenharmony_ciint Http2Handler::submit_non_final_response(const std::string &status,
10082c593315Sopenharmony_ci                                            int32_t stream_id) {
10092c593315Sopenharmony_ci  auto nva = make_array(http2::make_nv_ls(":status", status));
10102c593315Sopenharmony_ci  return nghttp2_submit_headers(session_, NGHTTP2_FLAG_NONE, stream_id, nullptr,
10112c593315Sopenharmony_ci                                nva.data(), nva.size(), nullptr);
10122c593315Sopenharmony_ci}
10132c593315Sopenharmony_ci
10142c593315Sopenharmony_ciint Http2Handler::submit_push_promise(Stream *stream,
10152c593315Sopenharmony_ci                                      const StringRef &push_path) {
10162c593315Sopenharmony_ci  auto authority = stream->header.authority;
10172c593315Sopenharmony_ci
10182c593315Sopenharmony_ci  if (authority.empty()) {
10192c593315Sopenharmony_ci    authority = stream->header.host;
10202c593315Sopenharmony_ci  }
10212c593315Sopenharmony_ci
10222c593315Sopenharmony_ci  auto scheme = get_config()->no_tls ? StringRef::from_lit("http")
10232c593315Sopenharmony_ci                                     : StringRef::from_lit("https");
10242c593315Sopenharmony_ci
10252c593315Sopenharmony_ci  auto nva = make_array(http2::make_nv_ll(":method", "GET"),
10262c593315Sopenharmony_ci                        http2::make_nv_ls_nocopy(":path", push_path),
10272c593315Sopenharmony_ci                        http2::make_nv_ls_nocopy(":scheme", scheme),
10282c593315Sopenharmony_ci                        http2::make_nv_ls_nocopy(":authority", authority));
10292c593315Sopenharmony_ci
10302c593315Sopenharmony_ci  auto promised_stream_id = nghttp2_submit_push_promise(
10312c593315Sopenharmony_ci      session_, NGHTTP2_FLAG_END_HEADERS, stream->stream_id, nva.data(),
10322c593315Sopenharmony_ci      nva.size(), nullptr);
10332c593315Sopenharmony_ci
10342c593315Sopenharmony_ci  if (promised_stream_id < 0) {
10352c593315Sopenharmony_ci    return promised_stream_id;
10362c593315Sopenharmony_ci  }
10372c593315Sopenharmony_ci
10382c593315Sopenharmony_ci  auto promised_stream = std::make_unique<Stream>(this, promised_stream_id);
10392c593315Sopenharmony_ci
10402c593315Sopenharmony_ci  auto &promised_header = promised_stream->header;
10412c593315Sopenharmony_ci  promised_header.method = StringRef::from_lit("GET");
10422c593315Sopenharmony_ci  promised_header.path = push_path;
10432c593315Sopenharmony_ci  promised_header.scheme = scheme;
10442c593315Sopenharmony_ci  promised_header.authority =
10452c593315Sopenharmony_ci      make_string_ref(promised_stream->balloc, authority);
10462c593315Sopenharmony_ci
10472c593315Sopenharmony_ci  add_stream(promised_stream_id, std::move(promised_stream));
10482c593315Sopenharmony_ci
10492c593315Sopenharmony_ci  return 0;
10502c593315Sopenharmony_ci}
10512c593315Sopenharmony_ci
10522c593315Sopenharmony_ciint Http2Handler::submit_rst_stream(Stream *stream, uint32_t error_code) {
10532c593315Sopenharmony_ci  remove_stream_read_timeout(stream);
10542c593315Sopenharmony_ci  remove_stream_write_timeout(stream);
10552c593315Sopenharmony_ci
10562c593315Sopenharmony_ci  return nghttp2_submit_rst_stream(session_, NGHTTP2_FLAG_NONE,
10572c593315Sopenharmony_ci                                   stream->stream_id, error_code);
10582c593315Sopenharmony_ci}
10592c593315Sopenharmony_ci
10602c593315Sopenharmony_civoid Http2Handler::add_stream(int32_t stream_id,
10612c593315Sopenharmony_ci                              std::unique_ptr<Stream> stream) {
10622c593315Sopenharmony_ci  id2stream_[stream_id] = std::move(stream);
10632c593315Sopenharmony_ci}
10642c593315Sopenharmony_ci
10652c593315Sopenharmony_civoid Http2Handler::remove_stream(int32_t stream_id) {
10662c593315Sopenharmony_ci  id2stream_.erase(stream_id);
10672c593315Sopenharmony_ci}
10682c593315Sopenharmony_ci
10692c593315Sopenharmony_ciStream *Http2Handler::get_stream(int32_t stream_id) {
10702c593315Sopenharmony_ci  auto itr = id2stream_.find(stream_id);
10712c593315Sopenharmony_ci  if (itr == std::end(id2stream_)) {
10722c593315Sopenharmony_ci    return nullptr;
10732c593315Sopenharmony_ci  } else {
10742c593315Sopenharmony_ci    return (*itr).second.get();
10752c593315Sopenharmony_ci  }
10762c593315Sopenharmony_ci}
10772c593315Sopenharmony_ci
10782c593315Sopenharmony_ciint64_t Http2Handler::session_id() const { return session_id_; }
10792c593315Sopenharmony_ci
10802c593315Sopenharmony_ciSessions *Http2Handler::get_sessions() const { return sessions_; }
10812c593315Sopenharmony_ci
10822c593315Sopenharmony_ciconst Config *Http2Handler::get_config() const {
10832c593315Sopenharmony_ci  return sessions_->get_config();
10842c593315Sopenharmony_ci}
10852c593315Sopenharmony_ci
10862c593315Sopenharmony_civoid Http2Handler::remove_settings_timer() {
10872c593315Sopenharmony_ci  ev_timer_stop(sessions_->get_loop(), &settings_timerev_);
10882c593315Sopenharmony_ci}
10892c593315Sopenharmony_ci
10902c593315Sopenharmony_civoid Http2Handler::terminate_session(uint32_t error_code) {
10912c593315Sopenharmony_ci  nghttp2_session_terminate_session(session_, error_code);
10922c593315Sopenharmony_ci}
10932c593315Sopenharmony_ci
10942c593315Sopenharmony_cissize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
10952c593315Sopenharmony_ci                           uint8_t *buf, size_t length, uint32_t *data_flags,
10962c593315Sopenharmony_ci                           nghttp2_data_source *source, void *user_data) {
10972c593315Sopenharmony_ci  int rv;
10982c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(user_data);
10992c593315Sopenharmony_ci  auto stream = hd->get_stream(stream_id);
11002c593315Sopenharmony_ci
11012c593315Sopenharmony_ci  auto nread = std::min(stream->body_length - stream->body_offset,
11022c593315Sopenharmony_ci                        static_cast<int64_t>(length));
11032c593315Sopenharmony_ci
11042c593315Sopenharmony_ci  *data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
11052c593315Sopenharmony_ci
11062c593315Sopenharmony_ci  if (nread == 0 || stream->body_length == stream->body_offset + nread) {
11072c593315Sopenharmony_ci    *data_flags |= NGHTTP2_DATA_FLAG_EOF;
11082c593315Sopenharmony_ci
11092c593315Sopenharmony_ci    auto config = hd->get_config();
11102c593315Sopenharmony_ci    if (!config->trailer.empty()) {
11112c593315Sopenharmony_ci      std::vector<nghttp2_nv> nva;
11122c593315Sopenharmony_ci      nva.reserve(config->trailer.size());
11132c593315Sopenharmony_ci      for (auto &kv : config->trailer) {
11142c593315Sopenharmony_ci        nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index));
11152c593315Sopenharmony_ci      }
11162c593315Sopenharmony_ci      rv = nghttp2_submit_trailer(session, stream_id, nva.data(), nva.size());
11172c593315Sopenharmony_ci      if (rv != 0) {
11182c593315Sopenharmony_ci        if (nghttp2_is_fatal(rv)) {
11192c593315Sopenharmony_ci          return NGHTTP2_ERR_CALLBACK_FAILURE;
11202c593315Sopenharmony_ci        }
11212c593315Sopenharmony_ci      } else {
11222c593315Sopenharmony_ci        *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
11232c593315Sopenharmony_ci      }
11242c593315Sopenharmony_ci    }
11252c593315Sopenharmony_ci
11262c593315Sopenharmony_ci    if (nghttp2_session_get_stream_remote_close(session, stream_id) == 0) {
11272c593315Sopenharmony_ci      remove_stream_read_timeout(stream);
11282c593315Sopenharmony_ci      remove_stream_write_timeout(stream);
11292c593315Sopenharmony_ci
11302c593315Sopenharmony_ci      hd->submit_rst_stream(stream, NGHTTP2_NO_ERROR);
11312c593315Sopenharmony_ci    }
11322c593315Sopenharmony_ci  }
11332c593315Sopenharmony_ci
11342c593315Sopenharmony_ci  return nread;
11352c593315Sopenharmony_ci}
11362c593315Sopenharmony_ci
11372c593315Sopenharmony_cinamespace {
11382c593315Sopenharmony_civoid prepare_status_response(Stream *stream, Http2Handler *hd, int status) {
11392c593315Sopenharmony_ci  auto sessions = hd->get_sessions();
11402c593315Sopenharmony_ci  auto status_page = sessions->get_server()->get_status_page(status);
11412c593315Sopenharmony_ci  auto file_ent = &status_page->file_ent;
11422c593315Sopenharmony_ci
11432c593315Sopenharmony_ci  // we don't set stream->file_ent since we don't want to expire it.
11442c593315Sopenharmony_ci  stream->body_length = file_ent->length;
11452c593315Sopenharmony_ci  nghttp2_data_provider data_prd;
11462c593315Sopenharmony_ci  data_prd.source.fd = file_ent->fd;
11472c593315Sopenharmony_ci  data_prd.read_callback = file_read_callback;
11482c593315Sopenharmony_ci
11492c593315Sopenharmony_ci  HeaderRefs headers;
11502c593315Sopenharmony_ci  headers.reserve(2);
11512c593315Sopenharmony_ci  headers.emplace_back(StringRef::from_lit("content-type"),
11522c593315Sopenharmony_ci                       StringRef::from_lit("text/html; charset=UTF-8"));
11532c593315Sopenharmony_ci  headers.emplace_back(
11542c593315Sopenharmony_ci      StringRef::from_lit("content-length"),
11552c593315Sopenharmony_ci      util::make_string_ref_uint(stream->balloc, file_ent->length));
11562c593315Sopenharmony_ci  hd->submit_response(StringRef{status_page->status}, stream->stream_id,
11572c593315Sopenharmony_ci                      headers, &data_prd);
11582c593315Sopenharmony_ci}
11592c593315Sopenharmony_ci} // namespace
11602c593315Sopenharmony_ci
11612c593315Sopenharmony_cinamespace {
11622c593315Sopenharmony_civoid prepare_echo_response(Stream *stream, Http2Handler *hd) {
11632c593315Sopenharmony_ci  auto length = lseek(stream->file_ent->fd, 0, SEEK_END);
11642c593315Sopenharmony_ci  if (length == -1) {
11652c593315Sopenharmony_ci    hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
11662c593315Sopenharmony_ci    return;
11672c593315Sopenharmony_ci  }
11682c593315Sopenharmony_ci  stream->body_length = length;
11692c593315Sopenharmony_ci  if (lseek(stream->file_ent->fd, 0, SEEK_SET) == -1) {
11702c593315Sopenharmony_ci    hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
11712c593315Sopenharmony_ci    return;
11722c593315Sopenharmony_ci  }
11732c593315Sopenharmony_ci  nghttp2_data_provider data_prd;
11742c593315Sopenharmony_ci  data_prd.source.fd = stream->file_ent->fd;
11752c593315Sopenharmony_ci  data_prd.read_callback = file_read_callback;
11762c593315Sopenharmony_ci
11772c593315Sopenharmony_ci  HeaderRefs headers;
11782c593315Sopenharmony_ci  headers.emplace_back(StringRef::from_lit("nghttpd-response"),
11792c593315Sopenharmony_ci                       StringRef::from_lit("echo"));
11802c593315Sopenharmony_ci  if (!hd->get_config()->no_content_length) {
11812c593315Sopenharmony_ci    headers.emplace_back(StringRef::from_lit("content-length"),
11822c593315Sopenharmony_ci                         util::make_string_ref_uint(stream->balloc, length));
11832c593315Sopenharmony_ci  }
11842c593315Sopenharmony_ci
11852c593315Sopenharmony_ci  hd->submit_response(StringRef::from_lit("200"), stream->stream_id, headers,
11862c593315Sopenharmony_ci                      &data_prd);
11872c593315Sopenharmony_ci}
11882c593315Sopenharmony_ci} // namespace
11892c593315Sopenharmony_ci
11902c593315Sopenharmony_cinamespace {
11912c593315Sopenharmony_cibool prepare_upload_temp_store(Stream *stream, Http2Handler *hd) {
11922c593315Sopenharmony_ci  auto sessions = hd->get_sessions();
11932c593315Sopenharmony_ci
11942c593315Sopenharmony_ci  char tempfn[] = "/tmp/nghttpd.temp.XXXXXX";
11952c593315Sopenharmony_ci  auto fd = mkstemp(tempfn);
11962c593315Sopenharmony_ci  if (fd == -1) {
11972c593315Sopenharmony_ci    return false;
11982c593315Sopenharmony_ci  }
11992c593315Sopenharmony_ci  unlink(tempfn);
12002c593315Sopenharmony_ci  // Ordinary request never start with "echo:".  The length is 0 for
12012c593315Sopenharmony_ci  // now.  We will update it when we get whole request body.
12022c593315Sopenharmony_ci  auto path = std::string("echo:") + tempfn;
12032c593315Sopenharmony_ci  stream->file_ent =
12042c593315Sopenharmony_ci      sessions->cache_fd(path, FileEntry(path, 0, 0, fd, nullptr, {}, true));
12052c593315Sopenharmony_ci  stream->echo_upload = true;
12062c593315Sopenharmony_ci  return true;
12072c593315Sopenharmony_ci}
12082c593315Sopenharmony_ci} // namespace
12092c593315Sopenharmony_ci
12102c593315Sopenharmony_cinamespace {
12112c593315Sopenharmony_civoid prepare_redirect_response(Stream *stream, Http2Handler *hd,
12122c593315Sopenharmony_ci                               const StringRef &path, int status) {
12132c593315Sopenharmony_ci  auto scheme = stream->header.scheme;
12142c593315Sopenharmony_ci
12152c593315Sopenharmony_ci  auto authority = stream->header.authority;
12162c593315Sopenharmony_ci  if (authority.empty()) {
12172c593315Sopenharmony_ci    authority = stream->header.host;
12182c593315Sopenharmony_ci  }
12192c593315Sopenharmony_ci
12202c593315Sopenharmony_ci  auto location = concat_string_ref(
12212c593315Sopenharmony_ci      stream->balloc, scheme, StringRef::from_lit("://"), authority, path);
12222c593315Sopenharmony_ci
12232c593315Sopenharmony_ci  auto headers = HeaderRefs{{StringRef::from_lit("location"), location}};
12242c593315Sopenharmony_ci
12252c593315Sopenharmony_ci  auto sessions = hd->get_sessions();
12262c593315Sopenharmony_ci  auto status_page = sessions->get_server()->get_status_page(status);
12272c593315Sopenharmony_ci
12282c593315Sopenharmony_ci  hd->submit_response(StringRef{status_page->status}, stream->stream_id,
12292c593315Sopenharmony_ci                      headers, nullptr);
12302c593315Sopenharmony_ci}
12312c593315Sopenharmony_ci} // namespace
12322c593315Sopenharmony_ci
12332c593315Sopenharmony_cinamespace {
12342c593315Sopenharmony_civoid prepare_response(Stream *stream, Http2Handler *hd,
12352c593315Sopenharmony_ci                      bool allow_push = true) {
12362c593315Sopenharmony_ci  int rv;
12372c593315Sopenharmony_ci  auto reqpath = stream->header.path;
12382c593315Sopenharmony_ci  if (reqpath.empty()) {
12392c593315Sopenharmony_ci    prepare_status_response(stream, hd, 405);
12402c593315Sopenharmony_ci    return;
12412c593315Sopenharmony_ci  }
12422c593315Sopenharmony_ci
12432c593315Sopenharmony_ci  auto ims = stream->header.ims;
12442c593315Sopenharmony_ci
12452c593315Sopenharmony_ci  time_t last_mod = 0;
12462c593315Sopenharmony_ci  bool last_mod_found = false;
12472c593315Sopenharmony_ci  if (!ims.empty()) {
12482c593315Sopenharmony_ci    last_mod_found = true;
12492c593315Sopenharmony_ci    last_mod = util::parse_http_date(ims);
12502c593315Sopenharmony_ci  }
12512c593315Sopenharmony_ci
12522c593315Sopenharmony_ci  StringRef raw_path, raw_query;
12532c593315Sopenharmony_ci  auto query_pos = std::find(std::begin(reqpath), std::end(reqpath), '?');
12542c593315Sopenharmony_ci  if (query_pos != std::end(reqpath)) {
12552c593315Sopenharmony_ci    // Do not response to this request to allow clients to test timeouts.
12562c593315Sopenharmony_ci    if (util::streq_l("nghttpd_do_not_respond_to_req=yes",
12572c593315Sopenharmony_ci                      StringRef{query_pos, std::end(reqpath)})) {
12582c593315Sopenharmony_ci      return;
12592c593315Sopenharmony_ci    }
12602c593315Sopenharmony_ci    raw_path = StringRef{std::begin(reqpath), query_pos};
12612c593315Sopenharmony_ci    raw_query = StringRef{query_pos, std::end(reqpath)};
12622c593315Sopenharmony_ci  } else {
12632c593315Sopenharmony_ci    raw_path = reqpath;
12642c593315Sopenharmony_ci  }
12652c593315Sopenharmony_ci
12662c593315Sopenharmony_ci  auto sessions = hd->get_sessions();
12672c593315Sopenharmony_ci
12682c593315Sopenharmony_ci  StringRef path;
12692c593315Sopenharmony_ci  if (std::find(std::begin(raw_path), std::end(raw_path), '%') ==
12702c593315Sopenharmony_ci      std::end(raw_path)) {
12712c593315Sopenharmony_ci    path = raw_path;
12722c593315Sopenharmony_ci  } else {
12732c593315Sopenharmony_ci    path = util::percent_decode(stream->balloc, raw_path);
12742c593315Sopenharmony_ci  }
12752c593315Sopenharmony_ci
12762c593315Sopenharmony_ci  path = http2::path_join(stream->balloc, StringRef{}, StringRef{}, path,
12772c593315Sopenharmony_ci                          StringRef{});
12782c593315Sopenharmony_ci
12792c593315Sopenharmony_ci  if (std::find(std::begin(path), std::end(path), '\\') != std::end(path)) {
12802c593315Sopenharmony_ci    if (stream->file_ent) {
12812c593315Sopenharmony_ci      sessions->release_fd(stream->file_ent);
12822c593315Sopenharmony_ci      stream->file_ent = nullptr;
12832c593315Sopenharmony_ci    }
12842c593315Sopenharmony_ci    prepare_status_response(stream, hd, 404);
12852c593315Sopenharmony_ci    return;
12862c593315Sopenharmony_ci  }
12872c593315Sopenharmony_ci
12882c593315Sopenharmony_ci  if (!hd->get_config()->push.empty()) {
12892c593315Sopenharmony_ci    auto push_itr = hd->get_config()->push.find(path.str());
12902c593315Sopenharmony_ci    if (allow_push && push_itr != std::end(hd->get_config()->push)) {
12912c593315Sopenharmony_ci      for (auto &push_path : (*push_itr).second) {
12922c593315Sopenharmony_ci        rv = hd->submit_push_promise(stream, StringRef{push_path});
12932c593315Sopenharmony_ci        if (rv != 0) {
12942c593315Sopenharmony_ci          std::cerr << "nghttp2_submit_push_promise() returned error: "
12952c593315Sopenharmony_ci                    << nghttp2_strerror(rv) << std::endl;
12962c593315Sopenharmony_ci        }
12972c593315Sopenharmony_ci      }
12982c593315Sopenharmony_ci    }
12992c593315Sopenharmony_ci  }
13002c593315Sopenharmony_ci
13012c593315Sopenharmony_ci  std::string file_path;
13022c593315Sopenharmony_ci  {
13032c593315Sopenharmony_ci    auto len = hd->get_config()->htdocs.size() + path.size();
13042c593315Sopenharmony_ci
13052c593315Sopenharmony_ci    auto trailing_slash = path[path.size() - 1] == '/';
13062c593315Sopenharmony_ci    if (trailing_slash) {
13072c593315Sopenharmony_ci      len += DEFAULT_HTML.size();
13082c593315Sopenharmony_ci    }
13092c593315Sopenharmony_ci
13102c593315Sopenharmony_ci    file_path.resize(len);
13112c593315Sopenharmony_ci
13122c593315Sopenharmony_ci    auto p = &file_path[0];
13132c593315Sopenharmony_ci
13142c593315Sopenharmony_ci    auto &htdocs = hd->get_config()->htdocs;
13152c593315Sopenharmony_ci    p = std::copy(std::begin(htdocs), std::end(htdocs), p);
13162c593315Sopenharmony_ci    p = std::copy(std::begin(path), std::end(path), p);
13172c593315Sopenharmony_ci    if (trailing_slash) {
13182c593315Sopenharmony_ci      std::copy(std::begin(DEFAULT_HTML), std::end(DEFAULT_HTML), p);
13192c593315Sopenharmony_ci    }
13202c593315Sopenharmony_ci  }
13212c593315Sopenharmony_ci
13222c593315Sopenharmony_ci  if (stream->echo_upload) {
13232c593315Sopenharmony_ci    assert(stream->file_ent);
13242c593315Sopenharmony_ci    prepare_echo_response(stream, hd);
13252c593315Sopenharmony_ci    return;
13262c593315Sopenharmony_ci  }
13272c593315Sopenharmony_ci
13282c593315Sopenharmony_ci  auto file_ent = sessions->get_cached_fd(file_path);
13292c593315Sopenharmony_ci
13302c593315Sopenharmony_ci  if (file_ent == nullptr) {
13312c593315Sopenharmony_ci    int file = open(file_path.c_str(), O_RDONLY | O_BINARY);
13322c593315Sopenharmony_ci    if (file == -1) {
13332c593315Sopenharmony_ci      prepare_status_response(stream, hd, 404);
13342c593315Sopenharmony_ci
13352c593315Sopenharmony_ci      return;
13362c593315Sopenharmony_ci    }
13372c593315Sopenharmony_ci
13382c593315Sopenharmony_ci    struct stat buf;
13392c593315Sopenharmony_ci
13402c593315Sopenharmony_ci    if (fstat(file, &buf) == -1) {
13412c593315Sopenharmony_ci      close(file);
13422c593315Sopenharmony_ci      prepare_status_response(stream, hd, 404);
13432c593315Sopenharmony_ci
13442c593315Sopenharmony_ci      return;
13452c593315Sopenharmony_ci    }
13462c593315Sopenharmony_ci
13472c593315Sopenharmony_ci    if (buf.st_mode & S_IFDIR) {
13482c593315Sopenharmony_ci      close(file);
13492c593315Sopenharmony_ci
13502c593315Sopenharmony_ci      auto reqpath = concat_string_ref(stream->balloc, raw_path,
13512c593315Sopenharmony_ci                                       StringRef::from_lit("/"), raw_query);
13522c593315Sopenharmony_ci
13532c593315Sopenharmony_ci      prepare_redirect_response(stream, hd, reqpath, 301);
13542c593315Sopenharmony_ci
13552c593315Sopenharmony_ci      return;
13562c593315Sopenharmony_ci    }
13572c593315Sopenharmony_ci
13582c593315Sopenharmony_ci    const std::string *content_type = nullptr;
13592c593315Sopenharmony_ci
13602c593315Sopenharmony_ci    auto ext = file_path.c_str() + file_path.size() - 1;
13612c593315Sopenharmony_ci    for (; file_path.c_str() < ext && *ext != '.' && *ext != '/'; --ext)
13622c593315Sopenharmony_ci      ;
13632c593315Sopenharmony_ci    if (*ext == '.') {
13642c593315Sopenharmony_ci      ++ext;
13652c593315Sopenharmony_ci
13662c593315Sopenharmony_ci      const auto &mime_types = hd->get_config()->mime_types;
13672c593315Sopenharmony_ci      auto content_type_itr = mime_types.find(ext);
13682c593315Sopenharmony_ci      if (content_type_itr != std::end(mime_types)) {
13692c593315Sopenharmony_ci        content_type = &(*content_type_itr).second;
13702c593315Sopenharmony_ci      }
13712c593315Sopenharmony_ci    }
13722c593315Sopenharmony_ci
13732c593315Sopenharmony_ci    file_ent = sessions->cache_fd(
13742c593315Sopenharmony_ci        file_path, FileEntry(file_path, buf.st_size, buf.st_mtime, file,
13752c593315Sopenharmony_ci                             content_type, std::chrono::steady_clock::now()));
13762c593315Sopenharmony_ci  }
13772c593315Sopenharmony_ci
13782c593315Sopenharmony_ci  stream->file_ent = file_ent;
13792c593315Sopenharmony_ci
13802c593315Sopenharmony_ci  if (last_mod_found && file_ent->mtime <= last_mod) {
13812c593315Sopenharmony_ci    hd->submit_response(StringRef::from_lit("304"), stream->stream_id, nullptr);
13822c593315Sopenharmony_ci
13832c593315Sopenharmony_ci    return;
13842c593315Sopenharmony_ci  }
13852c593315Sopenharmony_ci
13862c593315Sopenharmony_ci  auto method = stream->header.method;
13872c593315Sopenharmony_ci  if (method == StringRef::from_lit("HEAD")) {
13882c593315Sopenharmony_ci    hd->submit_file_response(StringRef::from_lit("200"), stream,
13892c593315Sopenharmony_ci                             file_ent->mtime, file_ent->length,
13902c593315Sopenharmony_ci                             file_ent->content_type, nullptr);
13912c593315Sopenharmony_ci    return;
13922c593315Sopenharmony_ci  }
13932c593315Sopenharmony_ci
13942c593315Sopenharmony_ci  stream->body_length = file_ent->length;
13952c593315Sopenharmony_ci
13962c593315Sopenharmony_ci  nghttp2_data_provider data_prd;
13972c593315Sopenharmony_ci
13982c593315Sopenharmony_ci  data_prd.source.fd = file_ent->fd;
13992c593315Sopenharmony_ci  data_prd.read_callback = file_read_callback;
14002c593315Sopenharmony_ci
14012c593315Sopenharmony_ci  hd->submit_file_response(StringRef::from_lit("200"), stream, file_ent->mtime,
14022c593315Sopenharmony_ci                           file_ent->length, file_ent->content_type, &data_prd);
14032c593315Sopenharmony_ci}
14042c593315Sopenharmony_ci} // namespace
14052c593315Sopenharmony_ci
14062c593315Sopenharmony_cinamespace {
14072c593315Sopenharmony_ciint on_header_callback2(nghttp2_session *session, const nghttp2_frame *frame,
14082c593315Sopenharmony_ci                        nghttp2_rcbuf *name, nghttp2_rcbuf *value,
14092c593315Sopenharmony_ci                        uint8_t flags, void *user_data) {
14102c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(user_data);
14112c593315Sopenharmony_ci
14122c593315Sopenharmony_ci  auto namebuf = nghttp2_rcbuf_get_buf(name);
14132c593315Sopenharmony_ci  auto valuebuf = nghttp2_rcbuf_get_buf(value);
14142c593315Sopenharmony_ci
14152c593315Sopenharmony_ci  if (hd->get_config()->verbose) {
14162c593315Sopenharmony_ci    print_session_id(hd->session_id());
14172c593315Sopenharmony_ci    verbose_on_header_callback(session, frame, namebuf.base, namebuf.len,
14182c593315Sopenharmony_ci                               valuebuf.base, valuebuf.len, flags, user_data);
14192c593315Sopenharmony_ci  }
14202c593315Sopenharmony_ci  if (frame->hd.type != NGHTTP2_HEADERS ||
14212c593315Sopenharmony_ci      frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
14222c593315Sopenharmony_ci    return 0;
14232c593315Sopenharmony_ci  }
14242c593315Sopenharmony_ci  auto stream = hd->get_stream(frame->hd.stream_id);
14252c593315Sopenharmony_ci  if (!stream) {
14262c593315Sopenharmony_ci    return 0;
14272c593315Sopenharmony_ci  }
14282c593315Sopenharmony_ci
14292c593315Sopenharmony_ci  if (stream->header_buffer_size + namebuf.len + valuebuf.len > 64_k) {
14302c593315Sopenharmony_ci    hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
14312c593315Sopenharmony_ci    return 0;
14322c593315Sopenharmony_ci  }
14332c593315Sopenharmony_ci
14342c593315Sopenharmony_ci  stream->header_buffer_size += namebuf.len + valuebuf.len;
14352c593315Sopenharmony_ci
14362c593315Sopenharmony_ci  auto token = http2::lookup_token(namebuf.base, namebuf.len);
14372c593315Sopenharmony_ci
14382c593315Sopenharmony_ci  auto &header = stream->header;
14392c593315Sopenharmony_ci
14402c593315Sopenharmony_ci  switch (token) {
14412c593315Sopenharmony_ci  case http2::HD__METHOD:
14422c593315Sopenharmony_ci    header.method = StringRef{valuebuf.base, valuebuf.len};
14432c593315Sopenharmony_ci    header.rcbuf.method = value;
14442c593315Sopenharmony_ci    nghttp2_rcbuf_incref(value);
14452c593315Sopenharmony_ci    break;
14462c593315Sopenharmony_ci  case http2::HD__SCHEME:
14472c593315Sopenharmony_ci    header.scheme = StringRef{valuebuf.base, valuebuf.len};
14482c593315Sopenharmony_ci    header.rcbuf.scheme = value;
14492c593315Sopenharmony_ci    nghttp2_rcbuf_incref(value);
14502c593315Sopenharmony_ci    break;
14512c593315Sopenharmony_ci  case http2::HD__AUTHORITY:
14522c593315Sopenharmony_ci    header.authority = StringRef{valuebuf.base, valuebuf.len};
14532c593315Sopenharmony_ci    header.rcbuf.authority = value;
14542c593315Sopenharmony_ci    nghttp2_rcbuf_incref(value);
14552c593315Sopenharmony_ci    break;
14562c593315Sopenharmony_ci  case http2::HD_HOST:
14572c593315Sopenharmony_ci    header.host = StringRef{valuebuf.base, valuebuf.len};
14582c593315Sopenharmony_ci    header.rcbuf.host = value;
14592c593315Sopenharmony_ci    nghttp2_rcbuf_incref(value);
14602c593315Sopenharmony_ci    break;
14612c593315Sopenharmony_ci  case http2::HD__PATH:
14622c593315Sopenharmony_ci    header.path = StringRef{valuebuf.base, valuebuf.len};
14632c593315Sopenharmony_ci    header.rcbuf.path = value;
14642c593315Sopenharmony_ci    nghttp2_rcbuf_incref(value);
14652c593315Sopenharmony_ci    break;
14662c593315Sopenharmony_ci  case http2::HD_IF_MODIFIED_SINCE:
14672c593315Sopenharmony_ci    header.ims = StringRef{valuebuf.base, valuebuf.len};
14682c593315Sopenharmony_ci    header.rcbuf.ims = value;
14692c593315Sopenharmony_ci    nghttp2_rcbuf_incref(value);
14702c593315Sopenharmony_ci    break;
14712c593315Sopenharmony_ci  case http2::HD_EXPECT:
14722c593315Sopenharmony_ci    header.expect = StringRef{valuebuf.base, valuebuf.len};
14732c593315Sopenharmony_ci    header.rcbuf.expect = value;
14742c593315Sopenharmony_ci    nghttp2_rcbuf_incref(value);
14752c593315Sopenharmony_ci    break;
14762c593315Sopenharmony_ci  }
14772c593315Sopenharmony_ci
14782c593315Sopenharmony_ci  return 0;
14792c593315Sopenharmony_ci}
14802c593315Sopenharmony_ci} // namespace
14812c593315Sopenharmony_ci
14822c593315Sopenharmony_cinamespace {
14832c593315Sopenharmony_ciint on_begin_headers_callback(nghttp2_session *session,
14842c593315Sopenharmony_ci                              const nghttp2_frame *frame, void *user_data) {
14852c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(user_data);
14862c593315Sopenharmony_ci
14872c593315Sopenharmony_ci  if (frame->hd.type != NGHTTP2_HEADERS ||
14882c593315Sopenharmony_ci      frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
14892c593315Sopenharmony_ci    return 0;
14902c593315Sopenharmony_ci  }
14912c593315Sopenharmony_ci
14922c593315Sopenharmony_ci  auto stream = std::make_unique<Stream>(hd, frame->hd.stream_id);
14932c593315Sopenharmony_ci
14942c593315Sopenharmony_ci  add_stream_read_timeout(stream.get());
14952c593315Sopenharmony_ci
14962c593315Sopenharmony_ci  hd->add_stream(frame->hd.stream_id, std::move(stream));
14972c593315Sopenharmony_ci
14982c593315Sopenharmony_ci  return 0;
14992c593315Sopenharmony_ci}
15002c593315Sopenharmony_ci} // namespace
15012c593315Sopenharmony_ci
15022c593315Sopenharmony_cinamespace {
15032c593315Sopenharmony_ciint hd_on_frame_recv_callback(nghttp2_session *session,
15042c593315Sopenharmony_ci                              const nghttp2_frame *frame, void *user_data) {
15052c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(user_data);
15062c593315Sopenharmony_ci  if (hd->get_config()->verbose) {
15072c593315Sopenharmony_ci    print_session_id(hd->session_id());
15082c593315Sopenharmony_ci    verbose_on_frame_recv_callback(session, frame, user_data);
15092c593315Sopenharmony_ci  }
15102c593315Sopenharmony_ci  switch (frame->hd.type) {
15112c593315Sopenharmony_ci  case NGHTTP2_DATA: {
15122c593315Sopenharmony_ci    // TODO Handle POST
15132c593315Sopenharmony_ci    auto stream = hd->get_stream(frame->hd.stream_id);
15142c593315Sopenharmony_ci    if (!stream) {
15152c593315Sopenharmony_ci      return 0;
15162c593315Sopenharmony_ci    }
15172c593315Sopenharmony_ci
15182c593315Sopenharmony_ci    if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
15192c593315Sopenharmony_ci      remove_stream_read_timeout(stream);
15202c593315Sopenharmony_ci      if (stream->echo_upload || !hd->get_config()->early_response) {
15212c593315Sopenharmony_ci        prepare_response(stream, hd);
15222c593315Sopenharmony_ci      }
15232c593315Sopenharmony_ci    } else {
15242c593315Sopenharmony_ci      add_stream_read_timeout(stream);
15252c593315Sopenharmony_ci    }
15262c593315Sopenharmony_ci
15272c593315Sopenharmony_ci    break;
15282c593315Sopenharmony_ci  }
15292c593315Sopenharmony_ci  case NGHTTP2_HEADERS: {
15302c593315Sopenharmony_ci    auto stream = hd->get_stream(frame->hd.stream_id);
15312c593315Sopenharmony_ci    if (!stream) {
15322c593315Sopenharmony_ci      return 0;
15332c593315Sopenharmony_ci    }
15342c593315Sopenharmony_ci
15352c593315Sopenharmony_ci    if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
15362c593315Sopenharmony_ci
15372c593315Sopenharmony_ci      auto expect100 = stream->header.expect;
15382c593315Sopenharmony_ci
15392c593315Sopenharmony_ci      if (util::strieq_l("100-continue", expect100)) {
15402c593315Sopenharmony_ci        hd->submit_non_final_response("100", frame->hd.stream_id);
15412c593315Sopenharmony_ci      }
15422c593315Sopenharmony_ci
15432c593315Sopenharmony_ci      auto method = stream->header.method;
15442c593315Sopenharmony_ci      if (hd->get_config()->echo_upload &&
15452c593315Sopenharmony_ci          (method == StringRef::from_lit("POST") ||
15462c593315Sopenharmony_ci           method == StringRef::from_lit("PUT"))) {
15472c593315Sopenharmony_ci        if (!prepare_upload_temp_store(stream, hd)) {
15482c593315Sopenharmony_ci          hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
15492c593315Sopenharmony_ci          return 0;
15502c593315Sopenharmony_ci        }
15512c593315Sopenharmony_ci      } else if (hd->get_config()->early_response) {
15522c593315Sopenharmony_ci        prepare_response(stream, hd);
15532c593315Sopenharmony_ci      }
15542c593315Sopenharmony_ci    }
15552c593315Sopenharmony_ci
15562c593315Sopenharmony_ci    if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
15572c593315Sopenharmony_ci      remove_stream_read_timeout(stream);
15582c593315Sopenharmony_ci      if (stream->echo_upload || !hd->get_config()->early_response) {
15592c593315Sopenharmony_ci        prepare_response(stream, hd);
15602c593315Sopenharmony_ci      }
15612c593315Sopenharmony_ci    } else {
15622c593315Sopenharmony_ci      add_stream_read_timeout(stream);
15632c593315Sopenharmony_ci    }
15642c593315Sopenharmony_ci
15652c593315Sopenharmony_ci    break;
15662c593315Sopenharmony_ci  }
15672c593315Sopenharmony_ci  case NGHTTP2_SETTINGS:
15682c593315Sopenharmony_ci    if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
15692c593315Sopenharmony_ci      hd->remove_settings_timer();
15702c593315Sopenharmony_ci    }
15712c593315Sopenharmony_ci    break;
15722c593315Sopenharmony_ci  default:
15732c593315Sopenharmony_ci    break;
15742c593315Sopenharmony_ci  }
15752c593315Sopenharmony_ci  return 0;
15762c593315Sopenharmony_ci}
15772c593315Sopenharmony_ci} // namespace
15782c593315Sopenharmony_ci
15792c593315Sopenharmony_cinamespace {
15802c593315Sopenharmony_ciint hd_on_frame_send_callback(nghttp2_session *session,
15812c593315Sopenharmony_ci                              const nghttp2_frame *frame, void *user_data) {
15822c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(user_data);
15832c593315Sopenharmony_ci
15842c593315Sopenharmony_ci  if (hd->get_config()->verbose) {
15852c593315Sopenharmony_ci    print_session_id(hd->session_id());
15862c593315Sopenharmony_ci    verbose_on_frame_send_callback(session, frame, user_data);
15872c593315Sopenharmony_ci  }
15882c593315Sopenharmony_ci
15892c593315Sopenharmony_ci  switch (frame->hd.type) {
15902c593315Sopenharmony_ci  case NGHTTP2_DATA:
15912c593315Sopenharmony_ci  case NGHTTP2_HEADERS: {
15922c593315Sopenharmony_ci    auto stream = hd->get_stream(frame->hd.stream_id);
15932c593315Sopenharmony_ci
15942c593315Sopenharmony_ci    if (!stream) {
15952c593315Sopenharmony_ci      return 0;
15962c593315Sopenharmony_ci    }
15972c593315Sopenharmony_ci
15982c593315Sopenharmony_ci    if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
15992c593315Sopenharmony_ci      remove_stream_write_timeout(stream);
16002c593315Sopenharmony_ci    } else if (std::min(nghttp2_session_get_stream_remote_window_size(
16012c593315Sopenharmony_ci                            session, frame->hd.stream_id),
16022c593315Sopenharmony_ci                        nghttp2_session_get_remote_window_size(session)) <= 0) {
16032c593315Sopenharmony_ci      // If stream is blocked by flow control, enable write timeout.
16042c593315Sopenharmony_ci      add_stream_read_timeout_if_pending(stream);
16052c593315Sopenharmony_ci      add_stream_write_timeout(stream);
16062c593315Sopenharmony_ci    } else {
16072c593315Sopenharmony_ci      add_stream_read_timeout_if_pending(stream);
16082c593315Sopenharmony_ci      remove_stream_write_timeout(stream);
16092c593315Sopenharmony_ci    }
16102c593315Sopenharmony_ci
16112c593315Sopenharmony_ci    break;
16122c593315Sopenharmony_ci  }
16132c593315Sopenharmony_ci  case NGHTTP2_SETTINGS: {
16142c593315Sopenharmony_ci    if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
16152c593315Sopenharmony_ci      return 0;
16162c593315Sopenharmony_ci    }
16172c593315Sopenharmony_ci
16182c593315Sopenharmony_ci    hd->start_settings_timer();
16192c593315Sopenharmony_ci
16202c593315Sopenharmony_ci    break;
16212c593315Sopenharmony_ci  }
16222c593315Sopenharmony_ci  case NGHTTP2_PUSH_PROMISE: {
16232c593315Sopenharmony_ci    auto promised_stream_id = frame->push_promise.promised_stream_id;
16242c593315Sopenharmony_ci    auto promised_stream = hd->get_stream(promised_stream_id);
16252c593315Sopenharmony_ci    auto stream = hd->get_stream(frame->hd.stream_id);
16262c593315Sopenharmony_ci
16272c593315Sopenharmony_ci    if (!stream || !promised_stream) {
16282c593315Sopenharmony_ci      return 0;
16292c593315Sopenharmony_ci    }
16302c593315Sopenharmony_ci
16312c593315Sopenharmony_ci    add_stream_read_timeout_if_pending(stream);
16322c593315Sopenharmony_ci    add_stream_write_timeout(stream);
16332c593315Sopenharmony_ci
16342c593315Sopenharmony_ci    prepare_response(promised_stream, hd, /*allow_push */ false);
16352c593315Sopenharmony_ci  }
16362c593315Sopenharmony_ci  }
16372c593315Sopenharmony_ci  return 0;
16382c593315Sopenharmony_ci}
16392c593315Sopenharmony_ci} // namespace
16402c593315Sopenharmony_ci
16412c593315Sopenharmony_cinamespace {
16422c593315Sopenharmony_ciint send_data_callback(nghttp2_session *session, nghttp2_frame *frame,
16432c593315Sopenharmony_ci                       const uint8_t *framehd, size_t length,
16442c593315Sopenharmony_ci                       nghttp2_data_source *source, void *user_data) {
16452c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(user_data);
16462c593315Sopenharmony_ci  auto wb = hd->get_wb();
16472c593315Sopenharmony_ci  auto padlen = frame->data.padlen;
16482c593315Sopenharmony_ci  auto stream = hd->get_stream(frame->hd.stream_id);
16492c593315Sopenharmony_ci
16502c593315Sopenharmony_ci  if (wb->wleft() < 9 + length + padlen) {
16512c593315Sopenharmony_ci    return NGHTTP2_ERR_WOULDBLOCK;
16522c593315Sopenharmony_ci  }
16532c593315Sopenharmony_ci
16542c593315Sopenharmony_ci  int fd = source->fd;
16552c593315Sopenharmony_ci
16562c593315Sopenharmony_ci  auto p = wb->last;
16572c593315Sopenharmony_ci
16582c593315Sopenharmony_ci  p = std::copy_n(framehd, 9, p);
16592c593315Sopenharmony_ci
16602c593315Sopenharmony_ci  if (padlen) {
16612c593315Sopenharmony_ci    *p++ = padlen - 1;
16622c593315Sopenharmony_ci  }
16632c593315Sopenharmony_ci
16642c593315Sopenharmony_ci  while (length) {
16652c593315Sopenharmony_ci    ssize_t nread;
16662c593315Sopenharmony_ci    while ((nread = pread(fd, p, length, stream->body_offset)) == -1 &&
16672c593315Sopenharmony_ci           errno == EINTR)
16682c593315Sopenharmony_ci      ;
16692c593315Sopenharmony_ci
16702c593315Sopenharmony_ci    if (nread == -1) {
16712c593315Sopenharmony_ci      remove_stream_read_timeout(stream);
16722c593315Sopenharmony_ci      remove_stream_write_timeout(stream);
16732c593315Sopenharmony_ci
16742c593315Sopenharmony_ci      return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
16752c593315Sopenharmony_ci    }
16762c593315Sopenharmony_ci
16772c593315Sopenharmony_ci    stream->body_offset += nread;
16782c593315Sopenharmony_ci    length -= nread;
16792c593315Sopenharmony_ci    p += nread;
16802c593315Sopenharmony_ci  }
16812c593315Sopenharmony_ci
16822c593315Sopenharmony_ci  if (padlen) {
16832c593315Sopenharmony_ci    std::fill(p, p + padlen - 1, 0);
16842c593315Sopenharmony_ci    p += padlen - 1;
16852c593315Sopenharmony_ci  }
16862c593315Sopenharmony_ci
16872c593315Sopenharmony_ci  wb->last = p;
16882c593315Sopenharmony_ci
16892c593315Sopenharmony_ci  return 0;
16902c593315Sopenharmony_ci}
16912c593315Sopenharmony_ci} // namespace
16922c593315Sopenharmony_ci
16932c593315Sopenharmony_cinamespace {
16942c593315Sopenharmony_cissize_t select_padding_callback(nghttp2_session *session,
16952c593315Sopenharmony_ci                                const nghttp2_frame *frame, size_t max_payload,
16962c593315Sopenharmony_ci                                void *user_data) {
16972c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(user_data);
16982c593315Sopenharmony_ci  return std::min(max_payload, frame->hd.length + hd->get_config()->padding);
16992c593315Sopenharmony_ci}
17002c593315Sopenharmony_ci} // namespace
17012c593315Sopenharmony_ci
17022c593315Sopenharmony_cinamespace {
17032c593315Sopenharmony_ciint on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
17042c593315Sopenharmony_ci                                int32_t stream_id, const uint8_t *data,
17052c593315Sopenharmony_ci                                size_t len, void *user_data) {
17062c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(user_data);
17072c593315Sopenharmony_ci  auto stream = hd->get_stream(stream_id);
17082c593315Sopenharmony_ci
17092c593315Sopenharmony_ci  if (!stream) {
17102c593315Sopenharmony_ci    return 0;
17112c593315Sopenharmony_ci  }
17122c593315Sopenharmony_ci
17132c593315Sopenharmony_ci  if (stream->echo_upload) {
17142c593315Sopenharmony_ci    assert(stream->file_ent);
17152c593315Sopenharmony_ci    while (len) {
17162c593315Sopenharmony_ci      ssize_t n;
17172c593315Sopenharmony_ci      while ((n = write(stream->file_ent->fd, data, len)) == -1 &&
17182c593315Sopenharmony_ci             errno == EINTR)
17192c593315Sopenharmony_ci        ;
17202c593315Sopenharmony_ci      if (n == -1) {
17212c593315Sopenharmony_ci        hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
17222c593315Sopenharmony_ci        return 0;
17232c593315Sopenharmony_ci      }
17242c593315Sopenharmony_ci      len -= n;
17252c593315Sopenharmony_ci      data += n;
17262c593315Sopenharmony_ci    }
17272c593315Sopenharmony_ci  }
17282c593315Sopenharmony_ci  // TODO Handle POST
17292c593315Sopenharmony_ci
17302c593315Sopenharmony_ci  add_stream_read_timeout(stream);
17312c593315Sopenharmony_ci
17322c593315Sopenharmony_ci  return 0;
17332c593315Sopenharmony_ci}
17342c593315Sopenharmony_ci} // namespace
17352c593315Sopenharmony_ci
17362c593315Sopenharmony_cinamespace {
17372c593315Sopenharmony_ciint on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
17382c593315Sopenharmony_ci                             uint32_t error_code, void *user_data) {
17392c593315Sopenharmony_ci  auto hd = static_cast<Http2Handler *>(user_data);
17402c593315Sopenharmony_ci  hd->remove_stream(stream_id);
17412c593315Sopenharmony_ci  if (hd->get_config()->verbose) {
17422c593315Sopenharmony_ci    print_session_id(hd->session_id());
17432c593315Sopenharmony_ci    print_timer();
17442c593315Sopenharmony_ci    printf(" stream_id=%d closed\n", stream_id);
17452c593315Sopenharmony_ci    fflush(stdout);
17462c593315Sopenharmony_ci  }
17472c593315Sopenharmony_ci  return 0;
17482c593315Sopenharmony_ci}
17492c593315Sopenharmony_ci} // namespace
17502c593315Sopenharmony_ci
17512c593315Sopenharmony_cinamespace {
17522c593315Sopenharmony_civoid fill_callback(nghttp2_session_callbacks *callbacks, const Config *config) {
17532c593315Sopenharmony_ci  nghttp2_session_callbacks_set_on_stream_close_callback(
17542c593315Sopenharmony_ci      callbacks, on_stream_close_callback);
17552c593315Sopenharmony_ci
17562c593315Sopenharmony_ci  nghttp2_session_callbacks_set_on_frame_recv_callback(
17572c593315Sopenharmony_ci      callbacks, hd_on_frame_recv_callback);
17582c593315Sopenharmony_ci
17592c593315Sopenharmony_ci  nghttp2_session_callbacks_set_on_frame_send_callback(
17602c593315Sopenharmony_ci      callbacks, hd_on_frame_send_callback);
17612c593315Sopenharmony_ci
17622c593315Sopenharmony_ci  if (config->verbose) {
17632c593315Sopenharmony_ci    nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
17642c593315Sopenharmony_ci        callbacks, verbose_on_invalid_frame_recv_callback);
17652c593315Sopenharmony_ci
17662c593315Sopenharmony_ci    nghttp2_session_callbacks_set_error_callback2(callbacks,
17672c593315Sopenharmony_ci                                                  verbose_error_callback);
17682c593315Sopenharmony_ci  }
17692c593315Sopenharmony_ci
17702c593315Sopenharmony_ci  nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
17712c593315Sopenharmony_ci      callbacks, on_data_chunk_recv_callback);
17722c593315Sopenharmony_ci
17732c593315Sopenharmony_ci  nghttp2_session_callbacks_set_on_header_callback2(callbacks,
17742c593315Sopenharmony_ci                                                    on_header_callback2);
17752c593315Sopenharmony_ci
17762c593315Sopenharmony_ci  nghttp2_session_callbacks_set_on_begin_headers_callback(
17772c593315Sopenharmony_ci      callbacks, on_begin_headers_callback);
17782c593315Sopenharmony_ci
17792c593315Sopenharmony_ci  nghttp2_session_callbacks_set_send_data_callback(callbacks,
17802c593315Sopenharmony_ci                                                   send_data_callback);
17812c593315Sopenharmony_ci
17822c593315Sopenharmony_ci  if (config->padding) {
17832c593315Sopenharmony_ci    nghttp2_session_callbacks_set_select_padding_callback(
17842c593315Sopenharmony_ci        callbacks, select_padding_callback);
17852c593315Sopenharmony_ci  }
17862c593315Sopenharmony_ci}
17872c593315Sopenharmony_ci} // namespace
17882c593315Sopenharmony_ci
17892c593315Sopenharmony_cistruct ClientInfo {
17902c593315Sopenharmony_ci  int fd;
17912c593315Sopenharmony_ci};
17922c593315Sopenharmony_ci
17932c593315Sopenharmony_cistruct Worker {
17942c593315Sopenharmony_ci  std::unique_ptr<Sessions> sessions;
17952c593315Sopenharmony_ci  ev_async w;
17962c593315Sopenharmony_ci  // protects q
17972c593315Sopenharmony_ci  std::mutex m;
17982c593315Sopenharmony_ci  std::deque<ClientInfo> q;
17992c593315Sopenharmony_ci};
18002c593315Sopenharmony_ci
18012c593315Sopenharmony_cinamespace {
18022c593315Sopenharmony_civoid worker_acceptcb(struct ev_loop *loop, ev_async *w, int revents) {
18032c593315Sopenharmony_ci  auto worker = static_cast<Worker *>(w->data);
18042c593315Sopenharmony_ci  auto &sessions = worker->sessions;
18052c593315Sopenharmony_ci
18062c593315Sopenharmony_ci  std::deque<ClientInfo> q;
18072c593315Sopenharmony_ci  {
18082c593315Sopenharmony_ci    std::lock_guard<std::mutex> lock(worker->m);
18092c593315Sopenharmony_ci    q.swap(worker->q);
18102c593315Sopenharmony_ci  }
18112c593315Sopenharmony_ci
18122c593315Sopenharmony_ci  for (const auto &c : q) {
18132c593315Sopenharmony_ci    sessions->accept_connection(c.fd);
18142c593315Sopenharmony_ci  }
18152c593315Sopenharmony_ci}
18162c593315Sopenharmony_ci} // namespace
18172c593315Sopenharmony_ci
18182c593315Sopenharmony_cinamespace {
18192c593315Sopenharmony_civoid run_worker(Worker *worker) {
18202c593315Sopenharmony_ci  auto loop = worker->sessions->get_loop();
18212c593315Sopenharmony_ci
18222c593315Sopenharmony_ci  ev_run(loop, 0);
18232c593315Sopenharmony_ci}
18242c593315Sopenharmony_ci} // namespace
18252c593315Sopenharmony_ci
18262c593315Sopenharmony_cinamespace {
18272c593315Sopenharmony_ciint get_ev_loop_flags() {
18282c593315Sopenharmony_ci  if (ev_supported_backends() & ~ev_recommended_backends() & EVBACKEND_KQUEUE) {
18292c593315Sopenharmony_ci    return ev_recommended_backends() | EVBACKEND_KQUEUE;
18302c593315Sopenharmony_ci  }
18312c593315Sopenharmony_ci
18322c593315Sopenharmony_ci  return 0;
18332c593315Sopenharmony_ci}
18342c593315Sopenharmony_ci} // namespace
18352c593315Sopenharmony_ci
18362c593315Sopenharmony_ciclass AcceptHandler {
18372c593315Sopenharmony_cipublic:
18382c593315Sopenharmony_ci  AcceptHandler(HttpServer *sv, Sessions *sessions, const Config *config)
18392c593315Sopenharmony_ci      : sessions_(sessions), config_(config), next_worker_(0) {
18402c593315Sopenharmony_ci    if (config_->num_worker == 1) {
18412c593315Sopenharmony_ci      return;
18422c593315Sopenharmony_ci    }
18432c593315Sopenharmony_ci    for (size_t i = 0; i < config_->num_worker; ++i) {
18442c593315Sopenharmony_ci      if (config_->verbose) {
18452c593315Sopenharmony_ci        std::cerr << "spawning thread #" << i << std::endl;
18462c593315Sopenharmony_ci      }
18472c593315Sopenharmony_ci      auto worker = std::make_unique<Worker>();
18482c593315Sopenharmony_ci      auto loop = ev_loop_new(get_ev_loop_flags());
18492c593315Sopenharmony_ci      worker->sessions = std::make_unique<Sessions>(sv, loop, config_,
18502c593315Sopenharmony_ci                                                    sessions_->get_ssl_ctx());
18512c593315Sopenharmony_ci      ev_async_init(&worker->w, worker_acceptcb);
18522c593315Sopenharmony_ci      worker->w.data = worker.get();
18532c593315Sopenharmony_ci      ev_async_start(loop, &worker->w);
18542c593315Sopenharmony_ci
18552c593315Sopenharmony_ci      auto t = std::thread(run_worker, worker.get());
18562c593315Sopenharmony_ci      t.detach();
18572c593315Sopenharmony_ci      workers_.push_back(std::move(worker));
18582c593315Sopenharmony_ci    }
18592c593315Sopenharmony_ci  }
18602c593315Sopenharmony_ci  void accept_connection(int fd) {
18612c593315Sopenharmony_ci    if (config_->num_worker == 1) {
18622c593315Sopenharmony_ci      sessions_->accept_connection(fd);
18632c593315Sopenharmony_ci      return;
18642c593315Sopenharmony_ci    }
18652c593315Sopenharmony_ci
18662c593315Sopenharmony_ci    // Dispatch client to the one of the worker threads, in a round
18672c593315Sopenharmony_ci    // robin manner.
18682c593315Sopenharmony_ci    auto &worker = workers_[next_worker_];
18692c593315Sopenharmony_ci    if (next_worker_ == config_->num_worker - 1) {
18702c593315Sopenharmony_ci      next_worker_ = 0;
18712c593315Sopenharmony_ci    } else {
18722c593315Sopenharmony_ci      ++next_worker_;
18732c593315Sopenharmony_ci    }
18742c593315Sopenharmony_ci    {
18752c593315Sopenharmony_ci      std::lock_guard<std::mutex> lock(worker->m);
18762c593315Sopenharmony_ci      worker->q.push_back({fd});
18772c593315Sopenharmony_ci    }
18782c593315Sopenharmony_ci    ev_async_send(worker->sessions->get_loop(), &worker->w);
18792c593315Sopenharmony_ci  }
18802c593315Sopenharmony_ci
18812c593315Sopenharmony_ciprivate:
18822c593315Sopenharmony_ci  std::vector<std::unique_ptr<Worker>> workers_;
18832c593315Sopenharmony_ci  Sessions *sessions_;
18842c593315Sopenharmony_ci  const Config *config_;
18852c593315Sopenharmony_ci  // In multi threading mode, this points to the next thread that
18862c593315Sopenharmony_ci  // client will be dispatched.
18872c593315Sopenharmony_ci  size_t next_worker_;
18882c593315Sopenharmony_ci};
18892c593315Sopenharmony_ci
18902c593315Sopenharmony_cinamespace {
18912c593315Sopenharmony_civoid acceptcb(struct ev_loop *loop, ev_io *w, int revents);
18922c593315Sopenharmony_ci} // namespace
18932c593315Sopenharmony_ci
18942c593315Sopenharmony_ciclass ListenEventHandler {
18952c593315Sopenharmony_cipublic:
18962c593315Sopenharmony_ci  ListenEventHandler(Sessions *sessions, int fd,
18972c593315Sopenharmony_ci                     std::shared_ptr<AcceptHandler> acceptor)
18982c593315Sopenharmony_ci      : acceptor_(std::move(acceptor)), sessions_(sessions), fd_(fd) {
18992c593315Sopenharmony_ci    ev_io_init(&w_, acceptcb, fd, EV_READ);
19002c593315Sopenharmony_ci    w_.data = this;
19012c593315Sopenharmony_ci    ev_io_start(sessions_->get_loop(), &w_);
19022c593315Sopenharmony_ci  }
19032c593315Sopenharmony_ci  void accept_connection() {
19042c593315Sopenharmony_ci    for (;;) {
19052c593315Sopenharmony_ci#ifdef HAVE_ACCEPT4
19062c593315Sopenharmony_ci      auto fd = accept4(fd_, nullptr, nullptr, SOCK_NONBLOCK);
19072c593315Sopenharmony_ci#else  // !HAVE_ACCEPT4
19082c593315Sopenharmony_ci      auto fd = accept(fd_, nullptr, nullptr);
19092c593315Sopenharmony_ci#endif // !HAVE_ACCEPT4
19102c593315Sopenharmony_ci      if (fd == -1) {
19112c593315Sopenharmony_ci        break;
19122c593315Sopenharmony_ci      }
19132c593315Sopenharmony_ci#ifndef HAVE_ACCEPT4
19142c593315Sopenharmony_ci      util::make_socket_nonblocking(fd);
19152c593315Sopenharmony_ci#endif // !HAVE_ACCEPT4
19162c593315Sopenharmony_ci      acceptor_->accept_connection(fd);
19172c593315Sopenharmony_ci    }
19182c593315Sopenharmony_ci  }
19192c593315Sopenharmony_ci
19202c593315Sopenharmony_ciprivate:
19212c593315Sopenharmony_ci  ev_io w_;
19222c593315Sopenharmony_ci  std::shared_ptr<AcceptHandler> acceptor_;
19232c593315Sopenharmony_ci  Sessions *sessions_;
19242c593315Sopenharmony_ci  int fd_;
19252c593315Sopenharmony_ci};
19262c593315Sopenharmony_ci
19272c593315Sopenharmony_cinamespace {
19282c593315Sopenharmony_civoid acceptcb(struct ev_loop *loop, ev_io *w, int revents) {
19292c593315Sopenharmony_ci  auto handler = static_cast<ListenEventHandler *>(w->data);
19302c593315Sopenharmony_ci  handler->accept_connection();
19312c593315Sopenharmony_ci}
19322c593315Sopenharmony_ci} // namespace
19332c593315Sopenharmony_ci
19342c593315Sopenharmony_cinamespace {
19352c593315Sopenharmony_ciFileEntry make_status_body(int status, uint16_t port) {
19362c593315Sopenharmony_ci  BlockAllocator balloc(1024, 1024);
19372c593315Sopenharmony_ci
19382c593315Sopenharmony_ci  auto status_string = http2::stringify_status(balloc, status);
19392c593315Sopenharmony_ci  auto reason_pharase = http2::get_reason_phrase(status);
19402c593315Sopenharmony_ci
19412c593315Sopenharmony_ci  std::string body;
19422c593315Sopenharmony_ci  body = "<html><head><title>";
19432c593315Sopenharmony_ci  body += status_string;
19442c593315Sopenharmony_ci  body += ' ';
19452c593315Sopenharmony_ci  body += reason_pharase;
19462c593315Sopenharmony_ci  body += "</title></head><body><h1>";
19472c593315Sopenharmony_ci  body += status_string;
19482c593315Sopenharmony_ci  body += ' ';
19492c593315Sopenharmony_ci  body += reason_pharase;
19502c593315Sopenharmony_ci  body += "</h1><hr><address>";
19512c593315Sopenharmony_ci  body += NGHTTPD_SERVER;
19522c593315Sopenharmony_ci  body += " at port ";
19532c593315Sopenharmony_ci  body += util::utos(port);
19542c593315Sopenharmony_ci  body += "</address>";
19552c593315Sopenharmony_ci  body += "</body></html>";
19562c593315Sopenharmony_ci
19572c593315Sopenharmony_ci  char tempfn[] = "/tmp/nghttpd.temp.XXXXXX";
19582c593315Sopenharmony_ci  int fd = mkstemp(tempfn);
19592c593315Sopenharmony_ci  if (fd == -1) {
19602c593315Sopenharmony_ci    auto error = errno;
19612c593315Sopenharmony_ci    std::cerr << "Could not open status response body file: errno=" << error;
19622c593315Sopenharmony_ci    assert(0);
19632c593315Sopenharmony_ci  }
19642c593315Sopenharmony_ci  unlink(tempfn);
19652c593315Sopenharmony_ci  ssize_t nwrite;
19662c593315Sopenharmony_ci  while ((nwrite = write(fd, body.c_str(), body.size())) == -1 &&
19672c593315Sopenharmony_ci         errno == EINTR)
19682c593315Sopenharmony_ci    ;
19692c593315Sopenharmony_ci  if (nwrite == -1) {
19702c593315Sopenharmony_ci    auto error = errno;
19712c593315Sopenharmony_ci    std::cerr << "Could not write status response body into file: errno="
19722c593315Sopenharmony_ci              << error;
19732c593315Sopenharmony_ci    assert(0);
19742c593315Sopenharmony_ci  }
19752c593315Sopenharmony_ci
19762c593315Sopenharmony_ci  return FileEntry(util::utos(status), nwrite, 0, fd, nullptr, {});
19772c593315Sopenharmony_ci}
19782c593315Sopenharmony_ci} // namespace
19792c593315Sopenharmony_ci
19802c593315Sopenharmony_ci// index into HttpServer::status_pages_
19812c593315Sopenharmony_cienum {
19822c593315Sopenharmony_ci  IDX_200,
19832c593315Sopenharmony_ci  IDX_301,
19842c593315Sopenharmony_ci  IDX_400,
19852c593315Sopenharmony_ci  IDX_404,
19862c593315Sopenharmony_ci  IDX_405,
19872c593315Sopenharmony_ci};
19882c593315Sopenharmony_ci
19892c593315Sopenharmony_ciHttpServer::HttpServer(const Config *config) : config_(config) {
19902c593315Sopenharmony_ci  status_pages_ = std::vector<StatusPage>{
19912c593315Sopenharmony_ci      {"200", make_status_body(200, config_->port)},
19922c593315Sopenharmony_ci      {"301", make_status_body(301, config_->port)},
19932c593315Sopenharmony_ci      {"400", make_status_body(400, config_->port)},
19942c593315Sopenharmony_ci      {"404", make_status_body(404, config_->port)},
19952c593315Sopenharmony_ci      {"405", make_status_body(405, config_->port)},
19962c593315Sopenharmony_ci  };
19972c593315Sopenharmony_ci}
19982c593315Sopenharmony_ci
19992c593315Sopenharmony_ci#ifndef OPENSSL_NO_NEXTPROTONEG
20002c593315Sopenharmony_cinamespace {
20012c593315Sopenharmony_ciint next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
20022c593315Sopenharmony_ci                  void *arg) {
20032c593315Sopenharmony_ci  auto next_proto = static_cast<std::vector<unsigned char> *>(arg);
20042c593315Sopenharmony_ci  *data = next_proto->data();
20052c593315Sopenharmony_ci  *len = next_proto->size();
20062c593315Sopenharmony_ci  return SSL_TLSEXT_ERR_OK;
20072c593315Sopenharmony_ci}
20082c593315Sopenharmony_ci} // namespace
20092c593315Sopenharmony_ci#endif // !OPENSSL_NO_NEXTPROTONEG
20102c593315Sopenharmony_ci
20112c593315Sopenharmony_cinamespace {
20122c593315Sopenharmony_ciint verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
20132c593315Sopenharmony_ci  // We don't verify the client certificate. Just request it for the
20142c593315Sopenharmony_ci  // testing purpose.
20152c593315Sopenharmony_ci  return 1;
20162c593315Sopenharmony_ci}
20172c593315Sopenharmony_ci} // namespace
20182c593315Sopenharmony_ci
20192c593315Sopenharmony_cinamespace {
20202c593315Sopenharmony_ciint start_listen(HttpServer *sv, struct ev_loop *loop, Sessions *sessions,
20212c593315Sopenharmony_ci                 const Config *config) {
20222c593315Sopenharmony_ci  int r;
20232c593315Sopenharmony_ci  bool ok = false;
20242c593315Sopenharmony_ci  const char *addr = nullptr;
20252c593315Sopenharmony_ci
20262c593315Sopenharmony_ci  std::shared_ptr<AcceptHandler> acceptor;
20272c593315Sopenharmony_ci  auto service = util::utos(config->port);
20282c593315Sopenharmony_ci
20292c593315Sopenharmony_ci  addrinfo hints{};
20302c593315Sopenharmony_ci  hints.ai_family = AF_UNSPEC;
20312c593315Sopenharmony_ci  hints.ai_socktype = SOCK_STREAM;
20322c593315Sopenharmony_ci  hints.ai_flags = AI_PASSIVE;
20332c593315Sopenharmony_ci#ifdef AI_ADDRCONFIG
20342c593315Sopenharmony_ci  hints.ai_flags |= AI_ADDRCONFIG;
20352c593315Sopenharmony_ci#endif // AI_ADDRCONFIG
20362c593315Sopenharmony_ci
20372c593315Sopenharmony_ci  if (!config->address.empty()) {
20382c593315Sopenharmony_ci    addr = config->address.c_str();
20392c593315Sopenharmony_ci  }
20402c593315Sopenharmony_ci
20412c593315Sopenharmony_ci  addrinfo *res, *rp;
20422c593315Sopenharmony_ci  r = getaddrinfo(addr, service.c_str(), &hints, &res);
20432c593315Sopenharmony_ci  if (r != 0) {
20442c593315Sopenharmony_ci    std::cerr << "getaddrinfo() failed: " << gai_strerror(r) << std::endl;
20452c593315Sopenharmony_ci    return -1;
20462c593315Sopenharmony_ci  }
20472c593315Sopenharmony_ci
20482c593315Sopenharmony_ci  for (rp = res; rp; rp = rp->ai_next) {
20492c593315Sopenharmony_ci    int fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
20502c593315Sopenharmony_ci    if (fd == -1) {
20512c593315Sopenharmony_ci      continue;
20522c593315Sopenharmony_ci    }
20532c593315Sopenharmony_ci    int val = 1;
20542c593315Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
20552c593315Sopenharmony_ci                   static_cast<socklen_t>(sizeof(val))) == -1) {
20562c593315Sopenharmony_ci      close(fd);
20572c593315Sopenharmony_ci      continue;
20582c593315Sopenharmony_ci    }
20592c593315Sopenharmony_ci    (void)util::make_socket_nonblocking(fd);
20602c593315Sopenharmony_ci#ifdef IPV6_V6ONLY
20612c593315Sopenharmony_ci    if (rp->ai_family == AF_INET6) {
20622c593315Sopenharmony_ci      if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
20632c593315Sopenharmony_ci                     static_cast<socklen_t>(sizeof(val))) == -1) {
20642c593315Sopenharmony_ci        close(fd);
20652c593315Sopenharmony_ci        continue;
20662c593315Sopenharmony_ci      }
20672c593315Sopenharmony_ci    }
20682c593315Sopenharmony_ci#endif // IPV6_V6ONLY
20692c593315Sopenharmony_ci    if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0 && listen(fd, 1000) == 0) {
20702c593315Sopenharmony_ci      if (!acceptor) {
20712c593315Sopenharmony_ci        acceptor = std::make_shared<AcceptHandler>(sv, sessions, config);
20722c593315Sopenharmony_ci      }
20732c593315Sopenharmony_ci      new ListenEventHandler(sessions, fd, acceptor);
20742c593315Sopenharmony_ci
20752c593315Sopenharmony_ci      if (config->verbose) {
20762c593315Sopenharmony_ci        std::string s = util::numeric_name(rp->ai_addr, rp->ai_addrlen);
20772c593315Sopenharmony_ci        std::cout << (rp->ai_family == AF_INET ? "IPv4" : "IPv6") << ": listen "
20782c593315Sopenharmony_ci                  << s << ":" << config->port << std::endl;
20792c593315Sopenharmony_ci      }
20802c593315Sopenharmony_ci      ok = true;
20812c593315Sopenharmony_ci      continue;
20822c593315Sopenharmony_ci    } else {
20832c593315Sopenharmony_ci      std::cerr << strerror(errno) << std::endl;
20842c593315Sopenharmony_ci    }
20852c593315Sopenharmony_ci    close(fd);
20862c593315Sopenharmony_ci  }
20872c593315Sopenharmony_ci  freeaddrinfo(res);
20882c593315Sopenharmony_ci
20892c593315Sopenharmony_ci  if (!ok) {
20902c593315Sopenharmony_ci    return -1;
20912c593315Sopenharmony_ci  }
20922c593315Sopenharmony_ci  return 0;
20932c593315Sopenharmony_ci}
20942c593315Sopenharmony_ci} // namespace
20952c593315Sopenharmony_ci
20962c593315Sopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10002000L
20972c593315Sopenharmony_cinamespace {
20982c593315Sopenharmony_ciint alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
20992c593315Sopenharmony_ci                         unsigned char *outlen, const unsigned char *in,
21002c593315Sopenharmony_ci                         unsigned int inlen, void *arg) {
21012c593315Sopenharmony_ci  auto config = static_cast<HttpServer *>(arg)->get_config();
21022c593315Sopenharmony_ci  if (config->verbose) {
21032c593315Sopenharmony_ci    std::cout << "[ALPN] client offers:" << std::endl;
21042c593315Sopenharmony_ci  }
21052c593315Sopenharmony_ci  if (config->verbose) {
21062c593315Sopenharmony_ci    for (unsigned int i = 0; i < inlen; i += in[i] + 1) {
21072c593315Sopenharmony_ci      std::cout << " * ";
21082c593315Sopenharmony_ci      std::cout.write(reinterpret_cast<const char *>(&in[i + 1]), in[i]);
21092c593315Sopenharmony_ci      std::cout << std::endl;
21102c593315Sopenharmony_ci    }
21112c593315Sopenharmony_ci  }
21122c593315Sopenharmony_ci  if (!util::select_h2(out, outlen, in, inlen)) {
21132c593315Sopenharmony_ci    return SSL_TLSEXT_ERR_NOACK;
21142c593315Sopenharmony_ci  }
21152c593315Sopenharmony_ci  return SSL_TLSEXT_ERR_OK;
21162c593315Sopenharmony_ci}
21172c593315Sopenharmony_ci} // namespace
21182c593315Sopenharmony_ci#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
21192c593315Sopenharmony_ci
21202c593315Sopenharmony_ciint HttpServer::run() {
21212c593315Sopenharmony_ci  SSL_CTX *ssl_ctx = nullptr;
21222c593315Sopenharmony_ci  std::vector<unsigned char> next_proto;
21232c593315Sopenharmony_ci
21242c593315Sopenharmony_ci  if (!config_->no_tls) {
21252c593315Sopenharmony_ci    ssl_ctx = SSL_CTX_new(TLS_server_method());
21262c593315Sopenharmony_ci    if (!ssl_ctx) {
21272c593315Sopenharmony_ci      std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
21282c593315Sopenharmony_ci      return -1;
21292c593315Sopenharmony_ci    }
21302c593315Sopenharmony_ci
21312c593315Sopenharmony_ci    auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
21322c593315Sopenharmony_ci                    SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
21332c593315Sopenharmony_ci                    SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
21342c593315Sopenharmony_ci                    SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET |
21352c593315Sopenharmony_ci                    SSL_OP_CIPHER_SERVER_PREFERENCE;
21362c593315Sopenharmony_ci
21372c593315Sopenharmony_ci#ifdef SSL_OP_ENABLE_KTLS
21382c593315Sopenharmony_ci    if (config_->ktls) {
21392c593315Sopenharmony_ci      ssl_opts |= SSL_OP_ENABLE_KTLS;
21402c593315Sopenharmony_ci    }
21412c593315Sopenharmony_ci#endif // SSL_OP_ENABLE_KTLS
21422c593315Sopenharmony_ci
21432c593315Sopenharmony_ci    SSL_CTX_set_options(ssl_ctx, ssl_opts);
21442c593315Sopenharmony_ci    SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
21452c593315Sopenharmony_ci    SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
21462c593315Sopenharmony_ci
21472c593315Sopenharmony_ci    if (nghttp2::tls::ssl_ctx_set_proto_versions(
21482c593315Sopenharmony_ci            ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
21492c593315Sopenharmony_ci            nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
21502c593315Sopenharmony_ci      std::cerr << "Could not set TLS versions" << std::endl;
21512c593315Sopenharmony_ci      return -1;
21522c593315Sopenharmony_ci    }
21532c593315Sopenharmony_ci
21542c593315Sopenharmony_ci    if (SSL_CTX_set_cipher_list(ssl_ctx, tls::DEFAULT_CIPHER_LIST) == 0) {
21552c593315Sopenharmony_ci      std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
21562c593315Sopenharmony_ci      return -1;
21572c593315Sopenharmony_ci    }
21582c593315Sopenharmony_ci
21592c593315Sopenharmony_ci    const unsigned char sid_ctx[] = "nghttpd";
21602c593315Sopenharmony_ci    SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx) - 1);
21612c593315Sopenharmony_ci    SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER);
21622c593315Sopenharmony_ci
21632c593315Sopenharmony_ci#ifndef OPENSSL_NO_EC
21642c593315Sopenharmony_ci#  if !LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L
21652c593315Sopenharmony_ci    if (SSL_CTX_set1_curves_list(ssl_ctx, "P-256") != 1) {
21662c593315Sopenharmony_ci      std::cerr << "SSL_CTX_set1_curves_list failed: "
21672c593315Sopenharmony_ci                << ERR_error_string(ERR_get_error(), nullptr);
21682c593315Sopenharmony_ci      return -1;
21692c593315Sopenharmony_ci    }
21702c593315Sopenharmony_ci#  else  // !(!LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L)
21712c593315Sopenharmony_ci    auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
21722c593315Sopenharmony_ci    if (ecdh == nullptr) {
21732c593315Sopenharmony_ci      std::cerr << "EC_KEY_new_by_curv_name failed: "
21742c593315Sopenharmony_ci                << ERR_error_string(ERR_get_error(), nullptr);
21752c593315Sopenharmony_ci      return -1;
21762c593315Sopenharmony_ci    }
21772c593315Sopenharmony_ci    SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
21782c593315Sopenharmony_ci    EC_KEY_free(ecdh);
21792c593315Sopenharmony_ci#  endif // !(!LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L)
21802c593315Sopenharmony_ci#endif   // OPENSSL_NO_EC
21812c593315Sopenharmony_ci
21822c593315Sopenharmony_ci    if (!config_->dh_param_file.empty()) {
21832c593315Sopenharmony_ci      // Read DH parameters from file
21842c593315Sopenharmony_ci      auto bio = BIO_new_file(config_->dh_param_file.c_str(), "rb");
21852c593315Sopenharmony_ci      if (bio == nullptr) {
21862c593315Sopenharmony_ci        std::cerr << "BIO_new_file() failed: "
21872c593315Sopenharmony_ci                  << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
21882c593315Sopenharmony_ci        return -1;
21892c593315Sopenharmony_ci      }
21902c593315Sopenharmony_ci
21912c593315Sopenharmony_ci#if OPENSSL_3_0_0_API
21922c593315Sopenharmony_ci      EVP_PKEY *dh = nullptr;
21932c593315Sopenharmony_ci      auto dctx = OSSL_DECODER_CTX_new_for_pkey(
21942c593315Sopenharmony_ci          &dh, "PEM", nullptr, "DH", OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS,
21952c593315Sopenharmony_ci          nullptr, nullptr);
21962c593315Sopenharmony_ci
21972c593315Sopenharmony_ci      if (!OSSL_DECODER_from_bio(dctx, bio)) {
21982c593315Sopenharmony_ci        std::cerr << "OSSL_DECODER_from_bio() failed: "
21992c593315Sopenharmony_ci                  << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
22002c593315Sopenharmony_ci        return -1;
22012c593315Sopenharmony_ci      }
22022c593315Sopenharmony_ci
22032c593315Sopenharmony_ci      if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, dh) != 1) {
22042c593315Sopenharmony_ci        std::cerr << "SSL_CTX_set0_tmp_dh_pkey failed: "
22052c593315Sopenharmony_ci                  << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
22062c593315Sopenharmony_ci        return -1;
22072c593315Sopenharmony_ci      }
22082c593315Sopenharmony_ci#else  // !OPENSSL_3_0_0_API
22092c593315Sopenharmony_ci      auto dh = PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr);
22102c593315Sopenharmony_ci
22112c593315Sopenharmony_ci      if (dh == nullptr) {
22122c593315Sopenharmony_ci        std::cerr << "PEM_read_bio_DHparams() failed: "
22132c593315Sopenharmony_ci                  << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
22142c593315Sopenharmony_ci        return -1;
22152c593315Sopenharmony_ci      }
22162c593315Sopenharmony_ci
22172c593315Sopenharmony_ci      SSL_CTX_set_tmp_dh(ssl_ctx, dh);
22182c593315Sopenharmony_ci      DH_free(dh);
22192c593315Sopenharmony_ci#endif // !OPENSSL_3_0_0_API
22202c593315Sopenharmony_ci      BIO_free(bio);
22212c593315Sopenharmony_ci    }
22222c593315Sopenharmony_ci
22232c593315Sopenharmony_ci    if (SSL_CTX_use_PrivateKey_file(ssl_ctx, config_->private_key_file.c_str(),
22242c593315Sopenharmony_ci                                    SSL_FILETYPE_PEM) != 1) {
22252c593315Sopenharmony_ci      std::cerr << "SSL_CTX_use_PrivateKey_file failed." << std::endl;
22262c593315Sopenharmony_ci      return -1;
22272c593315Sopenharmony_ci    }
22282c593315Sopenharmony_ci    if (SSL_CTX_use_certificate_chain_file(ssl_ctx,
22292c593315Sopenharmony_ci                                           config_->cert_file.c_str()) != 1) {
22302c593315Sopenharmony_ci      std::cerr << "SSL_CTX_use_certificate_file failed." << std::endl;
22312c593315Sopenharmony_ci      return -1;
22322c593315Sopenharmony_ci    }
22332c593315Sopenharmony_ci    if (SSL_CTX_check_private_key(ssl_ctx) != 1) {
22342c593315Sopenharmony_ci      std::cerr << "SSL_CTX_check_private_key failed." << std::endl;
22352c593315Sopenharmony_ci      return -1;
22362c593315Sopenharmony_ci    }
22372c593315Sopenharmony_ci    if (config_->verify_client) {
22382c593315Sopenharmony_ci      SSL_CTX_set_verify(ssl_ctx,
22392c593315Sopenharmony_ci                         SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE |
22402c593315Sopenharmony_ci                             SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
22412c593315Sopenharmony_ci                         verify_callback);
22422c593315Sopenharmony_ci    }
22432c593315Sopenharmony_ci
22442c593315Sopenharmony_ci    next_proto = util::get_default_alpn();
22452c593315Sopenharmony_ci
22462c593315Sopenharmony_ci#ifndef OPENSSL_NO_NEXTPROTONEG
22472c593315Sopenharmony_ci    SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, &next_proto);
22482c593315Sopenharmony_ci#endif // !OPENSSL_NO_NEXTPROTONEG
22492c593315Sopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10002000L
22502c593315Sopenharmony_ci    // ALPN selection callback
22512c593315Sopenharmony_ci    SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this);
22522c593315Sopenharmony_ci#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
22532c593315Sopenharmony_ci  }
22542c593315Sopenharmony_ci
22552c593315Sopenharmony_ci  auto loop = EV_DEFAULT;
22562c593315Sopenharmony_ci
22572c593315Sopenharmony_ci  Sessions sessions(this, loop, config_, ssl_ctx);
22582c593315Sopenharmony_ci  if (start_listen(this, loop, &sessions, config_) != 0) {
22592c593315Sopenharmony_ci    std::cerr << "Could not listen" << std::endl;
22602c593315Sopenharmony_ci    if (ssl_ctx) {
22612c593315Sopenharmony_ci      SSL_CTX_free(ssl_ctx);
22622c593315Sopenharmony_ci    }
22632c593315Sopenharmony_ci    return -1;
22642c593315Sopenharmony_ci  }
22652c593315Sopenharmony_ci
22662c593315Sopenharmony_ci  ev_run(loop, 0);
22672c593315Sopenharmony_ci  return 0;
22682c593315Sopenharmony_ci}
22692c593315Sopenharmony_ci
22702c593315Sopenharmony_ciconst Config *HttpServer::get_config() const { return config_; }
22712c593315Sopenharmony_ci
22722c593315Sopenharmony_ciconst StatusPage *HttpServer::get_status_page(int status) const {
22732c593315Sopenharmony_ci  switch (status) {
22742c593315Sopenharmony_ci  case 200:
22752c593315Sopenharmony_ci    return &status_pages_[IDX_200];
22762c593315Sopenharmony_ci  case 301:
22772c593315Sopenharmony_ci    return &status_pages_[IDX_301];
22782c593315Sopenharmony_ci  case 400:
22792c593315Sopenharmony_ci    return &status_pages_[IDX_400];
22802c593315Sopenharmony_ci  case 404:
22812c593315Sopenharmony_ci    return &status_pages_[IDX_404];
22822c593315Sopenharmony_ci  case 405:
22832c593315Sopenharmony_ci    return &status_pages_[IDX_405];
22842c593315Sopenharmony_ci  default:
22852c593315Sopenharmony_ci    assert(0);
22862c593315Sopenharmony_ci  }
22872c593315Sopenharmony_ci  return nullptr;
22882c593315Sopenharmony_ci}
22892c593315Sopenharmony_ci
22902c593315Sopenharmony_ci} // namespace nghttp2
2291