(third-party) upgrade shttpd from 1.39 to the latest, 1.41
This commit is contained in:
parent
f89a5e23d5
commit
2281c39c1f
|
@ -328,7 +328,9 @@ startServer( tr_rpc_server * server )
|
|||
|
||||
if( !server->ctx )
|
||||
{
|
||||
char ports[128];
|
||||
int i;
|
||||
int argc = 0;
|
||||
char * argv[100];
|
||||
char passwd[MAX_PATH_LENGTH];
|
||||
const char * clutchDir = tr_getClutchDir( server->session );
|
||||
struct timeval tv = tr_timevalMsec( INACTIVE_INTERVAL_MSEC );
|
||||
|
@ -339,36 +341,41 @@ startServer( tr_rpc_server * server )
|
|||
else
|
||||
edit_passwords( passwd, MY_REALM, server->username, server->password );
|
||||
|
||||
server->ctx = shttpd_init( );
|
||||
tr_snprintf( ports, sizeof( ports ), "%d", server->port );
|
||||
argv[argc++] = tr_strdup( "appname-unused" );
|
||||
argv[argc++] = tr_strdup( "-ports" );
|
||||
argv[argc++] = tr_strdup_printf( "%d", server->port );
|
||||
argv[argc++] = tr_strdup( "-dir_list" );
|
||||
argv[argc++] = tr_strdup( "0" );
|
||||
argv[argc++] = tr_strdup( "-auth_realm" );
|
||||
argv[argc++] = tr_strdup( MY_REALM );
|
||||
if( server->acl )
|
||||
{
|
||||
argv[argc++] = tr_strdup( "-acl" );
|
||||
argv[argc++] = tr_strdup( server->acl );
|
||||
}
|
||||
if( server->isPasswordEnabled )
|
||||
{
|
||||
argv[argc++] = tr_strdup( "-protect" );
|
||||
argv[argc++] = tr_strdup_printf( "/transmission=%s", passwd );
|
||||
}
|
||||
if( clutchDir && *clutchDir )
|
||||
{
|
||||
tr_inf( _( "Serving the web interface files from \"%s\"" ), clutchDir );
|
||||
argv[argc++] = tr_strdup( "-aliases" );
|
||||
argv[argc++] = tr_strdup_printf( "%s=%s,%s=%s",
|
||||
"/transmission/clutch", clutchDir,
|
||||
"/transmission/web", clutchDir );
|
||||
}
|
||||
|
||||
server->ctx = shttpd_init( argc, argv );
|
||||
shttpd_register_uri( server->ctx, "/transmission/rpc", handle_rpc, server );
|
||||
shttpd_register_uri( server->ctx, "/transmission/upload", handle_upload, server );
|
||||
|
||||
if( clutchDir && *clutchDir ) {
|
||||
char * clutchAlias = tr_strdup_printf( "%s=%s,%s=%s",
|
||||
"/transmission/clutch", clutchDir,
|
||||
"/transmission/web", clutchDir );
|
||||
tr_inf( _( "Serving the web interface files from \"%s\"" ), clutchDir );
|
||||
shttpd_set_option( server->ctx, "aliases", clutchAlias );
|
||||
tr_free( clutchAlias );
|
||||
}
|
||||
|
||||
shttpd_set_option( server->ctx, "ports", ports );
|
||||
shttpd_set_option( server->ctx, "dir_list", "0" );
|
||||
//shttpd_set_option( server->ctx, "root", "/dev/null" );
|
||||
shttpd_set_option( server->ctx, "auth_realm", MY_REALM );
|
||||
if( server->acl ) {
|
||||
dbgmsg( "setting acl [%s]", server->acl );
|
||||
shttpd_set_option( server->ctx, "acl", server->acl );
|
||||
}
|
||||
if( server->isPasswordEnabled ) {
|
||||
char * buf = tr_strdup_printf( "/transmission=%s", passwd );
|
||||
shttpd_set_option( server->ctx, "protect", buf );
|
||||
tr_free( buf );
|
||||
}
|
||||
|
||||
evtimer_set( &server->timer, rpcPulse, server );
|
||||
evtimer_add( &server->timer, &tv );
|
||||
|
||||
for( i=0; i<argc; ++i )
|
||||
tr_free( argv[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,7 +436,7 @@ tr_rpcGetPort( const tr_rpc_server * server )
|
|||
****/
|
||||
|
||||
/*
|
||||
* DELIM_CHARS, FOR_EACH_WORD_IN_LIST, isbyte, and testACL are from, or modified from,
|
||||
* FOR_EACH_WORD_IN_LIST, isbyte, and testACL are from, or modified from,
|
||||
* shttpd, written by Sergey Lyubka under this license:
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Sergey Lyubka wrote this file. As long as you retain this notice you
|
||||
|
@ -437,8 +444,6 @@ tr_rpcGetPort( const tr_rpc_server * server )
|
|||
* this stuff is worth it, you can buy me a beer in return.
|
||||
*/
|
||||
|
||||
#define DELIM_CHARS "," /* Separators for lists */
|
||||
|
||||
#define FOR_EACH_WORD_IN_LIST(s,len) \
|
||||
for (; s != NULL && (len = strcspn(s, DELIM_CHARS)) != 0; \
|
||||
s += len, s+= strspn(s, DELIM_CHARS))
|
||||
|
|
|
@ -4,7 +4,7 @@ noinst_LIBRARIES = libshttpd.a
|
|||
AM_CPPFLAGS = -DEMBEDDED -DNDEBUG -DNO_CGI -DNO_SSI
|
||||
|
||||
libshttpd_a_SOURCES = \
|
||||
string.c shttpd.c log.c auth.c md5.c cgi.c config.c \
|
||||
string.c shttpd.c log.c auth.c md5.c \
|
||||
io_file.c io_socket.c io_ssl.c io_emb.c io_dir.c io_cgi.c \
|
||||
compat_unix.c
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
http://shttpd.sourceforge.net/
|
||||
Sergey Lyubka wrote this software.
|
||||
This snapshot si from shttpd-1.39
|
||||
This snapshot is from shttpd-1.41
|
||||
|
|
|
@ -281,12 +281,12 @@ check_authorization(struct conn *c, const char *path)
|
|||
|
||||
if (!memcmp(c->uri, s, p - s)) {
|
||||
|
||||
n = s + len - p + 1;
|
||||
n = s + len - p;
|
||||
if (n > (int) sizeof(protected_path) - 1)
|
||||
n = sizeof(protected_path) - 1;
|
||||
|
||||
|
||||
my_strlcpy(protected_path, p + 1, n);
|
||||
|
||||
|
||||
if ((fp = fopen(protected_path, "r")) == NULL)
|
||||
elog(E_LOG, c, "check_auth: cannot open %s: %s",
|
||||
protected_path, strerror(errno));
|
||||
|
|
|
@ -18,58 +18,6 @@ struct env_block {
|
|||
int nvars; /* Number of variables */
|
||||
};
|
||||
|
||||
/*
|
||||
* UNIX socketpair() implementation. Why? Because Windows does not have it.
|
||||
* Return 0 on success, -1 on error.
|
||||
*/
|
||||
static int
|
||||
my_socketpair(struct conn *c, int sp[2])
|
||||
{
|
||||
struct sockaddr_in sa;
|
||||
int sock, ret = -1;
|
||||
socklen_t len = sizeof(sa);
|
||||
|
||||
(void) memset(&sa, 0, sizeof(sa));
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(0);
|
||||
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
elog(E_LOG, c, "mysocketpair: socket(): %d", ERRNO);
|
||||
} else if (bind(sock, (struct sockaddr *) &sa, len) != 0) {
|
||||
elog(E_LOG, c, "mysocketpair: bind(): %d", ERRNO);
|
||||
(void) closesocket(sock);
|
||||
} else if (listen(sock, 1) != 0) {
|
||||
elog(E_LOG, c, "mysocketpair: listen(): %d", ERRNO);
|
||||
(void) closesocket(sock);
|
||||
} else if (getsockname(sock, (struct sockaddr *) &sa, &len) != 0) {
|
||||
elog(E_LOG, c, "mysocketpair: getsockname(): %d", ERRNO);
|
||||
(void) closesocket(sock);
|
||||
} else if ((sp[0] = socket(AF_INET, SOCK_STREAM, 6)) == -1) {
|
||||
elog(E_LOG, c, "mysocketpair: socket(): %d", ERRNO);
|
||||
(void) closesocket(sock);
|
||||
} else if (connect(sp[0], (struct sockaddr *) &sa, len) != 0) {
|
||||
elog(E_LOG, c, "mysocketpair: connect(): %d", ERRNO);
|
||||
(void) closesocket(sock);
|
||||
(void) closesocket(sp[0]);
|
||||
} else if ((sp[1] = accept(sock,(struct sockaddr *) &sa, &len)) == -1) {
|
||||
elog(E_LOG, c, "mysocketpair: accept(): %d", ERRNO);
|
||||
(void) closesocket(sock);
|
||||
(void) closesocket(sp[0]);
|
||||
} else {
|
||||
/* Success */
|
||||
ret = 0;
|
||||
(void) closesocket(sock);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
(void) fcntl(sp[0], F_SETFD, FD_CLOEXEC);
|
||||
(void) fcntl(sp[1], F_SETFD, FD_CLOEXEC);
|
||||
#endif /* _WIN32*/
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
addenv(struct env_block *block, const char *fmt, ...)
|
||||
{
|
||||
|
@ -145,11 +93,16 @@ prepare_environment(const struct conn *c, const char *prog,
|
|||
struct env_block *blk)
|
||||
{
|
||||
const struct headers *h = &c->ch;
|
||||
const char *s, *root = c->ctx->options[OPT_ROOT];
|
||||
const char *s, *fname, *root = c->ctx->options[OPT_ROOT];
|
||||
size_t len;
|
||||
|
||||
blk->len = blk->nvars = 0;
|
||||
|
||||
/* SCRIPT_FILENAME */
|
||||
fname = prog;
|
||||
if ((s = strrchr(prog, '/')))
|
||||
fname = s + 1;
|
||||
|
||||
/* Prepare the environment block */
|
||||
addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
|
||||
addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
|
||||
|
@ -163,7 +116,7 @@ prepare_environment(const struct conn *c, const char *prog,
|
|||
addenv(blk, "REMOTE_PORT=%hu", ntohs(c->sa.u.sin.sin_port));
|
||||
addenv(blk, "REQUEST_URI=%s", c->uri);
|
||||
addenv(blk, "SCRIPT_NAME=%s", prog + strlen(root));
|
||||
addenv(blk, "SCRIPT_FILENAME=%s", prog); /* PHP */
|
||||
addenv(blk, "SCRIPT_FILENAME=%s", fname); /* PHP */
|
||||
addenv(blk, "PATH_TRANSLATED=%s", prog);
|
||||
|
||||
if (h->ct.v_vec.len > 0)
|
||||
|
@ -244,7 +197,7 @@ run_cgi(struct conn *c, const char *prog)
|
|||
break;
|
||||
}
|
||||
|
||||
if (my_socketpair(c, pair) != 0) {
|
||||
if (shttpd_socketpair(pair) != 0) {
|
||||
ret = -1;
|
||||
} else if (spawn_process(c, prog, blk.buf, blk.vars, pair[1], dir)) {
|
||||
ret = -1;
|
||||
|
|
|
@ -20,14 +20,16 @@
|
|||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#if !defined(NO_THREADS)
|
||||
#include "pthread.h"
|
||||
#define _beginthread(a, b, c) do { pthread_t tid; \
|
||||
pthread_create(&tid, NULL, (void *(*)(void *))a, c); } while (0)
|
||||
#endif /* !NO_THREADS */
|
||||
|
||||
#define SSL_LIB "libssl.so"
|
||||
#define DIRSEP '/'
|
||||
#define IS_DIRSEP_CHAR(c) ((c) == '/')
|
||||
#define O_BINARY 0
|
||||
#define closesocket(a) close(a)
|
||||
#define ERRNO errno
|
||||
#define NO_GUI
|
||||
|
||||
#define InitializeCriticalSection(x) /* FIXME UNIX version is not MT safe */
|
||||
#define EnterCriticalSection(x)
|
||||
#define LeaveCriticalSection(x)
|
||||
|
|
|
@ -1,309 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
|
||||
* All rights reserved
|
||||
*
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Sergey Lyubka wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return.
|
||||
*/
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
static int isbyte(int n) { return (n >= 0 && n <= 255); }
|
||||
|
||||
static void
|
||||
set_acl(struct shttpd_ctx *ctx, const char *s)
|
||||
{
|
||||
struct acl *acl = NULL;
|
||||
char flag;
|
||||
int len, a, b, c, d, n, mask;
|
||||
struct llhead *lp, *tmp;
|
||||
|
||||
/* Delete the old ACLs if any */
|
||||
LL_FOREACH_SAFE(&ctx->acl, lp, tmp)
|
||||
free(LL_ENTRY(lp, struct acl, link));
|
||||
|
||||
FOR_EACH_WORD_IN_LIST(s, len) {
|
||||
|
||||
mask = 32;
|
||||
|
||||
if (sscanf(s, "%c%d.%d.%d.%d%n",&flag,&a,&b,&c,&d,&n) != 5) {
|
||||
elog(E_FATAL, NULL, "[%s]: subnet must be "
|
||||
"[+|-]x.x.x.x[/x]", s);
|
||||
} else if (flag != '+' && flag != '-') {
|
||||
elog(E_FATAL, NULL, "flag must be + or -: [%s]", s);
|
||||
} else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) {
|
||||
elog(E_FATAL, NULL, "bad ip address: [%s]", s);
|
||||
} else if ((acl = malloc(sizeof(*acl))) == NULL) {
|
||||
elog(E_FATAL, NULL, "%s", "cannot malloc subnet");
|
||||
} else if (sscanf(s + n, "/%d", &mask) == 0) {
|
||||
/* Do nothing, no mask specified */
|
||||
} else if (mask < 0 || mask > 32) {
|
||||
elog(E_FATAL, NULL, "bad subnet mask: %d [%s]", n, s);
|
||||
}
|
||||
|
||||
acl->ip = (a << 24) | (b << 16) | (c << 8) | d;
|
||||
acl->mask = mask ? 0xffffffffU << (32 - mask) : 0;
|
||||
acl->flag = flag;
|
||||
LL_TAIL(&ctx->acl, &acl->link);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_SSL
|
||||
/*
|
||||
* Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
|
||||
*/
|
||||
static void
|
||||
set_ssl(struct shttpd_ctx *ctx, const char *pem)
|
||||
{
|
||||
SSL_CTX *CTX;
|
||||
void *lib;
|
||||
struct ssl_func *fp;
|
||||
|
||||
/* Load SSL library dynamically */
|
||||
if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL)
|
||||
elog(E_FATAL, NULL, "set_ssl: cannot load %s", SSL_LIB);
|
||||
|
||||
for (fp = ssl_sw; fp->name != NULL; fp++)
|
||||
if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL)
|
||||
elog(E_FATAL, NULL,"set_ssl: cannot find %s", fp->name);
|
||||
|
||||
/* Initialize SSL crap */
|
||||
SSL_library_init();
|
||||
|
||||
if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
|
||||
elog(E_FATAL, NULL, "SSL_CTX_new error");
|
||||
else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
|
||||
elog(E_FATAL, NULL, "cannot open %s", pem);
|
||||
else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
|
||||
elog(E_FATAL, NULL, "cannot open %s", pem);
|
||||
ctx->ssl_ctx = CTX;
|
||||
}
|
||||
#endif /* NO_SSL */
|
||||
|
||||
static void
|
||||
open_log_file(FILE **fpp, const char *path)
|
||||
{
|
||||
if (*fpp != NULL)
|
||||
(void) fclose(*fpp);
|
||||
|
||||
if (path == NULL) {
|
||||
*fpp = NULL;
|
||||
} else if ((*fpp = fopen(path, "a")) == NULL) {
|
||||
elog(E_FATAL, NULL, "cannot open log file %s: %s",
|
||||
path, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_alog(struct shttpd_ctx *ctx, const char *path)
|
||||
{
|
||||
open_log_file(&ctx->access_log, path);
|
||||
}
|
||||
|
||||
static void
|
||||
set_elog(struct shttpd_ctx *ctx, const char *path)
|
||||
{
|
||||
open_log_file(&ctx->error_log, path);
|
||||
}
|
||||
|
||||
static void show_cfg_page(struct shttpd_arg *arg);
|
||||
|
||||
static void
|
||||
set_cfg_uri(struct shttpd_ctx *ctx, const char *uri)
|
||||
{
|
||||
free_list(&ctx->registered_uris, ®istered_uri_destructor);
|
||||
|
||||
if (uri != NULL) {
|
||||
shttpd_register_uri(ctx, uri, &show_cfg_page, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_ports(struct shttpd_ctx *ctx, const char *p)
|
||||
{
|
||||
int len, is_ssl;
|
||||
|
||||
free_list(&ctx->listeners, &listener_destructor);
|
||||
|
||||
FOR_EACH_WORD_IN_LIST(p, len) {
|
||||
is_ssl = p[len - 1] == 's' ? 1 : 0;
|
||||
if (shttpd_listen(ctx, atoi(p), is_ssl) == -1)
|
||||
elog(E_FATAL, NULL,
|
||||
"Cannot open socket on port %d", atoi(p));
|
||||
}
|
||||
}
|
||||
|
||||
static const struct opt {
|
||||
int index; /* Index in shttpd_ctx */
|
||||
const char *name; /* Option name in config file */
|
||||
const char *description; /* Description */
|
||||
const char *default_value; /* Default option value */
|
||||
void (*setter)(struct shttpd_ctx *, const char *);
|
||||
} known_options[] = {
|
||||
{OPT_ROOT, "root", "\tWeb root directory", ".", NULL},
|
||||
{OPT_INDEX_FILES, "index_files", "Index files", INDEX_FILES, NULL},
|
||||
{OPT_PORTS, "ports", "Listening ports", LISTENING_PORTS, set_ports},
|
||||
{OPT_DIR_LIST, "dir_list", "Directory listing", "1", NULL},
|
||||
{OPT_CFG_URI, "cfg_uri", "Config uri", NULL, set_cfg_uri},
|
||||
{OPT_PROTECT, "protect", "URI to htpasswd mapping", NULL, NULL},
|
||||
#ifndef NO_CGI
|
||||
{OPT_CGI_EXTENSIONS, "cgi_ext", "CGI extensions", CGI_EXT, NULL},
|
||||
{OPT_CGI_INTERPRETER, "cgi_interp", "CGI interpreter", NULL, NULL},
|
||||
{OPT_CGI_ENVIRONMENT, "cgi_env", "Additional CGI env vars", NULL, NULL},
|
||||
#endif /* NO_CGI */
|
||||
{OPT_SSI_EXTENSIONS, "ssi_ext", "SSI extensions", SSI_EXT, NULL},
|
||||
#ifndef NO_AUTH
|
||||
{OPT_AUTH_REALM, "auth_realm", "Authentication domain name",REALM,NULL},
|
||||
{OPT_AUTH_GPASSWD, "auth_gpass", "Global passwords file", NULL, NULL},
|
||||
{OPT_AUTH_PUT, "auth_PUT", "PUT,DELETE auth file", NULL, NULL},
|
||||
#endif /* !NO_AUTH */
|
||||
{OPT_ACCESS_LOG, "access_log", "Access log file", NULL, set_alog},
|
||||
{OPT_ERROR_LOG, "error_log", "Error log file", NULL, set_elog},
|
||||
{OPT_MIME_TYPES, "mime_types", "Additional mime types list", NULL,NULL},
|
||||
#ifndef NO_SSL
|
||||
{OPT_SSL_CERTIFICATE, "ssl_cert", "SSL certificate file", NULL,set_ssl},
|
||||
#endif /* NO_SSL */
|
||||
{OPT_ALIASES, "aliases", "Path=URI mappings", NULL, NULL},
|
||||
{OPT_ACL, "acl", "\tAllow/deny IP addresses/subnets", NULL, set_acl},
|
||||
#ifdef _WIN32
|
||||
#else
|
||||
{OPT_INETD, "inetd", "Inetd mode", "0", NULL},
|
||||
{OPT_UID, "uid", "\tRun as user", NULL, NULL},
|
||||
#endif /* _WIN32 */
|
||||
{-1, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
void shttpd_set_option(struct shttpd_ctx *ctx, const char *opt, const char *val)
|
||||
{
|
||||
const struct opt *o;
|
||||
|
||||
for (o = known_options; o->name != NULL; o++)
|
||||
if (!strcmp(opt, o->name))
|
||||
break;
|
||||
|
||||
if (o->name == NULL)
|
||||
elog(E_FATAL, NULL, "no such option: [%s]", opt);
|
||||
|
||||
/* Call option setter first, so it can use both new and old values */
|
||||
if (o->setter != NULL)
|
||||
o->setter(ctx, val);
|
||||
|
||||
/* Free old value if any */
|
||||
if (ctx->options[o->index] != NULL)
|
||||
free(ctx->options[o->index]);
|
||||
|
||||
/* Set new option value */
|
||||
ctx->options[o->index] = val ? my_strdup(val) : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
show_cfg_page(struct shttpd_arg *arg)
|
||||
{
|
||||
struct shttpd_ctx *ctx = arg->user_data;
|
||||
char opt_name[20], value[BUFSIZ];
|
||||
const struct opt *o;
|
||||
|
||||
opt_name[0] = value[0] = '\0';
|
||||
|
||||
if (!strcmp(shttpd_get_env(arg, "REQUEST_METHOD"), "POST")) {
|
||||
if (arg->flags & SHTTPD_MORE_POST_DATA)
|
||||
return;
|
||||
(void) shttpd_get_var("o", arg->in.buf, arg->in.len,
|
||||
opt_name, sizeof(opt_name));
|
||||
(void) shttpd_get_var("v", arg->in.buf, arg->in.len,
|
||||
value, sizeof(value));
|
||||
shttpd_set_option(ctx, opt_name, value[0] ? value : NULL);
|
||||
}
|
||||
|
||||
shttpd_printf(arg, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"
|
||||
"<html><body><h1>SHTTPD v. %s</h1>", shttpd_version());
|
||||
|
||||
shttpd_printf(arg, "%s", "<table border=1"
|
||||
"<tr><th>Option</th><th>Description</th>"
|
||||
"<th colspan=2>Value</th></tr>");
|
||||
|
||||
if (opt_name[0] != '\0' && value[0] != '\0')
|
||||
shttpd_printf(arg, "<p style='color: green'>Saved: %s=%s</p>",
|
||||
opt_name, value[0] ? value : "NULL");
|
||||
|
||||
|
||||
for (o = known_options; o->name != NULL; o++) {
|
||||
shttpd_printf(arg,
|
||||
"<form method=post><tr><td>%s</td><td>%s</td>"
|
||||
"<input type=hidden name=o value='%s'>"
|
||||
"<td><input type=text name=v value='%s'></td>"
|
||||
"<td><input type=submit value=save></td></form></tr>",
|
||||
o->name, o->description, o->name,
|
||||
ctx->options[o->index] ? ctx->options[o->index] : "");
|
||||
}
|
||||
|
||||
shttpd_printf(arg, "%s", "</table></body></html>");
|
||||
arg->flags |= SHTTPD_END_OF_OUTPUT;
|
||||
}
|
||||
/*
|
||||
* Show usage string and exit.
|
||||
*/
|
||||
void
|
||||
usage(const char *prog)
|
||||
{
|
||||
const struct opt *o;
|
||||
|
||||
(void) fprintf(stderr,
|
||||
"SHTTPD version %s (c) Sergey Lyubka\n"
|
||||
"usage: %s [options] [config_file]\n", VERSION, prog);
|
||||
|
||||
#if !defined(NO_AUTH)
|
||||
fprintf(stderr, " -A <htpasswd_file> <realm> <user> <passwd>\n");
|
||||
#endif /* NO_AUTH */
|
||||
|
||||
for (o = known_options; o->name != NULL; o++) {
|
||||
(void) fprintf(stderr, " -%s\t%s", o->name, o->description);
|
||||
if (o->default_value != NULL)
|
||||
fprintf(stderr, " (default: %s)", o->default_value);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct shttpd_ctx *shttpd_init(void)
|
||||
{
|
||||
struct shttpd_ctx *ctx;
|
||||
struct tm *tm;
|
||||
const struct opt *o;
|
||||
|
||||
if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
|
||||
elog(E_FATAL, NULL, "cannot allocate shttpd context");
|
||||
|
||||
/* Set default values */
|
||||
for (o = known_options; o->name != NULL; o++) {
|
||||
ctx->options[o->index] = o->default_value == NULL ?
|
||||
NULL : my_strdup(o->default_value);
|
||||
}
|
||||
|
||||
current_time = ctx->start_time = time(NULL);
|
||||
tm = localtime(¤t_time);
|
||||
tz_offset = 0;
|
||||
#if 0
|
||||
tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0);
|
||||
#endif
|
||||
|
||||
InitializeCriticalSection(&ctx->mutex);
|
||||
|
||||
LL_INIT(&ctx->connections);
|
||||
LL_INIT(&ctx->registered_uris);
|
||||
LL_INIT(&ctx->error_handlers);
|
||||
LL_INIT(&ctx->acl);
|
||||
#if !defined(NO_SSI)
|
||||
LL_INIT(&ctx->ssi_funcs);
|
||||
#endif
|
||||
LL_INIT(&ctx->listeners);
|
||||
|
||||
#ifdef _WIN32
|
||||
{WSADATA data; WSAStartup(MAKEWORD(2,2), &data);}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
return (ctx);
|
||||
}
|
|
@ -11,8 +11,8 @@
|
|||
#ifndef CONFIG_HEADER_DEFINED
|
||||
#define CONFIG_HEADER_DEFINED
|
||||
|
||||
#undef VERSION
|
||||
#define VERSION "1.39" /* Version */
|
||||
#undef VERSION
|
||||
#define VERSION "1.41" /* Version */
|
||||
#define CONFIG_FILE "shttpd.conf" /* Configuration file */
|
||||
#define HTPASSWD ".htpasswd" /* Passwords file name */
|
||||
#define URI_MAX 16384 /* Default max request size */
|
||||
|
@ -25,5 +25,6 @@
|
|||
#define EXPIRE_TIME 3600 /* Expiration time, seconds */
|
||||
#define ENV_MAX 4096 /* Size of environment block */
|
||||
#define CGI_ENV_VARS 64 /* Maximum vars passed to CGI */
|
||||
#define SERVICE_NAME "SHTTPD " VERSION /* NT service name */
|
||||
|
||||
#endif /* CONFIG_HEADER_DEFINED */
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#include "std_includes.h"
|
||||
#include "llist.h"
|
||||
#include "io.h"
|
||||
#include "shttpd.h"
|
||||
#include "md5.h"
|
||||
#include "config.h"
|
||||
#include "shttpd.h"
|
||||
|
||||
#define NELEMS(ar) (sizeof(ar) / sizeof(ar[0]))
|
||||
|
||||
|
@ -26,10 +26,6 @@
|
|||
#define DBG(x)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifdef EMBEDDED
|
||||
#include "shttpd.h"
|
||||
#endif /* EMBEDDED */
|
||||
|
||||
/*
|
||||
* Darwin prior to 7.0 and Win32 do not have socklen_t
|
||||
*/
|
||||
|
@ -45,9 +41,10 @@ struct vec {
|
|||
int len;
|
||||
};
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#if !defined(FALSE)
|
||||
enum {FALSE, TRUE};
|
||||
#endif /* _WIN32 */
|
||||
#endif /* !FALSE */
|
||||
|
||||
enum {METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE, METHOD_HEAD};
|
||||
enum {HDR_DATE, HDR_INT, HDR_STRING}; /* HTTP header types */
|
||||
enum {E_FATAL = 1, E_LOG = 2}; /* Flags for elog() function */
|
||||
|
@ -175,7 +172,6 @@ struct stream {
|
|||
union channel chan; /* Descriptor */
|
||||
struct io io; /* IO buffer */
|
||||
const struct io_class *io_class; /* IO class */
|
||||
int nread_last; /* Bytes last read */
|
||||
int headers_len;
|
||||
big_int_t content_len;
|
||||
unsigned int flags;
|
||||
|
@ -186,10 +182,21 @@ struct stream {
|
|||
#define FLAG_CLOSED 16
|
||||
#define FLAG_DONT_CLOSE 32
|
||||
#define FLAG_ALWAYS_READY 64 /* File, dir, user_func */
|
||||
#define FLAG_SUSPEND 128
|
||||
};
|
||||
|
||||
struct worker {
|
||||
struct llhead link;
|
||||
int num_conns; /* Num of active connections */
|
||||
int exit_flag; /* Ditto - exit flag */
|
||||
int ctl[2]; /* Control socket pair */
|
||||
struct shttpd_ctx *ctx; /* Context reference */
|
||||
struct llhead connections; /* List of connections */
|
||||
};
|
||||
|
||||
struct conn {
|
||||
struct llhead link; /* Connections chain */
|
||||
struct worker *worker; /* Worker this conn belongs to */
|
||||
struct shttpd_ctx *ctx; /* Context this conn belongs to */
|
||||
struct usa sa; /* Remote socket address */
|
||||
time_t birth_time; /* Creation time */
|
||||
|
@ -223,7 +230,7 @@ enum {
|
|||
OPT_SSI_EXTENSIONS, OPT_AUTH_REALM, OPT_AUTH_GPASSWD,
|
||||
OPT_AUTH_PUT, OPT_ACCESS_LOG, OPT_ERROR_LOG, OPT_MIME_TYPES,
|
||||
OPT_SSL_CERTIFICATE, OPT_ALIASES, OPT_ACL, OPT_INETD, OPT_UID,
|
||||
OPT_CFG_URI, OPT_PROTECT,
|
||||
OPT_CFG_URI, OPT_PROTECT, OPT_SERVICE, OPT_HIDE, OPT_THREADS,
|
||||
NUM_OPTIONS
|
||||
};
|
||||
|
||||
|
@ -231,35 +238,33 @@ enum {
|
|||
* SHTTPD context
|
||||
*/
|
||||
struct shttpd_ctx {
|
||||
time_t start_time; /* Start time */
|
||||
int nactive; /* # of connections now */
|
||||
unsigned long nrequests; /* Requests made */
|
||||
uint64_t in, out; /* IN/OUT traffic counters */
|
||||
SSL_CTX *ssl_ctx; /* SSL context */
|
||||
struct llhead connections; /* List of connections */
|
||||
|
||||
struct llhead registered_uris;/* User urls */
|
||||
struct llhead error_handlers; /* Embedded error handlers */
|
||||
struct llhead acl; /* Access control list */
|
||||
#if !defined(NO_SSI)
|
||||
struct llhead ssi_funcs; /* SSI callback functions */
|
||||
#endif
|
||||
struct llhead listeners; /* Listening sockets */
|
||||
struct llhead workers; /* Worker workers */
|
||||
|
||||
FILE *access_log; /* Access log stream */
|
||||
FILE *error_log; /* Error log stream */
|
||||
FILE *access_log; /* Access log stream */
|
||||
FILE *error_log; /* Error log stream */
|
||||
|
||||
char *options[NUM_OPTIONS]; /* Configurable options */
|
||||
|
||||
#if defined(_WIN32)
|
||||
CRITICAL_SECTION mutex; /* For MT case */
|
||||
HANDLE ev[2]; /* For thread synchronization */
|
||||
#elif defined(__rtems__)
|
||||
#if defined(__rtems__)
|
||||
rtems_id mutex;
|
||||
#endif /* _WIN32 */
|
||||
};
|
||||
|
||||
#define IS_TRUE(ctx, opt) ((ctx)->options[opt] && (ctx)->options[opt][0] =='1')
|
||||
struct listener {
|
||||
struct llhead link;
|
||||
struct shttpd_ctx *ctx; /* Context that socket belongs */
|
||||
int sock; /* Listening socket */
|
||||
int is_ssl; /* Should be SSL-ed */
|
||||
};
|
||||
|
||||
/* Types of messages that could be sent over the control socket */
|
||||
enum {CTL_PASS_SOCKET, CTL_WAKEUP};
|
||||
|
||||
/*
|
||||
* In SHTTPD, list of values are represented as comma or space separated
|
||||
|
@ -300,11 +305,11 @@ extern int url_decode(const char *, int, char *dst, int);
|
|||
extern void send_server_error(struct conn *, int code, const char *reason);
|
||||
extern int get_headers_len(const char *buf, size_t buflen);
|
||||
extern void parse_headers(const char *s, int len, struct headers *parsed);
|
||||
extern void open_listening_ports(struct shttpd_ctx *ctx);
|
||||
extern int is_true(const char *str);
|
||||
extern int shttpd_socketpair(int pair[2]);
|
||||
extern void get_mime_type(struct shttpd_ctx *, const char *, int, struct vec *);
|
||||
extern void free_list(struct llhead *head, void (*)(struct llhead *));
|
||||
extern void registered_uri_destructor(struct llhead *);
|
||||
extern void listener_destructor(struct llhead *);
|
||||
|
||||
#define IS_TRUE(ctx, opt) is_true((ctx)->options[opt])
|
||||
|
||||
/*
|
||||
* config.c
|
||||
|
@ -342,6 +347,10 @@ extern char * my_getcwd(char *, int);
|
|||
extern int spawn_process(struct conn *c, const char *prog,
|
||||
char *envblk, char *envp[], int sock, const char *dir);
|
||||
|
||||
extern void set_nt_service(struct shttpd_ctx *, const char *);
|
||||
extern void set_systray(struct shttpd_ctx *, const char *);
|
||||
extern void try_to_run_as_nt_service(void);
|
||||
|
||||
/*
|
||||
* io_*.c
|
||||
*/
|
||||
|
@ -360,10 +369,8 @@ extern void ssl_handshake(struct stream *stream);
|
|||
extern void setup_embedded_stream(struct conn *, union variant, void *);
|
||||
extern struct registered_uri *is_registered_uri(struct shttpd_ctx *,
|
||||
const char *uri);
|
||||
#if !defined(NO_SSI)
|
||||
extern void do_ssi(struct conn *);
|
||||
extern void ssi_func_destructor(struct llhead *lp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* auth.c
|
||||
|
|
|
@ -52,6 +52,9 @@ call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func)
|
|||
c->loc.flags &= ~FLAG_DONT_CLOSE;
|
||||
else
|
||||
c->loc.flags |= FLAG_DONT_CLOSE;
|
||||
|
||||
if (arg->flags & SHTTPD_SUSPEND)
|
||||
c->loc.flags |= FLAG_SUSPEND;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -90,14 +93,10 @@ close_embedded(struct stream *stream)
|
|||
size_t
|
||||
shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...)
|
||||
{
|
||||
struct conn *c = arg->priv;
|
||||
struct io *io = &c->loc.io;
|
||||
char *buf = arg->out.buf + arg->out.num_bytes;
|
||||
int buflen = arg->out.len - arg->out.num_bytes, len = 0;
|
||||
va_list ap;
|
||||
|
||||
assert(buf <= io->buf + io->size);
|
||||
|
||||
if (buflen > 0) {
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, buflen, fmt, ap);
|
||||
|
@ -267,6 +266,22 @@ shttpd_handle_error(struct shttpd_ctx *ctx, int code,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
shttpd_wakeup(const void *priv)
|
||||
{
|
||||
const struct conn *conn = priv;
|
||||
char buf[sizeof(int) + sizeof(void *)];
|
||||
int cmd = CTL_WAKEUP;
|
||||
|
||||
#if 0
|
||||
conn->flags &= ~SHTTPD_SUSPEND;
|
||||
#endif
|
||||
(void) memcpy(buf, &cmd, sizeof(cmd));
|
||||
(void) memcpy(buf + sizeof(cmd), conn, sizeof(conn));
|
||||
|
||||
(void) send(conn->worker->ctl[1], buf, sizeof(buf), 0);
|
||||
}
|
||||
|
||||
const struct io_class io_embedded = {
|
||||
"embedded",
|
||||
do_embedded,
|
||||
|
|
|
@ -20,7 +20,7 @@ write_file(struct stream *stream, const void *buf, size_t len)
|
|||
assert(fd != -1);
|
||||
n = write(fd, buf, len);
|
||||
|
||||
DBG(("put_file(%p, %d): %d bytes", (void *) stream, len, n));
|
||||
DBG(("put_file(%p, %d): %d bytes", (void *) stream, (int) len, n));
|
||||
|
||||
if (n <= 0 || (rem->io.total >= (big_int_t) rem->headers_len)) {
|
||||
(void) fstat(fd, &st);
|
||||
|
|
|
@ -33,21 +33,21 @@ ssl_handshake(struct stream *stream)
|
|||
{
|
||||
int n;
|
||||
|
||||
if ((n = SSL_accept(stream->chan.ssl.ssl)) == 0) {
|
||||
if ((n = SSL_accept(stream->chan.ssl.ssl)) == 1) {
|
||||
DBG(("handshake: SSL accepted"));
|
||||
stream->flags |= FLAG_SSL_ACCEPTED;
|
||||
} else {
|
||||
n = SSL_get_error(stream->chan.ssl.ssl, n);
|
||||
if (n != SSL_ERROR_WANT_READ && n != SSL_ERROR_WANT_WRITE)
|
||||
stream->flags |= FLAG_CLOSED;
|
||||
elog(E_LOG, stream->conn, "SSL_accept error %d", n);
|
||||
} else {
|
||||
DBG(("handshake: SSL accepted"));
|
||||
stream->flags |= FLAG_SSL_ACCEPTED;
|
||||
DBG(("SSL_accept error %d", n));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
read_ssl(struct stream *stream, void *buf, size_t len)
|
||||
{
|
||||
int nread = 0;
|
||||
int nread = -1;
|
||||
|
||||
assert(stream->chan.ssl.ssl != NULL);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,25 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
|
||||
* Copyright (c) 2004-2008 Sergey Lyubka <valenok@gmail.com>
|
||||
* All rights reserved
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Sergey Lyubka wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* $Id: shttpd.h,v 1.9 2008/02/13 20:44:32 drozd Exp $
|
||||
* $Id: shttpd.h,v 1.16 2008/05/31 09:02:02 drozd Exp $
|
||||
*/
|
||||
|
||||
#ifndef SHTTPD_HEADER_INCLUDED
|
||||
|
@ -41,54 +29,62 @@ struct ubuf {
|
|||
struct shttpd_arg {
|
||||
void *priv; /* Private! Do not touch! */
|
||||
void *state; /* User state */
|
||||
void *user_data; /* User-defined data */
|
||||
void *user_data; /* Data from register_uri() */
|
||||
struct ubuf in; /* Input is here, POST data */
|
||||
struct ubuf out; /* Output goes here */
|
||||
|
||||
unsigned int flags;
|
||||
#define SHTTPD_END_OF_OUTPUT 1
|
||||
#define SHTTPD_CONNECTION_ERROR 2
|
||||
#define SHTTPD_MORE_POST_DATA 4
|
||||
#define SHTTPD_POST_BUFFER_FULL 8
|
||||
#define SHTTPD_SSI_EVAL_TRUE 16
|
||||
#define SHTTPD_END_OF_OUTPUT 1 /* No more data do send */
|
||||
#define SHTTPD_CONNECTION_ERROR 2 /* Server closed the connection */
|
||||
#define SHTTPD_MORE_POST_DATA 4 /* arg->in has incomplete data */
|
||||
#define SHTTPD_POST_BUFFER_FULL 8 /* arg->in has max data */
|
||||
#define SHTTPD_SSI_EVAL_TRUE 16 /* SSI eval callback must set it*/
|
||||
#define SHTTPD_SUSPEND 32 /* User wants to suspend output */
|
||||
};
|
||||
|
||||
/*
|
||||
* User callback function. Called when certain registered URLs have been
|
||||
* requested. These are the requirements to the callback function:
|
||||
*
|
||||
* 1. it must copy data into 'out.buf' buffer, not more than 'out.len' bytes,
|
||||
* 1. It must copy data into 'out.buf' buffer, not more than 'out.len' bytes,
|
||||
* and record how many bytes are copied, into 'out.num_bytes'
|
||||
* 2. it must not block the execution
|
||||
* 3. it must set SHTTPD_END_OF_OUTPUT flag when finished
|
||||
* 4. for POST requests, it must process the incoming data (in.buf) of length
|
||||
* 2. It must not call any blocking functions
|
||||
* 3. It must set SHTTPD_END_OF_OUTPUT flag when there is no more data to send
|
||||
* 4. For POST requests, it must process the incoming data (in.buf) of length
|
||||
* 'in.len', and set 'in.num_bytes', which is how many bytes of POST
|
||||
* data is read and can be discarded by SHTTPD.
|
||||
* data was processed and can be discarded by SHTTPD.
|
||||
* 5. If callback allocates arg->state, to keep state, it must deallocate it
|
||||
* at the end of coonection SHTTPD_CONNECTION_ERROR or SHTTPD_END_OF_OUTPUT
|
||||
* 6. If callback function wants to suspend until some event, it must store
|
||||
* arg->priv pointer elsewhere, set SHTTPD_SUSPEND flag and return. When
|
||||
* the event happens, user code should call shttpd_wakeup(priv).
|
||||
* It is safe to call shttpd_wakeup() from any thread. User code must
|
||||
* not call shttpd_wakeup once the connection is closed.
|
||||
*/
|
||||
typedef void (*shttpd_callback_t)(struct shttpd_arg *);
|
||||
|
||||
/*
|
||||
* shttpd_init Initialize shttpd context.
|
||||
* shttpd_set_option Set new value for option.
|
||||
* shttpd_fini Dealocate the context
|
||||
* shttpd_register_uri Setup the callback function for specified URL.
|
||||
* shtppd_listen Setup a listening socket in the SHTTPD context
|
||||
* shttpd_init Initialize shttpd context
|
||||
* shttpd_fini Dealocate the context, close all connections
|
||||
* shttpd_set_option Set new value for option
|
||||
* shttpd_register_uri Setup the callback function for specified URL
|
||||
* shttpd_poll Do connections processing
|
||||
* shttpd_version return string with SHTTPD version
|
||||
* shttpd_get_var Fetch POST/GET variable value by name. Return value len
|
||||
* shttpd_get_header return value of the specified HTTP header
|
||||
* shttpd_get_env return string values for the following
|
||||
* pseudo-variables: "REQUEST_METHOD", "REQUEST_URI",
|
||||
* "REMOTE_USER" and "REMOTE_ADDR".
|
||||
* shttpd_get_env return values for the following pseudo-variables:
|
||||
"REQUEST_METHOD", "REQUEST_URI",
|
||||
* "REMOTE_USER" and "REMOTE_ADDR"
|
||||
* shttpd_printf helper function to output data
|
||||
* shttpd_handle_error register custom HTTP error handler
|
||||
* shttpd_wakeup clear SHTTPD_SUSPEND state for the connection
|
||||
*/
|
||||
|
||||
struct shttpd_ctx;
|
||||
|
||||
struct shttpd_ctx *shttpd_init(void);
|
||||
struct shttpd_ctx *shttpd_init(int argc, char *argv[]);
|
||||
void shttpd_set_option(struct shttpd_ctx *, const char *opt, const char *val);
|
||||
void shttpd_fini(struct shttpd_ctx *);
|
||||
int shttpd_listen(struct shttpd_ctx *ctx, int port, int is_ssl);
|
||||
void shttpd_register_uri(struct shttpd_ctx *ctx, const char *uri,
|
||||
shttpd_callback_t callback, void *const user_data);
|
||||
void shttpd_poll(struct shttpd_ctx *, int milliseconds);
|
||||
|
@ -104,19 +100,7 @@ void shttpd_handle_error(struct shttpd_ctx *ctx, int status,
|
|||
shttpd_callback_t func, void *const data);
|
||||
void shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name,
|
||||
shttpd_callback_t func, void *const user_data);
|
||||
|
||||
/*
|
||||
* The following three functions are for applications that need to
|
||||
* load-balance the connections on their own. Many threads may be spawned
|
||||
* with one SHTTPD context per thread. Boss thread may only wait for
|
||||
* new connections by means of shttpd_accept(). Then it may scan thread
|
||||
* pool for the idle thread by means of shttpd_active(), and add new
|
||||
* connection to the context by means of shttpd_add().
|
||||
*/
|
||||
void shttpd_add_socket(struct shttpd_ctx *, int sock, int is_ssl);
|
||||
int shttpd_accept(int lsn_sock, int milliseconds);
|
||||
int shttpd_active(struct shttpd_ctx *);
|
||||
|
||||
void shttpd_wakeup(const void *priv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "defs.h"
|
||||
|
||||
static int exit_flag;
|
||||
static int exit_flag; /* Program termination flag */
|
||||
|
||||
static void
|
||||
signal_handler(int sig_num)
|
||||
|
@ -27,70 +27,6 @@ signal_handler(int sig_num)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
process_command_line_arguments(struct shttpd_ctx *ctx, char *argv[])
|
||||
{
|
||||
const char *config_file = CONFIG_FILE;
|
||||
char line[BUFSIZ], opt[BUFSIZ],
|
||||
val[BUFSIZ], path[FILENAME_MAX], *p;
|
||||
FILE *fp;
|
||||
size_t i, line_no = 0;
|
||||
|
||||
/* First find out, which config file to open */
|
||||
for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
|
||||
if (argv[i + 1] == NULL)
|
||||
usage(argv[0]);
|
||||
|
||||
if (argv[i] != NULL && argv[i + 1] != NULL) {
|
||||
/* More than one non-option arguments are given w*/
|
||||
usage(argv[0]);
|
||||
} else if (argv[i] != NULL) {
|
||||
/* Just one non-option argument is given, this is config file */
|
||||
config_file = argv[i];
|
||||
} else {
|
||||
/* No config file specified. Look for one where shttpd lives */
|
||||
if ((p = strrchr(argv[0], DIRSEP)) != 0) {
|
||||
my_snprintf(path, sizeof(path), "%.*s%s",
|
||||
p - argv[0] + 1, argv[0], config_file);
|
||||
config_file = path;
|
||||
}
|
||||
}
|
||||
|
||||
fp = fopen(config_file, "r");
|
||||
|
||||
/* If config file was set in command line and open failed, exit */
|
||||
if (fp == NULL && argv[i] != NULL)
|
||||
elog(E_FATAL, NULL, "cannot open config file %s: %s",
|
||||
config_file, strerror(errno));
|
||||
|
||||
if (fp != NULL) {
|
||||
|
||||
elog(E_LOG, NULL, "Loading config file %s", config_file);
|
||||
|
||||
/* Loop over the lines in config file */
|
||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||
|
||||
line_no++;
|
||||
|
||||
/* Ignore empty lines and comments */
|
||||
if (line[0] == '#' || line[0] == '\n')
|
||||
continue;
|
||||
|
||||
if (sscanf(line, "%s %[^\n#]", opt, val) != 2)
|
||||
elog(E_FATAL, NULL, "line %d in %s is invalid",
|
||||
line_no, config_file);
|
||||
|
||||
shttpd_set_option(ctx, opt, val);
|
||||
}
|
||||
|
||||
(void) fclose(fp);
|
||||
}
|
||||
|
||||
/* Now pass through the command line options */
|
||||
for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
|
||||
shttpd_set_option(ctx, &argv[i][1], argv[i + 1]);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -107,24 +43,11 @@ main(int argc, char *argv[])
|
|||
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
|
||||
usage(argv[0]);
|
||||
|
||||
ctx = shttpd_init();
|
||||
process_command_line_arguments(ctx, argv);
|
||||
#if defined(_WIN32)
|
||||
try_to_run_as_nt_service();
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Switch to alternate UID, it is safe now, after shttpd_listen() */
|
||||
if (ctx->options[OPT_UID] != NULL) {
|
||||
struct passwd *pw;
|
||||
|
||||
if ((pw = getpwnam(ctx->options[OPT_UID])) == NULL)
|
||||
elog(E_FATAL, 0, "main: unknown user [%s]",
|
||||
ctx->options[OPT_UID]);
|
||||
else if (setgid(pw->pw_gid) == -1)
|
||||
elog(E_FATAL, NULL, "main: setgid(%s): %s",
|
||||
ctx->options[OPT_UID], strerror(errno));
|
||||
else if (setuid(pw->pw_uid) == -1)
|
||||
elog(E_FATAL, NULL, "main: setuid(%s): %s",
|
||||
ctx->options[OPT_UID], strerror(errno));
|
||||
}
|
||||
(void) signal(SIGCHLD, signal_handler);
|
||||
(void) signal(SIGPIPE, SIG_IGN);
|
||||
#endif /* _WIN32 */
|
||||
|
@ -132,22 +55,15 @@ main(int argc, char *argv[])
|
|||
(void) signal(SIGTERM, signal_handler);
|
||||
(void) signal(SIGINT, signal_handler);
|
||||
|
||||
if (IS_TRUE(ctx, OPT_INETD)) {
|
||||
shttpd_set_option(ctx, "ports", NULL);
|
||||
(void) freopen("/dev/null", "a", stderr);
|
||||
shttpd_add_socket(ctx, fileno(stdin), 0);
|
||||
}
|
||||
ctx = shttpd_init(argc, argv);
|
||||
|
||||
elog(E_LOG, NULL, "shttpd %s started on port(s) %s, serving %s",
|
||||
VERSION, ctx->options[OPT_PORTS], ctx->options[OPT_ROOT]);
|
||||
|
||||
while (exit_flag == 0)
|
||||
shttpd_poll(ctx, 5000);
|
||||
|
||||
elog(E_LOG, NULL, "%d requests %.2lf Mb in %.2lf Mb out. "
|
||||
"Exit on signal %d", ctx->nrequests, (double) (ctx->in / 1048576),
|
||||
(double) ctx->out / 1048576, exit_flag);
|
||||
shttpd_poll(ctx, 10 * 1000);
|
||||
|
||||
elog(E_LOG, NULL, "Exit on signal %d", exit_flag);
|
||||
shttpd_fini(ctx);
|
||||
|
||||
return (EXIT_SUCCESS);
|
||||
|
|
Loading…
Reference in New Issue