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