tizen 2.4 release
[external/nghttp2.git] / src / nghttpd.cc
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 "nghttp2_config.h"
26
27 #include <unistd.h>
28 #include <signal.h>
29 #include <getopt.h>
30
31 #include <cstdlib>
32 #include <cstring>
33 #include <cassert>
34 #include <string>
35 #include <iostream>
36 #include <string>
37
38 #include <openssl/ssl.h>
39 #include <openssl/err.h>
40 #include <openssl/conf.h>
41 #include <nghttp2/nghttp2.h>
42
43 #include "app_helper.h"
44 #include "HttpServer.h"
45 #include "util.h"
46 #include "ssl.h"
47
48 namespace nghttp2 {
49
50 namespace {
51 int parse_push_config(Config &config, const char *optarg) {
52   const char *eq = strchr(optarg, '=');
53   if (eq == NULL) {
54     return -1;
55   }
56   auto &paths = config.push[std::string(optarg, eq)];
57   auto optarg_end = optarg + strlen(optarg);
58   auto i = eq + 1;
59   for (;;) {
60     const char *j = strchr(i, ',');
61     if (j == NULL) {
62       j = optarg_end;
63     }
64     paths.emplace_back(i, j);
65     if (j == optarg_end) {
66       break;
67     }
68     i = j;
69     ++i;
70   }
71
72   return 0;
73 }
74 } // namespace
75
76 namespace {
77 void print_version(std::ostream &out) {
78   out << "nghttpd nghttp2/" NGHTTP2_VERSION << std::endl;
79 }
80 } // namespace
81
82 namespace {
83 void print_usage(std::ostream &out) {
84   out << "Usage: nghttpd [OPTION]... <PORT> [<PRIVATE_KEY> <CERT>]\n"
85       << "HTTP/2 experimental server" << std::endl;
86 }
87 } // namespace
88
89 namespace {
90 void print_help(std::ostream &out) {
91   print_usage(out);
92   out << R"(
93   <PORT>      Specify listening port number.
94   <PRIVATE_KEY>
95               Set  path  to  server's private  key.   Required  unless
96               --no-tls is specified.
97   <CERT>      Set  path  to  server's  certificate.   Required  unless
98               --no-tls is specified.
99 Options:
100   -D, --daemon
101               Run in a background.  If -D is used, the current working
102               directory is  changed to '/'.  Therefore  if this option
103               is used, -d option must be specified.
104   -V, --verify-client
105               The server  sends a client certificate  request.  If the
106               client did  not return  a certificate, the  handshake is
107               terminated.   Currently,  this  option just  requests  a
108               client certificate and does not verify it.
109   -d, --htdocs=<PATH>
110               Specify document root.  If this option is not specified,
111               the document root is the current working directory.
112   -v, --verbose
113               Print debug information  such as reception/ transmission
114               of frames and name/value pairs.
115   --no-tls    Disable SSL/TLS.
116   -c, --header-table-size=<SIZE>
117               Specify decoder header table size.
118   --color     Force colored log output.
119   -p, --push=<PATH>=<PUSH_PATH,...>
120               Push  resources <PUSH_PATH>s  when <PATH>  is requested.
121               This option  can be used repeatedly  to specify multiple
122               push  configurations.    <PATH>  and   <PUSH_PATH>s  are
123               relative  to   document  root.   See   --htdocs  option.
124               Example: -p/=/foo.png -p/doc=/bar.css
125   -b, --padding=<N>
126               Add at  most <N>  bytes to a  frame payload  as padding.
127               Specify 0 to disable padding.
128   -n, --workers=<N>
129               Set the number of worker threads.
130               Default: 1
131   -e, --error-gzip
132               Make error response gzipped.
133   --dh-param-file=<PATH>
134               Path to file that contains  DH parameters in PEM format.
135               Without  this   option,  DHE   cipher  suites   are  not
136               available.
137   --early-response
138               Start sending response when request HEADERS is received,
139               rather than complete request is received.
140   --version   Display version information and exit.
141   -h, --help  Display this help and exit.
142
143   The <SIZE> argument is an integer and an optional unit (e.g., 10K is
144   10 * 1024).  Units are K, M and G (powers of 1024).)" << std::endl;
145 }
146 } // namespace
147
148 int main(int argc, char **argv) {
149   Config config;
150   bool color = false;
151   while (1) {
152     static int flag = 0;
153     static option long_options[] = {
154         {"daemon", no_argument, nullptr, 'D'},
155         {"htdocs", required_argument, nullptr, 'd'},
156         {"help", no_argument, nullptr, 'h'},
157         {"verbose", no_argument, nullptr, 'v'},
158         {"verify-client", no_argument, nullptr, 'V'},
159         {"header-table-size", required_argument, nullptr, 'c'},
160         {"push", required_argument, nullptr, 'p'},
161         {"padding", required_argument, nullptr, 'b'},
162         {"workers", required_argument, nullptr, 'n'},
163         {"error-gzip", no_argument, nullptr, 'e'},
164         {"no-tls", no_argument, &flag, 1},
165         {"color", no_argument, &flag, 2},
166         {"version", no_argument, &flag, 3},
167         {"dh-param-file", required_argument, &flag, 4},
168         {"early-response", no_argument, &flag, 5},
169         {nullptr, 0, nullptr, 0}};
170     int option_index = 0;
171     int c =
172         getopt_long(argc, argv, "DVb:c:d:ehn:p:v", long_options, &option_index);
173     char *end;
174     if (c == -1) {
175       break;
176     }
177     switch (c) {
178     case 'D':
179       config.daemon = true;
180       break;
181     case 'V':
182       config.verify_client = true;
183       break;
184     case 'b':
185       config.padding = strtol(optarg, nullptr, 10);
186       break;
187     case 'd':
188       config.htdocs = optarg;
189       break;
190     case 'e':
191       config.error_gzip = true;
192       break;
193     case 'n':
194 #ifdef NOTHREADS
195       std::cerr << "-n: WARNING: Threading disabled at build time, "
196                 << "no threads created." << std::endl;
197 #else
198       errno = 0;
199       config.num_worker = strtoul(optarg, &end, 10);
200       if (errno == ERANGE || *end != '\0' || config.num_worker == 0) {
201         std::cerr << "-n: Bad option value: " << optarg << std::endl;
202         exit(EXIT_FAILURE);
203       }
204 #endif // NOTHREADS
205       break;
206     case 'h':
207       print_help(std::cout);
208       exit(EXIT_SUCCESS);
209     case 'v':
210       config.verbose = true;
211       break;
212     case 'c':
213       errno = 0;
214       config.header_table_size = util::parse_uint_with_unit(optarg);
215       if (config.header_table_size == -1) {
216         std::cerr << "-c: Bad option value: " << optarg << std::endl;
217         exit(EXIT_FAILURE);
218       }
219       break;
220     case 'p':
221       if (parse_push_config(config, optarg) != 0) {
222         std::cerr << "-p: Bad option value: " << optarg << std::endl;
223       }
224       break;
225     case '?':
226       util::show_candidates(argv[optind - 1], long_options);
227       exit(EXIT_FAILURE);
228     case 0:
229       switch (flag) {
230       case 1:
231         // no-tls option
232         config.no_tls = true;
233         break;
234       case 2:
235         // color option
236         color = true;
237         break;
238       case 3:
239         // version
240         print_version(std::cout);
241         exit(EXIT_SUCCESS);
242       case 4:
243         // dh-param-file
244         config.dh_param_file = optarg;
245         break;
246       case 5:
247         // early-response
248         config.early_response = true;
249         break;
250       }
251       break;
252     default:
253       break;
254     }
255   }
256   if (argc - optind < (config.no_tls ? 1 : 3)) {
257     print_usage(std::cerr);
258     std::cerr << "Too few arguments" << std::endl;
259     exit(EXIT_FAILURE);
260   }
261
262   config.port = strtol(argv[optind++], nullptr, 10);
263
264   if (!config.no_tls) {
265     config.private_key_file = argv[optind++];
266     config.cert_file = argv[optind++];
267   }
268
269   if (config.daemon) {
270     if (config.htdocs.empty()) {
271       print_usage(std::cerr);
272       std::cerr << "-d option must be specified when -D is used." << std::endl;
273       exit(EXIT_FAILURE);
274     }
275     if (daemon(0, 0) == -1) {
276       perror("daemon");
277       exit(EXIT_FAILURE);
278     }
279   }
280   if (config.htdocs.empty()) {
281     config.htdocs = "./";
282   }
283
284   set_color_output(color || isatty(fileno(stdout)));
285
286   struct sigaction act;
287   memset(&act, 0, sizeof(struct sigaction));
288   act.sa_handler = SIG_IGN;
289   sigaction(SIGPIPE, &act, nullptr);
290   OPENSSL_config(nullptr);
291   OpenSSL_add_all_algorithms();
292   SSL_load_error_strings();
293   SSL_library_init();
294 #ifndef NOTHREADS
295   ssl::LibsslGlobalLock lock;
296 #endif // NOTHREADS
297
298   reset_timer();
299
300   HttpServer server(&config);
301   server.run();
302   return 0;
303 }
304
305 } // namespace nghttp2
306
307 int main(int argc, char **argv) { return nghttp2::main(argc, argv); }