|
|
|
#include "first.h"
|
|
|
|
|
|
|
|
#include "server.h"
|
|
|
|
#include "buffer.h"
|
|
|
|
#include "network.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "keyvalue.h"
|
|
|
|
#include "rand.h"
|
|
|
|
#include "response.h"
|
|
|
|
#include "request.h"
|
|
|
|
#include "chunk.h"
|
|
|
|
#include "http_auth.h"
|
|
|
|
#include "http_chunk.h"
|
|
|
|
#include "http_vhostdb.h"
|
|
|
|
#include "fdevent.h"
|
|
|
|
#include "connections.h"
|
|
|
|
#include "stat_cache.h"
|
|
|
|
#include "plugin.h"
|
|
|
|
#include "joblist.h"
|
|
|
|
#include "network_backends.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_VERSIONSTAMP_H
|
|
|
|
# include "versionstamp.h"
|
|
|
|
#else
|
|
|
|
# define REPO_VERSION ""
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define PACKAGE_DESC PACKAGE_NAME "/" PACKAGE_VERSION REPO_VERSION
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <locale.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_GETOPT_H
|
|
|
|
/* posix says getopt() should be in <unistd.h>... */
|
|
|
|
# include <getopt.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(WITH_VALGRIND)
|
|
|
|
# include <valgrind/valgrind.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
|
|
|
# include <sys/wait.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_PWD_H
|
|
|
|
# include <grp.h>
|
|
|
|
# include <pwd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYSLOG_H
|
|
|
|
# include <syslog.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_RESOURCE_H
|
|
|
|
# include <sys/resource.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_PRCTL_H
|
|
|
|
# include <sys/prctl.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(WITH_OPENSSL)
|
|
|
|
#define TEXT_SSL " (ssl)"
|
|
|
|
#else
|
|
|
|
#define TEXT_SSL
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int oneshot_fd = 0;
|
|
|
|
static volatile int pid_fd = -2;
|
|
|
|
static server_socket_array graceful_sockets;
|
|
|
|
static volatile sig_atomic_t graceful_restart = 0;
|
|
|
|
static volatile sig_atomic_t graceful_shutdown = 0;
|
|
|
|
static volatile sig_atomic_t srv_shutdown = 0;
|
|
|
|
static volatile sig_atomic_t handle_sig_child = 0;
|
|
|
|
static volatile sig_atomic_t handle_sig_alarm = 1;
|
|
|
|
static volatile sig_atomic_t handle_sig_hup = 0;
|
|
|
|
|
|
|
|
#if defined(HAVE_SIGACTION) && defined(SA_SIGINFO)
|
|
|
|
static volatile siginfo_t last_sigterm_info;
|
|
|
|
static volatile siginfo_t last_sighup_info;
|
|
|
|
|
|
|
|
static void sigaction_handler(int sig, siginfo_t *si, void *context) {
|
|
|
|
static const siginfo_t empty_siginfo;
|
|
|
|
UNUSED(context);
|
|
|
|
|
|
|
|
if (!si) *(const siginfo_t **)&si = &empty_siginfo;
|
|
|
|
|
|
|
|
switch (sig) {
|
|
|
|
case SIGTERM:
|
|
|
|
srv_shutdown = 1;
|
|
|
|
last_sigterm_info = *si;
|
|
|
|
break;
|
|
|
|
case SIGUSR1:
|
|
|
|
if (!graceful_shutdown) {
|
|
|
|
graceful_restart = 1;
|
|
|
|
graceful_shutdown = 1;
|
|
|
|
last_sigterm_info = *si;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGINT:
|
|
|
|
if (graceful_shutdown) {
|
|
|
|
if (2 == graceful_restart)
|
|
|
|
graceful_restart = 1;
|
|
|
|
else
|
|
|
|
srv_shutdown = 1;
|
|
|
|
} else {
|
|
|
|
graceful_shutdown = 1;
|
|
|
|
}
|
|
|
|
last_sigterm_info = *si;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case SIGALRM:
|
|
|
|
handle_sig_alarm = 1;
|
|
|
|
break;
|
|
|
|
case SIGHUP:
|
|
|
|
handle_sig_hup = 1;
|
|
|
|
last_sighup_info = *si;
|
|
|
|
break;
|
|
|
|
case SIGCHLD:
|
|
|
|
handle_sig_child = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
|
|
|
|
static void signal_handler(int sig) {
|
|
|
|
switch (sig) {
|
|
|
|
case SIGTERM: srv_shutdown = 1; break;
|
|
|
|
case SIGUSR1:
|
|
|
|
if (!graceful_shutdown) {
|
|
|
|
graceful_restart = 1;
|
|
|
|
graceful_shutdown = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGINT:
|
|
|
|
if (graceful_shutdown) {
|
|
|
|
if (2 == graceful_restart)
|
|
|
|
graceful_restart = 1;
|
|
|
|
else
|
|
|
|
srv_shutdown = 1;
|
|
|
|
} else {
|
|
|
|
graceful_shutdown = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SIGALRM: handle_sig_alarm = 1; break;
|
|
|
|
case SIGHUP: handle_sig_hup = 1; break;
|
|
|
|
case SIGCHLD: handle_sig_child = 1; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_FORK
|
|
|
|
static int daemonize(void) {
|
|
|
|
int pipefd[2];
|
|
|
|
pid_t pid;
|
|
|
|
#ifdef SIGTTOU
|
|
|
|
signal(SIGTTOU, SIG_IGN);
|
|
|
|
#endif
|
|
|
|
#ifdef SIGTTIN
|
|
|
|
signal(SIGTTIN, SIG_IGN);
|
|
|
|
#endif
|
|
|
|
#ifdef SIGTSTP
|
|
|
|
signal(SIGTSTP, SIG_IGN);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (pipe(pipefd) < 0) exit(-1);
|
|
|
|
|
|
|
|
if (0 > (pid = fork())) exit(-1);
|
|
|
|
|
|
|
|
if (0 < pid) {
|
|
|
|
char buf;
|
|
|
|
ssize_t bytes;
|
|
|
|
|
|
|
|
close(pipefd[1]);
|
|
|
|
/* parent waits for grandchild to be ready */
|
|
|
|
do {
|
|
|
|
bytes = read(pipefd[0], &buf, sizeof(buf));
|
|
|
|
} while (bytes < 0 && EINTR == errno);
|
|
|
|
close(pipefd[0]);
|
|
|
|
|
|
|
|
if (bytes <= 0) {
|
|
|
|
/* closed fd (without writing) == failure in grandchild */
|
|
|
|
fputs("daemonized server failed to start; check error log for details\n", stderr);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(pipefd[0]);
|
|
|
|
|
|
|
|
if (-1 == setsid()) exit(0);
|
|
|
|
|
|
|
|
signal(SIGHUP, SIG_IGN);
|
|
|
|
|
|
|
|
if (0 != fork()) exit(0);
|
|
|
|
|
|
|
|
if (0 != chdir("/")) exit(0);
|
|
|
|
|
|
|
|
fdevent_setfd_cloexec(pipefd[1]);
|
|
|
|
return pipefd[1];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static server *server_init(void) {
|
|
|
|
int i;
|
|
|
|
server *srv = calloc(1, sizeof(*srv));
|
|
|
|
force_assert(srv);
|
|
|
|
#define CLEAN(x) \
|
|
|
|
srv->x = buffer_init();
|
|
|
|
|
|
|
|
CLEAN(response_header);
|
|
|
|
CLEAN(parse_full_path);
|
|
|
|
CLEAN(ts_debug_str);
|
|
|
|
CLEAN(ts_date_str);
|
|
|
|
CLEAN(errorlog_buf);
|
|
|
|
CLEAN(response_range);
|
|
|
|
CLEAN(tmp_buf);
|
|
|
|
srv->empty_string = buffer_init_string("");
|
|
|
|
CLEAN(cond_check_buf);
|
|
|
|
|
|
|
|
CLEAN(srvconf.errorlog_file);
|
|
|
|
CLEAN(srvconf.breakagelog_file);
|
|
|
|
CLEAN(srvconf.groupname);
|
|
|
|
CLEAN(srvconf.username);
|
|
|
|
CLEAN(srvconf.changeroot);
|
|
|
|
CLEAN(srvconf.bindhost);
|
|
|
|
CLEAN(srvconf.event_handler);
|
|
|
|
CLEAN(srvconf.pid_file);
|
|
|
|
CLEAN(srvconf.syslog_facility);
|
|
|
|
|
|
|
|
CLEAN(tmp_chunk_len);
|
|
|
|
#undef CLEAN
|
|
|
|
|
|
|
|
#define CLEAN(x) \
|
|
|
|
srv->x = array_init();
|
|
|
|
|
|
|
|
CLEAN(config_context);
|
|
|
|
CLEAN(config_touched);
|
|
|
|
CLEAN(status);
|
|
|
|
#undef CLEAN
|
|
|
|
|
|
|
|
for (i = 0; i < FILE_CACHE_MAX; i++) {
|
|
|
|
srv->mtime_cache[i].mtime = (time_t)-1;
|
|
|
|
srv->mtime_cache[i].str = buffer_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
li_rand_reseed();
|
|
|
|
|
|
|
|
srv->cur_ts = time(NULL);
|
|
|
|
srv->startup_ts = srv->cur_ts;
|
|
|
|
|
|
|
|
srv->conns = calloc(1, sizeof(*srv->conns));
|
|
|
|
force_assert(srv->conns);
|
|
|
|
|
|
|
|
srv->joblist = calloc(1, sizeof(*srv->joblist));
|
|
|
|
force_assert(srv->joblist);
|
|
|
|
|
|
|
|
srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
|
|
|
|
force_assert(srv->fdwaitqueue);
|
|
|
|
|
|
|
|
srv->srvconf.modules = array_init();
|
|
|
|
srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
|
|
|
|
srv->srvconf.network_backend = buffer_init();
|
|
|
|
srv->srvconf.upload_tempdirs = array_init();
|
|
|
|
srv->srvconf.reject_expect_100_with_417 = 1;
|
|
|
|
srv->srvconf.xattr_name = buffer_init_string("Content-Type");
|
[config] opts for http header parsing strictness (fixes #551, fixes #1086, fixes #1184, fixes #2143, #2258, #2281, fixes #946, fixes #1330, fixes #602, #1016)
server.http-parseopt-header-strict = "enable"
server.http-parseopt-host-strict = "enable" (implies host-normalize)
server.http-parseopt-host-normalize = "disable"
defaults retain current behavior, which is strict header parsing
and strict host parsing, with enhancement to normalize IPv4 address
and port number strings.
For lighttpd tests, these need to be enabled (and are by default)
For marginally faster HTTP header parsing for benchmarks, disable these.
To allow
- underscores in hostname
- hypen ('-') at beginning of hostname
- all-numeric TLDs
server.http-parseopt-host-strict = "disable"
x-ref:
"lighttpd doesn't allow underscores in host names"
https://redmine.lighttpd.net/issues/551
"hyphen in hostname"
https://redmine.lighttpd.net/issues/1086
"a numeric tld"
https://redmine.lighttpd.net/issues/1184
"Numeric tld's"
https://redmine.lighttpd.net/issues/2143
"Bad Request"
https://redmine.lighttpd.net/issues/2258
"400 Bad Request when using Numeric TLDs"
https://redmine.lighttpd.net/issues/2281
To allow a variety of numerical formats to be converted to IP addresses
server.http-parseopt-host-strict = "disable"
server.http-parseopt-host-normalize = "enable"
x-ref:
"URL encoding leads to "400 - Bad Request""
https://redmine.lighttpd.net/issues/946
"400 Bad Request when using IP's numeric value ("ip2long()")"
https://redmine.lighttpd.net/issues/1330
To allow most 8-bit and 7-bit chars in headers
server.http-parseopt-header-strict = "disable" (not recommended)
x-ref:
"Russian letters not alowed?"
https://redmine.lighttpd.net/issues/602
"header Content-Disposition with russian '?' (CP1251, ascii code 255) causes error"
https://redmine.lighttpd.net/issues/1016
6 years ago
|
|
|
srv->srvconf.http_header_strict = 1;
|
|
|
|
srv->srvconf.http_host_strict = 1; /*(implies http_host_normalize)*/
|
|
|
|
srv->srvconf.http_host_normalize = 0;
|
|
|
|
srv->srvconf.high_precision_timestamps = 0;
|
|
|
|
srv->srvconf.max_request_field_size = 8192;
|
|
|
|
srv->srvconf.loadavg[0] = 0.0;
|
|
|
|
srv->srvconf.loadavg[1] = 0.0;
|
|
|
|
srv->srvconf.loadavg[2] = 0.0;
|
|
|
|
|
|
|
|
/* use syslog */
|
|
|
|
srv->errorlog_fd = STDERR_FILENO;
|
|
|
|
srv->errorlog_mode = ERRORLOG_FD;
|
|
|
|
|
|
|
|
srv->split_vals = array_init();
|
|
|
|
srv->request_env = plugins_call_handle_request_env;
|
|
|
|
|
|
|
|
return srv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void server_free(server *srv) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < FILE_CACHE_MAX; i++) {
|
|
|
|
buffer_free(srv->mtime_cache[i].str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oneshot_fd > 0) {
|
|
|
|
close(oneshot_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CLEAN(x) \
|
|
|
|
buffer_free(srv->x);
|
|
|
|
|
|
|
|
CLEAN(response_header);
|
|
|
|
CLEAN(parse_full_path);
|
|
|
|
CLEAN(ts_debug_str);
|
|
|
|
CLEAN(ts_date_str);
|
|
|
|
CLEAN(errorlog_buf);
|
|
|
|
CLEAN(response_range);
|
|
|
|
CLEAN(tmp_buf);
|
|
|
|
CLEAN(empty_string);
|
|
|
|
CLEAN(cond_check_buf);
|
|
|
|
|
|
|
|
CLEAN(srvconf.errorlog_file);
|
|
|
|
CLEAN(srvconf.breakagelog_file);
|
|
|
|
CLEAN(srvconf.groupname);
|
|
|
|
CLEAN(srvconf.username);
|
|
|
|
CLEAN(srvconf.changeroot);
|
|
|
|
CLEAN(srvconf.bindhost);
|
|
|
|
CLEAN(srvconf.event_handler);
|
|
|
|
CLEAN(srvconf.pid_file);
|
|
|
|
CLEAN(srvconf.modules_dir);
|
|
|
|
CLEAN(srvconf.network_backend);
|
|
|
|
CLEAN(srvconf.xattr_name);
|
|
|
|
CLEAN(srvconf.syslog_facility);
|
|
|
|
|
|
|
|
CLEAN(tmp_chunk_len);
|
|
|
|
#undef CLEAN
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
fdevent_unregister(srv->ev, srv->fd);
|
|
|
|
#endif
|
|
|
|
fdevent_free(srv->ev);
|
|
|
|
|
|
|
|
free(srv->conns);
|
|
|
|
|
|
|
|
if (srv->config_storage) {
|
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
|
|
|
specific_config *s = srv->config_storage[i];
|
|
|
|
|
|
|
|
if (!s) continue;
|
|
|
|
|
|
|
|
buffer_free(s->document_root);
|
|
|
|
buffer_free(s->server_name);
|
|
|
|
buffer_free(s->server_tag);
|
|
|
|
buffer_free(s->error_handler);
|
[core] server.error-handler new directive for error pages (fixes #2702)
server.error-handler preserves HTTP status error code when error page
is static, and allows dynamic handlers to change HTTP status code
when error page is provided by dynamic handler. server.error-handler
intercepts all HTTP status codes >= 400 except when the content is
generated by a dynamic handler (cgi, ssi, fastcgi, scgi, proxy, lua).
The request method is unconditionally changed to GET for the request
to service the error handler, and the original request method is
later restored (for logging purposes). request body from the
original request, if present, is discarded.
server.error-handler is somewhat similar to server.error-handler-404,
but server.error-handler-404 is now deprecated, intercepts only 404
and 403 HTTP status codes, and returns 200 OK for static error pages,
a source of confusion for some admins. On the other hand, the new
server.error-handler, when set, will intercept all HTTP status error
codes >= 400. server.error-handler takes precedence over
server.error-handler-404 when both are set.
NOTE: a major difference between server.error-handler and the
now-deprecated server.error-handler-404 is that the values of the
non-standard CGI environment variables REQUEST_URI and REDIRECT_URI
have been swapped. Since REDIRECT_STATUS is the original HTTP
status code, REDIRECT_URI is now the original request, and REQUEST_URI
is the current request (e.g. the URI/URL to the error handler).
The prior behavior -- which reversed REQUEST_URI and REDIRECT_URI values
from those described above -- is preserved for server.error-handler-404.
Additionally, REDIRECT_STATUS is now available to mod_magnet, which
continues to have access to request.uri and request.orig_uri.
See further discussion at https://redmine.lighttpd.net/issues/2702
and https://redmine.lighttpd.net/issues/1828
github: closes #36
6 years ago
|
|
|
buffer_free(s->error_handler_404);
|
|
|
|
buffer_free(s->errorfile_prefix);
|
|
|
|
buffer_free(s->socket_perms);
|
|
|
|
array_free(s->mimetypes);
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
free(srv->config_storage);
|
|
|
|
srv->config_storage = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CLEAN(x) \
|
|
|
|
array_free(srv->x);
|
|
|
|
|
|
|
|
CLEAN(config_context);
|
|
|
|
CLEAN(config_touched);
|
|
|
|
CLEAN(status);
|
|
|
|
CLEAN(srvconf.upload_tempdirs);
|
|
|
|
#undef CLEAN
|
|
|
|
|
|
|
|
joblist_free(srv, srv->joblist);
|
|
|
|
fdwaitqueue_free(srv, srv->fdwaitqueue);
|
|
|
|
|
|
|
|
if (srv->stat_cache) {
|
|
|
|
stat_cache_free(srv->stat_cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
array_free(srv->srvconf.modules);
|
|
|
|
array_free(srv->split_vals);
|
|
|
|
|
|
|
|
li_rand_cleanup();
|
|
|
|
|
|
|
|
free(srv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_pid_file(server *srv) {
|
|
|
|
if (pid_fd <= -2) return;
|
|
|
|
if (!buffer_string_is_empty(srv->srvconf.pid_file) && 0 <= pid_fd) {
|
|
|
|
if (0 != ftruncate(pid_fd, 0)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbds",
|
|
|
|
"ftruncate failed for:",
|
|
|
|
srv->srvconf.pid_file,
|
|
|
|
errno,
|
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (0 <= pid_fd) {
|
|
|
|
close(pid_fd);
|
|
|
|
pid_fd = -1;
|
|
|
|
}
|
|
|
|
if (!buffer_string_is_empty(srv->srvconf.pid_file) &&
|
|
|
|
buffer_string_is_empty(srv->srvconf.changeroot)) {
|
|
|
|
if (0 != unlink(srv->srvconf.pid_file->ptr)) {
|
|
|
|
if (errno != EACCES && errno != EPERM) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbds",
|
|
|
|
"unlink failed for:",
|
|
|
|
srv->srvconf.pid_file,
|
|
|
|
errno,
|
|
|
|
strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static server_socket * server_oneshot_getsock(server *srv, sock_addr *cnt_addr) {
|
|
|
|
server_socket *srv_socket, *srv_socket_wild = NULL;
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < srv->srv_sockets.used; ++i) {
|
|
|
|
srv_socket = srv->srv_sockets.ptr[i];
|
|
|
|
if (cnt_addr->plain.sa_family != srv_socket->addr.plain.sa_family) continue;
|
|
|
|
switch (cnt_addr->plain.sa_family) {
|
|
|
|
case AF_INET:
|
|
|
|
if (srv_socket->addr.ipv4.sin_port != cnt_addr->ipv4.sin_port) continue;
|
|
|
|
if (srv_socket->addr.ipv4.sin_addr.s_addr == cnt_addr->ipv4.sin_addr.s_addr) {
|
|
|
|
return srv_socket;
|
|
|
|
}
|
|
|
|
if (srv_socket->addr.ipv4.sin_addr.s_addr == htonl(INADDR_ANY)) {
|
|
|
|
srv_socket_wild = srv_socket;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
case AF_INET6:
|
|
|
|
if (srv_socket->addr.ipv6.sin6_port != cnt_addr->ipv6.sin6_port) continue;
|
|
|
|
if (0 == memcmp(&srv_socket->addr.ipv6.sin6_addr, &cnt_addr->ipv6.sin6_addr, sizeof(struct in6_addr))) {
|
|
|
|
return srv_socket;
|
|
|
|
}
|
|
|
|
if (0 == memcmp(&srv_socket->addr.ipv6.sin6_addr, &in6addr_any, sizeof(struct in6_addr))) {
|
|
|
|
srv_socket_wild = srv_socket;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
case AF_UNIX:
|
|
|
|
if (0 == strcmp(srv_socket->addr.un.sun_path, cnt_addr->un.sun_path)) {
|
|
|
|
return srv_socket;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
default: continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NULL != srv_socket_wild) {
|
|
|
|
return srv_socket_wild;
|
|
|
|
} else if (srv->srv_sockets.used) {
|
|
|
|
return srv->srv_sockets.ptr[0];
|
|
|
|
} else {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s", "no sockets configured");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int server_oneshot_init(server *srv, int fd) {
|
|
|
|
/* Note: does not work with netcat due to requirement that fd be socket.
|
|
|
|
* STDOUT_FILENO was not saved earlier in startup, and that is to where
|
|
|
|
* netcat expects output to be sent. Since lighttpd expects connections
|
|
|
|
* to be sockets, con->fd is where output is sent; separate fds are not
|
|
|
|
* stored for input and output, but netcat has different fds for stdin
|
|
|
|
* and * stdout. To support netcat, would additionally need to avoid
|
|
|
|
* S_ISSOCK(), getsockname(), and getpeername() below, reconstructing
|
|
|
|
* addresses from environment variables:
|
|
|
|
* NCAT_LOCAL_ADDR NCAT_LOCAL_PORT
|
|
|
|
* NCAT_REMOTE_ADDR NCAT_REMOTE_PORT
|
|
|
|
* NCAT_PROTO
|
|
|
|
*/
|
|
|
|
connection *con;
|
|
|
|
server_socket *srv_socket;
|
|
|
|
sock_addr cnt_addr;
|
|
|
|
socklen_t cnt_len;
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (0 != fstat(fd, &st)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ss", "fstat:", strerror(errno));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISSOCK(st.st_mode)) {
|
|
|
|
/* require that fd is a socket
|
|
|
|
* (modules might expect STDIN_FILENO and STDOUT_FILENO opened to /dev/null) */
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s", "lighttpd -1 stdin is not a socket");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cnt_len = sizeof(cnt_addr);
|
|
|
|
if (0 != getsockname(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ss", "getsockname:", strerror(errno));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
srv_socket = server_oneshot_getsock(srv, &cnt_addr);
|
|
|
|
if (NULL == srv_socket) return 0;
|
|
|
|
|
|
|
|
cnt_len = sizeof(cnt_addr);
|
|
|
|
if (0 != getpeername(fd, (struct sockaddr *)&cnt_addr, &cnt_len)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ss", "getpeername:", strerror(errno));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*(must set flags; fd did not pass through fdevent accept() logic)*/
|
|
|
|
if (-1 == fdevent_fcntl_set_nb_cloexec(srv->ev, fd)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl:", strerror(errno));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cnt_addr.plain.sa_family != AF_UNIX) {
|
|
|
|
network_accept_tcp_nagle_disable(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
con = connection_accepted(srv, srv_socket, &cnt_addr, fd);
|
|
|
|
if (NULL == con) return 0;
|
|
|
|
|
|
|
|
connection_state_machine(srv, con);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void show_version (void) {
|
|
|
|
char *b = PACKAGE_DESC TEXT_SSL \
|
|
|
|
" - a light and fast webserver\n"
|
|
|
|
#ifdef NONREPRODUCIBLE_BUILD
|
|
|
|
"Build-Date: " __DATE__ " " __TIME__ "\n";
|
|
|
|
#endif
|
|
|
|
;
|
|
|
|
write_all(STDOUT_FILENO, b, strlen(b));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void show_features (void) {
|
|
|
|
const char features[] = ""
|
|
|
|
#ifdef USE_SELECT
|
|
|
|
"\t+ select (generic)\n"
|
|
|
|
#else
|
|
|
|
"\t- select (generic)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_POLL
|
|
|
|
"\t+ poll (Unix)\n"
|
|
|
|
#else
|
|
|
|
"\t- poll (Unix)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_LINUX_EPOLL
|
|
|
|
"\t+ epoll (Linux 2.6)\n"
|
|
|
|
#else
|
|
|
|
"\t- epoll (Linux 2.6)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_SOLARIS_DEVPOLL
|
|
|
|
"\t+ /dev/poll (Solaris)\n"
|
|
|
|
#else
|
|
|
|
"\t- /dev/poll (Solaris)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_SOLARIS_PORT
|
|
|
|
"\t+ eventports (Solaris)\n"
|
|
|
|
#else
|
|
|
|
"\t- eventports (Solaris)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef USE_FREEBSD_KQUEUE
|
|
|
|
"\t+ kqueue (FreeBSD)\n"
|
|
|
|
#else
|
|
|
|
"\t- kqueue (FreeBSD)\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_LIBEV)
|
|
|
|
"\t+ libev (generic)\n"
|
|
|
|
#else
|
|
|
|
"\t- libev (generic)\n"
|
|
|
|
#endif
|
|
|
|
"\nNetwork handler:\n\n"
|
|
|
|
#if defined USE_LINUX_SENDFILE
|
|
|
|
"\t+ linux-sendfile\n"
|
|
|
|
#else
|
|
|
|
"\t- linux-sendfile\n"
|
|
|
|
#endif
|
|
|
|
#if defined USE_FREEBSD_SENDFILE
|
|
|
|
"\t+ freebsd-sendfile\n"
|
|
|
|
#else
|
|
|
|
"\t- freebsd-sendfile\n"
|
|
|
|
#endif
|
|
|
|
#if defined USE_DARWIN_SENDFILE
|
|
|
|
"\t+ darwin-sendfile\n"
|
|
|
|
#else
|
|
|
|
"\t- darwin-sendfile\n"
|
|
|
|
#endif
|
|
|
|
#if defined USE_SOLARIS_SENDFILEV
|
|
|
|
"\t+ solaris-sendfilev\n"
|
|
|
|
#else
|
|
|
|
"\t- solaris-sendfilev\n"
|
|
|
|
#endif
|
|
|
|
#if defined USE_WRITEV
|
|
|
|
"\t+ writev\n"
|
|
|
|
#else
|
|
|
|
"\t- writev\n"
|
|
|
|
#endif
|
|
|
|
"\t+ write\n"
|
|
|
|
#ifdef USE_MMAP
|
|
|
|
"\t+ mmap support\n"
|
|
|
|
#else
|
|
|
|
"\t- mmap support\n"
|
|
|
|
#endif
|
|
|
|
"\nFeatures:\n\n"
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
"\t+ IPv6 support\n"
|
|
|
|
#else
|
|
|
|
"\t- IPv6 support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_ZLIB)
|
|
|
|
"\t+ zlib support\n"
|
|
|
|
#else
|
|
|
|
"\t- zlib support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_BZIP)
|
|
|
|
"\t+ bzip2 support\n"
|
|
|
|
#else
|
|
|
|
"\t- bzip2 support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(HAVE_CRYPT) || defined(HAVE_CRYPT_R) || defined(HAVE_LIBCRYPT)
|
|
|
|
"\t+ crypt support\n"
|
|
|
|
#else
|
|
|
|
"\t- crypt support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_OPENSSL)
|
|
|
|
"\t+ SSL support\n"
|
|
|
|
#else
|
|
|
|
"\t- SSL support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_PCRE)
|
|
|
|
"\t+ PCRE support\n"
|
|
|
|
#else
|
|
|
|
"\t- PCRE support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_MYSQL)
|
|
|
|
"\t+ MySQL support\n"
|
|
|
|
#else
|
|
|
|
"\t- MySQL support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_PGSQL)
|
|
|
|
"\t+ PgSQL support\n"
|
|
|
|
#else
|
|
|
|
"\t- PgSQL support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_DBI)
|
|
|
|
"\t+ DBI support\n"
|
|
|
|
#else
|
|
|
|
"\t- DBI support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_KRB5)
|
|
|
|
"\t+ Kerberos support\n"
|
|
|
|
#else
|
|
|
|
"\t- Kerberos support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_LDAP)
|
|
|
|
"\t+ LDAP support\n"
|
|
|
|
#else
|
|
|
|
"\t- LDAP support\n"
|
|
|
|
#endif
|
|
|
|
#if defined(WITH_MEMCACHED)
|
|
|
|
"\t+ memcached support\n"
|
|
|
|
#else
|
|
|
|
"\t- memcached support\n"
|
|
|
|
#endif
|
|