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