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