1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2012 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "shrpx.h"
26 
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <sys/stat.h>
30 #ifdef HAVE_SYS_SOCKET_H
31 #  include <sys/socket.h>
32 #endif // HAVE_SYS_SOCKET_H
33 #include <sys/un.h>
34 #ifdef HAVE_NETDB_H
35 #  include <netdb.h>
36 #endif // HAVE_NETDB_H
37 #include <signal.h>
38 #ifdef HAVE_NETINET_IN_H
39 #  include <netinet/in.h>
40 #endif // HAVE_NETINET_IN_H
41 #include <netinet/tcp.h>
42 #ifdef HAVE_ARPA_INET_H
43 #  include <arpa/inet.h>
44 #endif // HAVE_ARPA_INET_H
45 #ifdef HAVE_UNISTD_H
46 #  include <unistd.h>
47 #endif // HAVE_UNISTD_H
48 #include <getopt.h>
49 #ifdef HAVE_SYSLOG_H
50 #  include <syslog.h>
51 #endif // HAVE_SYSLOG_H
52 #ifdef HAVE_LIMITS_H
53 #  include <limits.h>
54 #endif // HAVE_LIMITS_H
55 #ifdef HAVE_SYS_TIME_H
56 #  include <sys/time.h>
57 #endif // HAVE_SYS_TIME_H
58 #include <sys/resource.h>
59 #ifdef HAVE_LIBSYSTEMD
60 #  include <systemd/sd-daemon.h>
61 #endif // HAVE_LIBSYSTEMD
62 
63 #include <cinttypes>
64 #include <limits>
65 #include <cstdlib>
66 #include <iostream>
67 #include <fstream>
68 #include <vector>
69 #include <initializer_list>
70 #include <random>
71 
72 #include <openssl/ssl.h>
73 #include <openssl/err.h>
74 #include <ev.h>
75 
76 #include <nghttp2/nghttp2.h>
77 
78 #include "shrpx_config.h"
79 #include "shrpx_tls.h"
80 #include "shrpx_log_config.h"
81 #include "shrpx_worker.h"
82 #include "shrpx_http2_upstream.h"
83 #include "shrpx_http2_session.h"
84 #include "shrpx_worker_process.h"
85 #include "shrpx_process.h"
86 #include "shrpx_signal.h"
87 #include "shrpx_connection.h"
88 #include "shrpx_log.h"
89 #include "util.h"
90 #include "app_helper.h"
91 #include "tls.h"
92 #include "template.h"
93 #include "allocator.h"
94 #include "ssl_compat.h"
95 #include "xsi_strerror.h"
96 
97 extern char **environ;
98 
99 using namespace nghttp2;
100 
101 namespace shrpx {
102 
103 // Deprecated: Environment variables to tell new binary the listening
104 // socket's file descriptors.  They are not close-on-exec.
105 constexpr auto ENV_LISTENER4_FD = StringRef::from_lit("NGHTTPX_LISTENER4_FD");
106 constexpr auto ENV_LISTENER6_FD = StringRef::from_lit("NGHTTPX_LISTENER6_FD");
107 
108 // Deprecated: Environment variable to tell new binary the port number
109 // the current binary is listening to.
110 constexpr auto ENV_PORT = StringRef::from_lit("NGHTTPX_PORT");
111 
112 // Deprecated: Environment variable to tell new binary the listening
113 // socket's file descriptor if frontend listens UNIX domain socket.
114 constexpr auto ENV_UNIX_FD = StringRef::from_lit("NGHTTP2_UNIX_FD");
115 // Deprecated: Environment variable to tell new binary the UNIX domain
116 // socket path.
117 constexpr auto ENV_UNIX_PATH = StringRef::from_lit("NGHTTP2_UNIX_PATH");
118 
119 // Prefix of environment variables to tell new binary the listening
120 // socket's file descriptor.  They are not close-on-exec.  For TCP
121 // socket, the value must be comma separated 2 parameters: tcp,<FD>.
122 // <FD> is file descriptor.  For UNIX domain socket, the value must be
123 // comma separated 3 parameters: unix,<FD>,<PATH>.  <FD> is file
124 // descriptor.  <PATH> is a path to UNIX domain socket.
125 constexpr auto ENV_ACCEPT_PREFIX = StringRef::from_lit("NGHTTPX_ACCEPT_");
126 
127 // This environment variable contains PID of the original master
128 // process, assuming that it created this master process as a result
129 // of SIGUSR2.  The new master process is expected to send QUIT signal
130 // to the original master process to shut it down gracefully.
131 constexpr auto ENV_ORIG_PID = StringRef::from_lit("NGHTTPX_ORIG_PID");
132 
133 #ifndef _KERNEL_FASTOPEN
134 #  define _KERNEL_FASTOPEN
135 // conditional define for TCP_FASTOPEN mostly on ubuntu
136 #  ifndef TCP_FASTOPEN
137 #    define TCP_FASTOPEN 23
138 #  endif
139 
140 // conditional define for SOL_TCP mostly on ubuntu
141 #  ifndef SOL_TCP
142 #    define SOL_TCP 6
143 #  endif
144 #endif
145 
146 // This configuration is fixed at the first startup of the main
147 // process, and does not change after subsequent reloadings.
148 struct StartupConfig {
149   // This contains all options given in command-line.
150   std::vector<std::pair<StringRef, StringRef>> cmdcfgs;
151   // The current working directory where this process started.
152   char *cwd;
153   // The pointer to original argv (not sure why we have this?)
154   char **original_argv;
155   // The pointer to argv, this is a deep copy of original argv.
156   char **argv;
157   // The number of elements in argv.
158   int argc;
159 };
160 
161 namespace {
162 StartupConfig suconfig;
163 } // namespace
164 
165 struct InheritedAddr {
166   // IP address if TCP socket.  Otherwise, UNIX domain socket path.
167   StringRef host;
168   uint16_t port;
169   // true if UNIX domain socket path
170   bool host_unix;
171   int fd;
172   bool used;
173 };
174 
175 namespace {
176 void signal_cb(struct ev_loop *loop, ev_signal *w, int revents);
177 } // namespace
178 
179 namespace {
180 void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents);
181 } // namespace
182 
183 struct WorkerProcess {
WorkerProcessshrpx::WorkerProcess184   WorkerProcess(struct ev_loop *loop, pid_t worker_pid, int ipc_fd)
185       : loop(loop), worker_pid(worker_pid), ipc_fd(ipc_fd) {
186     ev_signal_init(&reopen_log_signalev, signal_cb, REOPEN_LOG_SIGNAL);
187     reopen_log_signalev.data = this;
188     ev_signal_start(loop, &reopen_log_signalev);
189 
190     ev_signal_init(&exec_binary_signalev, signal_cb, EXEC_BINARY_SIGNAL);
191     exec_binary_signalev.data = this;
192     ev_signal_start(loop, &exec_binary_signalev);
193 
194     ev_signal_init(&graceful_shutdown_signalev, signal_cb,
195                    GRACEFUL_SHUTDOWN_SIGNAL);
196     graceful_shutdown_signalev.data = this;
197     ev_signal_start(loop, &graceful_shutdown_signalev);
198 
199     ev_signal_init(&reload_signalev, signal_cb, RELOAD_SIGNAL);
200     reload_signalev.data = this;
201     ev_signal_start(loop, &reload_signalev);
202 
203     ev_child_init(&worker_process_childev, worker_process_child_cb, worker_pid,
204                   0);
205     worker_process_childev.data = this;
206     ev_child_start(loop, &worker_process_childev);
207   }
208 
~WorkerProcessshrpx::WorkerProcess209   ~WorkerProcess() {
210     shutdown_signal_watchers();
211 
212     ev_child_stop(loop, &worker_process_childev);
213 
214     if (ipc_fd != -1) {
215       shutdown(ipc_fd, SHUT_WR);
216       close(ipc_fd);
217     }
218   }
219 
shutdown_signal_watchersshrpx::WorkerProcess220   void shutdown_signal_watchers() {
221     ev_signal_stop(loop, &reopen_log_signalev);
222     ev_signal_stop(loop, &exec_binary_signalev);
223     ev_signal_stop(loop, &graceful_shutdown_signalev);
224     ev_signal_stop(loop, &reload_signalev);
225   }
226 
227   ev_signal reopen_log_signalev;
228   ev_signal exec_binary_signalev;
229   ev_signal graceful_shutdown_signalev;
230   ev_signal reload_signalev;
231   ev_child worker_process_childev;
232   struct ev_loop *loop;
233   pid_t worker_pid;
234   int ipc_fd;
235 };
236 
237 namespace {
238 void reload_config(WorkerProcess *wp);
239 } // namespace
240 
241 namespace {
242 std::deque<std::unique_ptr<WorkerProcess>> worker_processes;
243 } // namespace
244 
245 namespace {
worker_process_add(std::unique_ptr<WorkerProcess> wp)246 void worker_process_add(std::unique_ptr<WorkerProcess> wp) {
247   worker_processes.push_back(std::move(wp));
248 }
249 } // namespace
250 
251 namespace {
worker_process_remove(const WorkerProcess * wp)252 void worker_process_remove(const WorkerProcess *wp) {
253   for (auto it = std::begin(worker_processes); it != std::end(worker_processes);
254        ++it) {
255     auto &s = *it;
256 
257     if (s.get() != wp) {
258       continue;
259     }
260 
261     worker_processes.erase(it);
262     break;
263   }
264 }
265 } // namespace
266 
267 namespace {
worker_process_remove_all()268 void worker_process_remove_all() {
269   std::deque<std::unique_ptr<WorkerProcess>>().swap(worker_processes);
270 }
271 } // namespace
272 
273 namespace {
274 // Send signal |signum| to all worker processes, and clears
275 // worker_processes.
worker_process_kill(int signum)276 void worker_process_kill(int signum) {
277   for (auto &s : worker_processes) {
278     if (s->worker_pid == -1) {
279       continue;
280     }
281     kill(s->worker_pid, signum);
282   }
283   worker_process_remove_all();
284 }
285 } // namespace
286 
287 namespace {
288 // Returns the last PID of worker process.  Returns -1 if there is no
289 // worker process at the moment.
worker_process_last_pid()290 int worker_process_last_pid() {
291   if (worker_processes.empty()) {
292     return -1;
293   }
294 
295   return worker_processes.back()->worker_pid;
296 }
297 } // namespace
298 
299 namespace {
save_pid()300 int save_pid() {
301   std::array<char, STRERROR_BUFSIZE> errbuf;
302   auto config = get_config();
303 
304   constexpr auto SUFFIX = StringRef::from_lit(".XXXXXX");
305   auto &pid_file = config->pid_file;
306 
307   auto len = config->pid_file.size() + SUFFIX.size();
308   auto buf = std::make_unique<char[]>(len + 1);
309   auto p = buf.get();
310 
311   p = std::copy(std::begin(pid_file), std::end(pid_file), p);
312   p = std::copy(std::begin(SUFFIX), std::end(SUFFIX), p);
313   *p = '\0';
314 
315   auto temp_path = buf.get();
316 
317   auto fd = mkstemp(temp_path);
318   if (fd == -1) {
319     auto error = errno;
320     LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
321                << xsi_strerror(error, errbuf.data(), errbuf.size());
322     return -1;
323   }
324 
325   auto content = util::utos(config->pid) + '\n';
326 
327   if (write(fd, content.c_str(), content.size()) == -1) {
328     auto error = errno;
329     LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
330                << xsi_strerror(error, errbuf.data(), errbuf.size());
331     return -1;
332   }
333 
334   if (fsync(fd) == -1) {
335     auto error = errno;
336     LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
337                << xsi_strerror(error, errbuf.data(), errbuf.size());
338     return -1;
339   }
340 
341   close(fd);
342 
343   if (rename(temp_path, pid_file.c_str()) == -1) {
344     auto error = errno;
345     LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
346                << xsi_strerror(error, errbuf.data(), errbuf.size());
347 
348     unlink(temp_path);
349 
350     return -1;
351   }
352 
353   if (config->uid != 0) {
354     if (chown(pid_file.c_str(), config->uid, config->gid) == -1) {
355       auto error = errno;
356       LOG(WARN) << "Changing owner of pid file " << pid_file << " failed: "
357                 << xsi_strerror(error, errbuf.data(), errbuf.size());
358     }
359   }
360 
361   return 0;
362 }
363 } // namespace
364 
365 namespace {
shrpx_sd_notifyf(int unset_environment,const char * format,...)366 void shrpx_sd_notifyf(int unset_environment, const char *format, ...) {
367 #ifdef HAVE_LIBSYSTEMD
368   va_list args;
369 
370   va_start(args, format);
371   sd_notifyf(unset_environment, format, va_arg(args, char *));
372   va_end(args);
373 #endif // HAVE_LIBSYSTEMD
374 }
375 } // namespace
376 
377 namespace {
exec_binary()378 void exec_binary() {
379   int rv;
380   sigset_t oldset;
381   std::array<char, STRERROR_BUFSIZE> errbuf;
382 
383   LOG(NOTICE) << "Executing new binary";
384 
385   shrpx_sd_notifyf(0, "RELOADING=1");
386 
387   rv = shrpx_signal_block_all(&oldset);
388   if (rv != 0) {
389     auto error = errno;
390     LOG(ERROR) << "Blocking all signals failed: "
391                << xsi_strerror(error, errbuf.data(), errbuf.size());
392 
393     return;
394   }
395 
396   auto pid = fork();
397 
398   if (pid != 0) {
399     if (pid == -1) {
400       auto error = errno;
401       LOG(ERROR) << "fork() failed errno=" << error;
402     } else {
403       // update PID tracking information in systemd
404       shrpx_sd_notifyf(0, "MAINPID=%d\n", pid);
405     }
406 
407     rv = shrpx_signal_set(&oldset);
408 
409     if (rv != 0) {
410       auto error = errno;
411       LOG(FATAL) << "Restoring signal mask failed: "
412                  << xsi_strerror(error, errbuf.data(), errbuf.size());
413 
414       exit(EXIT_FAILURE);
415     }
416 
417     return;
418   }
419 
420   // child process
421 
422   shrpx_signal_unset_master_proc_ign_handler();
423 
424   rv = shrpx_signal_unblock_all();
425   if (rv != 0) {
426     auto error = errno;
427     LOG(ERROR) << "Unblocking all signals failed: "
428                << xsi_strerror(error, errbuf.data(), errbuf.size());
429 
430     nghttp2_Exit(EXIT_FAILURE);
431   }
432 
433   auto exec_path =
434       util::get_exec_path(suconfig.argc, suconfig.argv, suconfig.cwd);
435 
436   if (!exec_path) {
437     LOG(ERROR) << "Could not resolve the executable path";
438     nghttp2_Exit(EXIT_FAILURE);
439   }
440 
441   auto argv = std::make_unique<char *[]>(suconfig.argc + 1);
442 
443   argv[0] = exec_path;
444   for (int i = 1; i < suconfig.argc; ++i) {
445     argv[i] = suconfig.argv[i];
446   }
447   argv[suconfig.argc] = nullptr;
448 
449   size_t envlen = 0;
450   for (char **p = environ; *p; ++p, ++envlen)
451     ;
452 
453   auto config = get_config();
454   auto &listenerconf = config->conn.listener;
455 
456   // 2 for ENV_ORIG_PID and terminal nullptr.
457   auto envp =
458       std::make_unique<char *[]>(envlen + listenerconf.addrs.size() + 2);
459   size_t envidx = 0;
460 
461   std::vector<ImmutableString> fd_envs;
462   for (size_t i = 0; i < listenerconf.addrs.size(); ++i) {
463     auto &addr = listenerconf.addrs[i];
464     auto s = ENV_ACCEPT_PREFIX.str();
465     s += util::utos(i + 1);
466     s += '=';
467     if (addr.host_unix) {
468       s += "unix,";
469       s += util::utos(addr.fd);
470       s += ',';
471       s += addr.host;
472     } else {
473       s += "tcp,";
474       s += util::utos(addr.fd);
475     }
476 
477     fd_envs.emplace_back(s);
478     envp[envidx++] = const_cast<char *>(fd_envs.back().c_str());
479   }
480 
481   auto ipc_fd_str = ENV_ORIG_PID.str();
482   ipc_fd_str += '=';
483   ipc_fd_str += util::utos(config->pid);
484   envp[envidx++] = const_cast<char *>(ipc_fd_str.c_str());
485 
486   for (size_t i = 0; i < envlen; ++i) {
487     auto env = StringRef{environ[i]};
488     if (util::starts_with(env, ENV_ACCEPT_PREFIX) ||
489         util::starts_with(env, ENV_LISTENER4_FD) ||
490         util::starts_with(env, ENV_LISTENER6_FD) ||
491         util::starts_with(env, ENV_PORT) ||
492         util::starts_with(env, ENV_UNIX_FD) ||
493         util::starts_with(env, ENV_UNIX_PATH) ||
494         util::starts_with(env, ENV_ORIG_PID)) {
495       continue;
496     }
497 
498     envp[envidx++] = environ[i];
499   }
500 
501   envp[envidx++] = nullptr;
502 
503   if (LOG_ENABLED(INFO)) {
504     LOG(INFO) << "cmdline";
505     for (int i = 0; argv[i]; ++i) {
506       LOG(INFO) << i << ": " << argv[i];
507     }
508     LOG(INFO) << "environ";
509     for (int i = 0; envp[i]; ++i) {
510       LOG(INFO) << i << ": " << envp[i];
511     }
512   }
513 
514   // restores original stderr
515   restore_original_fds();
516 
517   // reloading finished
518   shrpx_sd_notifyf(0, "READY=1");
519 
520   if (execve(argv[0], argv.get(), envp.get()) == -1) {
521     auto error = errno;
522     LOG(ERROR) << "execve failed: errno=" << error;
523     nghttp2_Exit(EXIT_FAILURE);
524   }
525 }
526 } // namespace
527 
528 namespace {
ipc_send(WorkerProcess * wp,uint8_t ipc_event)529 void ipc_send(WorkerProcess *wp, uint8_t ipc_event) {
530   std::array<char, STRERROR_BUFSIZE> errbuf;
531   ssize_t nwrite;
532   while ((nwrite = write(wp->ipc_fd, &ipc_event, 1)) == -1 && errno == EINTR)
533     ;
534 
535   if (nwrite < 0) {
536     auto error = errno;
537     LOG(ERROR) << "Could not send IPC event to worker process: "
538                << xsi_strerror(error, errbuf.data(), errbuf.size());
539     return;
540   }
541 
542   if (nwrite == 0) {
543     LOG(ERROR) << "Could not send IPC event due to pipe overflow";
544     return;
545   }
546 }
547 } // namespace
548 
549 namespace {
reopen_log(WorkerProcess * wp)550 void reopen_log(WorkerProcess *wp) {
551   LOG(NOTICE) << "Reopening log files: master process";
552 
553   auto config = get_config();
554   auto &loggingconf = config->logging;
555 
556   (void)reopen_log_files(loggingconf);
557   redirect_stderr_to_errorlog(loggingconf);
558   ipc_send(wp, SHRPX_IPC_REOPEN_LOG);
559 }
560 } // namespace
561 
562 namespace {
signal_cb(struct ev_loop * loop,ev_signal * w,int revents)563 void signal_cb(struct ev_loop *loop, ev_signal *w, int revents) {
564   auto wp = static_cast<WorkerProcess *>(w->data);
565   if (wp->worker_pid == -1) {
566     ev_break(loop);
567     return;
568   }
569 
570   switch (w->signum) {
571   case REOPEN_LOG_SIGNAL:
572     reopen_log(wp);
573     return;
574   case EXEC_BINARY_SIGNAL:
575     exec_binary();
576     return;
577   case GRACEFUL_SHUTDOWN_SIGNAL: {
578     auto &listenerconf = get_config()->conn.listener;
579     for (auto &addr : listenerconf.addrs) {
580       close(addr.fd);
581     }
582     ipc_send(wp, SHRPX_IPC_GRACEFUL_SHUTDOWN);
583     return;
584   }
585   case RELOAD_SIGNAL:
586     reload_config(wp);
587     return;
588   default:
589     worker_process_kill(w->signum);
590     ev_break(loop);
591     return;
592   }
593 }
594 } // namespace
595 
596 namespace {
worker_process_child_cb(struct ev_loop * loop,ev_child * w,int revents)597 void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents) {
598   auto wp = static_cast<WorkerProcess *>(w->data);
599 
600   log_chld(w->rpid, w->rstatus, "Worker process");
601 
602   auto pid = wp->worker_pid;
603 
604   worker_process_remove(wp);
605 
606   if (worker_process_last_pid() == pid) {
607     ev_break(loop);
608   }
609 }
610 } // namespace
611 
612 namespace {
create_unix_domain_server_socket(UpstreamAddr & faddr,std::vector<InheritedAddr> & iaddrs)613 int create_unix_domain_server_socket(UpstreamAddr &faddr,
614                                      std::vector<InheritedAddr> &iaddrs) {
615   std::array<char, STRERROR_BUFSIZE> errbuf;
616   auto found = std::find_if(
617       std::begin(iaddrs), std::end(iaddrs), [&faddr](const InheritedAddr &ia) {
618         return !ia.used && ia.host_unix && ia.host == faddr.host;
619       });
620 
621   if (found != std::end(iaddrs)) {
622     LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host
623                 << (faddr.tls ? ", tls" : "");
624     (*found).used = true;
625     faddr.fd = (*found).fd;
626     faddr.hostport = StringRef::from_lit("localhost");
627 
628     return 0;
629   }
630 
631 #ifdef SOCK_NONBLOCK
632   auto fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
633   if (fd == -1) {
634     auto error = errno;
635     LOG(FATAL) << "socket() syscall failed: "
636                << xsi_strerror(error, errbuf.data(), errbuf.size());
637     return -1;
638   }
639 #else  // !SOCK_NONBLOCK
640   auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
641   if (fd == -1) {
642     auto error = errno;
643     LOG(FATAL) << "socket() syscall failed: "
644                << xsi_strerror(error, errbuf.data(), errbuf.size());
645     return -1;
646   }
647   util::make_socket_nonblocking(fd);
648 #endif // !SOCK_NONBLOCK
649   int val = 1;
650   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
651                  static_cast<socklen_t>(sizeof(val))) == -1) {
652     auto error = errno;
653     LOG(FATAL) << "Failed to set SO_REUSEADDR option to listener socket: "
654                << xsi_strerror(error, errbuf.data(), errbuf.size());
655     close(fd);
656     return -1;
657   }
658 
659   sockaddr_union addr;
660   addr.un.sun_family = AF_UNIX;
661   if (faddr.host.size() + 1 > sizeof(addr.un.sun_path)) {
662     LOG(FATAL) << "UNIX domain socket path " << faddr.host << " is too long > "
663                << sizeof(addr.un.sun_path);
664     close(fd);
665     return -1;
666   }
667   // copy path including terminal NULL
668   std::copy_n(faddr.host.c_str(), faddr.host.size() + 1, addr.un.sun_path);
669 
670   // unlink (remove) already existing UNIX domain socket path
671   unlink(faddr.host.c_str());
672 
673   if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) {
674     auto error = errno;
675     LOG(FATAL) << "Failed to bind UNIX domain socket: "
676                << xsi_strerror(error, errbuf.data(), errbuf.size());
677     close(fd);
678     return -1;
679   }
680 
681   auto &listenerconf = get_config()->conn.listener;
682 
683   if (listen(fd, listenerconf.backlog) != 0) {
684     auto error = errno;
685     LOG(FATAL) << "Failed to listen to UNIX domain socket: "
686                << xsi_strerror(error, errbuf.data(), errbuf.size());
687     close(fd);
688     return -1;
689   }
690 
691   LOG(NOTICE) << "Listening on UNIX domain socket " << faddr.host
692               << (faddr.tls ? ", tls" : "");
693 
694   faddr.fd = fd;
695   faddr.hostport = StringRef::from_lit("localhost");
696 
697   return 0;
698 }
699 } // namespace
700 
701 namespace {
create_tcp_server_socket(UpstreamAddr & faddr,std::vector<InheritedAddr> & iaddrs)702 int create_tcp_server_socket(UpstreamAddr &faddr,
703                              std::vector<InheritedAddr> &iaddrs) {
704   std::array<char, STRERROR_BUFSIZE> errbuf;
705   int fd = -1;
706   int rv;
707 
708   auto &listenerconf = get_config()->conn.listener;
709 
710   auto service = util::utos(faddr.port);
711   addrinfo hints{};
712   hints.ai_family = faddr.family;
713   hints.ai_socktype = SOCK_STREAM;
714   hints.ai_flags = AI_PASSIVE;
715 #ifdef AI_ADDRCONFIG
716   hints.ai_flags |= AI_ADDRCONFIG;
717 #endif // AI_ADDRCONFIG
718 
719   auto node =
720       faddr.host == StringRef::from_lit("*") ? nullptr : faddr.host.c_str();
721 
722   addrinfo *res, *rp;
723   rv = getaddrinfo(node, service.c_str(), &hints, &res);
724 #ifdef AI_ADDRCONFIG
725   if (rv != 0) {
726     // Retry without AI_ADDRCONFIG
727     hints.ai_flags &= ~AI_ADDRCONFIG;
728     rv = getaddrinfo(node, service.c_str(), &hints, &res);
729   }
730 #endif // AI_ADDRCONFIG
731   if (rv != 0) {
732     LOG(FATAL) << "Unable to get IPv" << (faddr.family == AF_INET ? "4" : "6")
733                << " address for " << faddr.host << ", port " << faddr.port
734                << ": " << gai_strerror(rv);
735     return -1;
736   }
737 
738   auto res_d = defer(freeaddrinfo, res);
739 
740   std::array<char, NI_MAXHOST> host;
741 
742   for (rp = res; rp; rp = rp->ai_next) {
743 
744     rv = getnameinfo(rp->ai_addr, rp->ai_addrlen, host.data(), host.size(),
745                      nullptr, 0, NI_NUMERICHOST);
746 
747     if (rv != 0) {
748       LOG(WARN) << "getnameinfo() failed: " << gai_strerror(rv);
749       continue;
750     }
751 
752     auto found = std::find_if(std::begin(iaddrs), std::end(iaddrs),
753                               [&host, &faddr](const InheritedAddr &ia) {
754                                 return !ia.used && !ia.host_unix &&
755                                        ia.host == host.data() &&
756                                        ia.port == faddr.port;
757                               });
758 
759     if (found != std::end(iaddrs)) {
760       (*found).used = true;
761       fd = (*found).fd;
762       break;
763     }
764 
765 #ifdef SOCK_NONBLOCK
766     fd =
767         socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
768     if (fd == -1) {
769       auto error = errno;
770       LOG(WARN) << "socket() syscall failed: "
771                 << xsi_strerror(error, errbuf.data(), errbuf.size());
772       continue;
773     }
774 #else  // !SOCK_NONBLOCK
775     fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
776     if (fd == -1) {
777       auto error = errno;
778       LOG(WARN) << "socket() syscall failed: "
779                 << xsi_strerror(error, errbuf.data(), errbuf.size());
780       continue;
781     }
782     util::make_socket_nonblocking(fd);
783 #endif // !SOCK_NONBLOCK
784     int val = 1;
785     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
786                    static_cast<socklen_t>(sizeof(val))) == -1) {
787       auto error = errno;
788       LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: "
789                 << xsi_strerror(error, errbuf.data(), errbuf.size());
790       close(fd);
791       continue;
792     }
793 
794 #ifdef IPV6_V6ONLY
795     if (faddr.family == AF_INET6) {
796       if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
797                      static_cast<socklen_t>(sizeof(val))) == -1) {
798         auto error = errno;
799         LOG(WARN) << "Failed to set IPV6_V6ONLY option to listener socket: "
800                   << xsi_strerror(error, errbuf.data(), errbuf.size());
801         close(fd);
802         continue;
803       }
804     }
805 #endif // IPV6_V6ONLY
806 
807 #ifdef TCP_DEFER_ACCEPT
808     val = 3;
809     if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val,
810                    static_cast<socklen_t>(sizeof(val))) == -1) {
811       auto error = errno;
812       LOG(WARN) << "Failed to set TCP_DEFER_ACCEPT option to listener socket: "
813                 << xsi_strerror(error, errbuf.data(), errbuf.size());
814     }
815 #endif // TCP_DEFER_ACCEPT
816 
817     // When we are executing new binary, and the old binary did not
818     // bind privileged port (< 1024) for some reason, binding to those
819     // ports will fail with permission denied error.
820     if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
821       auto error = errno;
822       LOG(WARN) << "bind() syscall failed: "
823                 << xsi_strerror(error, errbuf.data(), errbuf.size());
824       close(fd);
825       continue;
826     }
827 
828     if (listenerconf.fastopen > 0) {
829       val = listenerconf.fastopen;
830       if (setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &val,
831                      static_cast<socklen_t>(sizeof(val))) == -1) {
832         auto error = errno;
833         LOG(WARN) << "Failed to set TCP_FASTOPEN option to listener socket: "
834                   << xsi_strerror(error, errbuf.data(), errbuf.size());
835       }
836     }
837 
838     if (listen(fd, listenerconf.backlog) == -1) {
839       auto error = errno;
840       LOG(WARN) << "listen() syscall failed: "
841                 << xsi_strerror(error, errbuf.data(), errbuf.size());
842       close(fd);
843       continue;
844     }
845 
846     break;
847   }
848 
849   if (!rp) {
850     LOG(FATAL) << "Listening " << (faddr.family == AF_INET ? "IPv4" : "IPv6")
851                << " socket failed";
852 
853     return -1;
854   }
855 
856   faddr.fd = fd;
857   faddr.hostport = util::make_http_hostport(mod_config()->balloc,
858                                             StringRef{host.data()}, faddr.port);
859 
860   LOG(NOTICE) << "Listening on " << faddr.hostport
861               << (faddr.tls ? ", tls" : "");
862 
863   return 0;
864 }
865 } // namespace
866 
867 namespace {
868 // Returns array of InheritedAddr constructed from |config|.  This
869 // function is intended to be used when reloading configuration, and
870 // |config| is usually a current configuration.
871 std::vector<InheritedAddr>
get_inherited_addr_from_config(BlockAllocator & balloc,Config * config)872 get_inherited_addr_from_config(BlockAllocator &balloc, Config *config) {
873   std::array<char, STRERROR_BUFSIZE> errbuf;
874   int rv;
875 
876   auto &listenerconf = config->conn.listener;
877 
878   std::vector<InheritedAddr> iaddrs(listenerconf.addrs.size());
879 
880   size_t idx = 0;
881   for (auto &addr : listenerconf.addrs) {
882     auto &iaddr = iaddrs[idx++];
883 
884     if (addr.host_unix) {
885       iaddr.host = addr.host;
886       iaddr.host_unix = true;
887       iaddr.fd = addr.fd;
888 
889       continue;
890     }
891 
892     iaddr.port = addr.port;
893     iaddr.fd = addr.fd;
894 
895     // We have to getsockname/getnameinfo for fd, since we may have
896     // '*' appear in addr.host, which makes comparison against "real"
897     // address fail.
898 
899     sockaddr_union su;
900     socklen_t salen = sizeof(su);
901 
902     // We already added entry to iaddrs.  Even if we got errors, we
903     // don't remove it.  This is required because we have to close the
904     // socket if it is not reused.  The empty host name usually does
905     // not match anything.
906 
907     if (getsockname(addr.fd, &su.sa, &salen) != 0) {
908       auto error = errno;
909       LOG(WARN) << "getsockname() syscall failed (fd=" << addr.fd
910                 << "): " << xsi_strerror(error, errbuf.data(), errbuf.size());
911       continue;
912     }
913 
914     std::array<char, NI_MAXHOST> host;
915     rv = getnameinfo(&su.sa, salen, host.data(), host.size(), nullptr, 0,
916                      NI_NUMERICHOST);
917     if (rv != 0) {
918       LOG(WARN) << "getnameinfo() failed (fd=" << addr.fd
919                 << "): " << gai_strerror(rv);
920       continue;
921     }
922 
923     iaddr.host = make_string_ref(balloc, StringRef{host.data()});
924   }
925 
926   return iaddrs;
927 }
928 } // namespace
929 
930 namespace {
931 // Returns array of InheritedAddr constructed from environment
932 // variables.  This function handles the old environment variable
933 // names used in 1.7.0 or earlier.
get_inherited_addr_from_env(Config * config)934 std::vector<InheritedAddr> get_inherited_addr_from_env(Config *config) {
935   std::array<char, STRERROR_BUFSIZE> errbuf;
936   int rv;
937   std::vector<InheritedAddr> iaddrs;
938 
939   {
940     // Upgrade from 1.7.0 or earlier
941     auto portenv = getenv(ENV_PORT.c_str());
942     if (portenv) {
943       size_t i = 1;
944       for (auto env_name : {ENV_LISTENER4_FD, ENV_LISTENER6_FD}) {
945         auto fdenv = getenv(env_name.c_str());
946         if (fdenv) {
947           auto name = ENV_ACCEPT_PREFIX.str();
948           name += util::utos(i);
949           std::string value = "tcp,";
950           value += fdenv;
951           setenv(name.c_str(), value.c_str(), 0);
952           ++i;
953         }
954       }
955     } else {
956       // The return value of getenv may be allocated statically.
957       if (getenv(ENV_UNIX_PATH.c_str()) && getenv(ENV_UNIX_FD.c_str())) {
958         auto name = ENV_ACCEPT_PREFIX.str();
959         name += '1';
960         std::string value = "unix,";
961         value += getenv(ENV_UNIX_FD.c_str());
962         value += ',';
963         value += getenv(ENV_UNIX_PATH.c_str());
964         setenv(name.c_str(), value.c_str(), 0);
965       }
966     }
967   }
968 
969   for (size_t i = 1;; ++i) {
970     auto name = ENV_ACCEPT_PREFIX.str();
971     name += util::utos(i);
972     auto env = getenv(name.c_str());
973     if (!env) {
974       break;
975     }
976 
977     if (LOG_ENABLED(INFO)) {
978       LOG(INFO) << "Read env " << name << "=" << env;
979     }
980 
981     auto end_type = strchr(env, ',');
982     if (!end_type) {
983       continue;
984     }
985 
986     auto type = StringRef(env, end_type);
987     auto value = end_type + 1;
988 
989     if (type == StringRef::from_lit("unix")) {
990       auto endfd = strchr(value, ',');
991       if (!endfd) {
992         continue;
993       }
994       auto fd = util::parse_uint(reinterpret_cast<const uint8_t *>(value),
995                                  endfd - value);
996       if (fd == -1) {
997         LOG(WARN) << "Could not parse file descriptor from "
998                   << std::string(value, endfd - value);
999         continue;
1000       }
1001 
1002       auto path = endfd + 1;
1003       if (strlen(path) == 0) {
1004         LOG(WARN) << "Empty UNIX domain socket path (fd=" << fd << ")";
1005         close(fd);
1006         continue;
1007       }
1008 
1009       if (LOG_ENABLED(INFO)) {
1010         LOG(INFO) << "Inherit UNIX domain socket fd=" << fd
1011                   << ", path=" << path;
1012       }
1013 
1014       InheritedAddr addr{};
1015       addr.host = make_string_ref(config->balloc, StringRef{path});
1016       addr.host_unix = true;
1017       addr.fd = static_cast<int>(fd);
1018       iaddrs.push_back(std::move(addr));
1019     }
1020 
1021     if (type == StringRef::from_lit("tcp")) {
1022       auto fd = util::parse_uint(value);
1023       if (fd == -1) {
1024         LOG(WARN) << "Could not parse file descriptor from " << value;
1025         continue;
1026       }
1027 
1028       sockaddr_union su;
1029       socklen_t salen = sizeof(su);
1030 
1031       if (getsockname(fd, &su.sa, &salen) != 0) {
1032         auto error = errno;
1033         LOG(WARN) << "getsockname() syscall failed (fd=" << fd
1034                   << "): " << xsi_strerror(error, errbuf.data(), errbuf.size());
1035         close(fd);
1036         continue;
1037       }
1038 
1039       uint16_t port;
1040 
1041       switch (su.storage.ss_family) {
1042       case AF_INET:
1043         port = ntohs(su.in.sin_port);
1044         break;
1045       case AF_INET6:
1046         port = ntohs(su.in6.sin6_port);
1047         break;
1048       default:
1049         close(fd);
1050         continue;
1051       }
1052 
1053       std::array<char, NI_MAXHOST> host;
1054       rv = getnameinfo(&su.sa, salen, host.data(), host.size(), nullptr, 0,
1055                        NI_NUMERICHOST);
1056       if (rv != 0) {
1057         LOG(WARN) << "getnameinfo() failed (fd=" << fd
1058                   << "): " << gai_strerror(rv);
1059         close(fd);
1060         continue;
1061       }
1062 
1063       if (LOG_ENABLED(INFO)) {
1064         LOG(INFO) << "Inherit TCP socket fd=" << fd
1065                   << ", address=" << host.data() << ", port=" << port;
1066       }
1067 
1068       InheritedAddr addr{};
1069       addr.host = make_string_ref(config->balloc, StringRef{host.data()});
1070       addr.port = static_cast<uint16_t>(port);
1071       addr.fd = static_cast<int>(fd);
1072       iaddrs.push_back(std::move(addr));
1073       continue;
1074     }
1075   }
1076 
1077   return iaddrs;
1078 }
1079 } // namespace
1080 
1081 namespace {
1082 // Closes all sockets which are not reused.
close_unused_inherited_addr(const std::vector<InheritedAddr> & iaddrs)1083 void close_unused_inherited_addr(const std::vector<InheritedAddr> &iaddrs) {
1084   for (auto &ia : iaddrs) {
1085     if (ia.used) {
1086       continue;
1087     }
1088 
1089     close(ia.fd);
1090   }
1091 }
1092 } // namespace
1093 
1094 namespace {
1095 // Returns the PID of the original master process from environment
1096 // variable ENV_ORIG_PID.
get_orig_pid_from_env()1097 pid_t get_orig_pid_from_env() {
1098   auto s = getenv(ENV_ORIG_PID.c_str());
1099   if (s == nullptr) {
1100     return -1;
1101   }
1102   return util::parse_uint(s);
1103 }
1104 } // namespace
1105 
1106 namespace {
create_acceptor_socket(Config * config,std::vector<InheritedAddr> & iaddrs)1107 int create_acceptor_socket(Config *config, std::vector<InheritedAddr> &iaddrs) {
1108   std::array<char, STRERROR_BUFSIZE> errbuf;
1109   auto &listenerconf = config->conn.listener;
1110 
1111   for (auto &addr : listenerconf.addrs) {
1112     if (addr.host_unix) {
1113       if (create_unix_domain_server_socket(addr, iaddrs) != 0) {
1114         return -1;
1115       }
1116 
1117       if (config->uid != 0) {
1118         // fd is not associated to inode, so we cannot use fchown(2)
1119         // here.  https://lkml.org/lkml/2004/11/1/84
1120         if (chown(addr.host.c_str(), config->uid, config->gid) == -1) {
1121           auto error = errno;
1122           LOG(WARN) << "Changing owner of UNIX domain socket " << addr.host
1123                     << " failed: "
1124                     << xsi_strerror(error, errbuf.data(), errbuf.size());
1125         }
1126       }
1127       continue;
1128     }
1129 
1130     if (create_tcp_server_socket(addr, iaddrs) != 0) {
1131       return -1;
1132     }
1133   }
1134 
1135   return 0;
1136 }
1137 } // namespace
1138 
1139 namespace {
call_daemon()1140 int call_daemon() {
1141 #ifdef __sgi
1142   return _daemonize(0, 0, 0, 0);
1143 #else // !__sgi
1144 #  ifdef HAVE_LIBSYSTEMD
1145   if (sd_booted() && (getenv("NOTIFY_SOCKET") != nullptr)) {
1146     LOG(NOTICE) << "Daemonising disabled under systemd";
1147     chdir("/");
1148     return 0;
1149   }
1150 #  endif // HAVE_LIBSYSTEMD
1151   return util::daemonize(0, 0);
1152 #endif   // !__sgi
1153 }
1154 } // namespace
1155 
1156 namespace {
1157 // Opens IPC socket used to communicate with worker proess.  The
1158 // communication is unidirectional; that is main process sends
1159 // messages to the worker process.  On success, ipc_fd[0] is for
1160 // reading, and ipc_fd[1] for writing, just like pipe(2).
create_ipc_socket(std::array<int,2> & ipc_fd)1161 int create_ipc_socket(std::array<int, 2> &ipc_fd) {
1162   std::array<char, STRERROR_BUFSIZE> errbuf;
1163   int rv;
1164 
1165   rv = pipe(ipc_fd.data());
1166   if (rv == -1) {
1167     auto error = errno;
1168     LOG(WARN) << "Failed to create pipe to communicate worker process: "
1169               << xsi_strerror(error, errbuf.data(), errbuf.size());
1170     return -1;
1171   }
1172 
1173   for (int i = 0; i < 2; ++i) {
1174     auto fd = ipc_fd[i];
1175     util::make_socket_nonblocking(fd);
1176     util::make_socket_closeonexec(fd);
1177   }
1178 
1179   return 0;
1180 }
1181 } // namespace
1182 
1183 namespace {
1184 // Creates worker process, and returns PID of worker process.  On
1185 // success, file descriptor for IPC (send only) is assigned to
1186 // |main_ipc_fd|.  In child process, we will close file descriptors
1187 // which are inherited from previous configuration/process, but not
1188 // used in the current configuration.
fork_worker_process(int & main_ipc_fd,const std::vector<InheritedAddr> & iaddrs)1189 pid_t fork_worker_process(int &main_ipc_fd,
1190                           const std::vector<InheritedAddr> &iaddrs) {
1191   std::array<char, STRERROR_BUFSIZE> errbuf;
1192   int rv;
1193   sigset_t oldset;
1194 
1195   std::array<int, 2> ipc_fd;
1196 
1197   rv = create_ipc_socket(ipc_fd);
1198   if (rv != 0) {
1199     return -1;
1200   }
1201 
1202   rv = shrpx_signal_block_all(&oldset);
1203   if (rv != 0) {
1204     auto error = errno;
1205     LOG(ERROR) << "Blocking all signals failed: "
1206                << xsi_strerror(error, errbuf.data(), errbuf.size());
1207 
1208     close(ipc_fd[0]);
1209     close(ipc_fd[1]);
1210 
1211     return -1;
1212   }
1213 
1214   auto config = get_config();
1215 
1216   pid_t pid = 0;
1217 
1218   if (!config->single_process) {
1219     pid = fork();
1220   }
1221 
1222   if (pid == 0) {
1223     ev_loop_fork(EV_DEFAULT);
1224 
1225     for (auto &addr : config->conn.listener.addrs) {
1226       util::make_socket_closeonexec(addr.fd);
1227     }
1228 
1229     // Remove all WorkerProcesses to stop any registered watcher on
1230     // default loop.
1231     worker_process_remove_all();
1232 
1233     close_unused_inherited_addr(iaddrs);
1234 
1235     shrpx_signal_set_worker_proc_ign_handler();
1236 
1237     rv = shrpx_signal_unblock_all();
1238     if (rv != 0) {
1239       auto error = errno;
1240       LOG(FATAL) << "Unblocking all signals failed: "
1241                  << xsi_strerror(error, errbuf.data(), errbuf.size());
1242 
1243       if (config->single_process) {
1244         exit(EXIT_FAILURE);
1245       } else {
1246         nghttp2_Exit(EXIT_FAILURE);
1247       }
1248     }
1249 
1250     if (!config->single_process) {
1251       close(ipc_fd[1]);
1252     }
1253 
1254     WorkerProcessConfig wpconf{ipc_fd[0]};
1255     rv = worker_process_event_loop(&wpconf);
1256     if (rv != 0) {
1257       LOG(FATAL) << "Worker process returned error";
1258 
1259       if (config->single_process) {
1260         exit(EXIT_FAILURE);
1261       } else {
1262         nghttp2_Exit(EXIT_FAILURE);
1263       }
1264     }
1265 
1266     LOG(NOTICE) << "Worker process shutting down momentarily";
1267 
1268     // call exit(...) instead of nghttp2_Exit to get leak sanitizer report
1269     if (config->single_process) {
1270       exit(EXIT_SUCCESS);
1271     } else {
1272       nghttp2_Exit(EXIT_SUCCESS);
1273     }
1274   }
1275 
1276   // parent process
1277   if (pid == -1) {
1278     auto error = errno;
1279     LOG(ERROR) << "Could not spawn worker process: "
1280                << xsi_strerror(error, errbuf.data(), errbuf.size());
1281   }
1282 
1283   rv = shrpx_signal_set(&oldset);
1284   if (rv != 0) {
1285     auto error = errno;
1286     LOG(FATAL) << "Restoring signal mask failed: "
1287                << xsi_strerror(error, errbuf.data(), errbuf.size());
1288 
1289     exit(EXIT_FAILURE);
1290   }
1291 
1292   if (pid == -1) {
1293     close(ipc_fd[0]);
1294     close(ipc_fd[1]);
1295 
1296     return -1;
1297   }
1298 
1299   close(ipc_fd[0]);
1300 
1301   main_ipc_fd = ipc_fd[1];
1302 
1303   LOG(NOTICE) << "Worker process [" << pid << "] spawned";
1304 
1305   return pid;
1306 }
1307 } // namespace
1308 
1309 namespace {
event_loop()1310 int event_loop() {
1311   std::array<char, STRERROR_BUFSIZE> errbuf;
1312 
1313   shrpx_signal_set_master_proc_ign_handler();
1314 
1315   auto config = mod_config();
1316 
1317   if (config->daemon) {
1318     if (call_daemon() == -1) {
1319       auto error = errno;
1320       LOG(FATAL) << "Failed to daemonize: "
1321                  << xsi_strerror(error, errbuf.data(), errbuf.size());
1322       return -1;
1323     }
1324 
1325     // We get new PID after successful daemon().
1326     mod_config()->pid = getpid();
1327 
1328     // daemon redirects stderr file descriptor to /dev/null, so we
1329     // need this.
1330     redirect_stderr_to_errorlog(config->logging);
1331   }
1332 
1333   // update systemd PID tracking
1334   shrpx_sd_notifyf(0, "MAINPID=%d\n", config->pid);
1335 
1336   {
1337     auto iaddrs = get_inherited_addr_from_env(config);
1338 
1339     if (create_acceptor_socket(config, iaddrs) != 0) {
1340       return -1;
1341     }
1342 
1343     close_unused_inherited_addr(iaddrs);
1344   }
1345 
1346   auto orig_pid = get_orig_pid_from_env();
1347 
1348   auto loop = ev_default_loop(config->ev_loop_flags);
1349 
1350   int ipc_fd = 0;
1351 
1352   auto pid = fork_worker_process(ipc_fd, {});
1353 
1354   if (pid == -1) {
1355     return -1;
1356   }
1357 
1358   worker_process_add(std::make_unique<WorkerProcess>(loop, pid, ipc_fd));
1359 
1360   // Write PID file when we are ready to accept connection from peer.
1361   // This makes easier to write restart script for nghttpx.  Because
1362   // when we know that PID file is recreated, it means we can send
1363   // QUIT signal to the old process to make it shutdown gracefully.
1364   if (!config->pid_file.empty()) {
1365     save_pid();
1366   }
1367 
1368   // ready to serve requests
1369   shrpx_sd_notifyf(0, "READY=1");
1370 
1371   if (orig_pid != -1) {
1372     LOG(NOTICE) << "Send QUIT signal to the original master process to tell "
1373                    "that we are ready to serve requests.";
1374     kill(orig_pid, SIGQUIT);
1375   }
1376 
1377   ev_run(loop, 0);
1378 
1379   return 0;
1380 }
1381 } // namespace
1382 
1383 namespace {
1384 // Returns true if regular file or symbolic link |path| exists.
conf_exists(const char * path)1385 bool conf_exists(const char *path) {
1386   struct stat buf;
1387   int rv = stat(path, &buf);
1388   return rv == 0 && (buf.st_mode & (S_IFREG | S_IFLNK));
1389 }
1390 } // namespace
1391 
1392 namespace {
1393 constexpr auto DEFAULT_NPN_LIST =
1394     StringRef::from_lit("h2,h2-16,h2-14,http/1.1");
1395 } // namespace
1396 
1397 namespace {
1398 constexpr auto DEFAULT_TLS_MIN_PROTO_VERSION = StringRef::from_lit("TLSv1.2");
1399 #ifdef TLS1_3_VERSION
1400 constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.3");
1401 #else  // !TLS1_3_VERSION
1402 constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.2");
1403 #endif // !TLS1_3_VERSION
1404 } // namespace
1405 
1406 namespace {
1407 constexpr auto DEFAULT_ACCESSLOG_FORMAT =
1408     StringRef::from_lit(R"($remote_addr - - [$time_local] )"
1409                         R"("$request" $status $body_bytes_sent )"
1410                         R"("$http_referer" "$http_user_agent")");
1411 } // namespace
1412 
1413 namespace {
fill_default_config(Config * config)1414 void fill_default_config(Config *config) {
1415   config->num_worker = 1;
1416   config->conf_path = StringRef::from_lit("/etc/nghttpx/nghttpx.conf");
1417   config->pid = getpid();
1418 
1419 #ifdef NOTHREADS
1420   config->single_thread = true;
1421 #endif // NOTHREADS
1422 
1423   if (ev_supported_backends() & ~ev_recommended_backends() & EVBACKEND_KQUEUE) {
1424     config->ev_loop_flags = ev_recommended_backends() | EVBACKEND_KQUEUE;
1425   }
1426 
1427   auto &tlsconf = config->tls;
1428   {
1429     auto &ticketconf = tlsconf.ticket;
1430     {
1431       auto &memcachedconf = ticketconf.memcached;
1432       memcachedconf.max_retry = 3;
1433       memcachedconf.max_fail = 2;
1434       memcachedconf.interval = 10_min;
1435       memcachedconf.family = AF_UNSPEC;
1436     }
1437 
1438     auto &session_cacheconf = tlsconf.session_cache;
1439     {
1440       auto &memcachedconf = session_cacheconf.memcached;
1441       memcachedconf.family = AF_UNSPEC;
1442     }
1443 
1444     ticketconf.cipher = EVP_aes_128_cbc();
1445   }
1446 
1447   {
1448     auto &ocspconf = tlsconf.ocsp;
1449     // ocsp update interval = 14400 secs = 4 hours, borrowed from h2o
1450     ocspconf.update_interval = 4_h;
1451     ocspconf.fetch_ocsp_response_file =
1452         StringRef::from_lit(PKGDATADIR "/fetch-ocsp-response");
1453   }
1454 
1455   {
1456     auto &dyn_recconf = tlsconf.dyn_rec;
1457     dyn_recconf.warmup_threshold = 1_m;
1458     dyn_recconf.idle_timeout = 1_s;
1459   }
1460 
1461   tlsconf.session_timeout = std::chrono::hours(12);
1462   tlsconf.ciphers = StringRef::from_lit(nghttp2::tls::DEFAULT_CIPHER_LIST);
1463   tlsconf.tls13_ciphers =
1464       StringRef::from_lit(nghttp2::tls::DEFAULT_TLS13_CIPHER_LIST);
1465   tlsconf.client.ciphers =
1466       StringRef::from_lit(nghttp2::tls::DEFAULT_CIPHER_LIST);
1467   tlsconf.client.tls13_ciphers =
1468       StringRef::from_lit(nghttp2::tls::DEFAULT_TLS13_CIPHER_LIST);
1469   tlsconf.min_proto_version =
1470       tls::proto_version_from_string(DEFAULT_TLS_MIN_PROTO_VERSION);
1471   tlsconf.max_proto_version =
1472       tls::proto_version_from_string(DEFAULT_TLS_MAX_PROTO_VERSION);
1473   tlsconf.max_early_data = 16_k;
1474 #if OPENSSL_1_1_API || defined(OPENSSL_IS_BORINGSSL)
1475   tlsconf.ecdh_curves = StringRef::from_lit("X25519:P-256:P-384:P-521");
1476 #else  // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
1477   tlsconf.ecdh_curves = StringRef::from_lit("P-256:P-384:P-521");
1478 #endif // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
1479 
1480   auto &httpconf = config->http;
1481   httpconf.server_name = StringRef::from_lit("nghttpx");
1482   httpconf.no_host_rewrite = true;
1483   httpconf.request_header_field_buffer = 64_k;
1484   httpconf.max_request_header_fields = 100;
1485   httpconf.response_header_field_buffer = 64_k;
1486   httpconf.max_response_header_fields = 500;
1487   httpconf.redirect_https_port = StringRef::from_lit("443");
1488   httpconf.max_requests = std::numeric_limits<size_t>::max();
1489   httpconf.xfp.add = true;
1490   httpconf.xfp.strip_incoming = true;
1491   httpconf.early_data.strip_incoming = true;
1492 
1493   auto &http2conf = config->http2;
1494   {
1495     auto &upstreamconf = http2conf.upstream;
1496 
1497     {
1498       auto &timeoutconf = upstreamconf.timeout;
1499       timeoutconf.settings = 10_s;
1500     }
1501 
1502     // window size for HTTP/2 upstream connection per stream.  2**16-1
1503     // = 64KiB-1, which is HTTP/2 default.
1504     upstreamconf.window_size = 64_k - 1;
1505     // HTTP/2 has connection-level flow control. The default window
1506     // size for HTTP/2 is 64KiB - 1.
1507     upstreamconf.connection_window_size = 64_k - 1;
1508     upstreamconf.max_concurrent_streams = 100;
1509 
1510     upstreamconf.encoder_dynamic_table_size = 4_k;
1511     upstreamconf.decoder_dynamic_table_size = 4_k;
1512 
1513     nghttp2_option_new(&upstreamconf.option);
1514     nghttp2_option_set_no_auto_window_update(upstreamconf.option, 1);
1515     nghttp2_option_set_no_recv_client_magic(upstreamconf.option, 1);
1516     nghttp2_option_set_max_deflate_dynamic_table_size(
1517         upstreamconf.option, upstreamconf.encoder_dynamic_table_size);
1518 
1519     // For API endpoint, we enable automatic window update.  This is
1520     // because we are a sink.
1521     nghttp2_option_new(&upstreamconf.alt_mode_option);
1522     nghttp2_option_set_no_recv_client_magic(upstreamconf.alt_mode_option, 1);
1523     nghttp2_option_set_max_deflate_dynamic_table_size(
1524         upstreamconf.alt_mode_option, upstreamconf.encoder_dynamic_table_size);
1525   }
1526 
1527   http2conf.timeout.stream_write = 1_min;
1528 
1529   {
1530     auto &downstreamconf = http2conf.downstream;
1531 
1532     {
1533       auto &timeoutconf = downstreamconf.timeout;
1534       timeoutconf.settings = 10_s;
1535     }
1536 
1537     downstreamconf.window_size = 64_k - 1;
1538     downstreamconf.connection_window_size = (1u << 31) - 1;
1539     downstreamconf.max_concurrent_streams = 100;
1540 
1541     downstreamconf.encoder_dynamic_table_size = 4_k;
1542     downstreamconf.decoder_dynamic_table_size = 4_k;
1543 
1544     nghttp2_option_new(&downstreamconf.option);
1545     nghttp2_option_set_no_auto_window_update(downstreamconf.option, 1);
1546     nghttp2_option_set_peer_max_concurrent_streams(downstreamconf.option, 100);
1547     nghttp2_option_set_max_deflate_dynamic_table_size(
1548         downstreamconf.option, downstreamconf.encoder_dynamic_table_size);
1549   }
1550 
1551   auto &loggingconf = config->logging;
1552   {
1553     auto &accessconf = loggingconf.access;
1554     accessconf.format =
1555         parse_log_format(config->balloc, DEFAULT_ACCESSLOG_FORMAT);
1556 
1557     auto &errorconf = loggingconf.error;
1558     errorconf.file = StringRef::from_lit("/dev/stderr");
1559   }
1560 
1561   loggingconf.syslog_facility = LOG_DAEMON;
1562   loggingconf.severity = NOTICE;
1563 
1564   auto &connconf = config->conn;
1565   {
1566     auto &listenerconf = connconf.listener;
1567     {
1568       // Default accept() backlog
1569       listenerconf.backlog = 65536;
1570       listenerconf.timeout.sleep = 30_s;
1571     }
1572   }
1573 
1574   {
1575     auto &upstreamconf = connconf.upstream;
1576     {
1577       auto &timeoutconf = upstreamconf.timeout;
1578       // Read timeout for HTTP2 upstream connection
1579       timeoutconf.http2_read = 3_min;
1580 
1581       // Read timeout for non-HTTP2 upstream connection
1582       timeoutconf.read = 1_min;
1583 
1584       // Write timeout for HTTP2/non-HTTP2 upstream connection
1585       timeoutconf.write = 30_s;
1586 
1587       // Keep alive timeout for HTTP/1 upstream connection
1588       timeoutconf.idle_read = 1_min;
1589     }
1590   }
1591 
1592   {
1593     connconf.downstream = std::make_shared<DownstreamConfig>();
1594     auto &downstreamconf = *connconf.downstream;
1595     {
1596       auto &timeoutconf = downstreamconf.timeout;
1597       // Read/Write timeouts for downstream connection
1598       timeoutconf.read = 1_min;
1599       timeoutconf.write = 30_s;
1600       // Timeout for pooled (idle) connections
1601       timeoutconf.idle_read = 2_s;
1602       timeoutconf.connect = 30_s;
1603       timeoutconf.max_backoff = 120_s;
1604     }
1605 
1606     downstreamconf.connections_per_host = 8;
1607     downstreamconf.request_buffer_size = 16_k;
1608     downstreamconf.response_buffer_size = 128_k;
1609     downstreamconf.family = AF_UNSPEC;
1610   }
1611 
1612   auto &apiconf = config->api;
1613   apiconf.max_request_body = 32_m;
1614 
1615   auto &dnsconf = config->dns;
1616   {
1617     auto &timeoutconf = dnsconf.timeout;
1618     timeoutconf.cache = 10_s;
1619     timeoutconf.lookup = 5_s;
1620   }
1621   dnsconf.max_try = 2;
1622 }
1623 
1624 } // namespace
1625 
1626 namespace {
print_version(std::ostream & out)1627 void print_version(std::ostream &out) {
1628   out << "nghttpx nghttp2/" NGHTTP2_VERSION << std::endl;
1629 }
1630 } // namespace
1631 
1632 namespace {
print_usage(std::ostream & out)1633 void print_usage(std::ostream &out) {
1634   out << R"(Usage: nghttpx [OPTIONS]... [<PRIVATE_KEY> <CERT>]
1635 A reverse proxy for HTTP/2, and HTTP/1.)"
1636       << std::endl;
1637 }
1638 } // namespace
1639 
1640 namespace {
print_help(std::ostream & out)1641 void print_help(std::ostream &out) {
1642   auto config = get_config();
1643 
1644   print_usage(out);
1645   out << R"(
1646   <PRIVATE_KEY>
1647               Set  path  to  server's private  key.   Required  unless
1648               "no-tls" parameter is used in --frontend option.
1649   <CERT>      Set  path  to  server's  certificate.   Required  unless
1650               "no-tls"  parameter is  used in  --frontend option.   To
1651               make OCSP stapling work, this must be an absolute path.
1652 
1653 Options:
1654   The options are categorized into several groups.
1655 
1656 Connections:
1657   -b, --backend=(<HOST>,<PORT>|unix:<PATH>)[;[<PATTERN>[:...]][[;<PARAM>]...]
1658 
1659               Set  backend  host  and   port.   The  multiple  backend
1660               addresses are  accepted by repeating this  option.  UNIX
1661               domain socket  can be  specified by prefixing  path name
1662               with "unix:" (e.g., unix:/var/run/backend.sock).
1663 
1664               Optionally, if <PATTERN>s are given, the backend address
1665               is  only  used  if  request matches  the  pattern.   The
1666               pattern  matching is  closely  designed  to ServeMux  in
1667               net/http package of  Go programming language.  <PATTERN>
1668               consists of  path, host +  path or just host.   The path
1669               must start  with "/".  If  it ends with "/",  it matches
1670               all  request path  in  its subtree.   To  deal with  the
1671               request  to the  directory without  trailing slash,  the
1672               path which ends  with "/" also matches  the request path
1673               which  only  lacks  trailing  '/'  (e.g.,  path  "/foo/"
1674               matches request path  "/foo").  If it does  not end with
1675               "/", it  performs exact match against  the request path.
1676               If  host  is given,  it  performs  a match  against  the
1677               request host.   For a  request received on  the frontend
1678               listener with  "sni-fwd" parameter enabled, SNI  host is
1679               used instead of a request host.  If host alone is given,
1680               "/" is  appended to it,  so that it matches  all request
1681               paths  under the  host  (e.g., specifying  "nghttp2.org"
1682               equals  to "nghttp2.org/").   CONNECT method  is treated
1683               specially.  It  does not have  path, and we  don't allow
1684               empty path.  To workaround  this, we assume that CONNECT
1685               method has "/" as path.
1686 
1687               Patterns with  host take  precedence over  patterns with
1688               just path.   Then, longer patterns take  precedence over
1689               shorter ones.
1690 
1691               Host  can  include "*"  in  the  left most  position  to
1692               indicate  wildcard match  (only suffix  match is  done).
1693               The "*" must match at least one character.  For example,
1694               host    pattern    "*.nghttp2.org"    matches    against
1695               "www.nghttp2.org"  and  "git.ngttp2.org", but  does  not
1696               match  against  "nghttp2.org".   The exact  hosts  match
1697               takes precedence over the wildcard hosts match.
1698 
1699               If path  part ends with  "*", it is treated  as wildcard
1700               path.  The  wildcard path  behaves differently  from the
1701               normal path.  For normal path,  match is made around the
1702               boundary of path component  separator,"/".  On the other
1703               hand, the wildcard  path does not take  into account the
1704               path component  separator.  All paths which  include the
1705               wildcard  path  without  last  "*" as  prefix,  and  are
1706               strictly longer than wildcard  path without last "*" are
1707               matched.  "*"  must match  at least one  character.  For
1708               example,  the   pattern  "/foo*"  matches   "/foo/"  and
1709               "/foobar".  But it does not match "/foo", or "/fo".
1710 
1711               If <PATTERN> is omitted or  empty string, "/" is used as
1712               pattern,  which  matches  all request  paths  (catch-all
1713               pattern).  The catch-all backend must be given.
1714 
1715               When doing  a match, nghttpx made  some normalization to
1716               pattern, request host and path.  For host part, they are
1717               converted to lower case.  For path part, percent-encoded
1718               unreserved characters  defined in RFC 3986  are decoded,
1719               and any  dot-segments (".."  and ".")   are resolved and
1720               removed.
1721 
1722               For   example,   -b'127.0.0.1,8080;nghttp2.org/httpbin/'
1723               matches the  request host "nghttp2.org" and  the request
1724               path "/httpbin/get", but does not match the request host
1725               "nghttp2.org" and the request path "/index.html".
1726 
1727               The  multiple <PATTERN>s  can  be specified,  delimiting
1728               them            by           ":".             Specifying
1729               -b'127.0.0.1,8080;nghttp2.org:www.nghttp2.org'  has  the
1730               same  effect  to specify  -b'127.0.0.1,8080;nghttp2.org'
1731               and -b'127.0.0.1,8080;www.nghttp2.org'.
1732 
1733               The backend addresses sharing same <PATTERN> are grouped
1734               together forming  load balancing  group.
1735 
1736               Several parameters <PARAM> are accepted after <PATTERN>.
1737               The  parameters are  delimited  by  ";".  The  available
1738               parameters       are:      "proto=<PROTO>",       "tls",
1739               "sni=<SNI_HOST>",         "fall=<N>",        "rise=<N>",
1740               "affinity=<METHOD>",    "dns",    "redirect-if-not-tls",
1741               "upgrade-scheme",                        "mruby=<PATH>",
1742               "read-timeout=<DURATION>",   "write-timeout=<DURATION>",
1743               "group=<GROUP>",  "group-weight=<N>", and  "weight=<N>".
1744               The  parameter  consists   of  keyword,  and  optionally
1745               followed by  "=" and value.  For  example, the parameter
1746               "proto=h2"  consists of  the keyword  "proto" and  value
1747               "h2".  The parameter "tls" consists of the keyword "tls"
1748               without value.  Each parameter is described as follows.
1749 
1750               The backend application protocol  can be specified using
1751               optional  "proto"   parameter,  and   in  the   form  of
1752               "proto=<PROTO>".  <PROTO> should be one of the following
1753               list  without  quotes:  "h2", "http/1.1".   The  default
1754               value of <PROTO> is  "http/1.1".  Note that usually "h2"
1755               refers to HTTP/2  over TLS.  But in this  option, it may
1756               mean HTTP/2  over cleartext TCP unless  "tls" keyword is
1757               used (see below).
1758 
1759               TLS  can   be  enabled  by  specifying   optional  "tls"
1760               parameter.  TLS is not enabled by default.
1761 
1762               With "sni=<SNI_HOST>" parameter, it can override the TLS
1763               SNI  field  value  with  given  <SNI_HOST>.   This  will
1764               default to the backend <HOST> name
1765 
1766               The  feature  to detect  whether  backend  is online  or
1767               offline can be enabled  using optional "fall" and "rise"
1768               parameters.   Using  "fall=<N>"  parameter,  if  nghttpx
1769               cannot connect  to a  this backend <N>  times in  a row,
1770               this  backend  is  assumed  to be  offline,  and  it  is
1771               excluded from load balancing.  If <N> is 0, this backend
1772               never  be excluded  from load  balancing whatever  times
1773               nghttpx cannot connect  to it, and this  is the default.
1774               There is  also "rise=<N>" parameter.  After  backend was
1775               excluded from load balancing group, nghttpx periodically
1776               attempts to make a connection to the failed backend, and
1777               if the  connection is made  successfully <N> times  in a
1778               row, the backend is assumed to  be online, and it is now
1779               eligible  for load  balancing target.   If <N>  is 0,  a
1780               backend  is permanently  offline, once  it goes  in that
1781               state, and this is the default behaviour.
1782 
1783               The     session     affinity    is     enabled     using
1784               "affinity=<METHOD>"  parameter.   If  "ip" is  given  in
1785               <METHOD>, client  IP based session affinity  is enabled.
1786               If "cookie"  is given in <METHOD>,  cookie based session
1787               affinity is  enabled.  If  "none" is given  in <METHOD>,
1788               session affinity  is disabled, and this  is the default.
1789               The session  affinity is  enabled per <PATTERN>.   If at
1790               least  one backend  has  "affinity"  parameter, and  its
1791               <METHOD> is not "none",  session affinity is enabled for
1792               all backend  servers sharing the same  <PATTERN>.  It is
1793               advised  to  set  "affinity" parameter  to  all  backend
1794               explicitly if session affinity  is desired.  The session
1795               affinity  may   break  if   one  of  the   backend  gets
1796               unreachable,  or   backend  settings  are   reloaded  or
1797               replaced by API.
1798 
1799               If   "affinity=cookie"    is   used,    the   additional
1800               configuration                is                required.
1801               "affinity-cookie-name=<NAME>" must be  used to specify a
1802               name     of     cookie      to     use.      Optionally,
1803               "affinity-cookie-path=<PATH>" can  be used to  specify a
1804               path   which   cookie    is   applied.    The   optional
1805               "affinity-cookie-secure=<SECURE>"  controls  the  Secure
1806               attribute of a cookie.  The default value is "auto", and
1807               the Secure attribute is  determined by a request scheme.
1808               If a request scheme is "https", then Secure attribute is
1809               set.  Otherwise, it  is not set.  If  <SECURE> is "yes",
1810               the  Secure attribute  is  always set.   If <SECURE>  is
1811               "no", the Secure attribute is always omitted.
1812 
1813               By default, name resolution of backend host name is done
1814               at  start  up,  or reloading  configuration.   If  "dns"
1815               parameter   is  given,   name  resolution   takes  place
1816               dynamically.  This is useful  if backend address changes
1817               frequently.   If  "dns"  is given,  name  resolution  of
1818               backend   host   name   at  start   up,   or   reloading
1819               configuration is skipped.
1820 
1821               If "redirect-if-not-tls" parameter  is used, the matched
1822               backend  requires   that  frontend  connection   is  TLS
1823               encrypted.  If it isn't, nghttpx responds to the request
1824               with 308  status code, and  https URI the  client should
1825               use instead  is included in Location  header field.  The
1826               port number in  redirect URI is 443 by  default, and can
1827               be  changed using  --redirect-https-port option.   If at
1828               least one  backend has  "redirect-if-not-tls" parameter,
1829               this feature is enabled  for all backend servers sharing
1830               the   same   <PATTERN>.    It    is   advised   to   set
1831               "redirect-if-no-tls"    parameter   to    all   backends
1832               explicitly if this feature is desired.
1833 
1834               If "upgrade-scheme"  parameter is used along  with "tls"
1835               parameter, HTTP/2 :scheme pseudo header field is changed
1836               to "https" from "http" when forwarding a request to this
1837               particular backend.  This is  a workaround for a backend
1838               server  which  requires  "https" :scheme  pseudo  header
1839               field on TLS encrypted connection.
1840 
1841               "mruby=<PATH>"  parameter  specifies  a  path  to  mruby
1842               script  file  which  is  invoked when  this  pattern  is
1843               matched.  All backends which share the same pattern must
1844               have the same mruby path.
1845 
1846               "read-timeout=<DURATION>" and "write-timeout=<DURATION>"
1847               parameters  specify the  read and  write timeout  of the
1848               backend connection  when this  pattern is  matched.  All
1849               backends which share the same pattern must have the same
1850               timeouts.  If these timeouts  are entirely omitted for a
1851               pattern,            --backend-read-timeout           and
1852               --backend-write-timeout are used.
1853 
1854               "group=<GROUP>"  parameter specifies  the name  of group
1855               this backend address belongs to.  By default, it belongs
1856               to  the unnamed  default group.   The name  of group  is
1857               unique   per   pattern.   "group-weight=<N>"   parameter
1858               specifies the  weight of  the group.  The  higher weight
1859               gets  more frequently  selected  by  the load  balancing
1860               algorithm.  <N> must be  [1, 256] inclusive.  The weight
1861               8 has 4 times more weight  than 2.  <N> must be the same
1862               for  all addresses  which  share the  same <GROUP>.   If
1863               "group-weight" is  omitted in an address,  but the other
1864               address  which  belongs  to  the  same  group  specifies
1865               "group-weight",   its    weight   is   used.     If   no
1866               "group-weight"  is  specified  for  all  addresses,  the
1867               weight of a group becomes 1.  "group" and "group-weight"
1868               are ignored if session affinity is enabled.
1869 
1870               "weight=<N>"  parameter  specifies  the  weight  of  the
1871               backend  address  inside  a  group  which  this  address
1872               belongs  to.  The  higher  weight  gets more  frequently
1873               selected by  the load balancing algorithm.   <N> must be
1874               [1,  256] inclusive.   The  weight 8  has  4 times  more
1875               weight  than weight  2.  If  this parameter  is omitted,
1876               weight  becomes  1.   "weight"  is  ignored  if  session
1877               affinity is enabled.
1878 
1879               Since ";" and ":" are  used as delimiter, <PATTERN> must
1880               not contain  these characters.  In order  to include ":"
1881               in  <PATTERN>,  one  has  to  specify  "%3A"  (which  is
1882               percent-encoded  from of  ":") instead.   Since ";"  has
1883               special  meaning  in shell,  the  option  value must  be
1884               quoted.
1885 
1886               Default: )"
1887       << DEFAULT_DOWNSTREAM_HOST << "," << DEFAULT_DOWNSTREAM_PORT << R"(
1888   -f, --frontend=(<HOST>,<PORT>|unix:<PATH>)[[;<PARAM>]...]
1889               Set  frontend  host and  port.   If  <HOST> is  '*',  it
1890               assumes  all addresses  including  both  IPv4 and  IPv6.
1891               UNIX domain  socket can  be specified by  prefixing path
1892               name  with  "unix:" (e.g.,  unix:/var/run/nghttpx.sock).
1893               This  option can  be used  multiple times  to listen  to
1894               multiple addresses.
1895 
1896               This option  can take  0 or  more parameters,  which are
1897               described  below.   Note   that  "api"  and  "healthmon"
1898               parameters are mutually exclusive.
1899 
1900               Optionally, TLS  can be disabled by  specifying "no-tls"
1901               parameter.  TLS is enabled by default.
1902 
1903               If "sni-fwd" parameter is  used, when performing a match
1904               to select a backend server,  SNI host name received from
1905               the client  is used  instead of  the request  host.  See
1906               --backend option about the pattern match.
1907 
1908               To  make this  frontend as  API endpoint,  specify "api"
1909               parameter.   This   is  disabled  by  default.    It  is
1910               important  to  limit the  access  to  the API  frontend.
1911               Otherwise, someone  may change  the backend  server, and
1912               break your services,  or expose confidential information
1913               to the outside the world.
1914 
1915               To  make  this  frontend  as  health  monitor  endpoint,
1916               specify  "healthmon"  parameter.   This is  disabled  by
1917               default.  Any  requests which come through  this address
1918               are replied with 200 HTTP status, without no body.
1919 
1920               To accept  PROXY protocol  version 1  and 2  on frontend
1921               connection,  specify  "proxyproto" parameter.   This  is
1922               disabled by default.
1923 
1924               Default: *,3000
1925   --backlog=<N>
1926               Set listen backlog size.
1927               Default: )"
1928       << config->conn.listener.backlog << R"(
1929   --backend-address-family=(auto|IPv4|IPv6)
1930               Specify  address  family  of  backend  connections.   If
1931               "auto" is given, both IPv4  and IPv6 are considered.  If
1932               "IPv4" is  given, only  IPv4 address is  considered.  If
1933               "IPv6" is given, only IPv6 address is considered.
1934               Default: auto
1935   --backend-http-proxy-uri=<URI>
1936               Specify      proxy       URI      in       the      form
1937               http://[<USER>:<PASS>@]<PROXY>:<PORT>.    If   a   proxy
1938               requires  authentication,  specify  <USER>  and  <PASS>.
1939               Note that  they must be properly  percent-encoded.  This
1940               proxy  is used  when the  backend connection  is HTTP/2.
1941               First,  make  a CONNECT  request  to  the proxy  and  it
1942               connects  to the  backend  on behalf  of nghttpx.   This
1943               forms  tunnel.   After  that, nghttpx  performs  SSL/TLS
1944               handshake with  the downstream through the  tunnel.  The
1945               timeouts when connecting and  making CONNECT request can
1946               be     specified    by     --backend-read-timeout    and
1947               --backend-write-timeout options.
1948 
1949 Performance:
1950   -n, --workers=<N>
1951               Set the number of worker threads.
1952               Default: )"
1953       << config->num_worker << R"(
1954   --single-thread
1955               Run everything in one  thread inside the worker process.
1956               This   feature   is   provided  for   better   debugging
1957               experience,  or  for  the platforms  which  lack  thread
1958               support.   If  threading  is disabled,  this  option  is
1959               always enabled.
1960   --read-rate=<SIZE>
1961               Set maximum  average read  rate on  frontend connection.
1962               Setting 0 to this option means read rate is unlimited.
1963               Default: )"
1964       << config->conn.upstream.ratelimit.read.rate << R"(
1965   --read-burst=<SIZE>
1966               Set  maximum read  burst  size  on frontend  connection.
1967               Setting  0  to this  option  means  read burst  size  is
1968               unlimited.
1969               Default: )"
1970       << config->conn.upstream.ratelimit.read.burst << R"(
1971   --write-rate=<SIZE>
1972               Set maximum  average write rate on  frontend connection.
1973               Setting 0 to this option means write rate is unlimited.
1974               Default: )"
1975       << config->conn.upstream.ratelimit.write.rate << R"(
1976   --write-burst=<SIZE>
1977               Set  maximum write  burst size  on frontend  connection.
1978               Setting  0 to  this  option means  write  burst size  is
1979               unlimited.
1980               Default: )"
1981       << config->conn.upstream.ratelimit.write.burst << R"(
1982   --worker-read-rate=<SIZE>
1983               Set maximum average read rate on frontend connection per
1984               worker.  Setting  0 to  this option  means read  rate is
1985               unlimited.  Not implemented yet.
1986               Default: 0
1987   --worker-read-burst=<SIZE>
1988               Set maximum  read burst size on  frontend connection per
1989               worker.  Setting 0 to this  option means read burst size
1990               is unlimited.  Not implemented yet.
1991               Default: 0
1992   --worker-write-rate=<SIZE>
1993               Set maximum  average write  rate on  frontend connection
1994               per worker.  Setting  0 to this option  means write rate
1995               is unlimited.  Not implemented yet.
1996               Default: 0
1997   --worker-write-burst=<SIZE>
1998               Set maximum write burst  size on frontend connection per
1999               worker.  Setting 0 to this option means write burst size
2000               is unlimited.  Not implemented yet.
2001               Default: 0
2002   --worker-frontend-connections=<N>
2003               Set maximum number  of simultaneous connections frontend
2004               accepts.  Setting 0 means unlimited.
2005               Default: )"
2006       << config->conn.upstream.worker_connections << R"(
2007   --backend-connections-per-host=<N>
2008               Set  maximum number  of  backend concurrent  connections
2009               (and/or  streams in  case  of HTTP/2)  per origin  host.
2010               This option  is meaningful when --http2-proxy  option is
2011               used.   The  origin  host  is  determined  by  authority
2012               portion of  request URI (or :authority  header field for
2013               HTTP/2).   To  limit  the   number  of  connections  per
2014               frontend        for       default        mode,       use
2015               --backend-connections-per-frontend.
2016               Default: )"
2017       << config->conn.downstream->connections_per_host << R"(
2018   --backend-connections-per-frontend=<N>
2019               Set  maximum number  of  backend concurrent  connections
2020               (and/or streams  in case of HTTP/2)  per frontend.  This
2021               option  is   only  used  for  default   mode.   0  means
2022               unlimited.  To limit the  number of connections per host
2023               with          --http2-proxy         option,          use
2024               --backend-connections-per-host.
2025               Default: )"
2026       << config->conn.downstream->connections_per_frontend << R"(
2027   --rlimit-nofile=<N>
2028               Set maximum number of open files (RLIMIT_NOFILE) to <N>.
2029               If 0 is given, nghttpx does not set the limit.
2030               Default: )"
2031       << config->rlimit_nofile << R"(
2032   --backend-request-buffer=<SIZE>
2033               Set buffer size used to store backend request.
2034               Default: )"
2035       << util::utos_unit(config->conn.downstream->request_buffer_size) << R"(
2036   --backend-response-buffer=<SIZE>
2037               Set buffer size used to store backend response.
2038               Default: )"
2039       << util::utos_unit(config->conn.downstream->response_buffer_size) << R"(
2040   --fastopen=<N>
2041               Enables  "TCP Fast  Open" for  the listening  socket and
2042               limits the  maximum length for the  queue of connections
2043               that have not yet completed the three-way handshake.  If
2044               value is 0 then fast open is disabled.
2045               Default: )"
2046       << config->conn.listener.fastopen << R"(
2047   --no-kqueue Don't use  kqueue.  This  option is only  applicable for
2048               the platforms  which have kqueue.  For  other platforms,
2049               this option will be simply ignored.
2050 
2051 Timeout:
2052   --frontend-http2-read-timeout=<DURATION>
2053               Specify read timeout for HTTP/2 frontend connection.
2054               Default: )"
2055       << util::duration_str(config->conn.upstream.timeout.http2_read) << R"(
2056   --frontend-read-timeout=<DURATION>
2057               Specify read timeout for HTTP/1.1 frontend connection.
2058               Default: )"
2059       << util::duration_str(config->conn.upstream.timeout.read) << R"(
2060   --frontend-write-timeout=<DURATION>
2061               Specify write timeout for all frontend connections.
2062               Default: )"
2063       << util::duration_str(config->conn.upstream.timeout.write) << R"(
2064   --frontend-keep-alive-timeout=<DURATION>
2065               Specify   keep-alive   timeout   for   frontend   HTTP/1
2066               connection.
2067               Default: )"
2068       << util::duration_str(config->conn.upstream.timeout.idle_read) << R"(
2069   --stream-read-timeout=<DURATION>
2070               Specify  read timeout  for HTTP/2  streams.  0  means no
2071               timeout.
2072               Default: )"
2073       << util::duration_str(config->http2.timeout.stream_read) << R"(
2074   --stream-write-timeout=<DURATION>
2075               Specify write  timeout for  HTTP/2 streams.  0  means no
2076               timeout.
2077               Default: )"
2078       << util::duration_str(config->http2.timeout.stream_write) << R"(
2079   --backend-read-timeout=<DURATION>
2080               Specify read timeout for backend connection.
2081               Default: )"
2082       << util::duration_str(config->conn.downstream->timeout.read) << R"(
2083   --backend-write-timeout=<DURATION>
2084               Specify write timeout for backend connection.
2085               Default: )"
2086       << util::duration_str(config->conn.downstream->timeout.write) << R"(
2087   --backend-connect-timeout=<DURATION>
2088               Specify  timeout before  establishing TCP  connection to
2089               backend.
2090               Default: )"
2091       << util::duration_str(config->conn.downstream->timeout.connect) << R"(
2092   --backend-keep-alive-timeout=<DURATION>
2093               Specify   keep-alive   timeout    for   backend   HTTP/1
2094               connection.
2095               Default: )"
2096       << util::duration_str(config->conn.downstream->timeout.idle_read) << R"(
2097   --listener-disable-timeout=<DURATION>
2098               After accepting  connection failed,  connection listener
2099               is disabled  for a given  amount of time.   Specifying 0
2100               disables this feature.
2101               Default: )"
2102       << util::duration_str(config->conn.listener.timeout.sleep) << R"(
2103   --frontend-http2-setting-timeout=<DURATION>
2104               Specify  timeout before  SETTINGS ACK  is received  from
2105               client.
2106               Default: )"
2107       << util::duration_str(config->http2.upstream.timeout.settings) << R"(
2108   --backend-http2-settings-timeout=<DURATION>
2109               Specify  timeout before  SETTINGS ACK  is received  from
2110               backend server.
2111               Default: )"
2112       << util::duration_str(config->http2.downstream.timeout.settings) << R"(
2113   --backend-max-backoff=<DURATION>
2114               Specify  maximum backoff  interval.  This  is used  when
2115               doing health  check against offline backend  (see "fail"
2116               parameter  in --backend  option).   It is  also used  to
2117               limit  the  maximum   interval  to  temporarily  disable
2118               backend  when nghttpx  failed to  connect to  it.  These
2119               intervals are calculated  using exponential backoff, and
2120               consecutive failed attempts increase the interval.  This
2121               option caps its maximum value.
2122               Default: )"
2123       << util::duration_str(config->conn.downstream->timeout.max_backoff) << R"(
2124 
2125 SSL/TLS:
2126   --ciphers=<SUITE>
2127               Set allowed  cipher list  for frontend  connection.  The
2128               format of the string is described in OpenSSL ciphers(1).
2129               This option  sets cipher suites for  TLSv1.2 or earlier.
2130               Use --tls13-ciphers for TLSv1.3.
2131               Default: )"
2132       << config->tls.ciphers << R"(
2133   --tls13-ciphers=<SUITE>
2134               Set allowed  cipher list  for frontend  connection.  The
2135               format of the string is described in OpenSSL ciphers(1).
2136               This  option  sets  cipher   suites  for  TLSv1.3.   Use
2137               --ciphers for TLSv1.2 or earlier.
2138               Default: )"
2139       << config->tls.tls13_ciphers << R"(
2140   --client-ciphers=<SUITE>
2141               Set  allowed cipher  list for  backend connection.   The
2142               format of the string is described in OpenSSL ciphers(1).
2143               This option  sets cipher suites for  TLSv1.2 or earlier.
2144               Use --tls13-client-ciphers for TLSv1.3.
2145               Default: )"
2146       << config->tls.client.ciphers << R"(
2147   --tls13-client-ciphers=<SUITE>
2148               Set  allowed cipher  list for  backend connection.   The
2149               format of the string is described in OpenSSL ciphers(1).
2150               This  option  sets  cipher   suites  for  TLSv1.3.   Use
2151               --tls13-client-ciphers for TLSv1.2 or earlier.
2152               Default: )"
2153       << config->tls.client.tls13_ciphers << R"(
2154   --ecdh-curves=<LIST>
2155               Set  supported  curve  list  for  frontend  connections.
2156               <LIST> is a  colon separated list of curve  NID or names
2157               in the preference order.  The supported curves depend on
2158               the  linked  OpenSSL  library.  This  function  requires
2159               OpenSSL >= 1.0.2.
2160               Default: )"
2161       << config->tls.ecdh_curves << R"(
2162   -k, --insecure
2163               Don't  verify backend  server's  certificate  if TLS  is
2164               enabled for backend connections.
2165   --cacert=<PATH>
2166               Set path to trusted CA  certificate file.  It is used in
2167               backend  TLS connections  to verify  peer's certificate.
2168               It is also used to  verify OCSP response from the script
2169               set by --fetch-ocsp-response-file.  The  file must be in
2170               PEM format.   It can contain multiple  certificates.  If
2171               the  linked OpenSSL  is configured  to load  system wide
2172               certificates, they  are loaded at startup  regardless of
2173               this option.
2174   --private-key-passwd-file=<PATH>
2175               Path  to file  that contains  password for  the server's
2176               private key.   If none is  given and the private  key is
2177               password protected it'll be requested interactively.
2178   --subcert=<KEYPATH>:<CERTPATH>[[;<PARAM>]...]
2179               Specify  additional certificate  and  private key  file.
2180               nghttpx will  choose certificates based on  the hostname
2181               indicated by client using TLS SNI extension.  If nghttpx
2182               is  built with  OpenSSL  >= 1.0.2,  the shared  elliptic
2183               curves (e.g., P-256) between  client and server are also
2184               taken into  consideration.  This allows nghttpx  to send
2185               ECDSA certificate  to modern clients, while  sending RSA
2186               based certificate to older  clients.  This option can be
2187               used  multiple  times.   To  make  OCSP  stapling  work,
2188               <CERTPATH> must be absolute path.
2189 
2190               Additional parameter  can be specified in  <PARAM>.  The
2191               available <PARAM> is "sct-dir=<DIR>".
2192 
2193               "sct-dir=<DIR>"  specifies the  path to  directory which
2194               contains        *.sct        files        for        TLS
2195               signed_certificate_timestamp extension (RFC 6962).  This
2196               feature   requires   OpenSSL   >=   1.0.2.    See   also
2197               --tls-sct-dir option.
2198   --dh-param-file=<PATH>
2199               Path to file that contains  DH parameters in PEM format.
2200               Without  this   option,  DHE   cipher  suites   are  not
2201               available.
2202   --npn-list=<LIST>
2203               Comma delimited list of  ALPN protocol identifier sorted
2204               in the  order of preference.  That  means most desirable
2205               protocol comes  first.  This  is used  in both  ALPN and
2206               NPN.  The parameter must be  delimited by a single comma
2207               only  and any  white spaces  are  treated as  a part  of
2208               protocol string.
2209               Default: )"
2210       << DEFAULT_NPN_LIST
2211       << R"(
2212   --verify-client
2213               Require and verify client certificate.
2214   --verify-client-cacert=<PATH>
2215               Path  to file  that contains  CA certificates  to verify
2216               client certificate.  The file must be in PEM format.  It
2217               can contain multiple certificates.
2218   --verify-client-tolerate-expired
2219               Accept  expired  client  certificate.   Operator  should
2220               handle  the expired  client  certificate  by some  means
2221               (e.g.,  mruby  script).   Otherwise, this  option  might
2222               cause a security risk.
2223   --client-private-key-file=<PATH>
2224               Path to  file that contains  client private key  used in
2225               backend client authentication.
2226   --client-cert-file=<PATH>
2227               Path to  file that  contains client certificate  used in
2228               backend client authentication.
2229   --tls-min-proto-version=<VER>
2230               Specify minimum SSL/TLS protocol.   The name matching is
2231               done in  case-insensitive manner.  The  versions between
2232               --tls-min-proto-version and  --tls-max-proto-version are
2233               enabled.  If the protocol list advertised by client does
2234               not  overlap  this range,  you  will  receive the  error
2235               message "unknown protocol".  If a protocol version lower
2236               than TLSv1.2 is specified, make sure that the compatible
2237               ciphers are  included in --ciphers option.   The default
2238               cipher  list  only   includes  ciphers  compatible  with
2239               TLSv1.2 or above.  The available versions are:
2240               )"
2241 #ifdef TLS1_3_VERSION
2242          "TLSv1.3, "
2243 #endif // TLS1_3_VERSION
2244          "TLSv1.2, TLSv1.1, and TLSv1.0"
2245          R"(
2246               Default: )"
2247       << DEFAULT_TLS_MIN_PROTO_VERSION
2248       << R"(
2249   --tls-max-proto-version=<VER>
2250               Specify maximum SSL/TLS protocol.   The name matching is
2251               done in  case-insensitive manner.  The  versions between
2252               --tls-min-proto-version and  --tls-max-proto-version are
2253               enabled.  If the protocol list advertised by client does
2254               not  overlap  this range,  you  will  receive the  error
2255               message "unknown protocol".  The available versions are:
2256               )"
2257 #ifdef TLS1_3_VERSION
2258          "TLSv1.3, "
2259 #endif // TLS1_3_VERSION
2260          "TLSv1.2, TLSv1.1, and TLSv1.0"
2261          R"(
2262               Default: )"
2263       << DEFAULT_TLS_MAX_PROTO_VERSION << R"(
2264   --tls-ticket-key-file=<PATH>
2265               Path to file that contains  random data to construct TLS
2266               session ticket  parameters.  If aes-128-cbc is  given in
2267               --tls-ticket-key-cipher, the  file must  contain exactly
2268               48    bytes.     If     aes-256-cbc    is    given    in
2269               --tls-ticket-key-cipher, the  file must  contain exactly
2270               80  bytes.   This  options  can be  used  repeatedly  to
2271               specify  multiple ticket  parameters.  If  several files
2272               are given,  only the  first key is  used to  encrypt TLS
2273               session  tickets.  Other  keys are  accepted but  server
2274               will  issue new  session  ticket with  first key.   This
2275               allows  session  key  rotation.  Please  note  that  key
2276               rotation  does  not  occur automatically.   User  should
2277               rearrange  files or  change options  values and  restart
2278               nghttpx gracefully.   If opening  or reading  given file
2279               fails, all loaded  keys are discarded and  it is treated
2280               as if none  of this option is given.  If  this option is
2281               not given or an error  occurred while opening or reading
2282               a file,  key is  generated every  1 hour  internally and
2283               they are  valid for  12 hours.   This is  recommended if
2284               ticket  key sharing  between  nghttpx  instances is  not
2285               required.
2286   --tls-ticket-key-memcached=<HOST>,<PORT>[;tls]
2287               Specify address  of memcached  server to get  TLS ticket
2288               keys for  session resumption.   This enables  shared TLS
2289               ticket key between  multiple nghttpx instances.  nghttpx
2290               does not set TLS ticket  key to memcached.  The external
2291               ticket key generator is required.  nghttpx just gets TLS
2292               ticket  keys  from  memcached, and  use  them,  possibly
2293               replacing current set  of keys.  It is up  to extern TLS
2294               ticket  key generator  to rotate  keys frequently.   See
2295               "TLS SESSION  TICKET RESUMPTION" section in  manual page
2296               to know the data format in memcached entry.  Optionally,
2297               memcached  connection  can  be  encrypted  with  TLS  by
2298               specifying "tls" parameter.
2299   --tls-ticket-key-memcached-address-family=(auto|IPv4|IPv6)
2300               Specify address  family of memcached connections  to get
2301               TLS ticket keys.  If "auto" is given, both IPv4 and IPv6
2302               are considered.   If "IPv4" is given,  only IPv4 address
2303               is considered.  If "IPv6" is given, only IPv6 address is
2304               considered.
2305               Default: auto
2306   --tls-ticket-key-memcached-interval=<DURATION>
2307               Set interval to get TLS ticket keys from memcached.
2308               Default: )"
2309       << util::duration_str(config->tls.ticket.memcached.interval) << R"(
2310   --tls-ticket-key-memcached-max-retry=<N>
2311               Set  maximum   number  of  consecutive   retries  before
2312               abandoning TLS ticket key  retrieval.  If this number is
2313               reached,  the  attempt  is considered  as  failure,  and
2314               "failure" count  is incremented by 1,  which contributed
2315               to            the            value            controlled
2316               --tls-ticket-key-memcached-max-fail option.
2317               Default: )"
2318       << config->tls.ticket.memcached.max_retry << R"(
2319   --tls-ticket-key-memcached-max-fail=<N>
2320               Set  maximum   number  of  consecutive   failure  before
2321               disabling TLS ticket until next scheduled key retrieval.
2322               Default: )"
2323       << config->tls.ticket.memcached.max_fail << R"(
2324   --tls-ticket-key-cipher=<CIPHER>
2325               Specify cipher  to encrypt TLS session  ticket.  Specify
2326               either   aes-128-cbc   or  aes-256-cbc.    By   default,
2327               aes-128-cbc is used.
2328   --tls-ticket-key-memcached-cert-file=<PATH>
2329               Path to client certificate  for memcached connections to
2330               get TLS ticket keys.
2331   --tls-ticket-key-memcached-private-key-file=<PATH>
2332               Path to client private  key for memcached connections to
2333               get TLS ticket keys.
2334   --fetch-ocsp-response-file=<PATH>
2335               Path to  fetch-ocsp-response script file.  It  should be
2336               absolute path.
2337               Default: )"
2338       << config->tls.ocsp.fetch_ocsp_response_file << R"(
2339   --ocsp-update-interval=<DURATION>
2340               Set interval to update OCSP response cache.
2341               Default: )"
2342       << util::duration_str(config->tls.ocsp.update_interval) << R"(
2343   --ocsp-startup
2344               Start  accepting connections  after initial  attempts to
2345               get OCSP responses  finish.  It does not  matter some of
2346               the  attempts  fail.  This  feature  is  useful if  OCSP
2347               responses   must    be   available    before   accepting
2348               connections.
2349   --no-verify-ocsp
2350               nghttpx does not verify OCSP response.
2351   --no-ocsp   Disable OCSP stapling.
2352   --tls-session-cache-memcached=<HOST>,<PORT>[;tls]
2353               Specify  address of  memcached server  to store  session
2354               cache.   This  enables   shared  session  cache  between
2355               multiple   nghttpx  instances.    Optionally,  memcached
2356               connection can be encrypted with TLS by specifying "tls"
2357               parameter.
2358   --tls-session-cache-memcached-address-family=(auto|IPv4|IPv6)
2359               Specify address family of memcached connections to store
2360               session cache.  If  "auto" is given, both  IPv4 and IPv6
2361               are considered.   If "IPv4" is given,  only IPv4 address
2362               is considered.  If "IPv6" is given, only IPv6 address is
2363               considered.
2364               Default: auto
2365   --tls-session-cache-memcached-cert-file=<PATH>
2366               Path to client certificate  for memcached connections to
2367               store session cache.
2368   --tls-session-cache-memcached-private-key-file=<PATH>
2369               Path to client private  key for memcached connections to
2370               store session cache.
2371   --tls-dyn-rec-warmup-threshold=<SIZE>
2372               Specify the  threshold size for TLS  dynamic record size
2373               behaviour.  During  a TLS  session, after  the threshold
2374               number of bytes  have been written, the  TLS record size
2375               will be increased to the maximum allowed (16K).  The max
2376               record size will  continue to be used on  the active TLS
2377               session.  After  --tls-dyn-rec-idle-timeout has elapsed,
2378               the record size is reduced  to 1300 bytes.  Specify 0 to
2379               always use  the maximum record size,  regardless of idle
2380               period.   This  behaviour  applies   to  all  TLS  based
2381               frontends, and TLS HTTP/2 backends.
2382               Default: )"
2383       << util::utos_unit(config->tls.dyn_rec.warmup_threshold) << R"(
2384   --tls-dyn-rec-idle-timeout=<DURATION>
2385               Specify TLS dynamic record  size behaviour timeout.  See
2386               --tls-dyn-rec-warmup-threshold  for   more  information.
2387               This behaviour  applies to all TLS  based frontends, and
2388               TLS HTTP/2 backends.
2389               Default: )"
2390       << util::duration_str(config->tls.dyn_rec.idle_timeout) << R"(
2391   --no-http2-cipher-black-list
2392               Allow  black  listed  cipher suite  on  frontend  HTTP/2
2393               connection.                                          See
2394               https://tools.ietf.org/html/rfc7540#appendix-A  for  the
2395               complete HTTP/2 cipher suites black list.
2396   --client-no-http2-cipher-black-list
2397               Allow  black  listed  cipher  suite  on  backend  HTTP/2
2398               connection.                                          See
2399               https://tools.ietf.org/html/rfc7540#appendix-A  for  the
2400               complete HTTP/2 cipher suites black list.
2401   --tls-sct-dir=<DIR>
2402               Specifies the  directory where  *.sct files  exist.  All
2403               *.sct   files   in  <DIR>   are   read,   and  sent   as
2404               extension_data of  TLS signed_certificate_timestamp (RFC
2405               6962)  to  client.   These   *.sct  files  are  for  the
2406               certificate   specified   in   positional   command-line
2407               argument <CERT>, or  certificate option in configuration
2408               file.   For   additional  certificates,   use  --subcert
2409               option.  This option requires OpenSSL >= 1.0.2.
2410   --psk-secrets=<PATH>
2411               Read list of PSK identity and secrets from <PATH>.  This
2412               is used for frontend connection.  The each line of input
2413               file  is  formatted  as  <identity>:<hex-secret>,  where
2414               <identity> is  PSK identity, and <hex-secret>  is secret
2415               in hex.  An  empty line, and line which  starts with '#'
2416               are skipped.  The default  enabled cipher list might not
2417               contain any PSK cipher suite.  In that case, desired PSK
2418               cipher suites  must be  enabled using  --ciphers option.
2419               The  desired PSK  cipher suite  may be  black listed  by
2420               HTTP/2.   To  use  those   cipher  suites  with  HTTP/2,
2421               consider  to  use  --no-http2-cipher-black-list  option.
2422               But be aware its implications.
2423   --client-psk-secrets=<PATH>
2424               Read PSK identity and secrets from <PATH>.  This is used
2425               for backend connection.  The each  line of input file is
2426               formatted  as <identity>:<hex-secret>,  where <identity>
2427               is PSK identity, and <hex-secret>  is secret in hex.  An
2428               empty line, and line which  starts with '#' are skipped.
2429               The first identity and  secret pair encountered is used.
2430               The default  enabled cipher  list might not  contain any
2431               PSK  cipher suite.   In  that case,  desired PSK  cipher
2432               suites  must be  enabled using  --client-ciphers option.
2433               The  desired PSK  cipher suite  may be  black listed  by
2434               HTTP/2.   To  use  those   cipher  suites  with  HTTP/2,
2435               consider   to  use   --client-no-http2-cipher-black-list
2436               option.  But be aware its implications.
2437   --tls-no-postpone-early-data
2438               By default,  nghttpx postpones forwarding  HTTP requests
2439               sent in early data, including those sent in partially in
2440               it, until TLS handshake finishes.  If all backend server
2441               recognizes "Early-Data" header  field, using this option
2442               makes nghttpx  not postpone  forwarding request  and get
2443               full potential of 0-RTT data.
2444   --tls-max-early-data=<SIZE>
2445               Sets  the  maximum  amount  of 0-RTT  data  that  server
2446               accepts.
2447               Default: )"
2448       << util::utos_unit(config->tls.max_early_data) << R"(
2449 
2450 HTTP/2:
2451   -c, --frontend-http2-max-concurrent-streams=<N>
2452               Set the maximum number of  the concurrent streams in one
2453               frontend HTTP/2 session.
2454               Default: )"
2455       << config->http2.upstream.max_concurrent_streams << R"(
2456   --backend-http2-max-concurrent-streams=<N>
2457               Set the maximum number of  the concurrent streams in one
2458               backend  HTTP/2 session.   This sets  maximum number  of
2459               concurrent opened pushed streams.  The maximum number of
2460               concurrent requests are set by a remote server.
2461               Default: )"
2462       << config->http2.downstream.max_concurrent_streams << R"(
2463   --frontend-http2-window-size=<SIZE>
2464               Sets  the  per-stream  initial  window  size  of  HTTP/2
2465               frontend connection.
2466               Default: )"
2467       << config->http2.upstream.window_size << R"(
2468   --frontend-http2-connection-window-size=<SIZE>
2469               Sets the  per-connection window size of  HTTP/2 frontend
2470               connection.
2471               Default: )"
2472       << config->http2.upstream.connection_window_size << R"(
2473   --backend-http2-window-size=<SIZE>
2474               Sets  the   initial  window   size  of   HTTP/2  backend
2475               connection.
2476               Default: )"
2477       << config->http2.downstream.window_size << R"(
2478   --backend-http2-connection-window-size=<SIZE>
2479               Sets the  per-connection window  size of  HTTP/2 backend
2480               connection.
2481               Default: )"
2482       << config->http2.downstream.connection_window_size << R"(
2483   --http2-no-cookie-crumbling
2484               Don't crumble cookie header field.
2485   --padding=<N>
2486               Add  at most  <N> bytes  to  a HTTP/2  frame payload  as
2487               padding.  Specify 0 to  disable padding.  This option is
2488               meant for debugging purpose  and not intended to enhance
2489               protocol security.
2490   --no-server-push
2491               Disable HTTP/2 server push.  Server push is supported by
2492               default mode and HTTP/2  frontend via Link header field.
2493               It is  also supported if  both frontend and  backend are
2494               HTTP/2 in default mode.  In  this case, server push from
2495               backend session is relayed  to frontend, and server push
2496               via Link header field is also supported.
2497   --frontend-http2-optimize-write-buffer-size
2498               (Experimental) Enable write  buffer size optimization in
2499               frontend HTTP/2 TLS  connection.  This optimization aims
2500               to reduce  write buffer  size so  that it  only contains
2501               bytes  which can  send immediately.   This makes  server
2502               more responsive to prioritized HTTP/2 stream because the
2503               buffering  of lower  priority stream  is reduced.   This
2504               option is only effective on recent Linux platform.
2505   --frontend-http2-optimize-window-size
2506               (Experimental)   Automatically  tune   connection  level
2507               window size of frontend  HTTP/2 TLS connection.  If this
2508               feature is  enabled, connection window size  starts with
2509               the   default  window   size,   65535  bytes.    nghttpx
2510               automatically  adjusts connection  window size  based on
2511               TCP receiving  window size.  The maximum  window size is
2512               capped      by      the     value      specified      by
2513               --frontend-http2-connection-window-size.     Since   the
2514               stream is subject to stream level window size, it should
2515               be adjusted using --frontend-http2-window-size option as
2516               well.   This option  is only  effective on  recent Linux
2517               platform.
2518   --frontend-http2-encoder-dynamic-table-size=<SIZE>
2519               Specify the maximum dynamic  table size of HPACK encoder
2520               in the frontend HTTP/2 connection.  The decoder (client)
2521               specifies  the maximum  dynamic table  size it  accepts.
2522               Then the negotiated dynamic table size is the minimum of
2523               this option value and the value which client specified.
2524               Default: )"
2525       << util::utos_unit(config->http2.upstream.encoder_dynamic_table_size)
2526       << R"(
2527   --frontend-http2-decoder-dynamic-table-size=<SIZE>
2528               Specify the maximum dynamic  table size of HPACK decoder
2529               in the frontend HTTP/2 connection.
2530               Default: )"
2531       << util::utos_unit(config->http2.upstream.decoder_dynamic_table_size)
2532       << R"(
2533   --backend-http2-encoder-dynamic-table-size=<SIZE>
2534               Specify the maximum dynamic  table size of HPACK encoder
2535               in the backend HTTP/2 connection.  The decoder (backend)
2536               specifies  the maximum  dynamic table  size it  accepts.
2537               Then the negotiated dynamic table size is the minimum of
2538               this option value and the value which backend specified.
2539               Default: )"
2540       << util::utos_unit(config->http2.downstream.encoder_dynamic_table_size)
2541       << R"(
2542   --backend-http2-decoder-dynamic-table-size=<SIZE>
2543               Specify the maximum dynamic  table size of HPACK decoder
2544               in the backend HTTP/2 connection.
2545               Default: )"
2546       << util::utos_unit(config->http2.downstream.decoder_dynamic_table_size)
2547       << R"(
2548 
2549 Mode:
2550   (default mode)
2551               Accept  HTTP/2,  and  HTTP/1.1 over  SSL/TLS.   "no-tls"
2552               parameter is  used in  --frontend option,  accept HTTP/2
2553               and HTTP/1.1 over cleartext  TCP.  The incoming HTTP/1.1
2554               connection  can  be  upgraded  to  HTTP/2  through  HTTP
2555               Upgrade.
2556   -s, --http2-proxy
2557               Like default mode, but enable forward proxy.  This is so
2558               called HTTP/2 proxy mode.
2559 
2560 Logging:
2561   -L, --log-level=<LEVEL>
2562               Set the severity  level of log output.   <LEVEL> must be
2563               one of INFO, NOTICE, WARN, ERROR and FATAL.
2564               Default: NOTICE
2565   --accesslog-file=<PATH>
2566               Set path to write access log.  To reopen file, send USR1
2567               signal to nghttpx.
2568   --accesslog-syslog
2569               Send  access log  to syslog.   If this  option is  used,
2570               --accesslog-file option is ignored.
2571   --accesslog-format=<FORMAT>
2572               Specify  format  string  for access  log.   The  default
2573               format is combined format.   The following variables are
2574               available:
2575 
2576               * $remote_addr: client IP address.
2577               * $time_local: local time in Common Log format.
2578               * $time_iso8601: local time in ISO 8601 format.
2579               * $request: HTTP request line.
2580               * $status: HTTP response status code.
2581               * $body_bytes_sent: the  number of bytes sent  to client
2582                 as response body.
2583               * $http_<VAR>: value of HTTP  request header <VAR> where
2584                 '_' in <VAR> is replaced with '-'.
2585               * $remote_port: client  port.
2586               * $server_port: server port.
2587               * $request_time: request processing time in seconds with
2588                 milliseconds resolution.
2589               * $pid: PID of the running process.
2590               * $alpn: ALPN identifier of the protocol which generates
2591                 the response.   For HTTP/1,  ALPN is  always http/1.1,
2592                 regardless of minor version.
2593               * $tls_cipher: cipher used for SSL/TLS connection.
2594               * $tls_client_fingerprint_sha256: SHA-256 fingerprint of
2595                 client certificate.
2596               * $tls_client_fingerprint_sha1:  SHA-1   fingerprint  of
2597                 client certificate.
2598               * $tls_client_subject_name:   subject  name   in  client
2599                 certificate.
2600               * $tls_client_issuer_name:   issuer   name   in   client
2601                 certificate.
2602               * $tls_client_serial:    serial    number   in    client
2603                 certificate.
2604               * $tls_protocol: protocol for SSL/TLS connection.
2605               * $tls_session_id: session ID for SSL/TLS connection.
2606               * $tls_session_reused:  "r"   if  SSL/TLS   session  was
2607                 reused.  Otherwise, "."
2608               * $tls_sni: SNI server name for SSL/TLS connection.
2609               * $backend_host:  backend  host   used  to  fulfill  the
2610                 request.  "-" if backend host is not available.
2611               * $backend_port:  backend  port   used  to  fulfill  the
2612                 request.  "-" if backend host is not available.
2613               * $method: HTTP method
2614               * $path:  Request  path  including query.   For  CONNECT
2615                 request, authority is recorded.
2616               * $path_without_query:  $path   up  to  the   first  '?'
2617                 character.    For   CONNECT  request,   authority   is
2618                 recorded.
2619               * $protocol_version:   HTTP  version   (e.g.,  HTTP/1.1,
2620                 HTTP/2)
2621 
2622               The  variable  can  be  enclosed  by  "{"  and  "}"  for
2623               disambiguation (e.g., ${remote_addr}).
2624 
2625               Default: )"
2626       << DEFAULT_ACCESSLOG_FORMAT << R"(
2627   --accesslog-write-early
2628               Write  access  log  when   response  header  fields  are
2629               received   from  backend   rather   than  when   request
2630               transaction finishes.
2631   --errorlog-file=<PATH>
2632               Set path to write error  log.  To reopen file, send USR1
2633               signal  to nghttpx.   stderr will  be redirected  to the
2634               error log file unless --errorlog-syslog is used.
2635               Default: )"
2636       << config->logging.error.file << R"(
2637   --errorlog-syslog
2638               Send  error log  to  syslog.  If  this  option is  used,
2639               --errorlog-file option is ignored.
2640   --syslog-facility=<FACILITY>
2641               Set syslog facility to <FACILITY>.
2642               Default: )"
2643       << str_syslog_facility(config->logging.syslog_facility) << R"(
2644 
2645 HTTP:
2646   --add-x-forwarded-for
2647               Append  X-Forwarded-For header  field to  the downstream
2648               request.
2649   --strip-incoming-x-forwarded-for
2650               Strip X-Forwarded-For  header field from  inbound client
2651               requests.
2652   --no-add-x-forwarded-proto
2653               Don't append  additional X-Forwarded-Proto  header field
2654               to  the   backend  request.   If  inbound   client  sets
2655               X-Forwarded-Proto,                                   and
2656               --no-strip-incoming-x-forwarded-proto  option  is  used,
2657               they are passed to the backend.
2658   --no-strip-incoming-x-forwarded-proto
2659               Don't strip X-Forwarded-Proto  header field from inbound
2660               client requests.
2661   --add-forwarded=<LIST>
2662               Append RFC  7239 Forwarded header field  with parameters
2663               specified in comma delimited list <LIST>.  The supported
2664               parameters  are "by",  "for", "host",  and "proto".   By
2665               default,  the value  of  "by" and  "for" parameters  are
2666               obfuscated     string.     See     --forwarded-by    and
2667               --forwarded-for options respectively.  Note that nghttpx
2668               does  not  translate non-standard  X-Forwarded-*  header
2669               fields into Forwarded header field, and vice versa.
2670   --strip-incoming-forwarded
2671               Strip  Forwarded   header  field  from   inbound  client
2672               requests.
2673   --forwarded-by=(obfuscated|ip|<VALUE>)
2674               Specify the parameter value sent out with "by" parameter
2675               of Forwarded  header field.   If "obfuscated"  is given,
2676               the string is randomly generated at startup.  If "ip" is
2677               given,   the  interface   address  of   the  connection,
2678               including port number, is  sent with "by" parameter.  In
2679               case of UNIX domain  socket, "localhost" is used instead
2680               of address and  port.  User can also  specify the static
2681               obfuscated string.  The limitation is that it must start
2682               with   "_",  and   only   consists   of  character   set
2683               [A-Za-z0-9._-], as described in RFC 7239.
2684               Default: obfuscated
2685   --forwarded-for=(obfuscated|ip)
2686               Specify  the   parameter  value  sent  out   with  "for"
2687               parameter of Forwarded header field.  If "obfuscated" is
2688               given, the string is  randomly generated for each client
2689               connection.  If "ip" is given, the remote client address
2690               of  the connection,  without port  number, is  sent with
2691               "for"  parameter.   In  case   of  UNIX  domain  socket,
2692               "localhost" is used instead of address.
2693               Default: obfuscated
2694   --no-via    Don't append to  Via header field.  If  Via header field
2695               is received, it is left unaltered.
2696   --no-strip-incoming-early-data
2697               Don't strip Early-Data header  field from inbound client
2698               requests.
2699   --no-location-rewrite
2700               Don't  rewrite location  header field  in default  mode.
2701               When --http2-proxy  is used, location header  field will
2702               not be altered regardless of this option.
2703   --host-rewrite
2704               Rewrite  host and  :authority header  fields in  default
2705               mode.  When  --http2-proxy is  used, these  headers will
2706               not be altered regardless of this option.
2707   --altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
2708               Specify   protocol  ID,   port,  host   and  origin   of
2709               alternative service.  <HOST>  and <ORIGIN> are optional.
2710               They  are advertised  in  alt-svc header  field only  in
2711               HTTP/1.1  frontend.  This  option can  be used  multiple
2712               times   to   specify  multiple   alternative   services.
2713               Example: --altsvc=h2,443
2714   --add-request-header=<HEADER>
2715               Specify additional header field to add to request header
2716               set.  This  option just  appends header field  and won't
2717               replace anything  already set.  This option  can be used
2718               several  times   to  specify  multiple   header  fields.
2719               Example: --add-request-header="foo: bar"
2720   --add-response-header=<HEADER>
2721               Specify  additional  header  field to  add  to  response
2722               header set.   This option just appends  header field and
2723               won't replace anything already  set.  This option can be
2724               used several  times to  specify multiple  header fields.
2725               Example: --add-response-header="foo: bar"
2726   --request-header-field-buffer=<SIZE>
2727               Set maximum buffer size for incoming HTTP request header
2728               field list.  This is the sum of header name and value in
2729               bytes.   If  trailer  fields  exist,  they  are  counted
2730               towards this number.
2731               Default: )"
2732       << util::utos_unit(config->http.request_header_field_buffer) << R"(
2733   --max-request-header-fields=<N>
2734               Set  maximum  number  of incoming  HTTP  request  header
2735               fields.   If  trailer  fields exist,  they  are  counted
2736               towards this number.
2737               Default: )"
2738       << config->http.max_request_header_fields << R"(
2739   --response-header-field-buffer=<SIZE>
2740               Set  maximum  buffer  size for  incoming  HTTP  response
2741               header field list.   This is the sum of  header name and
2742               value  in  bytes.  If  trailer  fields  exist, they  are
2743               counted towards this number.
2744               Default: )"
2745       << util::utos_unit(config->http.response_header_field_buffer) << R"(
2746   --max-response-header-fields=<N>
2747               Set  maximum number  of  incoming  HTTP response  header
2748               fields.   If  trailer  fields exist,  they  are  counted
2749               towards this number.
2750               Default: )"
2751       << config->http.max_response_header_fields << R"(
2752   --error-page=(<CODE>|*)=<PATH>
2753               Set file path  to custom error page  served when nghttpx
2754               originally  generates  HTTP  error status  code  <CODE>.
2755               <CODE> must be greater than or equal to 400, and at most
2756               599.  If "*"  is used instead of <CODE>,  it matches all
2757               HTTP  status  code.  If  error  status  code comes  from
2758               backend server, the custom error pages are not used.
2759   --server-name=<NAME>
2760               Change server response header field value to <NAME>.
2761               Default: )"
2762       << config->http.server_name << R"(
2763   --no-server-rewrite
2764               Don't rewrite server header field in default mode.  When
2765               --http2-proxy is used, these headers will not be altered
2766               regardless of this option.
2767   --redirect-https-port=<PORT>
2768               Specify the port number which appears in Location header
2769               field  when  redirect  to  HTTPS  URI  is  made  due  to
2770               "redirect-if-not-tls" parameter in --backend option.
2771               Default: )"
2772       << config->http.redirect_https_port << R"(
2773 
2774 API:
2775   --api-max-request-body=<SIZE>
2776               Set the maximum size of request body for API request.
2777               Default: )"
2778       << util::utos_unit(config->api.max_request_body) << R"(
2779 
2780 DNS:
2781   --dns-cache-timeout=<DURATION>
2782               Set duration that cached DNS results remain valid.  Note
2783               that nghttpx caches the unsuccessful results as well.
2784               Default: )"
2785       << util::duration_str(config->dns.timeout.cache) << R"(
2786   --dns-lookup-timeout=<DURATION>
2787               Set timeout that  DNS server is given to  respond to the
2788               initial  DNS  query.  For  the  2nd  and later  queries,
2789               server is  given time based  on this timeout, and  it is
2790               scaled linearly.
2791               Default: )"
2792       << util::duration_str(config->dns.timeout.lookup) << R"(
2793   --dns-max-try=<N>
2794               Set the number of DNS query before nghttpx gives up name
2795               lookup.
2796               Default: )"
2797       << config->dns.max_try << R"(
2798   --frontend-max-requests=<N>
2799               The number  of requests that single  frontend connection
2800               can process.  For HTTP/2, this  is the number of streams
2801               in  one  HTTP/2 connection.   For  HTTP/1,  this is  the
2802               number of keep alive requests.  This is hint to nghttpx,
2803               and it  may allow additional few  requests.  The default
2804               value is unlimited.
2805 
2806 Debug:
2807   --frontend-http2-dump-request-header=<PATH>
2808               Dumps request headers received by HTTP/2 frontend to the
2809               file denoted  in <PATH>.  The  output is done  in HTTP/1
2810               header field format and each header block is followed by
2811               an empty line.  This option  is not thread safe and MUST
2812               NOT be used with option -n<N>, where <N> >= 2.
2813   --frontend-http2-dump-response-header=<PATH>
2814               Dumps response headers sent  from HTTP/2 frontend to the
2815               file denoted  in <PATH>.  The  output is done  in HTTP/1
2816               header field format and each header block is followed by
2817               an empty line.  This option  is not thread safe and MUST
2818               NOT be used with option -n<N>, where <N> >= 2.
2819   -o, --frontend-frame-debug
2820               Print HTTP/2 frames in  frontend to stderr.  This option
2821               is  not thread  safe and  MUST NOT  be used  with option
2822               -n=N, where N >= 2.
2823 
2824 Process:
2825   -D, --daemon
2826               Run in a background.  If -D is used, the current working
2827               directory is changed to '/'.
2828   --pid-file=<PATH>
2829               Set path to save PID of this program.
2830   --user=<USER>
2831               Run this program as <USER>.   This option is intended to
2832               be used to drop root privileges.
2833   --single-process
2834               Run this program in a  single process mode for debugging
2835               purpose.  Without this option,  nghttpx creates at least
2836               2  processes:  master  and worker  processes.   If  this
2837               option is  used, master  and worker  are unified  into a
2838               single process.  nghttpx still spawns additional process
2839               if neverbleed is used.  In  the single process mode, the
2840               signal handling feature is disabled.
2841 
2842 Scripting:
2843   --mruby-file=<PATH>
2844               Set mruby script file
2845   --ignore-per-pattern-mruby-error
2846               Ignore mruby compile error  for per-pattern mruby script
2847               file.  If error  occurred, it is treated as  if no mruby
2848               file were specified for the pattern.
2849 
2850 Misc:
2851   --conf=<PATH>
2852               Load  configuration  from   <PATH>.   Please  note  that
2853               nghttpx always  tries to read the  default configuration
2854               file if --conf is not given.
2855               Default: )"
2856       << config->conf_path << R"(
2857   --include=<PATH>
2858               Load additional configurations from <PATH>.  File <PATH>
2859               is  read  when  configuration  parser  encountered  this
2860               option.  This option can be used multiple times, or even
2861               recursively.
2862   -v, --version
2863               Print version and exit.
2864   -h, --help  Print this help and exit.
2865 
2866 --
2867 
2868   The <SIZE> argument is an integer and an optional unit (e.g., 10K is
2869   10 * 1024).  Units are K, M and G (powers of 1024).
2870 
2871   The <DURATION> argument is an integer and an optional unit (e.g., 1s
2872   is 1 second and 500ms is 500 milliseconds).  Units are h, m, s or ms
2873   (hours, minutes, seconds and milliseconds, respectively).  If a unit
2874   is omitted, a second is used as unit.)"
2875       << std::endl;
2876 }
2877 } // namespace
2878 
2879 namespace {
process_options(Config * config,std::vector<std::pair<StringRef,StringRef>> & cmdcfgs)2880 int process_options(Config *config,
2881                     std::vector<std::pair<StringRef, StringRef>> &cmdcfgs) {
2882   std::array<char, STRERROR_BUFSIZE> errbuf;
2883   std::map<StringRef, size_t> pattern_addr_indexer;
2884   if (conf_exists(config->conf_path.c_str())) {
2885     LOG(NOTICE) << "Loading configuration from " << config->conf_path;
2886     std::set<StringRef> include_set;
2887     if (load_config(config, config->conf_path.c_str(), include_set,
2888                     pattern_addr_indexer) == -1) {
2889       LOG(FATAL) << "Failed to load configuration from " << config->conf_path;
2890       return -1;
2891     }
2892     assert(include_set.empty());
2893   }
2894 
2895   // Reopen log files using configurations in file
2896   reopen_log_files(config->logging);
2897 
2898   {
2899     std::set<StringRef> include_set;
2900 
2901     for (auto &p : cmdcfgs) {
2902       if (parse_config(config, p.first, p.second, include_set,
2903                        pattern_addr_indexer) == -1) {
2904         LOG(FATAL) << "Failed to parse command-line argument.";
2905         return -1;
2906       }
2907     }
2908 
2909     assert(include_set.empty());
2910   }
2911 
2912   Log::set_severity_level(config->logging.severity);
2913 
2914   auto &loggingconf = config->logging;
2915 
2916   if (loggingconf.access.syslog || loggingconf.error.syslog) {
2917     openlog("nghttpx", LOG_NDELAY | LOG_NOWAIT | LOG_PID,
2918             loggingconf.syslog_facility);
2919   }
2920 
2921   if (reopen_log_files(config->logging) != 0) {
2922     LOG(FATAL) << "Failed to open log file";
2923     return -1;
2924   }
2925 
2926   redirect_stderr_to_errorlog(loggingconf);
2927 
2928   if (config->uid != 0) {
2929     if (log_config()->accesslog_fd != -1 &&
2930         fchown(log_config()->accesslog_fd, config->uid, config->gid) == -1) {
2931       auto error = errno;
2932       LOG(WARN) << "Changing owner of access log file failed: "
2933                 << xsi_strerror(error, errbuf.data(), errbuf.size());
2934     }
2935     if (log_config()->errorlog_fd != -1 &&
2936         fchown(log_config()->errorlog_fd, config->uid, config->gid) == -1) {
2937       auto error = errno;
2938       LOG(WARN) << "Changing owner of error log file failed: "
2939                 << xsi_strerror(error, errbuf.data(), errbuf.size());
2940     }
2941   }
2942 
2943   if (config->single_thread) {
2944     LOG(WARN) << "single-thread: Set workers to 1";
2945     config->num_worker = 1;
2946   }
2947 
2948   auto &http2conf = config->http2;
2949   {
2950     auto &dumpconf = http2conf.upstream.debug.dump;
2951 
2952     if (!dumpconf.request_header_file.empty()) {
2953       auto path = dumpconf.request_header_file.c_str();
2954       auto f = open_file_for_write(path);
2955 
2956       if (f == nullptr) {
2957         LOG(FATAL) << "Failed to open http2 upstream request header file: "
2958                    << path;
2959         return -1;
2960       }
2961 
2962       dumpconf.request_header = f;
2963 
2964       if (config->uid != 0) {
2965         if (chown(path, config->uid, config->gid) == -1) {
2966           auto error = errno;
2967           LOG(WARN) << "Changing owner of http2 upstream request header file "
2968                     << path << " failed: "
2969                     << xsi_strerror(error, errbuf.data(), errbuf.size());
2970         }
2971       }
2972     }
2973 
2974     if (!dumpconf.response_header_file.empty()) {
2975       auto path = dumpconf.response_header_file.c_str();
2976       auto f = open_file_for_write(path);
2977 
2978       if (f == nullptr) {
2979         LOG(FATAL) << "Failed to open http2 upstream response header file: "
2980                    << path;
2981         return -1;
2982       }
2983 
2984       dumpconf.response_header = f;
2985 
2986       if (config->uid != 0) {
2987         if (chown(path, config->uid, config->gid) == -1) {
2988           auto error = errno;
2989           LOG(WARN) << "Changing owner of http2 upstream response header file"
2990                     << " " << path << " failed: "
2991                     << xsi_strerror(error, errbuf.data(), errbuf.size());
2992         }
2993       }
2994     }
2995   }
2996 
2997   auto &tlsconf = config->tls;
2998 
2999   if (tlsconf.npn_list.empty()) {
3000     tlsconf.npn_list = util::split_str(DEFAULT_NPN_LIST, ',');
3001   }
3002 
3003   if (!tlsconf.tls_proto_list.empty()) {
3004     tlsconf.tls_proto_mask = tls::create_tls_proto_mask(tlsconf.tls_proto_list);
3005   }
3006 
3007   // TODO We depends on the ordering of protocol version macro in
3008   // OpenSSL.
3009   if (tlsconf.min_proto_version > tlsconf.max_proto_version) {
3010     LOG(ERROR) << "tls-max-proto-version must be equal to or larger than "
3011                   "tls-min-proto-version";
3012     return -1;
3013   }
3014 
3015   if (tls::set_alpn_prefs(tlsconf.alpn_prefs, tlsconf.npn_list) != 0) {
3016     return -1;
3017   }
3018 
3019   tlsconf.bio_method = create_bio_method();
3020 
3021   auto &listenerconf = config->conn.listener;
3022   auto &upstreamconf = config->conn.upstream;
3023 
3024   if (listenerconf.addrs.empty()) {
3025     UpstreamAddr addr{};
3026     addr.host = StringRef::from_lit("*");
3027     addr.port = 3000;
3028     addr.tls = true;
3029     addr.family = AF_INET;
3030     listenerconf.addrs.push_back(addr);
3031     addr.family = AF_INET6;
3032     listenerconf.addrs.push_back(std::move(addr));
3033   }
3034 
3035   if (upstreamconf.worker_connections == 0) {
3036     upstreamconf.worker_connections = std::numeric_limits<size_t>::max();
3037   }
3038 
3039   if (tls::upstream_tls_enabled(config->conn) &&
3040       (tlsconf.private_key_file.empty() || tlsconf.cert_file.empty())) {
3041     LOG(FATAL) << "TLS private key and certificate files are required.  "
3042                   "Specify them in command-line, or in configuration file "
3043                   "using private-key-file and certificate-file options.";
3044     return -1;
3045   }
3046 
3047   if (tls::upstream_tls_enabled(config->conn) && !tlsconf.ocsp.disabled) {
3048     struct stat buf;
3049     if (stat(tlsconf.ocsp.fetch_ocsp_response_file.c_str(), &buf) != 0) {
3050       tlsconf.ocsp.disabled = true;
3051       LOG(WARN) << "--fetch-ocsp-response-file: "
3052                 << tlsconf.ocsp.fetch_ocsp_response_file
3053                 << " not found.  OCSP stapling has been disabled.";
3054     }
3055   }
3056 
3057   if (configure_downstream_group(config, config->http2_proxy, false, tlsconf) !=
3058       0) {
3059     return -1;
3060   }
3061 
3062   auto &proxy = config->downstream_http_proxy;
3063   if (!proxy.host.empty()) {
3064     auto hostport = util::make_hostport(StringRef{proxy.host}, proxy.port);
3065     if (resolve_hostname(&proxy.addr, proxy.host.c_str(), proxy.port,
3066                          AF_UNSPEC) == -1) {
3067       LOG(FATAL) << "Resolving backend HTTP proxy address failed: " << hostport;
3068       return -1;
3069     }
3070     LOG(NOTICE) << "Backend HTTP proxy address: " << hostport << " -> "
3071                 << util::to_numeric_addr(&proxy.addr);
3072   }
3073 
3074   {
3075     auto &memcachedconf = tlsconf.session_cache.memcached;
3076     if (!memcachedconf.host.empty()) {
3077       auto hostport = util::make_hostport(StringRef{memcachedconf.host},
3078                                           memcachedconf.port);
3079       if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.c_str(),
3080                            memcachedconf.port, memcachedconf.family) == -1) {
3081         LOG(FATAL)
3082             << "Resolving memcached address for TLS session cache failed: "
3083             << hostport;
3084         return -1;
3085       }
3086       LOG(NOTICE) << "Memcached address for TLS session cache: " << hostport
3087                   << " -> " << util::to_numeric_addr(&memcachedconf.addr);
3088       if (memcachedconf.tls) {
3089         LOG(NOTICE) << "Connection to memcached for TLS session cache will be "
3090                        "encrypted by TLS";
3091       }
3092     }
3093   }
3094 
3095   {
3096     auto &memcachedconf = tlsconf.ticket.memcached;
3097     if (!memcachedconf.host.empty()) {
3098       auto hostport = util::make_hostport(StringRef{memcachedconf.host},
3099                                           memcachedconf.port);
3100       if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.c_str(),
3101                            memcachedconf.port, memcachedconf.family) == -1) {
3102         LOG(FATAL) << "Resolving memcached address for TLS ticket key failed: "
3103                    << hostport;
3104         return -1;
3105       }
3106       LOG(NOTICE) << "Memcached address for TLS ticket key: " << hostport
3107                   << " -> " << util::to_numeric_addr(&memcachedconf.addr);
3108       if (memcachedconf.tls) {
3109         LOG(NOTICE) << "Connection to memcached for TLS ticket key will be "
3110                        "encrypted by TLS";
3111       }
3112     }
3113   }
3114 
3115   if (config->rlimit_nofile) {
3116     struct rlimit lim = {static_cast<rlim_t>(config->rlimit_nofile),
3117                          static_cast<rlim_t>(config->rlimit_nofile)};
3118     if (setrlimit(RLIMIT_NOFILE, &lim) != 0) {
3119       auto error = errno;
3120       LOG(WARN) << "Setting rlimit-nofile failed: "
3121                 << xsi_strerror(error, errbuf.data(), errbuf.size());
3122     }
3123   }
3124 
3125   auto &fwdconf = config->http.forwarded;
3126 
3127   if (fwdconf.by_node_type == ForwardedNode::OBFUSCATED &&
3128       fwdconf.by_obfuscated.empty()) {
3129     // 2 for '_' and terminal NULL
3130     auto iov = make_byte_ref(config->balloc, SHRPX_OBFUSCATED_NODE_LENGTH + 2);
3131     auto p = iov.base;
3132     *p++ = '_';
3133     auto gen = util::make_mt19937();
3134     p = util::random_alpha_digit(p, p + SHRPX_OBFUSCATED_NODE_LENGTH, gen);
3135     *p = '\0';
3136     fwdconf.by_obfuscated = StringRef{iov.base, p};
3137   }
3138 
3139   if (config->http2.upstream.debug.frame_debug) {
3140     // To make it sync to logging
3141     set_output(stderr);
3142     if (isatty(fileno(stdout))) {
3143       set_color_output(true);
3144     }
3145     reset_timer();
3146   }
3147 
3148   config->http2.upstream.callbacks = create_http2_upstream_callbacks();
3149   config->http2.downstream.callbacks = create_http2_downstream_callbacks();
3150 
3151   return 0;
3152 }
3153 } // namespace
3154 
3155 namespace {
3156 // Closes file descriptor which are opened for listeners in config,
3157 // and are not inherited from |iaddrs|.
close_not_inherited_fd(Config * config,const std::vector<InheritedAddr> & iaddrs)3158 void close_not_inherited_fd(Config *config,
3159                             const std::vector<InheritedAddr> &iaddrs) {
3160   auto &listenerconf = config->conn.listener;
3161 
3162   for (auto &addr : listenerconf.addrs) {
3163     auto inherited = std::find_if(
3164         std::begin(iaddrs), std::end(iaddrs),
3165         [&addr](const InheritedAddr &iaddr) { return addr.fd == iaddr.fd; });
3166 
3167     if (inherited != std::end(iaddrs)) {
3168       continue;
3169     }
3170 
3171     close(addr.fd);
3172   }
3173 }
3174 } // namespace
3175 
3176 namespace {
reload_config(WorkerProcess * wp)3177 void reload_config(WorkerProcess *wp) {
3178   int rv;
3179 
3180   LOG(NOTICE) << "Reloading configuration";
3181 
3182   auto cur_config = mod_config();
3183   auto new_config = std::make_unique<Config>();
3184 
3185   fill_default_config(new_config.get());
3186 
3187   new_config->conf_path =
3188       make_string_ref(new_config->balloc, cur_config->conf_path);
3189   // daemon option is ignored here.
3190   new_config->daemon = cur_config->daemon;
3191   // loop is reused, and ev_loop_flags gets ignored
3192   new_config->ev_loop_flags = cur_config->ev_loop_flags;
3193   new_config->config_revision = cur_config->config_revision + 1;
3194 
3195   rv = process_options(new_config.get(), suconfig.cmdcfgs);
3196   if (rv != 0) {
3197     LOG(ERROR) << "Failed to process new configuration";
3198     return;
3199   }
3200 
3201   auto iaddrs = get_inherited_addr_from_config(new_config->balloc, cur_config);
3202 
3203   if (create_acceptor_socket(new_config.get(), iaddrs) != 0) {
3204     close_not_inherited_fd(new_config.get(), iaddrs);
3205     return;
3206   }
3207 
3208   // According to libev documentation, flags are ignored since we have
3209   // already created first default loop.
3210   auto loop = ev_default_loop(new_config->ev_loop_flags);
3211 
3212   int ipc_fd = 0;
3213 
3214   // fork_worker_process and forked child process assumes new
3215   // configuration can be obtained from get_config().
3216 
3217   auto old_config = replace_config(std::move(new_config));
3218 
3219   auto pid = fork_worker_process(ipc_fd, iaddrs);
3220 
3221   if (pid == -1) {
3222     LOG(ERROR) << "Failed to process new configuration";
3223 
3224     new_config = replace_config(std::move(old_config));
3225     close_not_inherited_fd(new_config.get(), iaddrs);
3226 
3227     return;
3228   }
3229 
3230   close_unused_inherited_addr(iaddrs);
3231 
3232   // Send last worker process a graceful shutdown notice
3233   auto &last_wp = worker_processes.back();
3234   ipc_send(last_wp.get(), SHRPX_IPC_GRACEFUL_SHUTDOWN);
3235   // We no longer use signals for this worker.
3236   last_wp->shutdown_signal_watchers();
3237 
3238   worker_process_add(std::make_unique<WorkerProcess>(loop, pid, ipc_fd));
3239 
3240   if (!get_config()->pid_file.empty()) {
3241     save_pid();
3242   }
3243 }
3244 } // namespace
3245 
main(int argc,char ** argv)3246 int main(int argc, char **argv) {
3247   int rv;
3248   std::array<char, STRERROR_BUFSIZE> errbuf;
3249 
3250   nghttp2::tls::libssl_init();
3251 
3252 #ifndef NOTHREADS
3253   nghttp2::tls::LibsslGlobalLock lock;
3254 #endif // NOTHREADS
3255 
3256   Log::set_severity_level(NOTICE);
3257   create_config();
3258   fill_default_config(mod_config());
3259 
3260   // make copy of stderr
3261   store_original_fds();
3262 
3263   // First open log files with default configuration, so that we can
3264   // log errors/warnings while reading configuration files.
3265   reopen_log_files(get_config()->logging);
3266 
3267   suconfig.original_argv = argv;
3268 
3269   // We have to copy argv, since getopt_long may change its content.
3270   suconfig.argc = argc;
3271   suconfig.argv = new char *[argc];
3272 
3273   for (int i = 0; i < argc; ++i) {
3274     suconfig.argv[i] = strdup(argv[i]);
3275     if (suconfig.argv[i] == nullptr) {
3276       auto error = errno;
3277       LOG(FATAL) << "failed to copy argv: "
3278                  << xsi_strerror(error, errbuf.data(), errbuf.size());
3279       exit(EXIT_FAILURE);
3280     }
3281   }
3282 
3283   suconfig.cwd = getcwd(nullptr, 0);
3284   if (suconfig.cwd == nullptr) {
3285     auto error = errno;
3286     LOG(FATAL) << "failed to get current working directory: errno=" << error;
3287     exit(EXIT_FAILURE);
3288   }
3289 
3290   auto &cmdcfgs = suconfig.cmdcfgs;
3291 
3292   while (1) {
3293     static int flag = 0;
3294     static constexpr option long_options[] = {
3295         {SHRPX_OPT_DAEMON.c_str(), no_argument, nullptr, 'D'},
3296         {SHRPX_OPT_LOG_LEVEL.c_str(), required_argument, nullptr, 'L'},
3297         {SHRPX_OPT_BACKEND.c_str(), required_argument, nullptr, 'b'},
3298         {SHRPX_OPT_HTTP2_MAX_CONCURRENT_STREAMS.c_str(), required_argument,
3299          nullptr, 'c'},
3300         {SHRPX_OPT_FRONTEND.c_str(), required_argument, nullptr, 'f'},
3301         {"help", no_argument, nullptr, 'h'},
3302         {SHRPX_OPT_INSECURE.c_str(), no_argument, nullptr, 'k'},
3303         {SHRPX_OPT_WORKERS.c_str(), required_argument, nullptr, 'n'},
3304         {SHRPX_OPT_CLIENT_PROXY.c_str(), no_argument, nullptr, 'p'},
3305         {SHRPX_OPT_HTTP2_PROXY.c_str(), no_argument, nullptr, 's'},
3306         {"version", no_argument, nullptr, 'v'},
3307         {SHRPX_OPT_FRONTEND_FRAME_DEBUG.c_str(), no_argument, nullptr, 'o'},
3308         {SHRPX_OPT_ADD_X_FORWARDED_FOR.c_str(), no_argument, &flag, 1},
3309         {SHRPX_OPT_FRONTEND_HTTP2_READ_TIMEOUT.c_str(), required_argument,
3310          &flag, 2},
3311         {SHRPX_OPT_FRONTEND_READ_TIMEOUT.c_str(), required_argument, &flag, 3},
3312         {SHRPX_OPT_FRONTEND_WRITE_TIMEOUT.c_str(), required_argument, &flag, 4},
3313         {SHRPX_OPT_BACKEND_READ_TIMEOUT.c_str(), required_argument, &flag, 5},
3314         {SHRPX_OPT_BACKEND_WRITE_TIMEOUT.c_str(), required_argument, &flag, 6},
3315         {SHRPX_OPT_ACCESSLOG_FILE.c_str(), required_argument, &flag, 7},
3316         {SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT.c_str(), required_argument, &flag,
3317          8},
3318         {SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS.c_str(), required_argument, &flag,
3319          9},
3320         {SHRPX_OPT_PID_FILE.c_str(), required_argument, &flag, 10},
3321         {SHRPX_OPT_USER.c_str(), required_argument, &flag, 11},
3322         {"conf", required_argument, &flag, 12},
3323         {SHRPX_OPT_SYSLOG_FACILITY.c_str(), required_argument, &flag, 14},
3324         {SHRPX_OPT_BACKLOG.c_str(), required_argument, &flag, 15},
3325         {SHRPX_OPT_CIPHERS.c_str(), required_argument, &flag, 16},
3326         {SHRPX_OPT_CLIENT.c_str(), no_argument, &flag, 17},
3327         {SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS.c_str(), required_argument, &flag,
3328          18},
3329         {SHRPX_OPT_CACERT.c_str(), required_argument, &flag, 19},
3330         {SHRPX_OPT_BACKEND_IPV4.c_str(), no_argument, &flag, 20},
3331         {SHRPX_OPT_BACKEND_IPV6.c_str(), no_argument, &flag, 21},
3332         {SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE.c_str(), required_argument, &flag,
3333          22},
3334         {SHRPX_OPT_NO_VIA.c_str(), no_argument, &flag, 23},
3335         {SHRPX_OPT_SUBCERT.c_str(), required_argument, &flag, 24},
3336         {SHRPX_OPT_HTTP2_BRIDGE.c_str(), no_argument, &flag, 25},
3337         {SHRPX_OPT_BACKEND_HTTP_PROXY_URI.c_str(), required_argument, &flag,
3338          26},
3339         {SHRPX_OPT_BACKEND_NO_TLS.c_str(), no_argument, &flag, 27},
3340         {SHRPX_OPT_OCSP_STARTUP.c_str(), no_argument, &flag, 28},
3341         {SHRPX_OPT_FRONTEND_NO_TLS.c_str(), no_argument, &flag, 29},
3342         {SHRPX_OPT_NO_VERIFY_OCSP.c_str(), no_argument, &flag, 30},
3343         {SHRPX_OPT_BACKEND_TLS_SNI_FIELD.c_str(), required_argument, &flag, 31},
3344         {SHRPX_OPT_DH_PARAM_FILE.c_str(), required_argument, &flag, 33},
3345         {SHRPX_OPT_READ_RATE.c_str(), required_argument, &flag, 34},
3346         {SHRPX_OPT_READ_BURST.c_str(), required_argument, &flag, 35},
3347         {SHRPX_OPT_WRITE_RATE.c_str(), required_argument, &flag, 36},
3348         {SHRPX_OPT_WRITE_BURST.c_str(), required_argument, &flag, 37},
3349         {SHRPX_OPT_NPN_LIST.c_str(), required_argument, &flag, 38},
3350         {SHRPX_OPT_VERIFY_CLIENT.c_str(), no_argument, &flag, 39},
3351         {SHRPX_OPT_VERIFY_CLIENT_CACERT.c_str(), required_argument, &flag, 40},
3352         {SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE.c_str(), required_argument, &flag,
3353          41},
3354         {SHRPX_OPT_CLIENT_CERT_FILE.c_str(), required_argument, &flag, 42},
3355         {SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER.c_str(),
3356          required_argument, &flag, 43},
3357         {SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER.c_str(),
3358          required_argument, &flag, 44},
3359         {SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING.c_str(), no_argument, &flag, 45},
3360         {SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS.c_str(),
3361          required_argument, &flag, 46},
3362         {SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS.c_str(),
3363          required_argument, &flag, 47},
3364         {SHRPX_OPT_TLS_PROTO_LIST.c_str(), required_argument, &flag, 48},
3365         {SHRPX_OPT_PADDING.c_str(), required_argument, &flag, 49},
3366         {SHRPX_OPT_WORKER_READ_RATE.c_str(), required_argument, &flag, 50},
3367         {SHRPX_OPT_WORKER_READ_BURST.c_str(), required_argument, &flag, 51},
3368         {SHRPX_OPT_WORKER_WRITE_RATE.c_str(), required_argument, &flag, 52},
3369         {SHRPX_OPT_WORKER_WRITE_BURST.c_str(), required_argument, &flag, 53},
3370         {SHRPX_OPT_ALTSVC.c_str(), required_argument, &flag, 54},
3371         {SHRPX_OPT_ADD_RESPONSE_HEADER.c_str(), required_argument, &flag, 55},
3372         {SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS.c_str(), required_argument,
3373          &flag, 56},
3374         {SHRPX_OPT_ACCESSLOG_SYSLOG.c_str(), no_argument, &flag, 57},
3375         {SHRPX_OPT_ERRORLOG_FILE.c_str(), required_argument, &flag, 58},
3376         {SHRPX_OPT_ERRORLOG_SYSLOG.c_str(), no_argument, &flag, 59},
3377         {SHRPX_OPT_STREAM_READ_TIMEOUT.c_str(), required_argument, &flag, 60},
3378         {SHRPX_OPT_STREAM_WRITE_TIMEOUT.c_str(), required_argument, &flag, 61},
3379         {SHRPX_OPT_NO_LOCATION_REWRITE.c_str(), no_argument, &flag, 62},
3380         {SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST.c_str(),
3381          required_argument, &flag, 63},
3382         {SHRPX_OPT_LISTENER_DISABLE_TIMEOUT.c_str(), required_argument, &flag,
3383          64},
3384         {SHRPX_OPT_STRIP_INCOMING_X_FORWARDED_FOR.c_str(), no_argument, &flag,
3385          65},
3386         {SHRPX_OPT_ACCESSLOG_FORMAT.c_str(), required_argument, &flag, 66},
3387         {SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND.c_str(),
3388          required_argument, &flag, 67},
3389         {SHRPX_OPT_TLS_TICKET_KEY_FILE.c_str(), required_argument, &flag, 68},
3390         {SHRPX_OPT_RLIMIT_NOFILE.c_str(), required_argument, &flag, 69},
3391         {SHRPX_OPT_BACKEND_RESPONSE_BUFFER.c_str(), required_argument, &flag,
3392          71},
3393         {SHRPX_OPT_BACKEND_REQUEST_BUFFER.c_str(), required_argument, &flag,
3394          72},
3395         {SHRPX_OPT_NO_HOST_REWRITE.c_str(), no_argument, &flag, 73},
3396         {SHRPX_OPT_NO_SERVER_PUSH.c_str(), no_argument, &flag, 74},
3397         {SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER.c_str(),
3398          required_argument, &flag, 76},
3399         {SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE.c_str(), required_argument, &flag,
3400          77},
3401         {SHRPX_OPT_OCSP_UPDATE_INTERVAL.c_str(), required_argument, &flag, 78},
3402         {SHRPX_OPT_NO_OCSP.c_str(), no_argument, &flag, 79},
3403         {SHRPX_OPT_HEADER_FIELD_BUFFER.c_str(), required_argument, &flag, 80},
3404         {SHRPX_OPT_MAX_HEADER_FIELDS.c_str(), required_argument, &flag, 81},
3405         {SHRPX_OPT_ADD_REQUEST_HEADER.c_str(), required_argument, &flag, 82},
3406         {SHRPX_OPT_INCLUDE.c_str(), required_argument, &flag, 83},
3407         {SHRPX_OPT_TLS_TICKET_KEY_CIPHER.c_str(), required_argument, &flag, 84},
3408         {SHRPX_OPT_HOST_REWRITE.c_str(), no_argument, &flag, 85},
3409         {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED.c_str(), required_argument,
3410          &flag, 86},
3411         {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED.c_str(), required_argument, &flag,
3412          87},
3413         {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_INTERVAL.c_str(), required_argument,
3414          &flag, 88},
3415         {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY.c_str(),
3416          required_argument, &flag, 89},
3417         {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL.c_str(), required_argument,
3418          &flag, 90},
3419         {SHRPX_OPT_MRUBY_FILE.c_str(), required_argument, &flag, 91},
3420         {SHRPX_OPT_ACCEPT_PROXY_PROTOCOL.c_str(), no_argument, &flag, 93},
3421         {SHRPX_OPT_FASTOPEN.c_str(), required_argument, &flag, 94},
3422         {SHRPX_OPT_TLS_DYN_REC_WARMUP_THRESHOLD.c_str(), required_argument,
3423          &flag, 95},
3424         {SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT.c_str(), required_argument, &flag,
3425          96},
3426         {SHRPX_OPT_ADD_FORWARDED.c_str(), required_argument, &flag, 97},
3427         {SHRPX_OPT_STRIP_INCOMING_FORWARDED.c_str(), no_argument, &flag, 98},
3428         {SHRPX_OPT_FORWARDED_BY.c_str(), required_argument, &flag, 99},
3429         {SHRPX_OPT_FORWARDED_FOR.c_str(), required_argument, &flag, 100},
3430         {SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER.c_str(), required_argument,
3431          &flag, 101},
3432         {SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS.c_str(), required_argument, &flag,
3433          102},
3434         {SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST.c_str(), no_argument, &flag, 103},
3435         {SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER.c_str(), required_argument,
3436          &flag, 104},
3437         {SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS.c_str(), required_argument, &flag,
3438          105},
3439         {SHRPX_OPT_BACKEND_HTTP1_TLS.c_str(), no_argument, &flag, 106},
3440         {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS.c_str(), no_argument, &flag,
3441          108},
3442         {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE.c_str(),
3443          required_argument, &flag, 109},
3444         {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE.c_str(),
3445          required_argument, &flag, 110},
3446         {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS.c_str(), no_argument, &flag,
3447          111},
3448         {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE.c_str(),
3449          required_argument, &flag, 112},
3450         {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE.c_str(),
3451          required_argument, &flag, 113},
3452         {SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY.c_str(),
3453          required_argument, &flag, 114},
3454         {SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY.c_str(),
3455          required_argument, &flag, 115},
3456         {SHRPX_OPT_BACKEND_ADDRESS_FAMILY.c_str(), required_argument, &flag,
3457          116},
3458         {SHRPX_OPT_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS.c_str(),
3459          required_argument, &flag, 117},
3460         {SHRPX_OPT_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS.c_str(),
3461          required_argument, &flag, 118},
3462         {SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND.c_str(), required_argument,
3463          &flag, 119},
3464         {SHRPX_OPT_BACKEND_TLS.c_str(), no_argument, &flag, 120},
3465         {SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST.c_str(), required_argument,
3466          &flag, 121},
3467         {SHRPX_OPT_ERROR_PAGE.c_str(), required_argument, &flag, 122},
3468         {SHRPX_OPT_NO_KQUEUE.c_str(), no_argument, &flag, 123},
3469         {SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument,
3470          &flag, 124},
3471         {SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument,
3472          &flag, 125},
3473         {SHRPX_OPT_API_MAX_REQUEST_BODY.c_str(), required_argument, &flag, 126},
3474         {SHRPX_OPT_BACKEND_MAX_BACKOFF.c_str(), required_argument, &flag, 127},
3475         {SHRPX_OPT_SERVER_NAME.c_str(), required_argument, &flag, 128},
3476         {SHRPX_OPT_NO_SERVER_REWRITE.c_str(), no_argument, &flag, 129},
3477         {SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE.c_str(),
3478          no_argument, &flag, 130},
3479         {SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE.c_str(), no_argument,
3480          &flag, 131},
3481         {SHRPX_OPT_FRONTEND_HTTP2_WINDOW_SIZE.c_str(), required_argument, &flag,
3482          132},
3483         {SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE.c_str(),
3484          required_argument, &flag, 133},
3485         {SHRPX_OPT_BACKEND_HTTP2_WINDOW_SIZE.c_str(), required_argument, &flag,
3486          134},
3487         {SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE.c_str(),
3488          required_argument, &flag, 135},
3489         {SHRPX_OPT_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE.c_str(),
3490          required_argument, &flag, 136},
3491         {SHRPX_OPT_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE.c_str(),
3492          required_argument, &flag, 137},
3493         {SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE.c_str(),
3494          required_argument, &flag, 138},
3495         {SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE.c_str(),
3496          required_argument, &flag, 139},
3497         {SHRPX_OPT_ECDH_CURVES.c_str(), required_argument, &flag, 140},
3498         {SHRPX_OPT_TLS_SCT_DIR.c_str(), required_argument, &flag, 141},
3499         {SHRPX_OPT_BACKEND_CONNECT_TIMEOUT.c_str(), required_argument, &flag,
3500          142},
3501         {SHRPX_OPT_DNS_CACHE_TIMEOUT.c_str(), required_argument, &flag, 143},
3502         {SHRPX_OPT_DNS_LOOKUP_TIMEOUT.c_str(), required_argument, &flag, 144},
3503         {SHRPX_OPT_DNS_MAX_TRY.c_str(), required_argument, &flag, 145},
3504         {SHRPX_OPT_FRONTEND_KEEP_ALIVE_TIMEOUT.c_str(), required_argument,
3505          &flag, 146},
3506         {SHRPX_OPT_PSK_SECRETS.c_str(), required_argument, &flag, 147},
3507         {SHRPX_OPT_CLIENT_PSK_SECRETS.c_str(), required_argument, &flag, 148},
3508         {SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST.c_str(), no_argument,
3509          &flag, 149},
3510         {SHRPX_OPT_CLIENT_CIPHERS.c_str(), required_argument, &flag, 150},
3511         {SHRPX_OPT_ACCESSLOG_WRITE_EARLY.c_str(), no_argument, &flag, 151},
3512         {SHRPX_OPT_TLS_MIN_PROTO_VERSION.c_str(), required_argument, &flag,
3513          152},
3514         {SHRPX_OPT_TLS_MAX_PROTO_VERSION.c_str(), required_argument, &flag,
3515          153},
3516         {SHRPX_OPT_REDIRECT_HTTPS_PORT.c_str(), required_argument, &flag, 154},
3517         {SHRPX_OPT_FRONTEND_MAX_REQUESTS.c_str(), required_argument, &flag,
3518          155},
3519         {SHRPX_OPT_SINGLE_THREAD.c_str(), no_argument, &flag, 156},
3520         {SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO.c_str(), no_argument, &flag, 157},
3521         {SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO.c_str(), no_argument,
3522          &flag, 158},
3523         {SHRPX_OPT_SINGLE_PROCESS.c_str(), no_argument, &flag, 159},
3524         {SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED.c_str(), no_argument, &flag,
3525          160},
3526         {SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR.c_str(), no_argument, &flag,
3527          161},
3528         {SHRPX_OPT_TLS_NO_POSTPONE_EARLY_DATA.c_str(), no_argument, &flag, 162},
3529         {SHRPX_OPT_TLS_MAX_EARLY_DATA.c_str(), required_argument, &flag, 163},
3530         {SHRPX_OPT_TLS13_CIPHERS.c_str(), required_argument, &flag, 164},
3531         {SHRPX_OPT_TLS13_CLIENT_CIPHERS.c_str(), required_argument, &flag, 165},
3532         {SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA.c_str(), no_argument, &flag,
3533          166},
3534         {nullptr, 0, nullptr, 0}};
3535 
3536     int option_index = 0;
3537     int c = getopt_long(argc, argv, "DL:b:c:f:hkn:opsv", long_options,
3538                         &option_index);
3539     if (c == -1) {
3540       break;
3541     }
3542     switch (c) {
3543     case 'D':
3544       cmdcfgs.emplace_back(SHRPX_OPT_DAEMON, StringRef::from_lit("yes"));
3545       break;
3546     case 'L':
3547       cmdcfgs.emplace_back(SHRPX_OPT_LOG_LEVEL, StringRef{optarg});
3548       break;
3549     case 'b':
3550       cmdcfgs.emplace_back(SHRPX_OPT_BACKEND, StringRef{optarg});
3551       break;
3552     case 'c':
3553       cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_MAX_CONCURRENT_STREAMS,
3554                            StringRef{optarg});
3555       break;
3556     case 'f':
3557       cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND, StringRef{optarg});
3558       break;
3559     case 'h':
3560       print_help(std::cout);
3561       exit(EXIT_SUCCESS);
3562     case 'k':
3563       cmdcfgs.emplace_back(SHRPX_OPT_INSECURE, StringRef::from_lit("yes"));
3564       break;
3565     case 'n':
3566       cmdcfgs.emplace_back(SHRPX_OPT_WORKERS, StringRef{optarg});
3567       break;
3568     case 'o':
3569       cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_FRAME_DEBUG,
3570                            StringRef::from_lit("yes"));
3571       break;
3572     case 'p':
3573       cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PROXY, StringRef::from_lit("yes"));
3574       break;
3575     case 's':
3576       cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_PROXY, StringRef::from_lit("yes"));
3577       break;
3578     case 'v':
3579       print_version(std::cout);
3580       exit(EXIT_SUCCESS);
3581     case '?':
3582       util::show_candidates(argv[optind - 1], long_options);
3583       exit(EXIT_FAILURE);
3584     case 0:
3585       switch (flag) {
3586       case 1:
3587         // --add-x-forwarded-for
3588         cmdcfgs.emplace_back(SHRPX_OPT_ADD_X_FORWARDED_FOR,
3589                              StringRef::from_lit("yes"));
3590         break;
3591       case 2:
3592         // --frontend-http2-read-timeout
3593         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_READ_TIMEOUT,
3594                              StringRef{optarg});
3595         break;
3596       case 3:
3597         // --frontend-read-timeout
3598         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_READ_TIMEOUT,
3599                              StringRef{optarg});
3600         break;
3601       case 4:
3602         // --frontend-write-timeout
3603         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_WRITE_TIMEOUT,
3604                              StringRef{optarg});
3605         break;
3606       case 5:
3607         // --backend-read-timeout
3608         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_READ_TIMEOUT, StringRef{optarg});
3609         break;
3610       case 6:
3611         // --backend-write-timeout
3612         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_WRITE_TIMEOUT,
3613                              StringRef{optarg});
3614         break;
3615       case 7:
3616         cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_FILE, StringRef{optarg});
3617         break;
3618       case 8:
3619         // --backend-keep-alive-timeout
3620         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT,
3621                              StringRef{optarg});
3622         break;
3623       case 9:
3624         // --frontend-http2-window-bits
3625         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS,
3626                              StringRef{optarg});
3627         break;
3628       case 10:
3629         cmdcfgs.emplace_back(SHRPX_OPT_PID_FILE, StringRef{optarg});
3630         break;
3631       case 11:
3632         cmdcfgs.emplace_back(SHRPX_OPT_USER, StringRef{optarg});
3633         break;
3634       case 12:
3635         // --conf
3636         mod_config()->conf_path =
3637             make_string_ref(mod_config()->balloc, StringRef{optarg});
3638         break;
3639       case 14:
3640         // --syslog-facility
3641         cmdcfgs.emplace_back(SHRPX_OPT_SYSLOG_FACILITY, StringRef{optarg});
3642         break;
3643       case 15:
3644         // --backlog
3645         cmdcfgs.emplace_back(SHRPX_OPT_BACKLOG, StringRef{optarg});
3646         break;
3647       case 16:
3648         // --ciphers
3649         cmdcfgs.emplace_back(SHRPX_OPT_CIPHERS, StringRef{optarg});
3650         break;
3651       case 17:
3652         // --client
3653         cmdcfgs.emplace_back(SHRPX_OPT_CLIENT, StringRef::from_lit("yes"));
3654         break;
3655       case 18:
3656         // --backend-http2-window-bits
3657         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS,
3658                              StringRef{optarg});
3659         break;
3660       case 19:
3661         // --cacert
3662         cmdcfgs.emplace_back(SHRPX_OPT_CACERT, StringRef{optarg});
3663         break;
3664       case 20:
3665         // --backend-ipv4
3666         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_IPV4,
3667                              StringRef::from_lit("yes"));
3668         break;
3669       case 21:
3670         // --backend-ipv6
3671         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_IPV6,
3672                              StringRef::from_lit("yes"));
3673         break;
3674       case 22:
3675         // --private-key-passwd-file
3676         cmdcfgs.emplace_back(SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE,
3677                              StringRef{optarg});
3678         break;
3679       case 23:
3680         // --no-via
3681         cmdcfgs.emplace_back(SHRPX_OPT_NO_VIA, StringRef::from_lit("yes"));
3682         break;
3683       case 24:
3684         // --subcert
3685         cmdcfgs.emplace_back(SHRPX_OPT_SUBCERT, StringRef{optarg});
3686         break;
3687       case 25:
3688         // --http2-bridge
3689         cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_BRIDGE,
3690                              StringRef::from_lit("yes"));
3691         break;
3692       case 26:
3693         // --backend-http-proxy-uri
3694         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP_PROXY_URI,
3695                              StringRef{optarg});
3696         break;
3697       case 27:
3698         // --backend-no-tls
3699         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_NO_TLS,
3700                              StringRef::from_lit("yes"));
3701         break;
3702       case 28:
3703         // --ocsp-startup
3704         cmdcfgs.emplace_back(SHRPX_OPT_OCSP_STARTUP,
3705                              StringRef::from_lit("yes"));
3706         break;
3707       case 29:
3708         // --frontend-no-tls
3709         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_NO_TLS,
3710                              StringRef::from_lit("yes"));
3711         break;
3712       case 30:
3713         // --no-verify-ocsp
3714         cmdcfgs.emplace_back(SHRPX_OPT_NO_VERIFY_OCSP,
3715                              StringRef::from_lit("yes"));
3716         break;
3717       case 31:
3718         // --backend-tls-sni-field
3719         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SNI_FIELD,
3720                              StringRef{optarg});
3721         break;
3722       case 33:
3723         // --dh-param-file
3724         cmdcfgs.emplace_back(SHRPX_OPT_DH_PARAM_FILE, StringRef{optarg});
3725         break;
3726       case 34:
3727         // --read-rate
3728         cmdcfgs.emplace_back(SHRPX_OPT_READ_RATE, StringRef{optarg});
3729         break;
3730       case 35:
3731         // --read-burst
3732         cmdcfgs.emplace_back(SHRPX_OPT_READ_BURST, StringRef{optarg});
3733         break;
3734       case 36:
3735         // --write-rate
3736         cmdcfgs.emplace_back(SHRPX_OPT_WRITE_RATE, StringRef{optarg});
3737         break;
3738       case 37:
3739         // --write-burst
3740         cmdcfgs.emplace_back(SHRPX_OPT_WRITE_BURST, StringRef{optarg});
3741         break;
3742       case 38:
3743         // --npn-list
3744         cmdcfgs.emplace_back(SHRPX_OPT_NPN_LIST, StringRef{optarg});
3745         break;
3746       case 39:
3747         // --verify-client
3748         cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT,
3749                              StringRef::from_lit("yes"));
3750         break;
3751       case 40:
3752         // --verify-client-cacert
3753         cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT_CACERT, StringRef{optarg});
3754         break;
3755       case 41:
3756         // --client-private-key-file
3757         cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE,
3758                              StringRef{optarg});
3759         break;
3760       case 42:
3761         // --client-cert-file
3762         cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_CERT_FILE, StringRef{optarg});
3763         break;
3764       case 43:
3765         // --frontend-http2-dump-request-header
3766         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER,
3767                              StringRef{optarg});
3768         break;
3769       case 44:
3770         // --frontend-http2-dump-response-header
3771         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER,
3772                              StringRef{optarg});
3773         break;
3774       case 45:
3775         // --http2-no-cookie-crumbling
3776         cmdcfgs.emplace_back(SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING,
3777                              StringRef::from_lit("yes"));
3778         break;
3779       case 46:
3780         // --frontend-http2-connection-window-bits
3781         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS,
3782                              StringRef{optarg});
3783         break;
3784       case 47:
3785         // --backend-http2-connection-window-bits
3786         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS,
3787                              StringRef{optarg});
3788         break;
3789       case 48:
3790         // --tls-proto-list
3791         cmdcfgs.emplace_back(SHRPX_OPT_TLS_PROTO_LIST, StringRef{optarg});
3792         break;
3793       case 49:
3794         // --padding
3795         cmdcfgs.emplace_back(SHRPX_OPT_PADDING, StringRef{optarg});
3796         break;
3797       case 50:
3798         // --worker-read-rate
3799         cmdcfgs.emplace_back(SHRPX_OPT_WORKER_READ_RATE, StringRef{optarg});
3800         break;
3801       case 51:
3802         // --worker-read-burst
3803         cmdcfgs.emplace_back(SHRPX_OPT_WORKER_READ_BURST, StringRef{optarg});
3804         break;
3805       case 52:
3806         // --worker-write-rate
3807         cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_RATE, StringRef{optarg});
3808         break;
3809       case 53:
3810         // --worker-write-burst
3811         cmdcfgs.emplace_back(SHRPX_OPT_WORKER_WRITE_BURST, StringRef{optarg});
3812         break;
3813       case 54:
3814         // --altsvc
3815         cmdcfgs.emplace_back(SHRPX_OPT_ALTSVC, StringRef{optarg});
3816         break;
3817       case 55:
3818         // --add-response-header
3819         cmdcfgs.emplace_back(SHRPX_OPT_ADD_RESPONSE_HEADER, StringRef{optarg});
3820         break;
3821       case 56:
3822         // --worker-frontend-connections
3823         cmdcfgs.emplace_back(SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS,
3824                              StringRef{optarg});
3825         break;
3826       case 57:
3827         // --accesslog-syslog
3828         cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_SYSLOG,
3829                              StringRef::from_lit("yes"));
3830         break;
3831       case 58:
3832         // --errorlog-file
3833         cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_FILE, StringRef{optarg});
3834         break;
3835       case 59:
3836         // --errorlog-syslog
3837         cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_SYSLOG,
3838                              StringRef::from_lit("yes"));
3839         break;
3840       case 60:
3841         // --stream-read-timeout
3842         cmdcfgs.emplace_back(SHRPX_OPT_STREAM_READ_TIMEOUT, StringRef{optarg});
3843         break;
3844       case 61:
3845         // --stream-write-timeout
3846         cmdcfgs.emplace_back(SHRPX_OPT_STREAM_WRITE_TIMEOUT, StringRef{optarg});
3847         break;
3848       case 62:
3849         // --no-location-rewrite
3850         cmdcfgs.emplace_back(SHRPX_OPT_NO_LOCATION_REWRITE,
3851                              StringRef::from_lit("yes"));
3852         break;
3853       case 63:
3854         // --backend-http1-connections-per-host
3855         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_HOST,
3856                              StringRef{optarg});
3857         break;
3858       case 64:
3859         // --listener-disable-timeout
3860         cmdcfgs.emplace_back(SHRPX_OPT_LISTENER_DISABLE_TIMEOUT,
3861                              StringRef{optarg});
3862         break;
3863       case 65:
3864         // --strip-incoming-x-forwarded-for
3865         cmdcfgs.emplace_back(SHRPX_OPT_STRIP_INCOMING_X_FORWARDED_FOR,
3866                              StringRef::from_lit("yes"));
3867         break;
3868       case 66:
3869         // --accesslog-format
3870         cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_FORMAT, StringRef{optarg});
3871         break;
3872       case 67:
3873         // --backend-http1-connections-per-frontend
3874         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND,
3875                              StringRef{optarg});
3876         break;
3877       case 68:
3878         // --tls-ticket-key-file
3879         cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_FILE, StringRef{optarg});
3880         break;
3881       case 69:
3882         // --rlimit-nofile
3883         cmdcfgs.emplace_back(SHRPX_OPT_RLIMIT_NOFILE, StringRef{optarg});
3884         break;
3885       case 71:
3886         // --backend-response-buffer
3887         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_RESPONSE_BUFFER,
3888                              StringRef{optarg});
3889         break;
3890       case 72:
3891         // --backend-request-buffer
3892         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_REQUEST_BUFFER,
3893                              StringRef{optarg});
3894         break;
3895       case 73:
3896         // --no-host-rewrite
3897         cmdcfgs.emplace_back(SHRPX_OPT_NO_HOST_REWRITE,
3898                              StringRef::from_lit("yes"));
3899         break;
3900       case 74:
3901         // --no-server-push
3902         cmdcfgs.emplace_back(SHRPX_OPT_NO_SERVER_PUSH,
3903                              StringRef::from_lit("yes"));
3904         break;
3905       case 76:
3906         // --backend-http2-connections-per-worker
3907         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER,
3908                              StringRef{optarg});
3909         break;
3910       case 77:
3911         // --fetch-ocsp-response-file
3912         cmdcfgs.emplace_back(SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE,
3913                              StringRef{optarg});
3914         break;
3915       case 78:
3916         // --ocsp-update-interval
3917         cmdcfgs.emplace_back(SHRPX_OPT_OCSP_UPDATE_INTERVAL, StringRef{optarg});
3918         break;
3919       case 79:
3920         // --no-ocsp
3921         cmdcfgs.emplace_back(SHRPX_OPT_NO_OCSP, StringRef::from_lit("yes"));
3922         break;
3923       case 80:
3924         // --header-field-buffer
3925         cmdcfgs.emplace_back(SHRPX_OPT_HEADER_FIELD_BUFFER, StringRef{optarg});
3926         break;
3927       case 81:
3928         // --max-header-fields
3929         cmdcfgs.emplace_back(SHRPX_OPT_MAX_HEADER_FIELDS, StringRef{optarg});
3930         break;
3931       case 82:
3932         // --add-request-header
3933         cmdcfgs.emplace_back(SHRPX_OPT_ADD_REQUEST_HEADER, StringRef{optarg});
3934         break;
3935       case 83:
3936         // --include
3937         cmdcfgs.emplace_back(SHRPX_OPT_INCLUDE, StringRef{optarg});
3938         break;
3939       case 84:
3940         // --tls-ticket-key-cipher
3941         cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_CIPHER,
3942                              StringRef{optarg});
3943         break;
3944       case 85:
3945         // --host-rewrite
3946         cmdcfgs.emplace_back(SHRPX_OPT_HOST_REWRITE,
3947                              StringRef::from_lit("yes"));
3948         break;
3949       case 86:
3950         // --tls-session-cache-memcached
3951         cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED,
3952                              StringRef{optarg});
3953         break;
3954       case 87:
3955         // --tls-ticket-key-memcached
3956         cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED,
3957                              StringRef{optarg});
3958         break;
3959       case 88:
3960         // --tls-ticket-key-memcached-interval
3961         cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_INTERVAL,
3962                              StringRef{optarg});
3963         break;
3964       case 89:
3965         // --tls-ticket-key-memcached-max-retry
3966         cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY,
3967                              StringRef{optarg});
3968         break;
3969       case 90:
3970         // --tls-ticket-key-memcached-max-fail
3971         cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL,
3972                              StringRef{optarg});
3973         break;
3974       case 91:
3975         // --mruby-file
3976         cmdcfgs.emplace_back(SHRPX_OPT_MRUBY_FILE, StringRef{optarg});
3977         break;
3978       case 93:
3979         // --accept-proxy-protocol
3980         cmdcfgs.emplace_back(SHRPX_OPT_ACCEPT_PROXY_PROTOCOL,
3981                              StringRef::from_lit("yes"));
3982         break;
3983       case 94:
3984         // --fastopen
3985         cmdcfgs.emplace_back(SHRPX_OPT_FASTOPEN, StringRef{optarg});
3986         break;
3987       case 95:
3988         // --tls-dyn-rec-warmup-threshold
3989         cmdcfgs.emplace_back(SHRPX_OPT_TLS_DYN_REC_WARMUP_THRESHOLD,
3990                              StringRef{optarg});
3991         break;
3992       case 96:
3993         // --tls-dyn-rec-idle-timeout
3994         cmdcfgs.emplace_back(SHRPX_OPT_TLS_DYN_REC_IDLE_TIMEOUT,
3995                              StringRef{optarg});
3996         break;
3997       case 97:
3998         // --add-forwarded
3999         cmdcfgs.emplace_back(SHRPX_OPT_ADD_FORWARDED, StringRef{optarg});
4000         break;
4001       case 98:
4002         // --strip-incoming-forwarded
4003         cmdcfgs.emplace_back(SHRPX_OPT_STRIP_INCOMING_FORWARDED,
4004                              StringRef::from_lit("yes"));
4005         break;
4006       case 99:
4007         // --forwarded-by
4008         cmdcfgs.emplace_back(SHRPX_OPT_FORWARDED_BY, StringRef{optarg});
4009         break;
4010       case 100:
4011         // --forwarded-for
4012         cmdcfgs.emplace_back(SHRPX_OPT_FORWARDED_FOR, StringRef{optarg});
4013         break;
4014       case 101:
4015         // --response-header-field-buffer
4016         cmdcfgs.emplace_back(SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER,
4017                              StringRef{optarg});
4018         break;
4019       case 102:
4020         // --max-response-header-fields
4021         cmdcfgs.emplace_back(SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS,
4022                              StringRef{optarg});
4023         break;
4024       case 103:
4025         // --no-http2-cipher-black-list
4026         cmdcfgs.emplace_back(SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST,
4027                              StringRef::from_lit("yes"));
4028         break;
4029       case 104:
4030         // --request-header-field-buffer
4031         cmdcfgs.emplace_back(SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER,
4032                              StringRef{optarg});
4033         break;
4034       case 105:
4035         // --max-request-header-fields
4036         cmdcfgs.emplace_back(SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS,
4037                              StringRef{optarg});
4038         break;
4039       case 106:
4040         // --backend-http1-tls
4041         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP1_TLS,
4042                              StringRef::from_lit("yes"));
4043         break;
4044       case 108:
4045         // --tls-session-cache-memcached-tls
4046         cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS,
4047                              StringRef::from_lit("yes"));
4048         break;
4049       case 109:
4050         // --tls-session-cache-memcached-cert-file
4051         cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE,
4052                              StringRef{optarg});
4053         break;
4054       case 110:
4055         // --tls-session-cache-memcached-private-key-file
4056         cmdcfgs.emplace_back(
4057             SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE,
4058             StringRef{optarg});
4059         break;
4060       case 111:
4061         // --tls-ticket-key-memcached-tls
4062         cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS,
4063                              StringRef::from_lit("yes"));
4064         break;
4065       case 112:
4066         // --tls-ticket-key-memcached-cert-file
4067         cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE,
4068                              StringRef{optarg});
4069         break;
4070       case 113:
4071         // --tls-ticket-key-memcached-private-key-file
4072         cmdcfgs.emplace_back(
4073             SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE,
4074             StringRef{optarg});
4075         break;
4076       case 114:
4077         // --tls-ticket-key-memcached-address-family
4078         cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY,
4079                              StringRef{optarg});
4080         break;
4081       case 115:
4082         // --tls-session-cache-memcached-address-family
4083         cmdcfgs.emplace_back(
4084             SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY,
4085             StringRef{optarg});
4086         break;
4087       case 116:
4088         // --backend-address-family
4089         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_ADDRESS_FAMILY,
4090                              StringRef{optarg});
4091         break;
4092       case 117:
4093         // --frontend-http2-max-concurrent-streams
4094         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS,
4095                              StringRef{optarg});
4096         break;
4097       case 118:
4098         // --backend-http2-max-concurrent-streams
4099         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS,
4100                              StringRef{optarg});
4101         break;
4102       case 119:
4103         // --backend-connections-per-frontend
4104         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECTIONS_PER_FRONTEND,
4105                              StringRef{optarg});
4106         break;
4107       case 120:
4108         // --backend-tls
4109         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS, StringRef::from_lit("yes"));
4110         break;
4111       case 121:
4112         // --backend-connections-per-host
4113         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST,
4114                              StringRef{optarg});
4115         break;
4116       case 122:
4117         // --error-page
4118         cmdcfgs.emplace_back(SHRPX_OPT_ERROR_PAGE, StringRef{optarg});
4119         break;
4120       case 123:
4121         // --no-kqueue
4122         cmdcfgs.emplace_back(SHRPX_OPT_NO_KQUEUE, StringRef::from_lit("yes"));
4123         break;
4124       case 124:
4125         // --frontend-http2-settings-timeout
4126         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT,
4127                              StringRef{optarg});
4128         break;
4129       case 125:
4130         // --backend-http2-settings-timeout
4131         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT,
4132                              StringRef{optarg});
4133         break;
4134       case 126:
4135         // --api-max-request-body
4136         cmdcfgs.emplace_back(SHRPX_OPT_API_MAX_REQUEST_BODY, StringRef{optarg});
4137         break;
4138       case 127:
4139         // --backend-max-backoff
4140         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_MAX_BACKOFF, StringRef{optarg});
4141         break;
4142       case 128:
4143         // --server-name
4144         cmdcfgs.emplace_back(SHRPX_OPT_SERVER_NAME, StringRef{optarg});
4145         break;
4146       case 129:
4147         // --no-server-rewrite
4148         cmdcfgs.emplace_back(SHRPX_OPT_NO_SERVER_REWRITE,
4149                              StringRef::from_lit("yes"));
4150         break;
4151       case 130:
4152         // --frontend-http2-optimize-write-buffer-size
4153         cmdcfgs.emplace_back(
4154             SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE,
4155             StringRef::from_lit("yes"));
4156         break;
4157       case 131:
4158         // --frontend-http2-optimize-window-size
4159         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE,
4160                              StringRef::from_lit("yes"));
4161         break;
4162       case 132:
4163         // --frontend-http2-window-size
4164         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_WINDOW_SIZE,
4165                              StringRef{optarg});
4166         break;
4167       case 133:
4168         // --frontend-http2-connection-window-size
4169         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE,
4170                              StringRef{optarg});
4171         break;
4172       case 134:
4173         // --backend-http2-window-size
4174         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_WINDOW_SIZE,
4175                              StringRef{optarg});
4176         break;
4177       case 135:
4178         // --backend-http2-connection-window-size
4179         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE,
4180                              StringRef{optarg});
4181         break;
4182       case 136:
4183         // --frontend-http2-encoder-dynamic-table-size
4184         cmdcfgs.emplace_back(
4185             SHRPX_OPT_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
4186             StringRef{optarg});
4187         break;
4188       case 137:
4189         // --frontend-http2-decoder-dynamic-table-size
4190         cmdcfgs.emplace_back(
4191             SHRPX_OPT_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
4192             StringRef{optarg});
4193         break;
4194       case 138:
4195         // --backend-http2-encoder-dynamic-table-size
4196         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
4197                              StringRef{optarg});
4198         break;
4199       case 139:
4200         // --backend-http2-decoder-dynamic-table-size
4201         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
4202                              StringRef{optarg});
4203         break;
4204       case 140:
4205         // --ecdh-curves
4206         cmdcfgs.emplace_back(SHRPX_OPT_ECDH_CURVES, StringRef{optarg});
4207         break;
4208       case 141:
4209         // --tls-sct-dir
4210         cmdcfgs.emplace_back(SHRPX_OPT_TLS_SCT_DIR, StringRef{optarg});
4211         break;
4212       case 142:
4213         // --backend-connect-timeout
4214         cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECT_TIMEOUT,
4215                              StringRef{optarg});
4216         break;
4217       case 143:
4218         // --dns-cache-timeout
4219         cmdcfgs.emplace_back(SHRPX_OPT_DNS_CACHE_TIMEOUT, StringRef{optarg});
4220         break;
4221       case 144:
4222         // --dns-lookup-timeou
4223         cmdcfgs.emplace_back(SHRPX_OPT_DNS_LOOKUP_TIMEOUT, StringRef{optarg});
4224         break;
4225       case 145:
4226         // --dns-max-try
4227         cmdcfgs.emplace_back(SHRPX_OPT_DNS_MAX_TRY, StringRef{optarg});
4228         break;
4229       case 146:
4230         // --frontend-keep-alive-timeout
4231         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_KEEP_ALIVE_TIMEOUT,
4232                              StringRef{optarg});
4233         break;
4234       case 147:
4235         // --psk-secrets
4236         cmdcfgs.emplace_back(SHRPX_OPT_PSK_SECRETS, StringRef{optarg});
4237         break;
4238       case 148:
4239         // --client-psk-secrets
4240         cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PSK_SECRETS, StringRef{optarg});
4241         break;
4242       case 149:
4243         // --client-no-http2-cipher-black-list
4244         cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_NO_HTTP2_CIPHER_BLACK_LIST,
4245                              StringRef::from_lit("yes"));
4246         break;
4247       case 150:
4248         // --client-ciphers
4249         cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_CIPHERS, StringRef{optarg});
4250         break;
4251       case 151:
4252         // --accesslog-write-early
4253         cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_WRITE_EARLY,
4254                              StringRef::from_lit("yes"));
4255         break;
4256       case 152:
4257         // --tls-min-proto-version
4258         cmdcfgs.emplace_back(SHRPX_OPT_TLS_MIN_PROTO_VERSION,
4259                              StringRef{optarg});
4260         break;
4261       case 153:
4262         // --tls-max-proto-version
4263         cmdcfgs.emplace_back(SHRPX_OPT_TLS_MAX_PROTO_VERSION,
4264                              StringRef{optarg});
4265         break;
4266       case 154:
4267         // --redirect-https-port
4268         cmdcfgs.emplace_back(SHRPX_OPT_REDIRECT_HTTPS_PORT, StringRef{optarg});
4269         break;
4270       case 155:
4271         // --frontend-max-requests
4272         cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_MAX_REQUESTS,
4273                              StringRef{optarg});
4274         break;
4275       case 156:
4276         // --single-thread
4277         cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_THREAD,
4278                              StringRef::from_lit("yes"));
4279         break;
4280       case 157:
4281         // --no-add-x-forwarded-proto
4282         cmdcfgs.emplace_back(SHRPX_OPT_NO_ADD_X_FORWARDED_PROTO,
4283                              StringRef::from_lit("yes"));
4284         break;
4285       case 158:
4286         // --no-strip-incoming-x-forwarded-proto
4287         cmdcfgs.emplace_back(SHRPX_OPT_NO_STRIP_INCOMING_X_FORWARDED_PROTO,
4288                              StringRef::from_lit("yes"));
4289         break;
4290       case 159:
4291         // --single-process
4292         cmdcfgs.emplace_back(SHRPX_OPT_SINGLE_PROCESS,
4293                              StringRef::from_lit("yes"));
4294         break;
4295       case 160:
4296         // --verify-client-tolerate-expired
4297         cmdcfgs.emplace_back(SHRPX_OPT_VERIFY_CLIENT_TOLERATE_EXPIRED,
4298                              StringRef::from_lit("yes"));
4299         break;
4300       case 161:
4301         // --ignore-per-pattern-mruby-error
4302         cmdcfgs.emplace_back(SHRPX_OPT_IGNORE_PER_PATTERN_MRUBY_ERROR,
4303                              StringRef::from_lit("yes"));
4304         break;
4305       case 162:
4306         // --tls-no-postpone-early-data
4307         cmdcfgs.emplace_back(SHRPX_OPT_TLS_NO_POSTPONE_EARLY_DATA,
4308                              StringRef::from_lit("yes"));
4309         break;
4310       case 163:
4311         // --tls-max-early-data
4312         cmdcfgs.emplace_back(SHRPX_OPT_TLS_MAX_EARLY_DATA, StringRef{optarg});
4313         break;
4314       case 164:
4315         // --tls13-ciphers
4316         cmdcfgs.emplace_back(SHRPX_OPT_TLS13_CIPHERS, StringRef{optarg});
4317         break;
4318       case 165:
4319         // --tls13-client-ciphers
4320         cmdcfgs.emplace_back(SHRPX_OPT_TLS13_CLIENT_CIPHERS, StringRef{optarg});
4321         break;
4322       case 166:
4323         // --no-strip-incoming-early-data
4324         cmdcfgs.emplace_back(SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA,
4325                              StringRef::from_lit("yes"));
4326         break;
4327       default:
4328         break;
4329       }
4330       break;
4331     default:
4332       break;
4333     }
4334   }
4335 
4336   if (argc - optind >= 2) {
4337     cmdcfgs.emplace_back(SHRPX_OPT_PRIVATE_KEY_FILE, StringRef{argv[optind++]});
4338     cmdcfgs.emplace_back(SHRPX_OPT_CERTIFICATE_FILE, StringRef{argv[optind++]});
4339   }
4340 
4341   rv = process_options(mod_config(), cmdcfgs);
4342   if (rv != 0) {
4343     return -1;
4344   }
4345 
4346   if (event_loop() != 0) {
4347     return -1;
4348   }
4349 
4350   LOG(NOTICE) << "Shutdown momentarily";
4351 
4352   delete_log_config();
4353 
4354   return 0;
4355 }
4356 
4357 } // namespace shrpx
4358 
main(int argc,char ** argv)4359 int main(int argc, char **argv) { return run_app(shrpx::main, argc, argv); }
4360