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