1 /*
2 * Copyright (C) 2004, 2005 James Antill
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * email: james@and.org
19 */
20 /* conditionally compliant HTTP/1.1 server. */
21 #define _GNU_SOURCE 1 /* strsignal() / posix_fadvise64 */
22 #include <vstr.h>
23
24 #include <socket_poll.h>
25 #include <timer_q.h>
26
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <errno.h>
36 #include <err.h>
37 #include <netinet/in.h>
38 #include <netinet/tcp.h>
39 #include <arpa/inet.h>
40
41 #include <grp.h>
42
43 #define EX_UTILS_NO_USE_INIT 1
44 #define EX_UTILS_NO_USE_EXIT 1
45 #define EX_UTILS_NO_USE_LIMIT 1
46 #define EX_UTILS_NO_USE_OPEN 1
47 #define EX_UTILS_NO_USE_GET 1
48 #define EX_UTILS_NO_USE_IO_FD 1
49 #define EX_UTILS_RET_FAIL 1
50 #include "ex_utils.h"
51
52 #include "mk.h"
53
54 MALLOC_CHECK_DECL();
55
56 #include "cntl.h"
57 #include "date.h"
58
59 #define HTTPD_HAVE_GLOBAL_OPTS 1
60
61 #include "httpd.h"
62 #include "httpd_policy.h"
63
64 #define CLEN VSTR__AT_COMPILE_STRLEN
65
66 /* is the cstr a prefix of the vstr */
67 #define VPREFIX(vstr, p, l, cstr) \
68 (((l) >= CLEN(cstr)) && \
69 vstr_cmp_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
70 /* is the cstr a suffix of the vstr */
71 #define VSUFFIX(vstr, p, l, cstr) \
72 (((l) >= CLEN(cstr)) && \
73 vstr_cmp_eod_buf_eq(vstr, p, l, cstr, CLEN(cstr)))
74
75 /* is the cstr a prefix of the vstr, no case */
76 #define VIPREFIX(vstr, p, l, cstr) \
77 (((l) >= CLEN(cstr)) && \
78 vstr_cmp_case_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
79
80 /* for simplicity */
81 #define VEQ(vstr, p, l, cstr) vstr_cmp_cstr_eq(vstr, p, l, cstr)
82
83 static Vlg *vlg = NULL;
84
usage(const char * program_name,int ret,const char * prefix)85 static void usage(const char *program_name, int ret, const char *prefix)
86 {
87 Vstr_base *out = vstr_make_base(NULL);
88
89 if (!out)
90 errno = ENOMEM, err(EXIT_FAILURE, "usage");
91
92 vstr_add_fmt(out, 0, "%s\n\
93 Format: %s [options] <dir>\n\
94 Daemon options\n\
95 --daemon - Toggle becoming a daemon%s.\n\
96 --chroot - Change root.\n\
97 --drop-privs - Toggle droping privilages%s.\n\
98 --priv-uid - Drop privilages to this uid.\n\
99 --priv-gid - Drop privilages to this gid.\n\
100 --pid-file - Log pid to file.\n\
101 --cntl-file - Create control file.\n\
102 --accept-filter-file\n\
103 - Load Linux Socket Filter code for accept().\n\
104 --processes - Number of processes to use (default: 1).\n\
105 --debug -d - Raise debug level (can be used upto 3 times).\n\
106 --host -H - IPv4 address to bind (default: \"all\").\n\
107 --help -h - Print this message.\n\
108 --max-connections\n\
109 -M - Max connections allowed (0 = no limit).\n\
110 --nagle -n - Toggle usage of nagle TCP option%s.\n\
111 --port -P - Port to bind to.\n\
112 --idle-timeout -t - Timeout (usecs) for connections that are idle.\n\
113 --defer-accept - Time to defer dataless connections (default: 8s)\n\
114 --version -V - Print the version string.\n\
115 \n\
116 HTTPD options\n\
117 --mmap - Toggle use of mmap() to load files%s.\n\
118 --sendfile - Toggle use of sendfile() to load files%s.\n\
119 --keep-alive - Toggle use of Keep-Alive handling%s.\n\
120 --keep-alive-1.0 - Toggle use of Keep-Alive handling for HTTP/1.0%s.\n\
121 --virtual-hosts\n\
122 --vhosts - Toggle use of directory virtual hostnames%s.\n\
123 --range - Toggle use of partial responces%s.\n\
124 --range-1.0 - Toggle use of partial responces for HTTP/1.0%s.\n\
125 --public-only - Toggle use of public only privilages%s.\n\
126 --directory-filename\n\
127 --dir-filename - Filename to use when requesting directories.\n\
128 --server-name - Contents of server header used in replies.\n\
129 --gzip-content-replacement\n\
130 - Toggle use of gzip content replacement%s.\n\
131 --mime-types-main - Main mime types filename (default: /etc/mime.types).\n\
132 --mime-types-xtra - Additional mime types filename.\n\
133 --error-406 - Toggle sending 406 responses%s.\n\
134 --canonize-host - Strip leading 'www.', strip trailing '.'%s.\n\
135 --error-host-400 - Give an 400 error for a bad host%s.\n\
136 --check-host - Whether we check host headers at all%s.\n\
137 --unspecified-hostname\n\
138 - Used for req with no Host header (default is hostname).\n\
139 --max-header-sz - Max size of http header (0 = no limit).\n\
140 ",
141 prefix, program_name,
142 opt_def_toggle(FALSE), opt_def_toggle(FALSE),
143 opt_def_toggle(EVNT_CONF_NAGLE),
144 opt_def_toggle(HTTPD_CONF_USE_MMAP),
145 opt_def_toggle(HTTPD_CONF_USE_SENDFILE),
146 opt_def_toggle(HTTPD_CONF_USE_KEEPA),
147 opt_def_toggle(HTTPD_CONF_USE_KEEPA_1_0),
148 opt_def_toggle(HTTPD_CONF_USE_VHOSTS_NAME),
149 opt_def_toggle(HTTPD_CONF_USE_RANGE),
150 opt_def_toggle(HTTPD_CONF_USE_RANGE_1_0),
151 opt_def_toggle(HTTPD_CONF_USE_PUBLIC_ONLY),
152 opt_def_toggle(HTTPD_CONF_USE_ENC_CONTENT_REPLACEMENT),
153 opt_def_toggle(HTTPD_CONF_USE_ERR_406),
154 opt_def_toggle(HTTPD_CONF_USE_CANONIZE_HOST),
155 opt_def_toggle(HTTPD_CONF_USE_HOST_ERR_400),
156 opt_def_toggle(HTTPD_CONF_USE_HOST_ERR_CHK));
157
158 if (io_put_all(out, ret ? STDERR_FILENO : STDOUT_FILENO) == IO_FAIL)
159 err(EXIT_FAILURE, "write");
160
161 exit (ret);
162 }
163
serv_init(void)164 static void serv_init(void)
165 {
166 if (!vstr_init()) /* init the library */
167 errno = ENOMEM, err(EXIT_FAILURE, "init");
168
169 vlg_init();
170
171 if (!vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE,
172 VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR))
173 errno = ENOMEM, err(EXIT_FAILURE, "init");
174
175 if (!vstr_cntl_conf(NULL,
176 VSTR_CNTL_CONF_SET_NUM_BUF_SZ, OPT_SERV_CONF_BUF_SZ))
177 errno = ENOMEM, err(EXIT_FAILURE, "init");
178
179 /* no passing of conf to evnt */
180 if (!vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '$') ||
181 !vstr_sc_fmt_add_all(NULL) ||
182 !vlg_sc_fmt_add_all(NULL) ||
183 !VSTR_SC_FMT_ADD(NULL, http_fmt_add_vstr_add_vstr,
184 "<http-esc.vstr", "p%zu%zu", ">") ||
185 !VSTR_SC_FMT_ADD(NULL, http_fmt_add_vstr_add_sect_vstr,
186 "<http-esc.vstr.sect", "p%p%u", ">"))
187 errno = ENOMEM, err(EXIT_FAILURE, "init");
188
189 if (!(vlg = vlg_make()))
190 errno = ENOMEM, err(EXIT_FAILURE, "init");
191
192 if (!VSTR_SC_FMT_ADD(vlg->out_vstr->conf, http_fmt_add_vstr_add_vstr,
193 "<http-esc.vstr", "p%zu%zu", ">") ||
194 !VSTR_SC_FMT_ADD(vlg->out_vstr->conf, http_fmt_add_vstr_add_sect_vstr,
195 "<http-esc.vstr.sect", "p%p%u", ">"))
196 errno = ENOMEM, err(EXIT_FAILURE, "init");
197 if (!VSTR_SC_FMT_ADD(vlg->sig_out_vstr->conf, http_fmt_add_vstr_add_vstr,
198 "<http-esc.vstr", "p%zu%zu", ">") ||
199 !VSTR_SC_FMT_ADD(vlg->sig_out_vstr->conf, http_fmt_add_vstr_add_sect_vstr,
200 "<http-esc.vstr.sect", "p%p%u", ">"))
201 errno = ENOMEM, err(EXIT_FAILURE, "init");
202
203 if (!socket_poll_init(0, SOCKET_POLL_TYPE_MAP_DIRECT))
204 errno = ENOMEM, err(EXIT_FAILURE, "init");
205
206 evnt_logger(vlg);
207 evnt_poll_init();
208 evnt_timeout_init();
209
210 vlg_time_set(vlg, evnt_sc_time);
211
212 opt_serv_logger(vlg);
213
214 httpd_init(vlg);
215
216 opt_serv_sc_signals();
217 }
218
serv_cb_func_send(struct Evnt * evnt)219 static int serv_cb_func_send(struct Evnt *evnt)
220 {
221 struct Con *con = (struct Con *)evnt;
222
223 assert(HTTPD_CONF_SEND_CALL_LIMIT >= 1);
224 con->io_limit_num = HTTPD_CONF_SEND_CALL_LIMIT;
225 return (httpd_serv_send(con));
226 }
227
serv_cb_func_recv(struct Evnt * evnt)228 static int serv_cb_func_recv(struct Evnt *evnt)
229 {
230 struct Con *con = (struct Con *)evnt;
231
232 assert(HTTPD_CONF_RECV_CALL_LIMIT >= 1);
233 con->io_limit_num = HTTPD_CONF_RECV_CALL_LIMIT;
234 return (httpd_serv_recv(con));
235 }
236
serv_cb_func_free(struct Evnt * evnt)237 static void serv_cb_func_free(struct Evnt *evnt)
238 {
239 struct Con *con = (struct Con *)evnt;
240
241 httpd_fin_fd_close(con);
242
243 opt_serv_sc_free_beg(evnt, con->acpt_sa_ref);
244
245 ASSERT(con->fs && !con->fs_num && !con->fs_off && (con->fs->fd == -1));
246
247 vstr_free_base(con->mpbr_ct);
248
249 if (con->fs_sz > 1)
250 {
251 ASSERT(con->fs != con->fs_store);
252 F(con->fs);
253 }
254 else
255 ASSERT(con->fs == con->fs_store);
256
257 F(con);
258 }
259
serv_cb_func_accept(struct Evnt * from_evnt,int fd,struct sockaddr * sa,socklen_t len)260 static struct Evnt *serv_cb_func_accept(struct Evnt *from_evnt, int fd,
261 struct sockaddr *sa, socklen_t len)
262 {
263 struct Acpt_listener *acpt_listener = (struct Acpt_listener *)from_evnt;
264 struct Con *con = MK(sizeof(struct Con));
265
266 if (sa->sa_family != AF_INET) /* only support IPv4 atm. */
267 goto sa_fail;
268
269 if (!con || !evnt_make_acpt_dup(con->evnt, fd, sa, len))
270 goto make_acpt_fail;
271
272 con->evnt->cbs->cb_func_recv = serv_cb_func_recv;
273 con->evnt->cbs->cb_func_send = serv_cb_func_send;
274 con->evnt->cbs->cb_func_free = serv_cb_func_free;
275
276 if (!httpd_con_init(con, acpt_listener))
277 goto evnt_fail;
278
279 if (!evnt_sc_timeout_via_mtime(con->evnt,
280 con->policy->s->idle_timeout * 1000))
281 VLG_WARNNOMEM_GOTO(evnt_fail, (vlg, "timeout: %m\n"));
282
283 if (!opt_serv_sc_acpt_end(con->policy->s, from_evnt, con->evnt))
284 goto evnt_fail;
285
286 ASSERT(!con->evnt->flag_q_closed);
287
288 return (con->evnt);
289
290 evnt_fail:
291 evnt_close(con->evnt);
292 return (con->evnt);
293
294 make_acpt_fail:
295 F(con);
296 VLG_WARNNOMEM_RET(NULL, (vlg, "%s: %m\n", "accept"));
297
298 sa_fail:
299 F(con);
300 VLG_WARNNOMEM_RET(NULL, (vlg, "%s: HTTPD sa == ipv4 fail\n", "accept"));
301 }
302
serv_make_bind(const char * program_name)303 static void serv_make_bind(const char *program_name)
304 {
305 Opt_serv_addr_opts *addr = httpd_opts->s->addr_beg;
306
307 while (addr)
308 {
309 const char *ipv4_address = NULL;
310 const char *acpt_filter_file = NULL;
311 struct Evnt *evnt = NULL;
312
313 OPT_SC_EXPORT_CSTR(ipv4_address, addr->ipv4_address, FALSE,
314 "ipv4 address");
315 OPT_SC_EXPORT_CSTR(acpt_filter_file, addr->acpt_filter_file, FALSE,
316 "accept filter file");
317
318 evnt = evnt_sc_serv_make_bind(ipv4_address, addr->tcp_port,
319 addr->q_listen_len,
320 addr->max_connections,
321 addr->defer_accept,
322 acpt_filter_file);
323
324 evnt->cbs->cb_func_accept = serv_cb_func_accept;
325
326 addr = addr->next;
327 }
328 }
329
330 #define VCMP_MT_EQ_ALL(x, y, z) \
331 vstr_cmp_eq(x -> mime_types_ ## z, 1, x -> mime_types_ ## z ->len, \
332 y -> mime_types_ ## z, 1, y -> mime_types_ ## z ->len)
serv__mime_types_eq(Httpd_policy_opts * node)333 static Httpd_policy_opts *serv__mime_types_eq(Httpd_policy_opts *node)
334 { /* compares both mime filenames ... */
335 Opt_serv_policy_opts *scan = httpd_opts->s->def_policy;
336
337 ASSERT(node);
338
339 while (scan != node->s)
340 {
341 Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
342
343 if (VCMP_MT_EQ_ALL(tmp, node, main) && VCMP_MT_EQ_ALL(tmp, node, xtra))
344 return (tmp);
345
346 scan = scan->next;
347 }
348
349 return (NULL);
350 }
351 #undef VCMP_MT_EQ_ALL
352
serv_mime_types(const char * program_name)353 static void serv_mime_types(const char *program_name)
354 {
355 Opt_serv_policy_opts *scan = httpd_opts->s->def_policy;
356
357 while (scan)
358 {
359 Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
360 Httpd_policy_opts *prev = NULL;
361
362 if (!mime_types_init(tmp->mime_types,
363 tmp->mime_types_def_ct, 1,
364 tmp->mime_types_def_ct->len))
365 errno = ENOMEM, err(EXIT_FAILURE, "init");
366
367 if ((prev = serv__mime_types_eq(tmp)))
368 mime_types_combine_filedata(tmp->mime_types, prev->mime_types);
369 else
370 {
371 const char *mime_types_main = NULL;
372 const char *mime_types_xtra = NULL;
373
374 OPT_SC_EXPORT_CSTR(mime_types_main, tmp->mime_types_main, FALSE,
375 "MIME types main file");
376 OPT_SC_EXPORT_CSTR(mime_types_xtra, tmp->mime_types_xtra, FALSE,
377 "MIME types extra file");
378
379 if (!mime_types_load_simple(tmp->mime_types, mime_types_main))
380 err(EXIT_FAILURE, "load_mime(%s)", mime_types_main);
381
382 if (!mime_types_load_simple(tmp->mime_types, mime_types_xtra))
383 err(EXIT_FAILURE, "load_mime(%s)", mime_types_xtra);
384 }
385
386 scan = scan->next;
387 }
388
389 /* we don't need the filenames after we've loaded... */
390 scan = httpd_opts->s->def_policy;
391 while (scan)
392 {
393 Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
394
395 vstr_free_base(tmp->mime_types_main); tmp->mime_types_main = NULL;
396 vstr_free_base(tmp->mime_types_xtra); tmp->mime_types_xtra = NULL;
397
398 scan = scan->next;
399 }
400 }
401
serv_canon_policies(void)402 static void serv_canon_policies(void)
403 {
404 Opt_serv_policy_opts *scan = httpd_opts->s->def_policy;
405
406 while (scan)
407 { /* check variables for things which will screw us too much */
408 Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
409 Vstr_base *s1 = NULL;
410
411 ASSERT(scan->beg == httpd_opts->s);
412
413 s1 = tmp->document_root;
414 if (!httpd_canon_dir_path(s1))
415 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "canon_dir_path($<vstr.all:%p>): %m\n",
416 s1));
417
418 s1 = tmp->req_conf_dir;
419 if (!httpd_canon_dir_path(s1))
420 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "canon_dir_path($<vstr.all:%p>): %m\n",
421 s1));
422
423 s1 = tmp->req_err_dir;
424 if (!httpd_canon_abs_dir_path(s1))
425 VLG_ERRNOMEM((vlg, EXIT_FAILURE,
426 "canon_abs_dir_path($<vstr.all:%p>): %m\n", s1));
427
428 if (!httpd_init_default_hostname(scan))
429 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "hostname(): %m\n"));
430
431 s1 = tmp->dir_filename;
432 if (!httpd_valid_url_filename(s1, 1, s1->len) &&
433 !vstr_sub_cstr_ptr(s1, 1, s1->len, HTTPD_CONF_DEF_DIR_FILENAME))
434 VLG_ERRNOMEM((vlg, EXIT_FAILURE, "dir_filename(): %m\n"));
435
436 scan = scan->next;
437 }
438 }
439
serv_cmd_line(int argc,char * argv[])440 static void serv_cmd_line(int argc, char *argv[])
441 {
442 int optchar = 0;
443 const char *program_name = NULL;
444 struct option long_options[] =
445 {
446 OPT_SERV_DECL_GETOPTS(),
447
448 {"configuration-file", required_argument, NULL, 'C'},
449 {"config-file", required_argument, NULL, 'C'},
450 {"configuration-data-daemon", required_argument, NULL, 143},
451 {"config-data-daemon", required_argument, NULL, 143},
452 {"configuration-data-jhttpd", required_argument, NULL, 144},
453 {"config-data-jhttpd", required_argument, NULL, 144},
454
455 {"sendfile", optional_argument, NULL, 31},
456 {"mmap", optional_argument, NULL, 30},
457
458 {"max-header-sz", required_argument, NULL, 128},
459 {"keep-alive", optional_argument, NULL, 129},
460 {"keep-alive-1.0", optional_argument, NULL, 130},
461 {"vhosts", optional_argument, NULL, 131},
462 {"virtual-hosts", optional_argument, NULL, 131},
463 {"range", optional_argument, NULL, 132},
464 {"range-1.0", optional_argument, NULL, 133},
465 {"public-only", optional_argument, NULL, 134}, /* FIXME: rm ? */
466 {"dir-filename", required_argument, NULL, 135},
467 {"server-name", required_argument, NULL, 136},
468 {"gzip-content-replacement", optional_argument, NULL, 137},
469 /* 138 */
470 {"error-406", optional_argument, NULL, 139},
471 /* 140 */
472 {"mime-types-main", required_argument, NULL, 141},
473 {"mime-types-extra", required_argument, NULL, 142},
474 {"mime-types-xtra", required_argument, NULL, 142},
475 /* 143 -- config data above */
476 /* 144 -- config data above */
477 {"unspecified-hostname", required_argument, NULL, 145},
478 {"canonize-host", optional_argument, NULL, 146},
479 {"error-host-400", optional_argument, NULL, 147},
480 {"check-host", optional_argument, NULL, 148},
481 /* {"404-file", required_argument, NULL, 0}, */
482 {NULL, 0, NULL, 0}
483 };
484 const char *chroot_dir = NULL;
485 const char *document_root = NULL;
486 Vstr_base *out = vstr_make_base(NULL);
487 Httpd_policy_opts *popts = NULL;
488
489 if (!out)
490 errno = ENOMEM, err(EXIT_FAILURE, "command line");
491
492 evnt_opt_nagle = TRUE;
493
494 program_name = opt_program_name(argv[0], HTTPD_CONF_PROG_NAME);
495 httpd_opts->s->name_cstr = program_name;
496 httpd_opts->s->name_len = strlen(program_name);
497
498 httpd_opts->s->make_policy = httpd_policy_make;
499 httpd_opts->s->copy_policy = httpd_policy_copy;
500
501 if (!httpd_conf_main_init(httpd_opts))
502 errno = ENOMEM, err(EXIT_FAILURE, "options");
503
504 if (!geteuid()) /* If root */
505 httpd_opts->s->addr_beg->tcp_port = HTTPD_CONF_SERV_DEF_PORT;
506 else /* somewhat common unprived port */
507 httpd_opts->s->addr_beg->tcp_port = 8008;
508
509 popts = (Httpd_policy_opts *)httpd_opts->s->def_policy;
510 while ((optchar = getopt_long(argc, argv, "C:dhH:M:nP:t:V",
511 long_options, NULL)) != -1)
512 {
513 switch (optchar)
514 {
515 case '?': usage(program_name, EXIT_FAILURE, "");
516 case 'h': usage(program_name, EXIT_SUCCESS, "");
517
518 case 'V':
519 vstr_add_fmt(out, 0, " %s version %s.\n",
520 program_name, HTTPD_CONF_VERSION);
521
522 if (io_put_all(out, STDOUT_FILENO) == IO_FAIL)
523 err(EXIT_FAILURE, "write");
524
525 exit (EXIT_SUCCESS);
526
527 OPT_SERV_GETOPTS(httpd_opts->s);
528
529 case 'C':
530 if (!httpd_conf_main_parse_file(out, httpd_opts, optarg))
531 goto out_err_conf_msg;
532 break;
533 case 143: /* FIXME: ... need to integrate */
534 if (!opt_serv_conf_parse_cstr(out, httpd_opts->s, optarg))
535 goto out_err_conf_msg;
536 break;
537 case 144:
538 if (!httpd_conf_main_parse_cstr(out, httpd_opts, optarg))
539 goto out_err_conf_msg;
540 break;
541
542 case 128: OPT_NUM_NR_ARG(popts->max_header_sz, "max header size"); break;
543
544 case 31: OPT_TOGGLE_ARG(popts->use_sendfile); break;
545 case 30: OPT_TOGGLE_ARG(popts->use_mmap); break;
546
547 case 129: OPT_TOGGLE_ARG(popts->use_keep_alive); break;
548 case 130: OPT_TOGGLE_ARG(popts->use_keep_alive_1_0); break;
549 case 131: OPT_TOGGLE_ARG(popts->use_vhosts_name); break;
550 case 132: OPT_TOGGLE_ARG(popts->use_range); break;
551 case 133: OPT_TOGGLE_ARG(popts->use_range_1_0); break;
552 case 134: OPT_TOGGLE_ARG(popts->use_public_only); break;
553 case 135: OPT_VSTR_ARG(popts->dir_filename); break;
554 case 136: OPT_VSTR_ARG(popts->server_name); break;
555 case 137: OPT_TOGGLE_ARG(popts->use_enc_content_replacement); break;
556 case 139: OPT_TOGGLE_ARG(popts->use_err_406); break;
557 /* case 140: */
558 case 141: OPT_VSTR_ARG(popts->mime_types_main); break;
559 case 142: OPT_VSTR_ARG(popts->mime_types_xtra); break;
560 /* case 143: */
561 /* case 144: */
562 case 145: OPT_VSTR_ARG(popts->default_hostname); break;
563 case 146: OPT_TOGGLE_ARG(popts->use_canonize_host); break;
564 case 147: OPT_TOGGLE_ARG(popts->use_host_err_400); break;
565 case 148: OPT_TOGGLE_ARG(popts->use_host_err_chk);
566
567
568 ASSERT_NO_SWITCH_DEF();
569 }
570 }
571 vstr_free_base(out); out = NULL;
572
573 argc -= optind;
574 argv += optind;
575
576 if (argc > 1)
577 usage(program_name, EXIT_FAILURE, " Too many arguments.\n");
578
579 if (argc == 1)
580 {
581 Vstr_base *tmp = popts->document_root;
582 vstr_sub_cstr_ptr(tmp, 1, tmp->len, argv[0]);
583 }
584
585 if (!popts->document_root->len)
586 usage(program_name, EXIT_FAILURE, " Not specified a document root.\n");
587
588 if (httpd_opts->s->become_daemon)
589 {
590 if (daemon(FALSE, FALSE) == -1)
591 err(EXIT_FAILURE, "daemon");
592 vlg_daemon(vlg, program_name);
593 }
594
595 if (httpd_opts->s->rlim_core_call)
596 opt_serv_sc_rlim_core_num(httpd_opts->s->rlim_core_num);
597 if (httpd_opts->s->rlim_file_call)
598 opt_serv_sc_rlim_file_num(httpd_opts->s->rlim_file_num);
599
600 {
601 const char *pid_file = NULL;
602 const char *cntl_file = NULL;
603 Opt_serv_opts *opts = httpd_opts->s;
604
605 OPT_SC_EXPORT_CSTR(pid_file, opts->pid_file, FALSE, "pid file");
606 OPT_SC_EXPORT_CSTR(cntl_file, opts->cntl_file, FALSE, "control file");
607 OPT_SC_EXPORT_CSTR(chroot_dir, opts->chroot_dir, FALSE, "chroot directory");
608
609 serv_make_bind(program_name);
610
611 if (!httpd_init_default_hostname(httpd_opts->s->def_policy))
612 errno = ENOMEM, err(EXIT_FAILURE, "default_hostname");
613
614 if (pid_file)
615 vlg_pid_file(vlg, pid_file);
616
617 if (cntl_file)
618 cntl_make_file(vlg, cntl_file);
619
620 serv_canon_policies();
621
622 OPT_SC_EXPORT_CSTR(document_root, popts->document_root, TRUE,
623 "document root");
624
625 serv_mime_types(program_name);
626
627 if (chroot_dir)
628 vlg_sc_bind_mount(chroot_dir);
629
630 /* after daemon so syslog works */
631 if (chroot_dir && ((chroot(chroot_dir) == -1) || (chdir("/") == -1)))
632 vlg_err(vlg, EXIT_FAILURE, "chroot(%s): %m\n", chroot_dir);
633
634 if (opts->drop_privs)
635 {
636 OPT_SC_RESOLVE_UID(opts);
637 OPT_SC_RESOLVE_GID(opts);
638 opt_serv_sc_drop_privs(opts);
639 }
640
641 if (opts->num_procs > 1)
642 cntl_sc_multiproc(vlg, opts->num_procs, !!cntl_file, opts->use_pdeathsig);
643 }
644
645 httpd_opts->beg_time = time(NULL);
646
647 /* if (make_dumpable && (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1))
648 * vlg_warn(vlg, "prctl(SET_DUMPABLE, TRUE): %m\n"); */
649
650 {
651 struct Evnt *evnt = evnt_queue("accept");
652
653 while (evnt)
654 {
655 vlg_info(vlg, "READY [$<sa:%p>]: %s%s%s\n", EVNT_SA(evnt),
656 chroot_dir ? chroot_dir : "",
657 chroot_dir ? "/" : "",
658 document_root);
659 evnt = evnt->next;
660 }
661 }
662
663 opt_serv_conf_free(httpd_opts->s);
664 return;
665
666 out_err_conf_msg:
667 vstr_add_cstr_ptr(out, out->len, "\n");
668 if (io_put_all(out, STDERR_FILENO) == IO_FAIL)
669 err(EXIT_FAILURE, "write");
670 exit (EXIT_FAILURE);
671 }
672
main(int argc,char * argv[])673 int main(int argc, char *argv[])
674 {
675 serv_init();
676
677 serv_cmd_line(argc, argv);
678
679 while (evnt_waiting())
680 {
681 evnt_sc_main_loop(HTTPD_CONF_MAX_WAIT_SEND);
682 opt_serv_sc_check_children();
683 opt_serv_sc_cntl_resources(httpd_opts->s);
684 }
685 evnt_out_dbg3("E");
686
687 evnt_timeout_exit();
688 cntl_child_free();
689 evnt_close_all();
690
691 httpd_exit();
692
693 http_req_exit();
694
695 vlg_free(vlg);
696 vlg_exit();
697
698 httpd_conf_main_free(httpd_opts);
699
700 vstr_exit();
701
702 MALLOC_CHECK_EMPTY();
703
704 exit (EXIT_SUCCESS);
705 }
706