2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
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:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
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.
25 #include "nghttp2_config.h"
29 #endif // HAVE_UNISTD_H
40 #include <openssl/ssl.h>
41 #include <openssl/err.h>
42 #include <openssl/conf.h>
43 #include <nghttp2/nghttp2.h>
45 #include "app_helper.h"
46 #include "HttpServer.h"
53 int parse_push_config(Config &config, const char *optarg) {
54 const char *eq = strchr(optarg, '=');
58 auto &paths = config.push[std::string(optarg, eq)];
59 auto optarg_end = optarg + strlen(optarg);
62 const char *j = strchr(i, ',');
66 paths.emplace_back(i, j);
67 if (j == optarg_end) {
79 void print_version(std::ostream &out) {
80 out << "nghttpd nghttp2/" NGHTTP2_VERSION << std::endl;
85 void print_usage(std::ostream &out) {
86 out << "Usage: nghttpd [OPTION]... <PORT> [<PRIVATE_KEY> <CERT>]\n"
87 << "HTTP/2 experimental server" << std::endl;
92 void print_help(std::ostream &out) {
96 <PORT> Specify listening port number.
98 Set path to server's private key. Required unless
99 --no-tls is specified.
100 <CERT> Set path to server's certificate. Required unless
101 --no-tls is specified.
104 The address to bind to. If not specified the default IP
105 address determined by getaddrinfo is used.
107 Run in a background. If -D is used, the current working
108 directory is changed to '/'. Therefore if this option
109 is used, -d option must be specified.
111 The server sends a client certificate request. If the
112 client did not return a certificate, the handshake is
113 terminated. Currently, this option just requests a
114 client certificate and does not verify it.
116 Specify document root. If this option is not specified,
117 the document root is the current working directory.
119 Print debug information such as reception/ transmission
120 of frames and name/value pairs.
121 --no-tls Disable SSL/TLS.
122 -c, --header-table-size=<SIZE>
123 Specify decoder header table size.
124 --color Force colored log output.
125 -p, --push=<PATH>=<PUSH_PATH,...>
126 Push resources <PUSH_PATH>s when <PATH> is requested.
127 This option can be used repeatedly to specify multiple
128 push configurations. <PATH> and <PUSH_PATH>s are
129 relative to document root. See --htdocs option.
130 Example: -p/=/foo.png -p/doc=/bar.css
132 Add at most <N> bytes to a frame payload as padding.
133 Specify 0 to disable padding.
134 -m, --max-concurrent-streams=<N>
135 Set the maximum number of the concurrent streams in one
137 Default: )" << config.max_concurrent_streams << R"(
139 Set the number of worker threads.
142 Make error response gzipped.
143 --dh-param-file=<PATH>
144 Path to file that contains DH parameters in PEM format.
145 Without this option, DHE cipher suites are not
148 Start sending response when request HEADERS is received,
149 rather than complete request is received.
151 Add a trailer header to a response. <HEADER> must not
152 include pseudo header field (header field name starting
153 with ':'). The trailer is sent only if a response has
154 body part. Example: --trailer 'foo: bar'.
155 --hexdump Display the incoming traffic in hexadecimal (Canonical
156 hex+ASCII display). If SSL/TLS is used, decrypted data
159 Send back uploaded content if method is POST or PUT.
160 --version Display version information and exit.
161 -h, --help Display this help and exit.
165 The <SIZE> argument is an integer and an optional unit (e.g., 10K is
166 10 * 1024). Units are K, M and G (powers of 1024).)" << std::endl;
170 int main(int argc, char **argv) {
175 static option long_options[] = {
176 {"address", required_argument, nullptr, 'a'},
177 {"daemon", no_argument, nullptr, 'D'},
178 {"htdocs", required_argument, nullptr, 'd'},
179 {"help", no_argument, nullptr, 'h'},
180 {"verbose", no_argument, nullptr, 'v'},
181 {"verify-client", no_argument, nullptr, 'V'},
182 {"header-table-size", required_argument, nullptr, 'c'},
183 {"push", required_argument, nullptr, 'p'},
184 {"padding", required_argument, nullptr, 'b'},
185 {"max-concurrent-streams", required_argument, nullptr, 'm'},
186 {"workers", required_argument, nullptr, 'n'},
187 {"error-gzip", no_argument, nullptr, 'e'},
188 {"no-tls", no_argument, &flag, 1},
189 {"color", no_argument, &flag, 2},
190 {"version", no_argument, &flag, 3},
191 {"dh-param-file", required_argument, &flag, 4},
192 {"early-response", no_argument, &flag, 5},
193 {"trailer", required_argument, &flag, 6},
194 {"hexdump", no_argument, &flag, 7},
195 {"echo-upload", no_argument, &flag, 8},
196 {nullptr, 0, nullptr, 0}};
197 int option_index = 0;
198 int c = getopt_long(argc, argv, "DVb:c:d:ehm:n:p:va:", long_options,
206 config.address = optarg;
209 config.daemon = true;
212 config.verify_client = true;
215 config.padding = strtol(optarg, nullptr, 10);
218 config.htdocs = optarg;
221 config.error_gzip = true;
224 // max-concurrent-streams option
225 auto n = util::parse_uint(optarg);
227 std::cerr << "-m: invalid argument: " << optarg << std::endl;
230 config.max_concurrent_streams = n;
235 std::cerr << "-n: WARNING: Threading disabled at build time, "
236 << "no threads created." << std::endl;
239 config.num_worker = strtoul(optarg, &end, 10);
240 if (errno == ERANGE || *end != '\0' || config.num_worker == 0) {
241 std::cerr << "-n: Bad option value: " << optarg << std::endl;
247 print_help(std::cout);
250 config.verbose = true;
254 config.header_table_size = util::parse_uint_with_unit(optarg);
255 if (config.header_table_size == -1) {
256 std::cerr << "-c: Bad option value: " << optarg << std::endl;
261 if (parse_push_config(config, optarg) != 0) {
262 std::cerr << "-p: Bad option value: " << optarg << std::endl;
266 util::show_candidates(argv[optind - 1], long_options);
272 config.no_tls = true;
280 print_version(std::cout);
284 config.dh_param_file = optarg;
288 config.early_response = true;
292 auto header = optarg;
293 auto value = strchr(optarg, ':');
295 std::cerr << "--trailer: invalid header: " << optarg << std::endl;
300 while (isspace(*value)) {
304 // This could also be a valid case for suppressing a header
306 std::cerr << "--trailer: invalid header - value missing: " << optarg
310 config.trailer.emplace_back(header, value, false);
311 util::inp_strlower(config.trailer.back().name);
316 config.hexdump = true;
319 // echo-upload option
320 config.echo_upload = true;
328 if (argc - optind < (config.no_tls ? 1 : 3)) {
329 print_usage(std::cerr);
330 std::cerr << "Too few arguments" << std::endl;
334 config.port = strtol(argv[optind++], nullptr, 10);
336 if (!config.no_tls) {
337 config.private_key_file = argv[optind++];
338 config.cert_file = argv[optind++];
342 if (config.htdocs.empty()) {
343 print_usage(std::cerr);
344 std::cerr << "-d option must be specified when -D is used." << std::endl;
347 if (daemon(0, 0) == -1) {
352 if (config.htdocs.empty()) {
353 config.htdocs = "./";
356 set_color_output(color || isatty(fileno(stdout)));
358 struct sigaction act;
359 memset(&act, 0, sizeof(struct sigaction));
360 act.sa_handler = SIG_IGN;
361 sigaction(SIGPIPE, &act, nullptr);
362 OPENSSL_config(nullptr);
363 OpenSSL_add_all_algorithms();
364 SSL_load_error_strings();
367 ssl::LibsslGlobalLock lock;
372 HttpServer server(&config);
373 if (server.run() != 0) {
379 } // namespace nghttp2
381 int main(int argc, char **argv) { return nghttp2::main(argc, argv); }