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