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