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