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