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