2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include <sys/types.h>
29 #ifdef HAVE_SYS_SOCKET_H
30 #include <sys/socket.h>
31 #endif // HAVE_SYS_SOCKET_H
35 #endif // HAVE_NETDB_H
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif // HAVE_NETINET_IN_H
40 #include <netinet/tcp.h>
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
43 #endif // HAVE_ARPA_INET_H
46 #endif // HAVE_UNISTD_H
50 #endif // HAVE_SYSLOG_H
54 #endif // HAVE_LIMITS_H
55 #ifdef HAVE_SYS_TIME_H
57 #endif // HAVE_SYS_TIME_H
58 #include <sys/resource.h>
67 #include <initializer_list>
69 #include <openssl/ssl.h>
70 #include <openssl/err.h>
71 #include <openssl/conf.h>
72 #include <openssl/rand.h>
76 #include <nghttp2/nghttp2.h>
78 #include "shrpx_config.h"
79 #include "shrpx_connection_handler.h"
80 #include "shrpx_ssl.h"
81 #include "shrpx_log_config.h"
82 #include "shrpx_worker.h"
83 #include "shrpx_accept_handler.h"
84 #include "shrpx_http2_upstream.h"
85 #include "shrpx_http2_session.h"
87 #include "app_helper.h"
91 extern char **environ;
93 using namespace nghttp2;
98 const int REOPEN_LOG_SIGNAL = SIGUSR1;
99 const int EXEC_BINARY_SIGNAL = SIGUSR2;
100 const int GRACEFUL_SHUTDOWN_SIGNAL = SIGQUIT;
103 // Environment variables to tell new binary the listening socket's
104 // file descriptors. They are not close-on-exec.
105 #define ENV_LISTENER4_FD "NGHTTPX_LISTENER4_FD"
106 #define ENV_LISTENER6_FD "NGHTTPX_LISTENER6_FD"
108 // Environment variable to tell new binary the port number the current
109 // binary is listening to.
110 #define ENV_PORT "NGHTTPX_PORT"
112 // Environment variable to tell new binary the listening socket's file
113 // descriptor if frontend listens UNIX domain socket.
114 #define ENV_UNIX_FD "NGHTTP2_UNIX_FD"
115 // Environment variable to tell new binary the UNIX domain socket
117 #define ENV_UNIX_PATH "NGHTTP2_UNIX_PATH"
120 int resolve_hostname(sockaddr_union *addr, size_t *addrlen,
121 const char *hostname, uint16_t port, int family) {
125 auto service = util::utos(port);
126 memset(&hints, 0, sizeof(addrinfo));
128 hints.ai_family = family;
129 hints.ai_socktype = SOCK_STREAM;
131 hints.ai_flags |= AI_ADDRCONFIG;
132 #endif // AI_ADDRCONFIG
135 rv = getaddrinfo(hostname, service.c_str(), &hints, &res);
137 LOG(FATAL) << "Unable to resolve address for " << hostname << ": "
142 char host[NI_MAXHOST];
143 rv = getnameinfo(res->ai_addr, res->ai_addrlen, host, sizeof(host), 0, 0,
146 LOG(FATAL) << "Address resolution for " << hostname
147 << " failed: " << gai_strerror(rv);
154 if (LOG_ENABLED(INFO)) {
155 LOG(INFO) << "Address resolution for " << hostname
156 << " succeeded: " << host;
159 memcpy(addr, res->ai_addr, res->ai_addrlen);
160 *addrlen = res->ai_addrlen;
167 void close_env_fd(std::initializer_list<const char *> envnames) {
168 for (auto envname : envnames) {
169 auto envfd = getenv(envname);
173 auto fd = strtol(envfd, nullptr, 10);
180 std::unique_ptr<AcceptHandler>
181 create_unix_domain_acceptor(ConnectionHandler *handler) {
182 auto path = get_config()->host.get();
183 auto pathlen = strlen(path);
185 auto envfd = getenv(ENV_UNIX_FD);
186 auto envpath = getenv(ENV_UNIX_PATH);
187 if (envfd && envpath) {
188 auto fd = strtoul(envfd, nullptr, 10);
190 if (util::streq(envpath, path)) {
191 LOG(NOTICE) << "Listening on UNIX domain socket " << path;
193 return make_unique<AcceptHandler>(fd, handler);
196 LOG(WARN) << "UNIX domain socket path was changed between old binary ("
197 << envpath << ") and new binary (" << path << ")";
203 auto fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
207 #else // !SOCK_NONBLOCK
208 auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
212 util::make_socket_nonblocking(fd);
213 #endif // !SOCK_NONBLOCK
215 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
216 static_cast<socklen_t>(sizeof(val))) == -1) {
222 addr.un.sun_family = AF_UNIX;
223 if (pathlen + 1 > sizeof(addr.un.sun_path)) {
224 LOG(FATAL) << "UNIX domain socket path " << path << " is too long > "
225 << sizeof(addr.un.sun_path);
229 // copy path including terminal NULL
230 std::copy_n(path, pathlen + 1, addr.un.sun_path);
232 // unlink (remove) already existing UNIX domain socket path
235 if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) {
237 LOG(FATAL) << "Failed to bind UNIX domain socket, error=" << error;
242 if (listen(fd, get_config()->backlog) != 0) {
244 LOG(FATAL) << "Failed to listen to UNIX domain socket, error=" << error;
249 LOG(NOTICE) << "Listening on UNIX domain socket " << path;
251 return make_unique<AcceptHandler>(fd, handler);
256 std::unique_ptr<AcceptHandler> create_acceptor(ConnectionHandler *handler,
260 getenv(family == AF_INET ? ENV_LISTENER4_FD : ENV_LISTENER6_FD);
261 auto envport = getenv(ENV_PORT);
263 if (envfd && envport) {
264 auto fd = strtoul(envfd, nullptr, 10);
265 auto port = strtoul(envport, nullptr, 10);
267 // Only do this iff NGHTTPX_PORT == get_config()->port.
268 // Otherwise, close fd, and create server socket as usual.
270 if (port == get_config()->port) {
271 LOG(NOTICE) << "Listening on port " << get_config()->port;
273 return make_unique<AcceptHandler>(fd, handler);
276 LOG(WARN) << "Port was changed between old binary (" << port
277 << ") and new binary (" << get_config()->port << ")";
286 auto service = util::utos(get_config()->port);
287 memset(&hints, 0, sizeof(addrinfo));
288 hints.ai_family = family;
289 hints.ai_socktype = SOCK_STREAM;
290 hints.ai_flags = AI_PASSIVE;
292 hints.ai_flags |= AI_ADDRCONFIG;
293 #endif // AI_ADDRCONFIG
295 auto node = strcmp("*", get_config()->host.get()) == 0
297 : get_config()->host.get();
300 rv = getaddrinfo(node, service.c_str(), &hints, &res);
302 if (LOG_ENABLED(INFO)) {
303 LOG(INFO) << "Unable to get IPv" << (family == AF_INET ? "4" : "6")
304 << " address for " << get_config()->host.get() << ": "
309 for (rp = res; rp; rp = rp->ai_next) {
312 socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
316 #else // !SOCK_NONBLOCK
317 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
321 util::make_socket_nonblocking(fd);
322 #endif // !SOCK_NONBLOCK
324 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
325 static_cast<socklen_t>(sizeof(val))) == -1) {
331 if (family == AF_INET6) {
332 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
333 static_cast<socklen_t>(sizeof(val))) == -1) {
338 #endif // IPV6_V6ONLY
340 #ifdef TCP_DEFER_ACCEPT
342 if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val,
343 static_cast<socklen_t>(sizeof(val))) == -1) {
344 LOG(WARN) << "Failed to set TCP_DEFER_ACCEPT option to listener socket";
346 #endif // TCP_DEFER_ACCEPT
348 if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0 &&
349 listen(fd, get_config()->backlog) == 0) {
356 LOG(WARN) << "Listening " << (family == AF_INET ? "IPv4" : "IPv6")
364 char host[NI_MAXHOST];
365 rv = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), nullptr, 0,
371 LOG(WARN) << gai_strerror(rv);
378 LOG(NOTICE) << "Listening on " << host << ", port " << get_config()->port;
380 return make_unique<AcceptHandler>(fd, handler);
385 void drop_privileges() {
386 if (getuid() == 0 && get_config()->uid != 0) {
387 if (initgroups(get_config()->user.get(), get_config()->gid) != 0) {
389 LOG(FATAL) << "Could not change supplementary groups: "
393 if (setgid(get_config()->gid) != 0) {
395 LOG(FATAL) << "Could not change gid: " << strerror(error);
398 if (setuid(get_config()->uid) != 0) {
400 LOG(FATAL) << "Could not change uid: " << strerror(error);
403 if (setuid(0) != -1) {
404 LOG(FATAL) << "Still have root privileges?";
413 std::ofstream out(get_config()->pid_file.get(), std::ios::binary);
414 out << get_config()->pid << "\n";
417 LOG(ERROR) << "Could not save PID to file " << get_config()->pid_file.get();
421 if (get_config()->uid != 0) {
422 if (chown(get_config()->pid_file.get(), get_config()->uid,
423 get_config()->gid) == -1) {
425 LOG(WARN) << "Changing owner of pid file " << get_config()->pid_file.get()
426 << " failed: " << strerror(error);
433 void reopen_log_signal_cb(struct ev_loop *loop, ev_signal *w, int revents) {
434 auto conn_handler = static_cast<ConnectionHandler *>(w->data);
436 LOG(NOTICE) << "Reopening log files: main";
438 (void)reopen_log_files();
439 redirect_stderr_to_errorlog();
441 if (get_config()->num_worker > 1) {
442 conn_handler->worker_reopen_log_files();
448 void exec_binary_signal_cb(struct ev_loop *loop, ev_signal *w, int revents) {
449 auto conn_handler = static_cast<ConnectionHandler *>(w->data);
451 LOG(NOTICE) << "Executing new binary";
457 LOG(ERROR) << "fork() failed errno=" << error;
465 auto exec_path = util::get_exec_path(get_config()->argc, get_config()->argv,
469 LOG(ERROR) << "Could not resolve the executable path";
473 auto argv = make_unique<char *[]>(get_config()->argc + 1);
476 for (int i = 1; i < get_config()->argc; ++i) {
477 argv[i] = strdup(get_config()->argv[i]);
479 argv[get_config()->argc] = nullptr;
482 for (char **p = environ; *p; ++p, ++envlen)
484 // 3 for missing (fd4, fd6 and port) or (unix fd and unix path)
485 auto envp = make_unique<char *[]>(envlen + 3 + 1);
488 if (get_config()->host_unix) {
489 auto acceptor = conn_handler->get_acceptor();
490 std::string fd = ENV_UNIX_FD "=";
491 fd += util::utos(acceptor->get_fd());
492 envp[envidx++] = strdup(fd.c_str());
494 std::string path = ENV_UNIX_PATH "=";
495 path += get_config()->host.get();
496 envp[envidx++] = strdup(path.c_str());
498 auto acceptor4 = conn_handler->get_acceptor();
500 std::string fd4 = ENV_LISTENER4_FD "=";
501 fd4 += util::utos(acceptor4->get_fd());
502 envp[envidx++] = strdup(fd4.c_str());
505 auto acceptor6 = conn_handler->get_acceptor6();
507 std::string fd6 = ENV_LISTENER6_FD "=";
508 fd6 += util::utos(acceptor6->get_fd());
509 envp[envidx++] = strdup(fd6.c_str());
512 std::string port = ENV_PORT "=";
513 port += util::utos(get_config()->port);
514 envp[envidx++] = strdup(port.c_str());
517 for (size_t i = 0; i < envlen; ++i) {
518 if (util::startsWith(environ[i], ENV_LISTENER4_FD) ||
519 util::startsWith(environ[i], ENV_LISTENER6_FD) ||
520 util::startsWith(environ[i], ENV_PORT) ||
521 util::startsWith(environ[i], ENV_UNIX_FD) ||
522 util::startsWith(environ[i], ENV_UNIX_PATH)) {
526 envp[envidx++] = environ[i];
529 envp[envidx++] = nullptr;
531 if (LOG_ENABLED(INFO)) {
532 LOG(INFO) << "cmdline";
533 for (int i = 0; argv[i]; ++i) {
534 LOG(INFO) << i << ": " << argv[i];
536 LOG(INFO) << "environ";
537 for (int i = 0; envp[i]; ++i) {
538 LOG(INFO) << i << ": " << envp[i];
542 if (execve(argv[0], argv.get(), envp.get()) == -1) {
544 LOG(ERROR) << "execve failed: errno=" << error;
551 void graceful_shutdown_signal_cb(struct ev_loop *loop, ev_signal *w,
553 auto conn_handler = static_cast<ConnectionHandler *>(w->data);
555 if (conn_handler->get_graceful_shutdown()) {
559 LOG(NOTICE) << "Graceful shutdown signal received";
561 conn_handler->set_graceful_shutdown(true);
563 conn_handler->disable_acceptor();
565 // After disabling accepting new connection, disptach incoming
566 // connection in backlog.
568 conn_handler->accept_pending_connection();
570 conn_handler->graceful_shutdown_worker();
572 if (get_config()->num_worker == 1 &&
573 conn_handler->get_single_worker()->get_worker_stat()->num_connections >
578 // We have accepted all pending connections. Shutdown main event
585 void renew_ticket_key_cb(struct ev_loop *loop, ev_timer *w, int revents) {
586 auto conn_handler = static_cast<ConnectionHandler *>(w->data);
587 const auto &old_ticket_keys = conn_handler->get_ticket_keys();
589 auto ticket_keys = std::make_shared<TicketKeys>();
590 LOG(NOTICE) << "Renew ticket keys: main";
592 // We store at most 2 ticket keys
593 if (old_ticket_keys) {
594 auto &old_keys = old_ticket_keys->keys;
595 auto &new_keys = ticket_keys->keys;
597 assert(!old_keys.empty());
600 new_keys[1] = old_keys[0];
602 ticket_keys->keys.resize(1);
605 if (RAND_bytes(reinterpret_cast<unsigned char *>(&ticket_keys->keys[0]),
606 sizeof(ticket_keys->keys[0])) == 0) {
607 if (LOG_ENABLED(INFO)) {
608 LOG(INFO) << "failed to renew ticket key";
613 if (LOG_ENABLED(INFO)) {
614 LOG(INFO) << "ticket keys generation done";
615 for (auto &key : ticket_keys->keys) {
616 LOG(INFO) << "name: " << util::format_hex(key.name, sizeof(key.name));
620 conn_handler->set_ticket_keys(ticket_keys);
621 conn_handler->worker_renew_ticket_keys(ticket_keys);
627 auto loop = EV_DEFAULT;
629 auto conn_handler = make_unique<ConnectionHandler>(loop);
630 if (get_config()->daemon) {
631 if (daemon(0, 0) == -1) {
633 LOG(FATAL) << "Failed to daemonize: " << strerror(error);
637 // We get new PID after successful daemon().
638 mod_config()->pid = getpid();
640 // daemon redirects stderr file descriptor to /dev/null, so we
642 redirect_stderr_to_errorlog();
645 if (get_config()->pid_file) {
649 if (get_config()->host_unix) {
650 close_env_fd({ENV_LISTENER4_FD, ENV_LISTENER6_FD});
651 auto acceptor = create_unix_domain_acceptor(conn_handler.get());
653 LOG(FATAL) << "Failed to listen on UNIX domain socket "
654 << get_config()->host.get();
658 conn_handler->set_acceptor(std::move(acceptor));
660 close_env_fd({ENV_UNIX_FD});
661 auto acceptor6 = create_acceptor(conn_handler.get(), AF_INET6);
662 auto acceptor4 = create_acceptor(conn_handler.get(), AF_INET);
663 if (!acceptor6 && !acceptor4) {
664 LOG(FATAL) << "Failed to listen on address " << get_config()->host.get()
665 << ", port " << get_config()->port;
669 conn_handler->set_acceptor(std::move(acceptor4));
670 conn_handler->set_acceptor6(std::move(acceptor6));
673 ev_timer renew_ticket_key_timer;
674 if (!get_config()->upstream_no_tls) {
675 bool auto_tls_ticket_key = true;
676 if (!get_config()->tls_ticket_key_files.empty()) {
678 read_tls_ticket_key_file(get_config()->tls_ticket_key_files);
680 LOG(WARN) << "Use internal session ticket key generator";
682 conn_handler->set_ticket_keys(std::move(ticket_keys));
683 auto_tls_ticket_key = false;
686 if (auto_tls_ticket_key) {
687 // Renew ticket key every 12hrs
688 ev_timer_init(&renew_ticket_key_timer, renew_ticket_key_cb, 0.,
690 renew_ticket_key_timer.data = conn_handler.get();
691 ev_timer_again(loop, &renew_ticket_key_timer);
693 // Generate first session ticket key before running workers.
694 renew_ticket_key_cb(loop, &renew_ticket_key_timer, 0);
698 // ListenHandler loads private key, and we listen on a priveleged port.
699 // After that, we drop the root privileges if needed.
705 sigemptyset(&signals);
706 sigaddset(&signals, REOPEN_LOG_SIGNAL);
707 sigaddset(&signals, EXEC_BINARY_SIGNAL);
708 sigaddset(&signals, GRACEFUL_SHUTDOWN_SIGNAL);
709 rv = pthread_sigmask(SIG_BLOCK, &signals, nullptr);
711 LOG(ERROR) << "Blocking signals failed: " << strerror(rv);
715 if (get_config()->num_worker == 1) {
716 conn_handler->create_single_worker();
718 conn_handler->create_worker_thread(get_config()->num_worker);
722 rv = pthread_sigmask(SIG_UNBLOCK, &signals, nullptr);
724 LOG(ERROR) << "Unblocking signals failed: " << strerror(rv);
728 ev_signal reopen_log_sig;
729 ev_signal_init(&reopen_log_sig, reopen_log_signal_cb, REOPEN_LOG_SIGNAL);
730 reopen_log_sig.data = conn_handler.get();
731 ev_signal_start(loop, &reopen_log_sig);
733 ev_signal exec_bin_sig;
734 ev_signal_init(&exec_bin_sig, exec_binary_signal_cb, EXEC_BINARY_SIGNAL);
735 exec_bin_sig.data = conn_handler.get();
736 ev_signal_start(loop, &exec_bin_sig);
738 ev_signal graceful_shutdown_sig;
739 ev_signal_init(&graceful_shutdown_sig, graceful_shutdown_signal_cb,
740 GRACEFUL_SHUTDOWN_SIGNAL);
741 graceful_shutdown_sig.data = conn_handler.get();
742 ev_signal_start(loop, &graceful_shutdown_sig);
744 if (!get_config()->upstream_no_tls && !get_config()->no_ocsp) {
745 conn_handler->proceed_next_cert_ocsp();
748 if (LOG_ENABLED(INFO)) {
749 LOG(INFO) << "Entering event loop";
754 conn_handler->join_worker();
755 conn_handler->cancel_ocsp_update();
762 // Returns true if regular file or symbolic link |path| exists.
763 bool conf_exists(const char *path) {
765 int rv = stat(path, &buf);
766 return rv == 0 && (buf.st_mode & (S_IFREG | S_IFLNK));
771 const char *DEFAULT_NPN_LIST = "h2,h2-16,h2-14,"
774 #endif // HAVE_SPDYLAY
779 const char *DEFAULT_TLS_PROTO_LIST = "TLSv1.2,TLSv1.1";
783 const char *DEFAULT_ACCESSLOG_FORMAT = "$remote_addr - - [$time_local] "
784 "\"$request\" $status $body_bytes_sent "
785 "\"$http_referer\" \"$http_user_agent\"";
789 auto DEFAULT_DOWNSTREAM_HOST = "127.0.0.1";
790 int16_t DEFAULT_DOWNSTREAM_PORT = 80;
794 void fill_default_config() {
795 memset(mod_config(), 0, sizeof(*mod_config()));
797 mod_config()->verbose = false;
798 mod_config()->daemon = false;
800 mod_config()->server_name = "nghttpx nghttp2/" NGHTTP2_VERSION;
801 mod_config()->host = strcopy("*");
802 mod_config()->port = 3000;
803 mod_config()->private_key_file = nullptr;
804 mod_config()->private_key_passwd = nullptr;
805 mod_config()->cert_file = nullptr;
807 // Read timeout for HTTP2 upstream connection
808 mod_config()->http2_upstream_read_timeout = 180.;
810 // Read timeout for non-HTTP2 upstream connection
811 mod_config()->upstream_read_timeout = 180.;
813 // Write timeout for HTTP2/non-HTTP2 upstream connection
814 mod_config()->upstream_write_timeout = 30.;
816 // Read/Write timeouts for downstream connection
817 mod_config()->downstream_read_timeout = 180.;
818 mod_config()->downstream_write_timeout = 30.;
820 // Read timeout for HTTP/2 stream
821 mod_config()->stream_read_timeout = 0.;
823 // Write timeout for HTTP/2 stream
824 mod_config()->stream_write_timeout = 0.;
826 // Timeout for pooled (idle) connections
827 mod_config()->downstream_idle_read_timeout = 2.;
829 // window bits for HTTP/2 and SPDY upstream/downstream connection
830 // per stream. 2**16-1 = 64KiB-1, which is HTTP/2 default. Please
831 // note that SPDY/3 default is 64KiB.
832 mod_config()->http2_upstream_window_bits = 16;
833 mod_config()->http2_downstream_window_bits = 16;
835 // HTTP/2 SPDY/3.1 has connection-level flow control. The default
836 // window size for HTTP/2 is 64KiB - 1. SPDY/3's default is 64KiB
837 mod_config()->http2_upstream_connection_window_bits = 16;
838 mod_config()->http2_downstream_connection_window_bits = 16;
840 mod_config()->upstream_no_tls = false;
841 mod_config()->downstream_no_tls = false;
843 mod_config()->num_worker = 1;
844 mod_config()->http2_max_concurrent_streams = 100;
845 mod_config()->add_x_forwarded_for = false;
846 mod_config()->strip_incoming_x_forwarded_for = false;
847 mod_config()->no_via = false;
848 mod_config()->accesslog_file = nullptr;
849 mod_config()->accesslog_syslog = false;
850 mod_config()->accesslog_format = parse_log_format(DEFAULT_ACCESSLOG_FORMAT);
851 #if defined(__ANDROID__) || defined(ANDROID)
852 // Android does not have /dev/stderr. Use /proc/self/fd/2 instead.
853 mod_config()->errorlog_file = strcopy("/proc/self/fd/2");
854 #else // !__ANDROID__ && ANDROID
855 mod_config()->errorlog_file = strcopy("/dev/stderr");
856 #endif // !__ANDROID__ && ANDROID
857 mod_config()->errorlog_syslog = false;
858 mod_config()->conf_path = strcopy("/etc/nghttpx/nghttpx.conf");
859 mod_config()->syslog_facility = LOG_DAEMON;
860 // Default accept() backlog
861 mod_config()->backlog = 512;
862 mod_config()->ciphers = nullptr;
863 mod_config()->http2_proxy = false;
864 mod_config()->http2_bridge = false;
865 mod_config()->client_proxy = false;
866 mod_config()->client = false;
867 mod_config()->client_mode = false;
868 mod_config()->insecure = false;
869 mod_config()->cacert = nullptr;
870 mod_config()->pid_file = nullptr;
871 mod_config()->user = nullptr;
872 mod_config()->uid = 0;
873 mod_config()->gid = 0;
874 mod_config()->pid = getpid();
875 mod_config()->backend_ipv4 = false;
876 mod_config()->backend_ipv6 = false;
877 mod_config()->downstream_http_proxy_userinfo = nullptr;
878 mod_config()->downstream_http_proxy_host = nullptr;
879 mod_config()->downstream_http_proxy_port = 0;
880 mod_config()->downstream_http_proxy_addrlen = 0;
881 mod_config()->read_rate = 0;
882 mod_config()->read_burst = 0;
883 mod_config()->write_rate = 0;
884 mod_config()->write_burst = 0;
885 mod_config()->worker_read_rate = 0;
886 mod_config()->worker_read_burst = 0;
887 mod_config()->worker_write_rate = 0;
888 mod_config()->worker_write_burst = 0;
889 mod_config()->verify_client = false;
890 mod_config()->verify_client_cacert = nullptr;
891 mod_config()->client_private_key_file = nullptr;
892 mod_config()->client_cert_file = nullptr;
893 mod_config()->http2_upstream_dump_request_header = nullptr;
894 mod_config()->http2_upstream_dump_response_header = nullptr;
895 mod_config()->http2_no_cookie_crumbling = false;
896 mod_config()->upstream_frame_debug = false;
897 mod_config()->padding = 0;
898 mod_config()->worker_frontend_connections = 0;
900 mod_config()->http2_upstream_callbacks = create_http2_upstream_callbacks();
901 mod_config()->http2_downstream_callbacks =
902 create_http2_downstream_callbacks();
904 nghttp2_option_new(&mod_config()->http2_option);
905 nghttp2_option_set_no_auto_window_update(get_config()->http2_option, 1);
906 nghttp2_option_set_no_recv_client_magic(get_config()->http2_option, 1);
908 nghttp2_option_new(&mod_config()->http2_client_option);
909 nghttp2_option_set_no_auto_window_update(get_config()->http2_client_option,
911 nghttp2_option_set_peer_max_concurrent_streams(
912 get_config()->http2_client_option, 100);
914 mod_config()->tls_proto_mask = 0;
915 mod_config()->no_location_rewrite = false;
916 mod_config()->no_host_rewrite = false;
917 mod_config()->argc = 0;
918 mod_config()->argv = nullptr;
919 mod_config()->downstream_connections_per_host = 8;
920 mod_config()->downstream_connections_per_frontend = 0;
921 mod_config()->listener_disable_timeout = 0.;
922 mod_config()->downstream_request_buffer_size = 16 * 1024;
923 mod_config()->downstream_response_buffer_size = 16 * 1024;
924 mod_config()->no_server_push = false;
925 mod_config()->host_unix = false;
926 mod_config()->http2_downstream_connections_per_worker = 0;
927 // ocsp update interval = 14400 secs = 4 hours, borrowed from h2o
928 mod_config()->ocsp_update_interval = 14400.;
929 mod_config()->fetch_ocsp_response_file =
930 strcopy(PKGDATADIR "/fetch-ocsp-response");
931 mod_config()->no_ocsp = false;
932 mod_config()->header_field_buffer = 64 * 1024;
933 mod_config()->max_header_fields = 100;
938 void print_version(std::ostream &out) {
939 out << get_config()->server_name << std::endl;
944 void print_usage(std::ostream &out) {
945 out << R"(Usage: nghttpx [OPTIONS]... [<PRIVATE_KEY> <CERT>]
946 A reverse proxy for HTTP/2, HTTP/1 and SPDY.)" << std::endl;
951 void print_help(std::ostream &out) {
955 Set path to server's private key. Required unless -p,
956 --client or --frontend-no-tls are given.
957 <CERT> Set path to server's certificate. Required unless -p,
958 --client or --frontend-no-tls are given. To make OCSP
959 stapling work, this must be absolute path.
962 The options are categorized into several groups.
965 -b, --backend=<HOST,PORT>
966 Set backend host and port. The multiple backend
967 addresses are accepted by repeating this option. UNIX
968 domain socket can be specified by prefixing path name
969 with "unix:" (e.g., unix:/var/run/backend.sock)
970 Default: )" << DEFAULT_DOWNSTREAM_HOST << ","
971 << DEFAULT_DOWNSTREAM_PORT << R"(
972 -f, --frontend=<HOST,PORT>
973 Set frontend host and port. If <HOST> is '*', it
974 assumes all addresses including both IPv4 and IPv6.
975 UNIX domain socket can be specified by prefixing path
976 name with "unix:" (e.g., unix:/var/run/nghttpx.sock)
977 Default: )" << get_config()->host.get() << ","
978 << get_config()->port << R"(
980 Set listen backlog size.
981 Default: )" << get_config()->backlog << R"(
983 Resolve backend hostname to IPv4 address only.
985 Resolve backend hostname to IPv6 address only.
986 --backend-http-proxy-uri=<URI>
987 Specify proxy URI in the form
988 http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a proxy
989 requires authentication, specify <USER> and <PASS>.
990 Note that they must be properly percent-encoded. This
991 proxy is used when the backend connection is HTTP/2.
992 First, make a CONNECT request to the proxy and it
993 connects to the backend on behalf of nghttpx. This
994 forms tunnel. After that, nghttpx performs SSL/TLS
995 handshake with the downstream through the tunnel. The
996 timeouts when connecting and making CONNECT request can
997 be specified by --backend-read-timeout and
998 --backend-write-timeout options.
1002 Set the number of worker threads.
1003 Default: )" << get_config()->num_worker << R"(
1005 Set maximum average read rate on frontend connection.
1006 Setting 0 to this option means read rate is unlimited.
1007 Default: )" << get_config()->read_rate << R"(
1009 Set maximum read burst size on frontend connection.
1010 Setting 0 to this option means read burst size is
1012 Default: )" << get_config()->read_burst << R"(
1014 Set maximum average write rate on frontend connection.
1015 Setting 0 to this option means write rate is unlimited.
1016 Default: )" << get_config()->write_rate << R"(
1017 --write-burst=<SIZE>
1018 Set maximum write burst size on frontend connection.
1019 Setting 0 to this option means write burst size is
1021 Default: )" << get_config()->write_burst << R"(
1022 --worker-read-rate=<SIZE>
1023 Set maximum average read rate on frontend connection per
1024 worker. Setting 0 to this option means read rate is
1025 unlimited. Not implemented yet.
1026 Default: )" << get_config()->worker_read_rate << R"(
1027 --worker-read-burst=<SIZE>
1028 Set maximum read burst size on frontend connection per
1029 worker. Setting 0 to this option means read burst size
1030 is unlimited. Not implemented yet.
1031 Default: )" << get_config()->worker_read_burst << R"(
1032 --worker-write-rate=<SIZE>
1033 Set maximum average write rate on frontend connection
1034 per worker. Setting 0 to this option means write rate
1035 is unlimited. Not implemented yet.
1036 Default: )" << get_config()->worker_write_rate << R"(
1037 --worker-write-burst=<SIZE>
1038 Set maximum write burst size on frontend connection per
1039 worker. Setting 0 to this option means write burst size
1040 is unlimited. Not implemented yet.
1041 Default: )" << get_config()->worker_write_burst << R"(
1042 --worker-frontend-connections=<N>
1043 Set maximum number of simultaneous connections frontend
1044 accepts. Setting 0 means unlimited.
1045 Default: )" << get_config()->worker_frontend_connections << R"(
1046 --backend-http2-connections-per-worker=<N>
1047 Set maximum number of HTTP/2 connections per worker.
1048 The default value is 0, which means the number of
1049 backend addresses specified by -b option.
1050 --backend-http1-connections-per-host=<N>
1051 Set maximum number of backend concurrent HTTP/1
1052 connections per host. This option is meaningful when -s
1053 option is used. To limit the number of connections per
1054 frontend for default mode, use
1055 --backend-http1-connections-per-frontend.
1056 Default: )" << get_config()->downstream_connections_per_host
1058 --backend-http1-connections-per-frontend=<N>
1059 Set maximum number of backend concurrent HTTP/1
1060 connections per frontend. This option is only used for
1061 default mode. 0 means unlimited. To limit the number
1062 of connections per host for HTTP/2 or SPDY proxy mode
1063 (-s option), use --backend-http1-connections-per-host.
1064 Default: )" << get_config()->downstream_connections_per_frontend
1067 Set maximum number of open files (RLIMIT_NOFILE) to <N>.
1068 If 0 is given, nghttpx does not set the limit.
1069 Default: )" << get_config()->rlimit_nofile << R"(
1070 --backend-request-buffer=<SIZE>
1071 Set buffer size used to store backend request.
1073 << util::utos_with_unit(get_config()->downstream_request_buffer_size)
1075 --backend-response-buffer=<SIZE>
1076 Set buffer size used to store backend response.
1078 << util::utos_with_unit(get_config()->downstream_response_buffer_size)
1082 --frontend-http2-read-timeout=<DURATION>
1083 Specify read timeout for HTTP/2 and SPDY frontend
1086 << util::duration_str(get_config()->http2_upstream_read_timeout) << R"(
1087 --frontend-read-timeout=<DURATION>
1088 Specify read timeout for HTTP/1.1 frontend connection.
1090 << util::duration_str(get_config()->upstream_read_timeout) << R"(
1091 --frontend-write-timeout=<DURATION>
1092 Specify write timeout for all frontend connections.
1094 << util::duration_str(get_config()->upstream_write_timeout) << R"(
1095 --stream-read-timeout=<DURATION>
1096 Specify read timeout for HTTP/2 and SPDY streams. 0
1099 << util::duration_str(get_config()->stream_read_timeout) << R"(
1100 --stream-write-timeout=<DURATION>
1101 Specify write timeout for HTTP/2 and SPDY streams. 0
1104 << util::duration_str(get_config()->stream_write_timeout) << R"(
1105 --backend-read-timeout=<DURATION>
1106 Specify read timeout for backend connection.
1108 << util::duration_str(get_config()->downstream_read_timeout) << R"(
1109 --backend-write-timeout=<DURATION>
1110 Specify write timeout for backend connection.
1112 << util::duration_str(get_config()->downstream_write_timeout) << R"(
1113 --backend-keep-alive-timeout=<DURATION>
1114 Specify keep-alive timeout for backend connection.
1116 << util::duration_str(get_config()->downstream_idle_read_timeout) << R"(
1117 --listener-disable-timeout=<DURATION>
1118 After accepting connection failed, connection listener
1119 is disabled for a given amount of time. Specifying 0
1120 disables this feature.
1122 << util::duration_str(get_config()->listener_disable_timeout) << R"(
1126 Set allowed cipher list. The format of the string is
1127 described in OpenSSL ciphers(1).
1129 Don't verify backend server's certificate if -p,
1130 --client or --http2-bridge are given and
1131 --backend-no-tls is not given.
1133 Set path to trusted CA certificate file if -p, --client
1134 or --http2-bridge are given and --backend-no-tls is not
1135 given. The file must be in PEM format. It can contain
1136 multiple certificates. If the linked OpenSSL is
1137 configured to load system wide certificates, they are
1138 loaded at startup regardless of this option.
1139 --private-key-passwd-file=<PATH>
1140 Path to file that contains password for the server's
1141 private key. If none is given and the private key is
1142 password protected it'll be requested interactively.
1143 --subcert=<KEYPATH>:<CERTPATH>
1144 Specify additional certificate and private key file.
1145 nghttpx will choose certificates based on the hostname
1146 indicated by client using TLS SNI extension. This
1147 option can be used multiple times. To make OCSP
1148 stapling work, <CERTPATH> must be absolute path.
1149 --backend-tls-sni-field=<HOST>
1150 Explicitly set the content of the TLS SNI extension.
1151 This will default to the backend HOST name.
1152 --dh-param-file=<PATH>
1153 Path to file that contains DH parameters in PEM format.
1154 Without this option, DHE cipher suites are not
1157 Comma delimited list of ALPN protocol identifier sorted
1158 in the order of preference. That means most desirable
1159 protocol comes first. This is used in both ALPN and
1160 NPN. The parameter must be delimited by a single comma
1161 only and any white spaces are treated as a part of
1163 Default: )" << DEFAULT_NPN_LIST << R"(
1165 Require and verify client certificate.
1166 --verify-client-cacert=<PATH>
1167 Path to file that contains CA certificates to verify
1168 client certificate. The file must be in PEM format. It
1169 can contain multiple certificates.
1170 --client-private-key-file=<PATH>
1171 Path to file that contains client private key used in
1172 backend client authentication.
1173 --client-cert-file=<PATH>
1174 Path to file that contains client certificate used in
1175 backend client authentication.
1176 --tls-proto-list=<LIST>
1177 Comma delimited list of SSL/TLS protocol to be enabled.
1178 The following protocols are available: TLSv1.2, TLSv1.1
1179 and TLSv1.0. The name matching is done in
1180 case-insensitive manner. The parameter must be
1181 delimited by a single comma only and any white spaces
1182 are treated as a part of protocol string.
1183 Default: )" << DEFAULT_TLS_PROTO_LIST << R"(
1184 --tls-ticket-key-file=<PATH>
1185 Path to file that contains 48 bytes random data to
1186 construct TLS session ticket parameters. This options
1187 can be used repeatedly to specify multiple ticket
1188 parameters. If several files are given, only the first
1189 key is used to encrypt TLS session tickets. Other keys
1190 are accepted but server will issue new session ticket
1191 with first key. This allows session key rotation.
1192 Please note that key rotation does not occur
1193 automatically. User should rearrange files or change
1194 options values and restart nghttpx gracefully. If
1195 opening or reading given file fails, all loaded keys are
1196 discarded and it is treated as if none of this option is
1197 given. If this option is not given or an error occurred
1198 while opening or reading a file, key is generated
1199 automatically and renewed every 12hrs. At most 2 keys
1200 are stored in memory.
1201 --fetch-ocsp-response-file=<PATH>
1202 Path to fetch-ocsp-response script file. It should be
1204 Default: )" << get_config()->fetch_ocsp_response_file.get() << R"(
1205 --ocsp-update-interval=<DURATION>
1206 Set interval to update OCSP response cache.
1208 << util::duration_str(get_config()->ocsp_update_interval) << R"(
1209 --no-ocsp Disable OCSP stapling.
1212 -c, --http2-max-concurrent-streams=<N>
1213 Set the maximum number of the concurrent streams in one
1214 HTTP/2 and SPDY session.
1215 Default: )" << get_config()->http2_max_concurrent_streams << R"(
1216 --frontend-http2-window-bits=<N>
1217 Sets the per-stream initial window size of HTTP/2 SPDY
1218 frontend connection. For HTTP/2, the size is 2**<N>-1.
1219 For SPDY, the size is 2**<N>.
1220 Default: )" << get_config()->http2_upstream_window_bits << R"(
1221 --frontend-http2-connection-window-bits=<N>
1222 Sets the per-connection window size of HTTP/2 and SPDY
1223 frontend connection. For HTTP/2, the size is
1224 2**<N>-1. For SPDY, the size is 2**<N>.
1225 Default: )" << get_config()->http2_upstream_connection_window_bits
1228 Disable SSL/TLS on frontend connections.
1229 --backend-http2-window-bits=<N>
1230 Sets the initial window size of HTTP/2 backend
1231 connection to 2**<N>-1.
1232 Default: )" << get_config()->http2_downstream_window_bits << R"(
1233 --backend-http2-connection-window-bits=<N>
1234 Sets the per-connection window size of HTTP/2 backend
1235 connection to 2**<N>-1.
1237 << get_config()->http2_downstream_connection_window_bits << R"(
1239 Disable SSL/TLS on backend connections.
1240 --http2-no-cookie-crumbling
1241 Don't crumble cookie header field.
1243 Add at most <N> bytes to a HTTP/2 frame payload as
1244 padding. Specify 0 to disable padding. This option is
1245 meant for debugging purpose and not intended to enhance
1248 Disable HTTP/2 server push. Server push is only
1249 supported by default mode and HTTP/2 frontend. SPDY
1250 frontend does not support server push.
1254 Accept HTTP/2, SPDY and HTTP/1.1 over SSL/TLS. If
1255 --frontend-no-tls is used, accept HTTP/2 and HTTP/1.1.
1256 The incoming HTTP/1.1 connection can be upgraded to
1257 HTTP/2 through HTTP Upgrade. The protocol to the
1258 backend is HTTP/1.1.
1260 Like default mode, but enable secure proxy mode.
1262 Like default mode, but communicate with the backend in
1263 HTTP/2 over SSL/TLS. Thus the incoming all connections
1264 are converted to HTTP/2 connection and relayed to the
1265 backend. See --backend-http-proxy-uri option if you are
1266 behind the proxy and want to connect to the outside
1268 --client Accept HTTP/2 and HTTP/1.1 without SSL/TLS. The
1269 incoming HTTP/1.1 connection can be upgraded to HTTP/2
1270 connection through HTTP Upgrade. The protocol to the
1271 backend is HTTP/2. To use nghttpx as a forward proxy,
1272 use -p option instead.
1274 Like --client option, but it also requires the request
1275 path from frontend must be an absolute URI, suitable for
1276 use as a forward proxy.
1279 -L, --log-level=<LEVEL>
1280 Set the severity level of log output. <LEVEL> must be
1281 one of INFO, NOTICE, WARN, ERROR and FATAL.
1283 --accesslog-file=<PATH>
1284 Set path to write access log. To reopen file, send USR1
1287 Send access log to syslog. If this option is used,
1288 --accesslog-file option is ignored.
1289 --accesslog-format=<FORMAT>
1290 Specify format string for access log. The default
1291 format is combined format. The following variables are
1294 * $remote_addr: client IP address.
1295 * $time_local: local time in Common Log format.
1296 * $time_iso8601: local time in ISO 8601 format.
1297 * $request: HTTP request line.
1298 * $status: HTTP response status code.
1299 * $body_bytes_sent: the number of bytes sent to client
1301 * $http_<VAR>: value of HTTP request header <VAR> where
1302 '_' in <VAR> is replaced with '-'.
1303 * $remote_port: client port.
1304 * $server_port: server port.
1305 * $request_time: request processing time in seconds with
1306 milliseconds resolution.
1307 * $pid: PID of the running process.
1308 * $alpn: ALPN identifier of the protocol which generates
1309 the response. For HTTP/1, ALPN is always http/1.1,
1310 regardless of minor version.
1312 Default: )" << DEFAULT_ACCESSLOG_FORMAT << R"(
1313 --errorlog-file=<PATH>
1314 Set path to write error log. To reopen file, send USR1
1315 signal to nghttpx. stderr will be redirected to the
1316 error log file unless --errorlog-syslog is used.
1317 Default: )" << get_config()->errorlog_file.get() << R"(
1319 Send error log to syslog. If this option is used,
1320 --errorlog-file option is ignored.
1321 --syslog-facility=<FACILITY>
1322 Set syslog facility to <FACILITY>.
1323 Default: )" << str_syslog_facility(get_config()->syslog_facility)
1327 --add-x-forwarded-for
1328 Append X-Forwarded-For header field to the downstream
1330 --strip-incoming-x-forwarded-for
1331 Strip X-Forwarded-For header field from inbound client
1333 --no-via Don't append to Via header field. If Via header field
1334 is received, it is left unaltered.
1335 --no-location-rewrite
1336 Don't rewrite location header field on --http2-bridge,
1337 --client and default mode. For --http2-proxy and
1338 --client-proxy mode, location header field will not be
1339 altered regardless of this option.
1341 Don't rewrite host and :authority header fields on
1342 --http2-bridge, --client and default mode. For
1343 --http2-proxy and --client-proxy mode, these headers
1344 will not be altered regardless of this option.
1345 --altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
1346 Specify protocol ID, port, host and origin of
1347 alternative service. <HOST> and <ORIGIN> are optional.
1348 They are advertised in alt-svc header field only in
1349 HTTP/1.1 frontend. This option can be used multiple
1350 times to specify multiple alternative services.
1351 Example: --altsvc=h2,443
1352 --add-response-header=<HEADER>
1353 Specify additional header field to add to response
1354 header set. This option just appends header field and
1355 won't replace anything already set. This option can be
1356 used several times to specify multiple header fields.
1357 Example: --add-response-header="foo: bar"
1358 --header-field-buffer=<SIZE>
1359 Set maximum buffer size for incoming HTTP header field
1360 list. This is the sum of header name and value in
1363 << util::utos_with_unit(get_config()->header_field_buffer) << R"(
1364 --max-header-fields=<N>
1365 Set maximum number of incoming HTTP header fields, which
1366 appear in one request or response header field list.
1367 Default: )" << get_config()->max_header_fields << R"(
1370 --frontend-http2-dump-request-header=<PATH>
1371 Dumps request headers received by HTTP/2 frontend to the
1372 file denoted in <PATH>. The output is done in HTTP/1
1373 header field format and each header block is followed by
1374 an empty line. This option is not thread safe and MUST
1375 NOT be used with option -n<N>, where <N> >= 2.
1376 --frontend-http2-dump-response-header=<PATH>
1377 Dumps response headers sent from HTTP/2 frontend to the
1378 file denoted in <PATH>. The output is done in HTTP/1
1379 header field format and each header block is followed by
1380 an empty line. This option is not thread safe and MUST
1381 NOT be used with option -n<N>, where <N> >= 2.
1382 -o, --frontend-frame-debug
1383 Print HTTP/2 frames in frontend to stderr. This option
1384 is not thread safe and MUST NOT be used with option
1389 Run in a background. If -D is used, the current working
1390 directory is changed to '/'.
1392 Set path to save PID of this program.
1394 Run this program as <USER>. This option is intended to
1395 be used to drop root privileges.
1399 Load configuration from <PATH>.
1400 Default: )" << get_config()->conf_path.get() << R"(
1402 Print version and exit.
1403 -h, --help Print this help and exit.
1407 The <SIZE> argument is an integer and an optional unit (e.g., 10K is
1408 10 * 1024). Units are K, M and G (powers of 1024).
1410 The <DURATION> argument is an integer and an optional unit (e.g., 1s
1411 is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
1412 (hours, minutes, seconds and milliseconds, respectively). If a unit
1413 is omitted, a second is used as unit.)" << std::endl;
1417 int main(int argc, char **argv) {
1418 Log::set_severity_level(NOTICE);
1420 fill_default_config();
1422 // We have to copy argv, since getopt_long may change its content.
1423 mod_config()->argc = argc;
1424 mod_config()->argv = new char *[argc];
1426 for (int i = 0; i < argc; ++i) {
1427 mod_config()->argv[i] = strdup(argv[i]);
1430 mod_config()->cwd = getcwd(nullptr, 0);
1431 if (mod_config()->cwd == nullptr) {
1433 LOG(FATAL) << "failed to get current working directory: errno=" << error;
1437 std::vector<std::pair<const char *, const char *>> cmdcfgs;
1439 static int flag = 0;
1440 static option long_options[] = {
1441 {"daemon", no_argument, nullptr, 'D'},
1442 {"log-level", required_argument, nullptr, 'L'},
1443 {"backend", required_argument, nullptr, 'b'},
1444 {"http2-max-concurrent-streams", required_argument, nullptr, 'c'},
1445 {"frontend", required_argument, nullptr, 'f'},
1446 {"help", no_argument, nullptr, 'h'},
1447 {"insecure", no_argument, nullptr, 'k'},
1448 {"workers", required_argument, nullptr, 'n'},
1449 {"client-proxy", no_argument, nullptr, 'p'},
1450 {"http2-proxy", no_argument, nullptr, 's'},
1451 {"version", no_argument, nullptr, 'v'},
1452 {"frontend-frame-debug", no_argument, nullptr, 'o'},
1453 {"add-x-forwarded-for", no_argument, &flag, 1},
1454 {"frontend-http2-read-timeout", required_argument, &flag, 2},
1455 {"frontend-read-timeout", required_argument, &flag, 3},
1456 {"frontend-write-timeout", required_argument, &flag, 4},
1457 {"backend-read-timeout", required_argument, &flag, 5},
1458 {"backend-write-timeout", required_argument, &flag, 6},
1459 {"accesslog-file", required_argument, &flag, 7},
1460 {"backend-keep-alive-timeout", required_argument, &flag, 8},
1461 {"frontend-http2-window-bits", required_argument, &flag, 9},
1462 {"pid-file", required_argument, &flag, 10},
1463 {"user", required_argument, &flag, 11},
1464 {"conf", required_argument, &flag, 12},
1465 {"syslog-facility", required_argument, &flag, 14},
1466 {"backlog", required_argument, &flag, 15},
1467 {"ciphers", required_argument, &flag, 16},
1468 {"client", no_argument, &flag, 17},
1469 {"backend-http2-window-bits", required_argument, &flag, 18},
1470 {"cacert", required_argument, &flag, 19},
1471 {"backend-ipv4", no_argument, &flag, 20},
1472 {"backend-ipv6", no_argument, &flag, 21},
1473 {"private-key-passwd-file", required_argument, &flag, 22},
1474 {"no-via", no_argument, &flag, 23},
1475 {"subcert", required_argument, &flag, 24},
1476 {"http2-bridge", no_argument, &flag, 25},
1477 {"backend-http-proxy-uri", required_argument, &flag, 26},
1478 {"backend-no-tls", no_argument, &flag, 27},
1479 {"frontend-no-tls", no_argument, &flag, 29},
1480 {"backend-tls-sni-field", required_argument, &flag, 31},
1481 {"dh-param-file", required_argument, &flag, 33},
1482 {"read-rate", required_argument, &flag, 34},
1483 {"read-burst", required_argument, &flag, 35},
1484 {"write-rate", required_argument, &flag, 36},
1485 {"write-burst", required_argument, &flag, 37},
1486 {"npn-list", required_argument, &flag, 38},
1487 {"verify-client", no_argument, &flag, 39},
1488 {"verify-client-cacert", required_argument, &flag, 40},
1489 {"client-private-key-file", required_argument, &flag, 41},
1490 {"client-cert-file", required_argument, &flag, 42},
1491 {"frontend-http2-dump-request-header", required_argument, &flag, 43},
1492 {"frontend-http2-dump-response-header", required_argument, &flag, 44},
1493 {"http2-no-cookie-crumbling", no_argument, &flag, 45},
1494 {"frontend-http2-connection-window-bits", required_argument, &flag, 46},
1495 {"backend-http2-connection-window-bits", required_argument, &flag, 47},
1496 {"tls-proto-list", required_argument, &flag, 48},
1497 {"padding", required_argument, &flag, 49},
1498 {"worker-read-rate", required_argument, &flag, 50},
1499 {"worker-read-burst", required_argument, &flag, 51},
1500 {"worker-write-rate", required_argument, &flag, 52},
1501 {"worker-write-burst", required_argument, &flag, 53},
1502 {"altsvc", required_argument, &flag, 54},
1503 {"add-response-header", required_argument, &flag, 55},
1504 {"worker-frontend-connections", required_argument, &flag, 56},
1505 {"accesslog-syslog", no_argument, &flag, 57},
1506 {"errorlog-file", required_argument, &flag, 58},
1507 {"errorlog-syslog", no_argument, &flag, 59},
1508 {"stream-read-timeout", required_argument, &flag, 60},
1509 {"stream-write-timeout", required_argument, &flag, 61},
1510 {"no-location-rewrite", no_argument, &flag, 62},
1511 {"backend-http1-connections-per-host", required_argument, &flag, 63},
1512 {"listener-disable-timeout", required_argument, &flag, 64},
1513 {"strip-incoming-x-forwarded-for", no_argument, &flag, 65},
1514 {"accesslog-format", required_argument, &flag, 66},
1515 {"backend-http1-connections-per-frontend", required_argument, &flag,
1517 {"tls-ticket-key-file", required_argument, &flag, 68},
1518 {"rlimit-nofile", required_argument, &flag, 69},
1519 {"tls-ctx-per-worker", no_argument, &flag, 70},
1520 {"backend-response-buffer", required_argument, &flag, 71},
1521 {"backend-request-buffer", required_argument, &flag, 72},
1522 {"no-host-rewrite", no_argument, &flag, 73},
1523 {"no-server-push", no_argument, &flag, 74},
1524 {"backend-http2-connections-per-worker", required_argument, &flag, 76},
1525 {"fetch-ocsp-response-file", required_argument, &flag, 77},
1526 {"ocsp-update-interval", required_argument, &flag, 78},
1527 {"no-ocsp", no_argument, &flag, 79},
1528 {"header-field-buffer", required_argument, &flag, 80},
1529 {"max-header-fields", required_argument, &flag, 81},
1530 {nullptr, 0, nullptr, 0}};
1532 int option_index = 0;
1533 int c = getopt_long(argc, argv, "DL:b:c:f:hkn:opsv", long_options,
1540 cmdcfgs.emplace_back(SHRPX_OPT_DAEMON, "yes");
1543 cmdcfgs.emplace_back(SHRPX_OPT_LOG_LEVEL, optarg);
1546 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND, optarg);
1549 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_MAX_CONCURRENT_STREAMS, optarg);
1552 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND, optarg);
1555 print_help(std::cout);
1558 cmdcfgs.emplace_back(SHRPX_OPT_INSECURE, "yes");
1562 LOG(WARN) << "Threading disabled at build time, no threads created.";
1564 cmdcfgs.emplace_back(SHRPX_OPT_WORKERS, optarg);
1568 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_FRAME_DEBUG, "yes");
1571 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PROXY, "yes");
1574 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_PROXY, "yes");
1577 print_version(std::cout);
1580 util::show_candidates(argv[optind - 1], long_options);
1585 // --add-x-forwarded-for
1586 cmdcfgs.emplace_back(SHRPX_OPT_ADD_X_FORWARDED_FOR, "yes");
1589 // --frontend-http2-read-timeout
1590 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_READ_TIMEOUT, optarg);
1593 // --frontend-read-timeout
1594 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_READ_TIMEOUT, optarg);
1597 // --frontend-write-timeout
1598 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_WRITE_TIMEOUT, optarg);
1601 // --backend-read-timeout
1602 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_READ_TIMEOUT, optarg);
1605 // --backend-write-timeout
1606 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_WRITE_TIMEOUT, optarg);
1609 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_FILE, optarg);
1612 // --backend-keep-alive-timeout
1613 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT, optarg);
1616 // --frontend-http2-window-bits
1617 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS, optarg);
1620 cmdcfgs.emplace_back(SHRPX_OPT_PID_FILE, optarg);
1623 cmdcfgs.emplace_back(SHRPX_OPT_USER, optarg);
1627 mod_config()->conf_path = strcopy(optarg);
1630 // --syslog-facility
1631 cmdcfgs.emplace_back(SHRPX_OPT_SYSLOG_FACILITY, optarg);
1635 cmdcfgs.emplace_back(SHRPX_OPT_BACKLOG, optarg);
1639 cmdcfgs.emplace_back(SHRPX_OPT_CIPHERS, optarg);
1643 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT, "yes");
1646 // --backend-http2-window-bits
1647 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS, optarg);
1651 cmdcfgs.emplace_back(SHRPX_OPT_CACERT, optarg);
1655 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_IPV4, "yes");
1659 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_IPV6, "yes");
1662 // --private-key-passwd-file
1663 cmdcfgs.emplace_back(SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE, optarg);
1667 cmdcfgs.emplace_back(SHRPX_OPT_NO_VIA, "yes");
1671 cmdcfgs.emplace_back(SHRPX_OPT_SUBCERT, optarg);
1675 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_BRIDGE, "yes");
1678 // --backend-http-proxy-uri
1679 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP_PROXY_URI, optarg);
1683 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_NO_TLS, "yes");
1686 // --frontend-no-tls
1687 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_NO_TLS, "yes");
1690 // --backend-tls-sni-field
1691 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SNI_FIELD, optarg);
1695 cmdcfgs.emplace_back(SHRPX_OPT_DH_PARAM_FILE, optarg);
1699 cmdcfgs.emplace_back(SHRPX_OPT_READ_RATE, optarg);
1703 cmdcfgs.emplace_back(SHRPX_OPT_READ_BURST, optarg);
1707 cmdcfgs.emplace_back(SHRPX_OPT_WRITE_RATE, optarg);
1711 cmdcfgs.emplace_back(SHRPX_OPT_WRITE_BURST, optarg);
1715 cmdcfgs.emplace_back(SHRPX_OPT_NPN_LIST, optarg);
1719 cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT, "yes");
1722 // --verify-client-cacert
1723 cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT_CACERT, optarg);
1726 // --client-private-key-file
1727 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE, optarg);
1730 // --client-cert-file
1731 cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_CERT_FILE, optarg);
1734 // --frontend-http2-dump-request-header
1735 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER,
1739 // --frontend-http2-dump-response-header
1740 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER,
1744 // --http2-no-cookie-crumbling
1745 cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING, "yes");
1748 // --frontend-http2-connection-window-bits
1749 cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS,
1753 // --backend-http2-connection-window-bits
1754 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS,
1759 cmdcfgs.emplace_back(SHRPX_OPT_TLS_PROTO_LIST, optarg);
1763 cmdcfgs.emplace_back(SHRPX_OPT_PADDING, optarg);
1766 // --worker-read-rate
1767 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_READ_RATE, optarg);
1770 // --worker-read-burst
1771 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_READ_BURST, optarg);
1774 // --worker-write-rate
1775 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_RATE, optarg);
1778 // --worker-write-burst
1779 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_BURST, optarg);
1783 cmdcfgs.emplace_back(SHRPX_OPT_ALTSVC, optarg);
1786 // --add-response-header
1787 cmdcfgs.emplace_back(SHRPX_OPT_ADD_RESPONSE_HEADER, optarg);
1790 // --worker-frontend-connections
1791 cmdcfgs.emplace_back(SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS, optarg);
1794 // --accesslog-syslog
1795 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_SYSLOG, "yes");
1799 cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_FILE, optarg);
1802 // --errorlog-syslog
1803 cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_SYSLOG, "yes");
1806 // --stream-read-timeout
1807 cmdcfgs.emplace_back(SHRPX_OPT_STREAM_READ_TIMEOUT, optarg);
1810 // --stream-write-timeout
1811 cmdcfgs.emplace_back(SHRPX_OPT_STREAM_WRITE_TIMEOUT, optarg);
1814 // --no-location-rewrite
1815 cmdcfgs.emplace_back(SHRPX_OPT_NO_LOCATION_REWRITE, "yes");
1818 // --backend-http1-connections-per-host
1819 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST,
1823 // --listener-disable-timeout
1824 cmdcfgs.emplace_back(SHRPX_OPT_LISTENER_DISABLE_TIMEOUT, optarg);
1827 // --strip-incoming-x-forwarded-for
1828 cmdcfgs.emplace_back(SHRPX_OPT_STRIP_INCOMING_X_FORWARDED_FOR, "yes");
1831 // --accesslog-format
1832 cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_FORMAT, optarg);
1835 // --backend-http1-connections-per-frontend
1836 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND,
1840 // --tls-ticket-key-file
1841 cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_FILE, optarg);
1845 cmdcfgs.emplace_back(SHRPX_OPT_RLIMIT_NOFILE, optarg);
1848 // --backend-response-buffer
1849 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_RESPONSE_BUFFER, optarg);
1852 // --backend-request-buffer
1853 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_REQUEST_BUFFER, optarg);
1856 // --no-host-rewrite
1857 cmdcfgs.emplace_back(SHRPX_OPT_NO_HOST_REWRITE, "yes");
1861 cmdcfgs.emplace_back(SHRPX_OPT_NO_SERVER_PUSH, "yes");
1864 // --backend-http2-connections-per-worker
1865 cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER,
1869 // --fetch-ocsp-response-file
1870 cmdcfgs.emplace_back(SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE, optarg);
1873 // --ocsp-update-interval
1874 cmdcfgs.emplace_back(SHRPX_OPT_OCSP_UPDATE_INTERVAL, optarg);
1878 cmdcfgs.emplace_back(SHRPX_OPT_NO_OCSP, "yes");
1881 // --header-field-buffer
1882 cmdcfgs.emplace_back(SHRPX_OPT_HEADER_FIELD_BUFFER, optarg);
1885 // --max-header-fields
1886 cmdcfgs.emplace_back(SHRPX_OPT_MAX_HEADER_FIELDS, optarg);
1897 // Initialize OpenSSL before parsing options because we create
1899 OPENSSL_config(nullptr);
1900 OpenSSL_add_all_algorithms();
1901 SSL_load_error_strings();
1904 if (conf_exists(get_config()->conf_path.get())) {
1905 if (load_config(get_config()->conf_path.get()) == -1) {
1906 LOG(FATAL) << "Failed to load configuration from "
1907 << get_config()->conf_path.get();
1912 if (argc - optind >= 2) {
1913 cmdcfgs.emplace_back(SHRPX_OPT_PRIVATE_KEY_FILE, argv[optind++]);
1914 cmdcfgs.emplace_back(SHRPX_OPT_CERTIFICATE_FILE, argv[optind++]);
1917 // First open default log files to deal with errors occurred while
1918 // parsing option values.
1921 for (size_t i = 0, len = cmdcfgs.size(); i < len; ++i) {
1922 if (parse_config(cmdcfgs[i].first, cmdcfgs[i].second) == -1) {
1923 LOG(FATAL) << "Failed to parse command-line argument.";
1929 auto lock = make_unique<nghttp2::ssl::LibsslGlobalLock>();
1932 if (get_config()->accesslog_syslog || get_config()->errorlog_syslog) {
1933 openlog("nghttpx", LOG_NDELAY | LOG_NOWAIT | LOG_PID,
1934 get_config()->syslog_facility);
1937 if (reopen_log_files() != 0) {
1938 LOG(FATAL) << "Failed to open log file";
1942 redirect_stderr_to_errorlog();
1944 if (get_config()->uid != 0) {
1945 if (log_config()->accesslog_fd != -1 &&
1946 fchown(log_config()->accesslog_fd, get_config()->uid,
1947 get_config()->gid) == -1) {
1949 LOG(WARN) << "Changing owner of access log file failed: "
1952 if (log_config()->errorlog_fd != -1 &&
1953 fchown(log_config()->errorlog_fd, get_config()->uid,
1954 get_config()->gid) == -1) {
1956 LOG(WARN) << "Changing owner of error log file failed: "
1961 if (get_config()->http2_upstream_dump_request_header_file) {
1962 auto path = get_config()->http2_upstream_dump_request_header_file.get();
1963 auto f = open_file_for_write(path);
1966 LOG(FATAL) << "Failed to open http2 upstream request header file: "
1971 mod_config()->http2_upstream_dump_request_header = f;
1973 if (get_config()->uid != 0) {
1974 if (chown(path, get_config()->uid, get_config()->gid) == -1) {
1976 LOG(WARN) << "Changing owner of http2 upstream request header file "
1977 << path << " failed: " << strerror(error);
1982 if (get_config()->http2_upstream_dump_response_header_file) {
1983 auto path = get_config()->http2_upstream_dump_response_header_file.get();
1984 auto f = open_file_for_write(path);
1987 LOG(FATAL) << "Failed to open http2 upstream response header file: "
1992 mod_config()->http2_upstream_dump_response_header = f;
1994 if (get_config()->uid != 0) {
1995 if (chown(path, get_config()->uid, get_config()->gid) == -1) {
1997 LOG(WARN) << "Changing owner of http2 upstream response header file"
1998 << " " << path << " failed: " << strerror(error);
2003 if (get_config()->npn_list.empty()) {
2004 mod_config()->npn_list = parse_config_str_list(DEFAULT_NPN_LIST);
2006 if (get_config()->tls_proto_list.empty()) {
2007 mod_config()->tls_proto_list =
2008 parse_config_str_list(DEFAULT_TLS_PROTO_LIST);
2011 mod_config()->tls_proto_mask =
2012 ssl::create_tls_proto_mask(get_config()->tls_proto_list);
2014 mod_config()->alpn_prefs = ssl::set_alpn_prefs(get_config()->npn_list);
2016 if (get_config()->backend_ipv4 && get_config()->backend_ipv6) {
2017 LOG(FATAL) << "--backend-ipv4 and --backend-ipv6 cannot be used at the "
2022 if (get_config()->worker_frontend_connections == 0) {
2023 mod_config()->worker_frontend_connections =
2024 std::numeric_limits<size_t>::max();
2027 if (get_config()->http2_proxy + get_config()->http2_bridge +
2028 get_config()->client_proxy + get_config()->client >
2030 LOG(FATAL) << "--http2-proxy, --http2-bridge, --client-proxy and --client "
2031 << "cannot be used at the same time.";
2035 if (get_config()->client || get_config()->client_proxy) {
2036 mod_config()->client_mode = true;
2037 mod_config()->upstream_no_tls = true;
2040 if (get_config()->client_mode || get_config()->http2_bridge) {
2041 mod_config()->downstream_proto = PROTO_HTTP2;
2043 mod_config()->downstream_proto = PROTO_HTTP;
2046 if (!get_config()->upstream_no_tls &&
2047 (!get_config()->private_key_file || !get_config()->cert_file)) {
2048 print_usage(std::cerr);
2049 LOG(FATAL) << "Too few arguments";
2053 if (!get_config()->upstream_no_tls && !get_config()->no_ocsp) {
2055 if (stat(get_config()->fetch_ocsp_response_file.get(), &buf) != 0) {
2056 mod_config()->no_ocsp = true;
2057 LOG(WARN) << "--fetch-ocsp-response-file: "
2058 << get_config()->fetch_ocsp_response_file.get()
2059 << " not found. OCSP stapling has been disabled.";
2063 if (get_config()->downstream_addrs.empty()) {
2064 DownstreamAddr addr;
2065 addr.host = strcopy(DEFAULT_DOWNSTREAM_HOST);
2066 addr.port = DEFAULT_DOWNSTREAM_PORT;
2068 mod_config()->downstream_addrs.push_back(std::move(addr));
2071 if (LOG_ENABLED(INFO)) {
2072 LOG(INFO) << "Resolving backend address";
2075 for (auto &addr : mod_config()->downstream_addrs) {
2077 if (addr.host_unix) {
2078 // for AF_UNIX socket, we use "localhost" as host for backend
2079 // hostport. This is used as Host header field to backend and
2080 // not going to be passed to any syscalls.
2082 strcopy(util::make_hostport("localhost", get_config()->port));
2084 auto path = addr.host.get();
2085 auto pathlen = strlen(path);
2087 if (pathlen + 1 > sizeof(addr.addr.un.sun_path)) {
2088 LOG(FATAL) << "UNIX domain socket path " << path << " is too long > "
2089 << sizeof(addr.addr.un.sun_path);
2093 LOG(INFO) << "Use UNIX domain socket path " << path
2094 << " for backend connection";
2096 addr.addr.un.sun_family = AF_UNIX;
2097 // copy path including terminal NULL
2098 std::copy_n(path, pathlen + 1, addr.addr.un.sun_path);
2099 addr.addrlen = sizeof(addr.addr.un);
2104 addr.hostport = strcopy(util::make_hostport(addr.host.get(), addr.port));
2106 if (resolve_hostname(
2107 &addr.addr, &addr.addrlen, addr.host.get(), addr.port,
2108 get_config()->backend_ipv4
2110 : (get_config()->backend_ipv6 ? AF_INET6 : AF_UNSPEC)) == -1) {
2115 if (get_config()->downstream_http_proxy_host) {
2116 if (LOG_ENABLED(INFO)) {
2117 LOG(INFO) << "Resolving backend http proxy address";
2119 if (resolve_hostname(&mod_config()->downstream_http_proxy_addr,
2120 &mod_config()->downstream_http_proxy_addrlen,
2121 get_config()->downstream_http_proxy_host.get(),
2122 get_config()->downstream_http_proxy_port,
2128 if (get_config()->http2_downstream_connections_per_worker == 0) {
2129 mod_config()->http2_downstream_connections_per_worker =
2130 get_config()->downstream_addrs.size();
2133 if (get_config()->rlimit_nofile) {
2134 struct rlimit lim = {static_cast<rlim_t>(get_config()->rlimit_nofile),
2135 static_cast<rlim_t>(get_config()->rlimit_nofile)};
2136 if (setrlimit(RLIMIT_NOFILE, &lim) != 0) {
2138 LOG(WARN) << "Setting rlimit-nofile failed: " << strerror(error);
2142 if (get_config()->upstream_frame_debug) {
2143 // To make it sync to logging
2145 if (isatty(fileno(stdout))) {
2146 set_color_output(true);
2151 struct sigaction act;
2152 memset(&act, 0, sizeof(struct sigaction));
2153 act.sa_handler = SIG_IGN;
2154 sigaction(SIGPIPE, &act, nullptr);
2158 LOG(NOTICE) << "Shutdown momentarily";
2163 } // namespace shrpx
2165 int main(int argc, char **argv) { return shrpx::main(argc, argv); }