summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kneschke <jan@kneschke.de>2005-08-15 09:55:23 +0000
committerJan Kneschke <jan@kneschke.de>2005-08-15 09:55:23 +0000
commitd8394f7f2e9b144ede2477d082d6669dec52acc7 (patch)
treebff5733fd85ab6ddaf94307294d15f8d02c605e7
parentc92984c270b4260325578265bb606b4bb8efe8fd (diff)
downloadlighttpd-git-d8394f7f2e9b144ede2477d082d6669dec52acc7.tar.gz
moved code to mod_staticfile, mod_dirlisting and mod_indexfile
git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-merge-1.4.x@541 152afb58-edef-0310-8abb-c4023f1b3aa9
-rw-r--r--src/Makefile.am14
-rw-r--r--src/base.h9
-rw-r--r--src/configfile-glue.c68
-rw-r--r--src/configfile.c135
-rw-r--r--src/connections.c314
-rw-r--r--src/mod_dirlisting.c650
-rw-r--r--src/mod_indexfile.c213
-rw-r--r--src/mod_staticfile.c575
-rw-r--r--src/request.c8
-rw-r--r--src/response.c1104
-rw-r--r--src/response.h5
-rw-r--r--src/server.c11
12 files changed, 1769 insertions, 1337 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8236b82a..e32c5dbd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -94,6 +94,20 @@ mod_scgi_la_SOURCES = mod_scgi.c
mod_scgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_scgi_la_LIBADD = $(common_libadd)
+lib_LTLIBRARIES += mod_staticfile.la
+mod_staticfile_la_SOURCES = mod_staticfile.c
+mod_staticfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_staticfile_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_dirlisting.la
+mod_dirlisting_la_SOURCES = mod_dirlisting.c
+mod_dirlisting_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_dirlisting_la_LIBADD = $(common_libadd)
+
+lib_LTLIBRARIES += mod_indexfile.la
+mod_indexfile_la_SOURCES = mod_indexfile.c
+mod_indexfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_indexfile_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_setenv.la
mod_setenv_la_SOURCES = mod_setenv.c
diff --git a/src/base.h b/src/base.h
index fd3dce86..e98d4917 100644
--- a/src/base.h
+++ b/src/base.h
@@ -223,7 +223,6 @@ typedef struct {
} stat_cache;
typedef struct {
- array *indexfiles;
array *mimetypes;
/* virtual-servers */
@@ -231,12 +230,9 @@ typedef struct {
buffer *server_name;
buffer *error_handler;
buffer *server_tag;
- buffer *dirlist_css;
buffer *dirlist_encoding;
buffer *errorfile_prefix;
- unsigned short dir_listing;
- unsigned short hide_dotfiles;
unsigned short max_keep_alive_requests;
unsigned short max_keep_alive_idle;
unsigned short max_read_idle;
@@ -260,6 +256,7 @@ typedef struct {
unsigned short use_ipv6;
unsigned short is_ssl;
unsigned short allow_http11;
+ unsigned short force_lower_case; /* if the FS is case-insensitive, force all files to lower-case */
unsigned short max_request_size;
unsigned short kbytes_per_second; /* connection kb/s limit */
@@ -513,9 +510,7 @@ typedef struct {
buffer *tmp_chunk_len;
- buffer *range_buf;
-
- buffer *empty_string; /* is necessary for cond_match */
+ buffer *cond_check_buf;
/* caches */
#ifdef HAVE_IPV6
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
index 3f20f6e7..c4c4c4ee 100644
--- a/src/configfile-glue.c
+++ b/src/configfile-glue.c
@@ -147,6 +147,14 @@ int config_insert_values_global(server *srv, array *ca, const config_values_t cv
return config_insert_values_internal(srv, ca, cv);
}
+unsigned short sock_addr_get_port(sock_addr *addr) {
+#ifdef HAVE_IPV6
+ return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port);
+#else
+ return ntohs(addr->ipv4.sin_port);
+#endif
+}
+
static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc);
static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
@@ -176,13 +184,8 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
/* pass the rules */
- l = srv->empty_string;
-
switch (dc->comp) {
case COMP_HTTP_HOST: {
- l = con->uri.authority;
-#if 0
- /* FIXME: get this working again */
char *ck_colon = NULL, *val_colon = NULL;
if (!buffer_is_empty(con->uri.authority)) {
@@ -191,23 +194,35 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
* append server-port to the HTTP_POST if necessary
*/
- buffer_copy_string_buffer(srv->cond_check_buf, con->uri.authority);
+ l = con->uri.authority;
switch(dc->cond) {
case CONFIG_COND_NE:
case CONFIG_COND_EQ:
ck_colon = strchr(dc->string->ptr, ':');
- val_colon = strchr(con->uri.authority->ptr, ':');
+ val_colon = strchr(l->ptr, ':');
- if (ck_colon && !val_colon) {
- /* colon found */
+ if (ck_colon == val_colon) {
+ /* nothing to do with it */
+ break;
+ }
+ if (ck_colon) {
+ /* condition "host:port" but client send "host" */
+ buffer_copy_string_buffer(srv->cond_check_buf, l);
BUFFER_APPEND_STRING_CONST(srv->cond_check_buf, ":");
buffer_append_long(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
+ l = srv->cond_check_buf;
+ } else if (!ck_colon) {
+ /* condition "host" but client send "host:port" */
+ buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
+ l = srv->cond_check_buf;
}
break;
default:
break;
}
+ } else {
+ l = NULL;
}
break;
}
@@ -271,21 +286,8 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
}
} else {
- const char *s;
-#ifdef HAVE_IPV6
- char b2[INET6_ADDRSTRLEN + 1];
-
- s = inet_ntop(con->dst_addr.plain.sa_family,
- con->dst_addr.plain.sa_family == AF_INET6 ?
- (const void *) &(con->dst_addr.ipv6.sin6_addr) :
- (const void *) &(con->dst_addr.ipv4.sin_addr),
- b2, sizeof(b2)-1);
-#else
- s = inet_ntoa(con->dst_addr.ipv4.sin_addr);
-#endif
- buffer_copy_string(srv->cond_check_buf, s);
+ l = con->dst_addr_buf;
}
-#endif
break;
}
case COMP_HTTP_URL:
@@ -301,6 +303,8 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
l = ds->value;
+ } else {
+ l = NULL;
}
break;
}
@@ -308,6 +312,8 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
data_string *ds;
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
l = ds->value;
+ } else {
+ l = NULL;
}
break;
}
@@ -315,6 +321,8 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
data_string *ds;
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
l = ds->value;
+ } else {
+ l = NULL;
}
break;
}
@@ -323,8 +331,17 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
return COND_RESULT_FALSE;
}
+ if (NULL == l) {
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
+ "(", l, ") compare to NULL");
+ }
+ return COND_RESULT_FALSE;
+ }
+
if (con->conf.log_condition_handling) {
- log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key, "(", l, ") compare to ", dc->string);
+ log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
+ "(", l, ") compare to ", dc->string);
}
switch(dc->cond) {
case CONFIG_COND_NE:
@@ -387,8 +404,7 @@ static cond_result_t config_check_cond_cached(server *srv, connection *con, data
"(uncached) result:",
caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
}
- }
- else {
+ } else {
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
"(cached) result:",
diff --git a/src/configfile.c b/src/configfile.c
index a58de1a1..537de673 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -26,6 +26,7 @@ static int config_insert(server *srv) {
size_t i;
int ret = 0;
buffer *stat_cache_string;
+ data_string *ds;
config_values_t cv[] = {
{ "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */
@@ -44,8 +45,8 @@ static int config_insert(server *srv) {
{ "server.max-request-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
{ "server.max-worker", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 13 */
{ "server.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
- { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
- { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
+ { "server.force-lower-case-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 15 */
+ { "debug.log-condition-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 16 */
{ "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
{ "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
{ "server.max-keep-alive-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
@@ -73,15 +74,9 @@ static int config_insert(server *srv) {
{ "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
{ "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 38 */
- { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 39 */
- { "dir-listing.external-css", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
-
- { "dir-listing.encoding", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
- { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 42 */
- { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
- { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
-
- { "debug.log-condition-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 45 */
+ { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 39 */
+ { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
+ { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
{ "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
@@ -113,10 +108,10 @@ static int config_insert(server *srv) {
cv[36].destination = &(srv->srvconf.log_request_header_on_error);
cv[37].destination = &(srv->srvconf.log_state_handling);
- cv[42].destination = &(srv->srvconf.errorlog_use_syslog);
+ cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
stat_cache_string = buffer_init();
- cv[44].destination = stat_cache_string;
+ cv[41].destination = stat_cache_string;
srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
@@ -128,9 +123,6 @@ static int config_insert(server *srv) {
s = calloc(1, sizeof(specific_config));
assert(s);
s->document_root = buffer_init();
- s->dir_listing = 0;
- s->hide_dotfiles = 1;
- s->indexfiles = array_init();
s->mimetypes = array_init();
s->server_name = buffer_init();
s->ssl_pemfile = buffer_init();
@@ -138,8 +130,6 @@ static int config_insert(server *srv) {
s->error_handler = buffer_init();
s->server_tag = buffer_init();
s->errorfile_prefix = buffer_init();
- s->dirlist_css = buffer_init();
- s->dirlist_encoding = buffer_init();
s->max_keep_alive_requests = 128;
s->max_keep_alive_idle = 30;
s->max_read_idle = 60;
@@ -151,6 +141,7 @@ static int config_insert(server *srv) {
s->kbytes_per_second = 0;
s->allow_http11 = 1;
s->range_requests = 1;
+ s->force_lower_case = 0;
s->global_kbytes_per_second = 0;
s->global_bytes_per_second_cnt = 0;
s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
@@ -164,8 +155,8 @@ static int config_insert(server *srv) {
cv[12].destination = &(s->max_request_size);
/* 13 max-worker */
cv[14].destination = s->document_root;
- cv[15].destination = &(s->dir_listing);
- cv[16].destination = s->indexfiles;
+ cv[15].destination = &(s->force_lower_case);
+ cv[16].destination = &(s->log_condition_handling);
cv[17].destination = &(s->max_keep_alive_requests);
cv[18].destination = s->server_name;
cv[19].destination = &(s->max_keep_alive_idle);
@@ -188,12 +179,7 @@ static int config_insert(server *srv) {
cv[35].destination = &(s->allow_http11);
cv[38].destination = s->ssl_ca_file;
- cv[39].destination = &(s->hide_dotfiles);
- cv[40].destination = s->dirlist_css;
- cv[41].destination = s->dirlist_encoding;
- cv[43].destination = &(s->range_requests);
-
- cv[45].destination = &(s->log_condition_handling);
+ cv[39].destination = &(s->range_requests);
srv->config_storage[i] = s;
@@ -218,6 +204,27 @@ static int config_insert(server *srv) {
buffer_free(stat_cache_string);
+ srv->srvconf.modules->unique_ndx = srv->srvconf.modules->used;
+
+ /* append default modules */
+ if (NULL == array_get_element(srv->srvconf.modules, "mod_indexfile")) {
+ ds = data_string_init();
+ buffer_copy_string(ds->value, "mod_indexfile");
+ array_insert_unique(srv->srvconf.modules, (data_unset *)ds);
+ }
+
+ if (NULL == array_get_element(srv->srvconf.modules, "mod_dirlisting")) {
+ ds = data_string_init();
+ buffer_copy_string(ds->value, "mod_dirlisting");
+ array_insert_unique(srv->srvconf.modules, (data_unset *)ds);
+ }
+
+ if (NULL == array_get_element(srv->srvconf.modules, "mod_staticfile")) {
+ ds = data_string_init();
+ buffer_copy_string(ds->value, "mod_staticfile");
+ array_insert_unique(srv->srvconf.modules, (data_unset *)ds);
+ }
+
return ret;
}
@@ -230,11 +237,6 @@ int config_setup_connection(server *srv, connection *con) {
PATCH(allow_http11);
PATCH(mimetypes);
PATCH(document_root);
- PATCH(dir_listing);
- PATCH(dirlist_css);
- PATCH(dirlist_encoding);
- PATCH(hide_dotfiles);
- PATCH(indexfiles);
PATCH(max_keep_alive_requests);
PATCH(max_keep_alive_idle);
PATCH(max_read_idle);
@@ -258,6 +260,7 @@ int config_setup_connection(server *srv, connection *con) {
PATCH(log_file_not_found);
PATCH(range_requests);
+ PATCH(force_lower_case);
return 0;
}
@@ -282,22 +285,12 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
PATCH(document_root);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
- PATCH(dir_listing);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
PATCH(range_requests);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
- PATCH(hide_dotfiles);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
- PATCH(dirlist_css);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
- PATCH(dirlist_encoding);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler-404"))) {
PATCH(error_handler);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.errorfile-prefix"))) {
PATCH(errorfile_prefix);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
- PATCH(indexfiles);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.assign"))) {
PATCH(mimetypes);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.max-keep-alive-requests"))) {
@@ -336,6 +329,8 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
PATCH(log_file_not_found);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
PATCH(allow_http11);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lower-case-files"))) {
+ PATCH(force_lower_case);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
PATCH(global_kbytes_per_second);
PATCH(global_bytes_per_second_cnt);
@@ -977,6 +972,7 @@ int config_read(server *srv, const char *fn) {
int config_set_defaults(server *srv) {
size_t i;
specific_config *s = srv->config_storage[0];
+ struct stat st1, st2;
struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
{
@@ -1005,32 +1001,45 @@ int config_set_defaults(server *srv) {
{ FDEVENT_HANDLER_UNSET, NULL }
};
-#ifdef USE_LICENSE
- license_t *l;
-
- if (srv->srvconf.license->used == 0) {
- /* license is missing */
- return -1;
- }
-
- l = license_init();
-
- if (0 != license_parse(l, srv->srvconf.license)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "parsing license information failed", srv->srvconf.license);
+ if (buffer_is_empty(s->document_root)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "a default document-root has to be set");
- license_free(l);
+ return -1;
+ }
+ if (-1 == stat(s->document_root->ptr, &st1)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "base-docroot doesn't exist:",
+ s->document_root);
return -1;
}
- if (!license_is_valid(l)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "license is not valid");
+
+ buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
+
+ buffer_to_lower(srv->tmp_buf);
+
+ if (0 == stat(srv->tmp_buf->ptr, &st1)) {
+
+ /* lower-case existed, check upper-case */
+
+ buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
+
+ buffer_to_upper(srv->tmp_buf);
- license_free(l);
- return -1;
- }
- license_free(l);
-#endif
+ if (0 == stat(srv->tmp_buf->ptr, &st2)) {
+
+ /* upper case exists too, doesn't the FS handle this ? */
+
+ /* upper and lower have the same inode -> case-insensitve FS */
+
+ if (st1.st_ino == st2.st_ino) {
+ /* upper and lower have the same inode -> case-insensitve FS */
+
+ s->force_lower_case = 1;
+ }
+ }
+ }
+
if (srv->srvconf.port == 0) {
srv->srvconf.port = s->is_ssl ? 443 : 80;
}
diff --git a/src/connections.c b/src/connections.c
index f525a5d5..595d417f 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -297,205 +297,138 @@ static int connection_handle_read(server *srv, connection *con) {
}
static int connection_handle_write_prepare(server *srv, connection *con) {
- struct stat st;
- int s_len;
-
- switch(con->mode) {
- case DIRECT:
- switch(con->http_status) {
- case 400: /* class: header + custom body */
- case 401:
- case 403:
- case 404:
- case 408:
- case 411:
- case 416:
- case 500:
- case 501:
- case 503:
- case 505: {
- con->file_finished = 1;
+ if (con->mode == DIRECT) {
+ /* static files */
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_POST:
+ case HTTP_METHOD_HEAD:
+ case HTTP_METHOD_OPTIONS:
+ case HTTP_METHOD_PUT:
+ break;
+ default:
+ switch(con->http_status) {
+ case 400: /* bad request */
+ case 505: /* unknown protocol */
+ break;
+ default:
+ con->http_status = 501;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (con->http_status == 0) {
+ con->http_status = 403;
+ }
+
+ switch(con->http_status) {
+ case 400: /* class: header + custom body */
+ case 401:
+ case 403:
+ case 404:
+ case 408:
+ case 411:
+ case 416:
+ case 500:
+ case 501:
+ case 503:
+ case 505:
+ if (con->mode != DIRECT) break;
+
+ con->file_finished = 0;
+
+ buffer_reset(con->physical.path);
- /* rewrite the filename */
-
- /* FIXME: use con.physical.errorfile
- *
- *
- */
- buffer_reset(con->physical.path);
+ /* try to send static errorfile */
+ if (!buffer_is_empty(con->conf.errorfile_prefix)) {
+ stat_cache_entry *sce = NULL;
- if (con->conf.errorfile_prefix->used) {
- buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
- buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
- }
+ buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
+ buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
- if ((con->physical.path->used <= 1) ||
- (-1 == (stat(con->physical.path->ptr, &st)))) {
- buffer *b;
-
- buffer_reset(con->physical.path);
-
- b = chunkqueue_get_append_buffer(con->write_queue);
-
- /* build default error-page */
- buffer_copy_string(b,
- "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
- "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
- " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
- "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
- " <head>\n"
- " <title>");
- buffer_append_long(b, con->http_status);
- buffer_append_string(b, " - ");
- buffer_append_string(b, get_http_status_name(con->http_status));
-
- buffer_append_string(b,
- "</title>\n"
- " </head>\n"
- " <body>\n"
- " <h1>");
- buffer_append_long(b, con->http_status);
- buffer_append_string(b, " - ");
- buffer_append_string(b, get_http_status_name(con->http_status));
-
- buffer_append_string(b,"</h1>\n"
- " </body>\n"
- "</html>\n"
- );
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
- } else {
- /* get content-type */
- size_t k;
- s_len = con->physical.path->used - 1;
-
- for (k = 0; k < con->conf.mimetypes->used; k++) {
- data_string *ds = (data_string *)con->conf.mimetypes->data[k];
- int ct_len = ds->key->used - 1;
-
- if (s_len < ct_len ||
- ds->key->used == 0) continue;
-
- if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(ds->value));
- break;
- }
- }
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ con->file_finished = 1;
- if (k == con->conf.mimetypes->used) {
- /* the error message should be HTML */
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
- }
+ http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
}
}
- /* fall through */
+
+ if (!con->file_finished) {
+ buffer *b;
- case 200: /* class: header + body */
- if (con->physical.path->used) {
- stat_cache_entry *sce = NULL;
- con->file_finished = 1;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- strerror(errno), con->physical.path);
-
- connection_set_state(srv, con, CON_STATE_ERROR);
-
- return -1;
- }
-
- if (S_ISREG(sce->st.st_mode)) {
- if (con->request.http_method == HTTP_METHOD_GET ||
- con->request.http_method == HTTP_METHOD_POST) {
- http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
- con->response.content_length = http_chunkqueue_length(srv, con);
- } else if (con->request.http_method == HTTP_METHOD_HEAD) {
- con->response.content_length = sce->st.st_size;
- } else {
- connection_set_state(srv, con, CON_STATE_ERROR);
- return -1;
- }
-
- http_response_write_header(srv, con,
- con->response.content_length,
- sce->st.st_mtime);
-
-
- } else {
- /* why the heck ? */
-
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "connection closed: no regular-file to send:",
- con->physical.path);
-
- con->file_finished = 1;
- }
- } else {
- if (con->file_finished) {
- con->response.content_length = (ssize_t)http_chunkqueue_length(srv, con);
- }
-
- /* disable keep-alive if size-info for the body is missing */
- if ((con->parsed_response & HTTP_CONTENT_LENGTH) &&
- ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
- con->keep_alive = 0;
- }
-
- if (con->request.http_method == HTTP_METHOD_HEAD) {
- chunkqueue_reset(con->write_queue);
- }
-
- http_response_write_header(srv, con,
- con->response.content_length,
- 0);
-
- }
- break;
+ buffer_reset(con->physical.path);
- case 206: /* write_queue is already prepared */
- http_response_write_header(srv, con,
- con->response.content_length,
- 0);
- con->file_finished = 1;
- break;
- case 302:
con->file_finished = 1;
-
- con->response.content_length = (ssize_t)http_chunkqueue_length(srv, con);
+ b = chunkqueue_get_append_buffer(con->write_queue);
- http_response_write_header(srv, con,
- con->response.content_length,
- 0);
-
- break;
- case 205: /* class: header only */
- case 301:
- case 304:
- default:
- /* disable chunked encoding again as we have no body */
- con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
- chunkqueue_reset(con->write_queue);
-
- http_response_write_header(srv, con, 0, 0);
- con->file_finished = 1;
- break;
+ /* build default error-page */
+ buffer_copy_string(b,
+ "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
+ " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
+ " <head>\n"
+ " <title>");
+ buffer_append_long(b, con->http_status);
+ buffer_append_string(b, " - ");
+ buffer_append_string(b, get_http_status_name(con->http_status));
+
+ buffer_append_string(b,
+ "</title>\n"
+ " </head>\n"
+ " <body>\n"
+ " <h1>");
+ buffer_append_long(b, con->http_status);
+ buffer_append_string(b, " - ");
+ buffer_append_string(b, get_http_status_name(con->http_status));
+
+ buffer_append_string(b,"</h1>\n"
+ " </body>\n"
+ "</html>\n"
+ );
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
}
+ /* fall through */
+ case 200: /* class: header + body */
+ break;
+
+ case 206: /* write_queue is already prepared */
+ case 302:
+ con->file_finished = 1;
- case 207:
break;
+ case 205: /* class: header only */
+ case 301:
+ case 304:
default:
- if (con->request.http_method == HTTP_METHOD_HEAD ||
- con->http_status == 301 ||
- con->http_status == 304 ||
- con->http_status == 205) {
- /* remove possible chunks */
- con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
- chunkqueue_reset(con->write_queue);
+ /* disable chunked encoding again as we have no body */
+ con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
+ chunkqueue_reset(con->write_queue);
+
+ con->file_finished = 1;
+ break;
+ }
+
+
+ if (con->file_finished) {
+ /* content-len */
+
+ buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
+ } else {
+ /* disable keep-alive if size-info for the body is missing */
+ if ((con->parsed_response & HTTP_CONTENT_LENGTH) &&
+ ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
+ con->keep_alive = 0;
}
if (0 == (con->parsed_response & HTTP_CONNECTION)) {
- /* (f)cgi did'nt send Connection: header
- *
+ /* (f)cgi did'nt send Connection: header
+ *
* shall we ?
*/
if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
@@ -512,13 +445,14 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
/* FIXME: we have to drop the Connection: Header from the subrequest */
}
}
-
- con->response.content_length = (ssize_t)http_chunkqueue_length(srv, con);
- http_response_write_basic_header(srv, con);
-
- break;
}
+ if (con->request.http_method == HTTP_METHOD_HEAD) {
+ chunkqueue_reset(con->write_queue);
+ }
+
+ http_response_write_header(srv, con);
+
return 0;
}
@@ -1324,7 +1258,11 @@ int connection_state_machine(server *srv, connection *con) {
"state for fd", con->fd, connection_get_state(con->state));
}
- connection_handle_write_prepare(srv, con);
+ if (-1 == connection_handle_write_prepare(srv, con)) {
+ connection_set_state(srv, con, CON_STATE_ERROR);
+
+ break;
+ }
connection_set_state(srv, con, CON_STATE_WRITE);
break;
diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
new file mode 100644
index 00000000..b24d63f1
--- /dev/null
+++ b/src/mod_dirlisting.c
@@ -0,0 +1,650 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "config.h"
+#include "response.h"
+#include "stat_cache.h"
+#include "stream.h"
+
+/**
+ * this is a dirlisting for a lighttpd plugin
+ */
+
+
+#ifdef HAVE_SYS_SYSLIMITS_H
+#include <sys/syslimits.h>
+#endif
+
+#ifdef HAVE_ATTR_ATTRIBUTES_H
+#include <attr/attributes.h>
+#endif
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ unsigned short dir_listing;
+ unsigned short hide_dot_files;
+ unsigned short show_readme;
+
+ buffer *external_css;
+ buffer *encoding;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *tmp_buf;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_dirlisting_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+ p->tmp_buf = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_dirlisting_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (!s) continue;
+
+ buffer_free(s->external_css);
+ buffer_free(s->encoding);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->tmp_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "dir-listing.external-css", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "dir-listing.encoding", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "dir-listing.show-readme", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->dir_listing = 0;
+ s->external_css = buffer_init();
+ s->hide_dot_files = 0;
+ s->show_readme = 0;
+ s->encoding = buffer_init();
+
+ cv[0].destination = &(s->dir_listing);
+ cv[1].destination = &(s->hide_dot_files);
+ cv[2].destination = s->external_css;
+ cv[3].destination = s->encoding;
+ cv[4].destination = &(s->show_readme);
+ cv[5].destination = &(s->dir_listing); /* old name */
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(dir_listing);
+ PATCH(external_css);
+ PATCH(hide_dot_files);
+ PATCH(encoding);
+ PATCH(show_readme);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate"))) {
+ PATCH(dir_listing);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
+ PATCH(hide_dot_files);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
+ PATCH(external_css);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
+ PATCH(encoding);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
+ PATCH(show_readme);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+typedef struct {
+ size_t namelen;
+ time_t mtime;
+ off_t size;
+} dirls_entry_t;
+
+typedef struct {
+ dirls_entry_t **ent;
+ size_t used;
+ size_t size;
+} dirls_list_t;
+
+#define DIRLIST_ENT_NAME(ent) ((char*)(ent) + sizeof(dirls_entry_t))
+#define DIRLIST_BLOB_SIZE 16
+
+/* simple combsort algorithm */
+static void http_dirls_sort(dirls_entry_t **ent, int num) {
+ int gap = num;
+ int i, j;
+ int swapped;
+ dirls_entry_t *tmp;
+
+ do {
+ gap = (gap * 10) / 13;
+ if (gap == 9 || gap == 10)
+ gap = 11;
+ if (gap < 1)
+ gap = 1;
+ swapped = 0;
+
+ for (i = 0; i < num - gap; i++) {
+ j = i + gap;
+ if (strcmp(DIRLIST_ENT_NAME(ent[i]), DIRLIST_ENT_NAME(ent[j])) > 0) {
+ tmp = ent[i];
+ ent[i] = ent[j];
+ ent[j] = tmp;
+ swapped = 1;
+ }
+ }
+
+ } while (gap > 1 || swapped);
+}
+
+/* buffer must be able to hold "999.9K"
+ * conversion is simple but not perfect
+ */
+static int http_list_directory_sizefmt(char *buf, off_t size) {
+ const char unit[] = "KMGTPE"; /* Kilo, Mega, Tera, Peta, Exa */
+ const char *u = unit - 1; /* u will always increment at least once */
+ int remain;
+ char *out = buf;
+
+ if (size < 100)
+ size += 99;
+ if (size < 100)
+ size = 0;
+
+ while (1) {
+ remain = (int) size & 1023;
+ size >>= 10;
+ u++;
+ if ((size & (~0 ^ 1023)) == 0)
+ break;
+ }
+
+ remain /= 100;
+ if (remain > 9)
+ remain = 9;
+ if (size > 999) {
+ size = 0;
+ remain = 9;
+ u++;
+ }
+
+ out += ltostr(out, size);
+ out[0] = '.';
+ out[1] = remain + '0';
+ out[2] = *u;
+ out[3] = '\0';
+
+ return (out + 3 - buf);
+}
+
+static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
+ UNUSED(srv);
+
+ BUFFER_APPEND_STRING_CONST(out,
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
+ "<head>\n"
+ "<title>Index of "
+ );
+ buffer_append_string_html_encoded(out, CONST_BUF_LEN(con->uri.path));
+ BUFFER_APPEND_STRING_CONST(out, "</title>\n");
+
+ if (p->conf.external_css->used > 1) {
+ BUFFER_APPEND_STRING_CONST(out, "<link rel=\"stylesheet\" type=\"text/css\" href=\"");
+ buffer_append_string_buffer(out, p->conf.external_css);
+ BUFFER_APPEND_STRING_CONST(out, "\" />\n");
+ } else {
+ BUFFER_APPEND_STRING_CONST(out,
+ "<style type=\"text/css\">\n"
+ "a, a:active {text-decoration: none; color: blue;}\n"
+ "a:visited {color: #48468F;}\n"
+ "a:hover, a:focus {text-decoration: underline; color: red;}\n"
+ "body {background-color: #F5F5F5;}\n"
+ "h2 {margin-bottom: 12px;}\n"
+ "table {margin-left: 12px;}\n"
+ "th, td {"
+ " font-family: \"Courier New\", Courier, monospace;"
+ " font-size: 10pt;"
+ " text-align: left;"
+ "}\n"
+ "th {"
+ " font-weight: bold;"
+ " padding-right: 14px;"
+ " padding-bottom: 3px;"
+ "}\n"
+ );
+ BUFFER_APPEND_STRING_CONST(out,
+ "td {padding-right: 14px;}\n"
+ "td.s, th.s {text-align: right;}\n"
+ "div.list {"
+ " background-color: white;"
+ " border-top: 1px solid #646464;"
+ " border-bottom: 1px solid #646464;"
+ " padding-top: 10px;"
+ " padding-bottom: 14px;"
+ "}\n"
+ "div.foot {"
+ " font-family: \"Courier New\", Courier, monospace;"
+ " font-size: 10pt;"
+ " color: #787878;"
+ " padding-top: 4px;"
+ "}\n"
+ "</style>\n"
+ );
+ }
+
+ BUFFER_APPEND_STRING_CONST(out, "</head>\n<body>\n<h2>Index of ");
+ buffer_append_string_html_encoded(out, CONST_BUF_LEN(con->uri.path));
+ BUFFER_APPEND_STRING_CONST(out,
+ "</h2>\n"
+ "<div class=\"list\">\n"
+ "<table cellpadding=\"0\" cellspacing=\"0\">\n"
+ "<thead>"
+ "<tr>"
+ "<th class=\"n\">Name</th>"
+ "<th class=\"m\">Last Modified</th>"
+ "<th class=\"s\">Size</th>"
+ "<th class=\"t\">Type</th>"
+ "</tr>"
+ "</thead>\n"
+ "<tbody>\n"
+ "<tr>"
+ "<td class=\"n\"><a href=\"../\">Parent Directory</a>/</td>"
+ "<td class=\"m\">&nbsp;</td>"
+ "<td class=\"s\">- &nbsp;</td>"
+ "<td class=\"t\">Directory</td>"
+ "</tr>\n"
+ );
+}
+
+static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
+ UNUSED(srv);
+
+ BUFFER_APPEND_STRING_CONST(out,
+ "</tbody>\n"
+ "</table>\n"
+ "</div>\n"
+ );
+
+ if (p->conf.show_readme) {
+ stream s;
+ /* if we have a README file, display it in <pre class="readme"></pre> */
+
+ buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
+ BUFFER_APPEND_SLASH(p->tmp_buf);
+ BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
+
+ if (-1 != stream_open(&s, p->tmp_buf)) {
+ BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
+ buffer_append_string_html_encoded(out, s.start, s.size);
+ BUFFER_APPEND_STRING_CONST(out, "</pre>");
+ }
+ stream_close(&s);
+ }
+
+ BUFFER_APPEND_STRING_CONST(out,
+ "<div class=\"foot\">"
+ );
+
+ if (buffer_is_empty(con->conf.server_tag)) {
+ BUFFER_APPEND_STRING_CONST(out, PACKAGE_NAME "/" PACKAGE_VERSION);
+ } else {
+ buffer_append_string_buffer(out, con->conf.server_tag);
+ }
+
+ BUFFER_APPEND_STRING_CONST(out,
+ "</div>\n"
+ "</body>\n"
+ "</html>\n"
+ );
+}
+
+static int http_list_directory(server *srv, connection *con, plugin_data *p, buffer *dir) {
+ DIR *dp;
+ buffer *out;
+ struct dirent *dent;
+ struct stat st;
+ char *path, *path_file;
+ size_t i;
+ int hide_dotfiles = p->conf.hide_dot_files;
+ dirls_list_t dirs, files, *list;
+ dirls_entry_t *tmp;
+ char sizebuf[sizeof("999.9K")];
+ char datebuf[sizeof("2005-Jan-01 22:23:24")];
+ size_t k;
+ const char *content_type;
+ long name_max;
+#ifdef HAVE_XATTR
+ char attrval[128];
+ int attrlen;
+#endif
+#ifdef HAVE_LOCALTIME_R
+ struct tm tm;
+#endif
+
+ if (dir->used == 0) return -1;
+
+ i = dir->used - 1;
+
+#ifdef HAVE_PATHCONF
+ name_max = pathconf(dir->ptr, _PC_NAME_MAX);
+#elif defined __WIN32
+ name_max = FILENAME_MAX;
+#else
+ name_max = NAME_MAX;
+#endif
+
+ path = malloc(dir->used + name_max);
+ assert(path);
+ strcpy(path, dir->ptr);
+ path_file = path + i;
+
+ if (NULL == (dp = opendir(path))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "opendir failed:", dir, strerror(errno));
+
+ free(path);
+ return -1;
+ }
+
+ dirs.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
+ assert(dirs.ent);
+ dirs.size = DIRLIST_BLOB_SIZE;
+ dirs.used = 0;
+ files.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
+ assert(files.ent);
+ files.size = DIRLIST_BLOB_SIZE;
+ files.used = 0;
+
+ while ((dent = readdir(dp)) != NULL) {
+ if (dent->d_name[0] == '.') {
+ if (hide_dotfiles)
+ continue;
+ if (dent->d_name[1] == '\0')
+ continue;
+ if (dent->d_name[1] == '.' && dent->d_name[2] == '\0')
+ continue;
+ }
+
+
+ i = strlen(dent->d_name);
+
+ /* NOTE: the manual says, d_name is never more than NAME_MAX
+ * so this should actually not be a buffer-overflow-risk
+ */
+ if (i > name_max) continue;
+
+ memcpy(path_file, dent->d_name, i + 1);
+ if (stat(path, &st) != 0)
+ continue;
+
+ list = &files;
+ if (S_ISDIR(st.st_mode))
+ list = &dirs;
+
+ if (list->used == list->size) {
+ list->size += DIRLIST_BLOB_SIZE;
+ list->ent = (dirls_entry_t**) realloc(list->ent, sizeof(dirls_entry_t*) * list->size);
+ assert(list->ent);
+ }
+
+ tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i);
+ tmp->mtime = st.st_mtime;
+ tmp->size = st.st_size;
+ tmp->namelen = i;
+ memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, i + 1);
+
+ list->ent[list->used++] = tmp;
+ }
+ closedir(dp);
+
+ if (dirs.used) http_dirls_sort(dirs.ent, dirs.used);
+
+ if (files.used) http_dirls_sort(files.ent, files.used);
+
+ out = chunkqueue_get_append_buffer(con->write_queue);
+ BUFFER_COPY_STRING_CONST(out, "<?xml version=\"1.0\" encoding=\"");
+ if (buffer_is_empty(p->conf.encoding)) {
+ BUFFER_APPEND_STRING_CONST(out, "iso-8859-1");
+ } else {
+ buffer_append_string_buffer(out, p->conf.encoding);
+ }
+ BUFFER_APPEND_STRING_CONST(out, "\"?>\n");
+ http_list_directory_header(srv, con, p, out);
+
+ /* directories */
+ for (i = 0; i < dirs.used; i++) {
+ tmp = dirs.ent[i];
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&(tmp->mtime), &tm);
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
+#else
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
+#endif
+
+ BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
+ buffer_append_string_url_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen);
+ BUFFER_APPEND_STRING_CONST(out, "/\">");
+ buffer_append_string_html_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen);
+ BUFFER_APPEND_STRING_CONST(out, "</a>/</td><td class=\"m\">");
+ buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
+ BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">- &nbsp;</td><td class=\"t\">Directory</td></tr>\n");
+
+ free(tmp);
+ }
+
+ /* files */
+ for (i = 0; i < files.used; i++) {
+ tmp = files.ent[i];
+
+ content_type = NULL;
+#ifdef HAVE_XATTR
+
+ if (con->conf.use_xattr) {
+ memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
+ attrlen = sizeof(attrval) - 1;
+ if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
+ attrval[attrlen] = '\0';
+ content_type = attrval;
+ }
+ }
+#endif
+
+ if (content_type == NULL) {
+ content_type = "application/octet-stream";
+ for (k = 0; k < con->conf.mimetypes->used; k++) {
+ data_string *ds = (data_string *)con->conf.mimetypes->data[k];
+ size_t ct_len;
+
+ if (ds->key->used == 0)
+ continue;
+
+ ct_len = ds->key->used - 1;
+ if (tmp->namelen < ct_len)
+ continue;
+
+ if (0 == strncasecmp(DIRLIST_ENT_NAME(tmp) + tmp->namelen - ct_len, ds->key->ptr, ct_len)) {
+ content_type = ds->value->ptr;
+ break;
+ }
+ }
+ }
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&(tmp->mtime), &tm);
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
+#else
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
+#endif
+ http_list_directory_sizefmt(sizebuf, tmp->size);
+
+ BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
+ buffer_append_string_url_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen);
+ BUFFER_APPEND_STRING_CONST(out, "\">");
+ buffer_append_string_html_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen);
+ BUFFER_APPEND_STRING_CONST(out, "</a></td><td class=\"m\">");
+ buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
+ BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">");
+ buffer_append_string(out, sizebuf);
+ BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"t\">");
+ buffer_append_string(out, content_type);
+ BUFFER_APPEND_STRING_CONST(out, "</td></tr>\n");
+
+ free(tmp);
+ }
+
+ free(files.ent);
+ free(dirs.ent);
+ free(path);
+
+ http_list_directory_footer(srv, con, p, out);
+ response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ con->file_finished = 1;
+
+ return 0;
+}
+
+
+
+URIHANDLER_FUNC(mod_dirlisting_subrequest) {
+ plugin_data *p = p_d;
+ stat_cache_entry *sce = NULL;
+
+ UNUSED(srv);
+
+ if (con->physical.path->used == 0) return HANDLER_GO_ON;
+ if (con->uri.path->used == 0) return HANDLER_GO_ON;
+ if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
+
+ mod_dirlisting_patch_connection(srv, con, p);
+
+ if (!p->conf.dir_listing) return HANDLER_GO_ON;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Dir-Listing");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
+ }
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
+ SEGFAULT();
+ }
+
+ if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
+
+ if (http_list_directory(srv, con, p, con->physical.path)) {
+ /* dirlisting failed */
+ con->http_status = 403;
+ }
+
+ buffer_reset(con->physical.path);
+
+ /* not found */
+ return HANDLER_FINISHED;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_dirlisting_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("dirlisting");
+
+ p->init = mod_dirlisting_init;
+ p->handle_subrequest_start = mod_dirlisting_subrequest;
+ p->set_defaults = mod_dirlisting_set_defaults;
+ p->cleanup = mod_dirlisting_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/src/mod_indexfile.c b/src/mod_indexfile.c
new file mode 100644
index 00000000..3a77f27b
--- /dev/null
+++ b/src/mod_indexfile.c
@@ -0,0 +1,213 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "stat_cache.h"
+
+#include "config.h"
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *indexfiles;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *tmp_buf;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_indexfile_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->tmp_buf = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_indexfile_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ array_free(s->indexfiles);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->tmp_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->indexfiles = array_init();
+
+ cv[0].destination = s->indexfiles;
+ cv[1].destination = s->indexfiles; /* old name for [0] */
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(indexfiles);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
+ PATCH(indexfiles);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
+ PATCH(indexfiles);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_indexfile_subrequest) {
+ plugin_data *p = p_d;
+ size_t k;
+ stat_cache_entry *sce = NULL;
+
+ if (con->uri.path->used == 0) return HANDLER_GO_ON;
+ if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
+
+ mod_indexfile_patch_connection(srv, con, p);
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
+ }
+
+ /* indexfile */
+ for (k = 0; k < p->conf.indexfiles->used; k++) {
+ data_string *ds = (data_string *)p->conf.indexfiles->data[k];
+
+ buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
+ buffer_append_string_buffer(p->tmp_buf, ds->value);
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
+ if (errno == EACCES) {
+ con->http_status = 403;
+ buffer_reset(con->physical.path);
+
+ return HANDLER_FINISHED;
+ }
+
+ if (errno != ENOENT &&
+ errno != ENOTDIR) {
+ /* we have no idea what happend. let's tell the user so. */
+
+ con->http_status = 500;
+
+ log_error_write(srv, __FILE__, __LINE__, "ssbsb",
+ "file not found ... or so: ", strerror(errno),
+ con->uri.path,
+ "->", con->physical.path);
+
+ buffer_reset(con->physical.path);
+
+ return HANDLER_FINISHED;
+ }
+ continue;
+ }
+
+ /* rewrite uri.path to the real path (/ -> /index.php) */
+ buffer_append_string_buffer(con->uri.path, ds->value);
+ buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
+
+ /* fce is already set up a few lines above */
+
+ return HANDLER_GO_ON;
+ }
+
+ /* not found */
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_indexfile_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("indexfile");
+
+ p->init = mod_indexfile_init;
+ p->handle_subrequest_start = mod_indexfile_subrequest;
+ p->set_defaults = mod_indexfile_set_defaults;
+ p->cleanup = mod_indexfile_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
new file mode 100644
index 00000000..1a038678
--- /dev/null
+++ b/src/mod_staticfile.c
@@ -0,0 +1,575 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "stat_cache.h"
+#include "etag.h"
+#include "http_chunk.h"
+#include "response.h"
+
+/**
+ * this is a staticfile for a lighttpd plugin
+ *
+ */
+
+
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *exclude_ext;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *range_buf;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_staticfile_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->range_buf = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_staticfile_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ array_free(s->exclude_ext);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+ buffer_free(p->range_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->exclude_ext = array_init();
+
+ cv[0].destination = s->exclude_ext;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(exclude_ext);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
+ PATCH(exclude_ext);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
+ int multipart = 0;
+ int error;
+ off_t start, end;
+ const char *s, *minus;
+ char *boundary = "fkj49sn38dcn3";
+ data_string *ds;
+ stat_cache_entry *sce = NULL;
+ buffer *content_type = NULL;
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ SEGFAULT();
+ }
+
+ start = 0;
+ end = sce->st.st_size - 1;
+
+ con->response.content_length = 0;
+
+ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
+ content_type = ds->value;
+ }
+
+ for (s = con->request.http_range, error = 0;
+ !error && *s && NULL != (minus = strchr(s, '-')); ) {
+ char *err;
+ long la, le;
+
+ if (s == minus) {
+ /* -<stop> */
+
+ le = strtol(s, &err, 10);
+
+ if (le == 0) {
+ /* RFC 2616 - 14.35.1 */
+
+ con->http_status = 416;
+ error = 1;
+ } else if (*err == '\0') {
+ /* end */
+ s = err;
+
+ end = sce->st.st_size - 1;
+ start = sce->st.st_size + le;
+ } else if (*err == ',') {
+ multipart = 1;
+ s = err + 1;
+
+ end = sce->st.st_size - 1;
+ start = sce->st.st_size + le;
+ } else {
+ error = 1;
+ }
+
+ } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
+ /* <start>- */
+
+ la = strtol(s, &err, 10);
+
+ if (err == minus) {
+ /* ok */
+
+ if (*(err + 1) == '\0') {
+ s = err + 1;
+
+ end = sce->st.st_size - 1;
+ start = la;
+
+ } else if (*(err + 1) == ',') {
+ multipart = 1;
+ s = err + 2;
+
+ end = sce->st.st_size - 1;
+ start = la;
+ } else {
+ error = 1;
+ }
+ } else {
+ /* error */
+ error = 1;
+ }
+ } else {
+ /* <start>-<stop> */
+
+ la = strtol(s, &err, 10);
+
+ if (err == minus) {
+ le = strtol(minus+1, &err, 10);
+
+ /* RFC 2616 - 14.35.1 */
+ if (la > le) {
+ error = 1;
+ }
+
+ if (*err == '\0') {
+ /* ok, end*/
+ s = err;
+
+ end = le;
+ start = la;
+ } else if (*err == ',') {
+ multipart = 1;
+ s = err + 1;
+
+ end = le;
+ start = la;
+ } else {
+ /* error */
+
+ error = 1;
+ }
+ } else {
+ /* error */
+
+ error = 1;
+ }
+ }
+
+ if (!error) {
+ if (start < 0) start = 0;
+
+ /* RFC 2616 - 14.35.1 */
+ if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
+
+ if (start > sce->st.st_size - 1) {
+ error = 1;
+
+ con->http_status = 416;
+ }
+ }
+
+ if (!error) {
+ if (multipart) {
+ /* write boundary-header */
+ buffer *b;
+
+ b = chunkqueue_get_append_buffer(con->write_queue);
+
+ buffer_copy_string(b, "\r\n--");
+ buffer_append_string(b, boundary);
+
+ /* write Content-Range */
+ buffer_append_string(b, "\r\nContent-Range: bytes ");
+ buffer_append_off_t(b, start);
+ buffer_append_string(b, "-");
+ buffer_append_off_t(b, end);
+ buffer_append_string(b, "/");
+ buffer_append_off_t(b, sce->st.st_size);
+
+ buffer_append_string(b, "\r\nContent-Type: ");
+ buffer_append_string_buffer(b, content_type);
+
+ /* write END-OF-HEADER */
+ buffer_append_string(b, "\r\n\r\n");
+
+ con->response.content_length += b->used - 1;
+
+ }
+
+ chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
+ con->response.content_length += end - start + 1;
+ }
+ }
+
+ /* something went wrong */
+ if (error) return -1;
+
+ if (multipart) {
+ /* add boundary end */
+ buffer *b;
+
+ b = chunkqueue_get_append_buffer(con->write_queue);
+
+ buffer_copy_string_len(b, "\r\n--", 4);
+ buffer_append_string(b, boundary);
+ buffer_append_string_len(b, "--\r\n", 4);
+
+ con->response.content_length += b->used - 1;
+
+ /* set header-fields */
+
+ buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
+ buffer_append_string(p->range_buf, boundary);
+
+ /* overwrite content-type */
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
+ } else {
+ /* add Content-Range-header */
+
+ buffer_copy_string(p->range_buf, "bytes ");
+ buffer_append_off_t(p->range_buf, start);
+ buffer_append_string(p->range_buf, "-");
+ buffer_append_off_t(p->range_buf, end);
+ buffer_append_string(p->range_buf, "/");
+ buffer_append_off_t(p->range_buf, sce->st.st_size);
+
+ response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
+ }
+
+ /* ok, the file is set-up */
+ return 0;
+}
+
+static buffer * strftime_cache_get(server *srv, time_t last_mod) {
+ struct tm *tm;
+ size_t i;
+
+ for (i = 0; i < FILE_CACHE_MAX; i++) {
+ /* found cache-entry */
+ if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
+
+ /* found empty slot */
+ if (srv->mtime_cache[i].mtime == 0) break;
+ }
+
+ if (i == FILE_CACHE_MAX) {
+ i = 0;
+ }
+
+ srv->mtime_cache[i].mtime = last_mod;
+ buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
+ tm = gmtime(&(srv->mtime_cache[i].mtime));
+ srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
+ srv->mtime_cache[i].str->size - 1,
+ "%a, %d %b %Y %H:%M:%S GMT", tm);
+ srv->mtime_cache[i].str->used++;
+
+ return srv->mtime_cache[i].str;
+}
+
+URIHANDLER_FUNC(mod_staticfile_subrequest) {
+ plugin_data *p = p_d;
+ size_t k;
+ int s_len;
+ buffer *mtime;
+ stat_cache_entry *sce = NULL;
+
+ /* someone else has done a decision for us */
+ if (con->http_status != 0) return HANDLER_GO_ON;
+ if (con->uri.path->used == 0) return HANDLER_GO_ON;
+ if (con->physical.path->used == 0) return HANDLER_GO_ON;
+
+ /* someone else has handled this request */
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ /* we only handle GET, POST and HEAD */
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_POST:
+ case HTTP_METHOD_HEAD:
+ break;
+ default:
+ return HANDLER_GO_ON;
+ }
+
+ mod_staticfile_patch_connection(srv, con, p);
+
+ s_len = con->uri.path->used - 1;
+
+ /* ignore certain extensions */
+ for (k = 0; k < p->conf.exclude_ext->used; k++) {
+ data_string *ds = (data_string *)p->conf.exclude_ext->data[k];
+ int ct_len = ds->value->used - 1;
+
+ if (ct_len > s_len) continue;
+
+ if (ds->value->used == 0) continue;
+
+ if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+ return HANDLER_GO_ON;
+ }
+ }
+
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
+ }
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ con->http_status = 403;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsb",
+ "not a regular file:", con->uri.path,
+ "->", con->physical.path);
+
+ return HANDLER_FINISHED;
+ }
+
+ /* we only handline regular files */
+ if (!S_ISREG(sce->st.st_mode)) {
+ con->http_status = 404;
+
+ if (con->conf.log_file_not_found) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsb",
+ "not a regular file:", con->uri.path,
+ "->", sce->name);
+ }
+
+ return HANDLER_FINISHED;
+ }
+
+ /* set response content-type */
+
+ if (buffer_is_empty(sce->content_type)) {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/octet-stream"));
+ } else {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
+ }
+
+ /* generate e-tag */
+ etag_mutate(con->physical.etag, sce->etag);
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+ response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
+
+ /* prepare header */
+ mtime = strftime_cache_get(srv, sce->st.st_mtime);
+ response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+
+ /*
+ * 14.26 If-None-Match
+ * [...]
+ * If none of the entity tags match, then the server MAY perform the
+ * requested method as if the If-None-Match header field did not exist,
+ * but MUST also ignore any If-Modified-Since header field(s) in the
+ * request. That is, if no entity tags match, then the server MUST NOT
+ * return a 304 (Not Modified) response.
+ */
+
+ /* last-modified handling */
+ if (con->request.http_if_none_match) {
+ if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
+ if (con->request.http_method == HTTP_METHOD_GET ||
+ con->request.http_method == HTTP_METHOD_HEAD) {
+
+ /* check if etag + last-modified */
+ if (con->request.http_if_modified_since) {
+
+ size_t used_len;
+ char *semicolon;
+
+ if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
+ used_len = strlen(con->request.http_if_modified_since);
+ } else {
+ used_len = semicolon - con->request.http_if_modified_since;
+ }
+
+ if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
+ con->http_status = 304;
+ return HANDLER_FINISHED;
+ } else {
+ char buf[64];
+
+ /* convert to timestamp */
+ if (used_len < sizeof(buf) - 1) {
+ time_t t;
+ struct tm tm;
+
+ strncpy(buf, con->request.http_if_modified_since, used_len);
+ buf[used_len] = '\0';
+
+ strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
+
+ if (-1 != (t = mktime(&tm)) &&
+ t <= sce->st.st_mtime) {
+ con->http_status = 304;
+ return HANDLER_FINISHED;
+ }
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ con->request.http_if_modified_since, buf);
+
+ con->http_status = 412;
+ return HANDLER_FINISHED;
+ }
+ }
+ } else {
+ con->http_status = 304;
+ return HANDLER_FINISHED;
+ }
+ } else {
+ con->http_status = 412;
+ return HANDLER_FINISHED;
+ }
+ }
+ } else if (con->request.http_if_modified_since) {
+ size_t used_len;
+ char *semicolon;
+
+ if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
+ used_len = strlen(con->request.http_if_modified_since);
+ } else {
+ used_len = semicolon - con->request.http_if_modified_since;
+ }
+
+ if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
+ con->http_status = 304;
+ return HANDLER_FINISHED;
+ }
+ } else if (con->request.http_range) {
+ /* content prepared, I'm done */
+ con->file_finished = 1;
+
+ if (0 == http_response_parse_range(srv, con, p)) {
+ con->http_status = 206;
+ }
+ return HANDLER_FINISHED;
+ }
+
+ /* if we are still here, prepare body */
+
+ /* we add it here for all requests
+ * the HEAD request will drop it afterwards again
+ */
+ http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
+
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_staticfile_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("staticfile");
+
+ p->init = mod_staticfile_init;
+ p->handle_subrequest_start = mod_staticfile_subrequest;
+ p->set_defaults = mod_staticfile_set_defaults;
+ p->cleanup = mod_staticfile_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/src/request.c b/src/request.c
index df5da536..40778e6f 100644
--- a/src/request.c
+++ b/src/request.c
@@ -950,7 +950,13 @@ int http_request_parse(server *srv, connection *con) {
}
/* check if we have read post data */
- if (con->request.http_method == HTTP_METHOD_POST) {
+ if (con->request.http_method == HTTP_METHOD_POST
+ || (con->request.http_method != HTTP_METHOD_GET
+ && con->request.http_method != HTTP_METHOD_HEAD
+ && con->request.http_method != HTTP_METHOD_OPTIONS
+ && con_length_set))
+ {
+
server_socket *srv_socket = con->srv_socket;
if (con->request.http_content_type == NULL) {
log_error_write(srv, __FILE__, __LINE__, "s",
diff --git a/src/response.c b/src/response.c
index 0e07396e..98653fc0 100644
--- a/src/response.c
+++ b/src/response.c
@@ -1,7 +1,6 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <dirent.h>
#include <limits.h>
#include <errno.h>
#include <fcntl.h>
@@ -18,6 +17,7 @@
#include "keyvalue.h"
#include "log.h"
#include "stat_cache.h"
+#include "chunk.h"
#include "etag.h"
#include "connections.h"
@@ -26,110 +26,7 @@
#include "sys-socket.h"
-#ifdef HAVE_ATTR_ATTRIBUTES_H
-#include <attr/attributes.h>
-#endif
-
-#ifdef HAVE_SYS_SYSLIMITS_H
-#include <sys/syslimits.h>
-#endif
-
-int http_response_write_basic_header(server *srv, connection *con) {
- size_t i;
- buffer *b;
-
- b = chunkqueue_get_prepend_buffer(con->write_queue);
-
- if (con->request.http_version == HTTP_VERSION_1_1) {
- buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
- } else {
- buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
- }
- buffer_append_long(b, con->http_status);
- buffer_append_string_len(b, CONST_STR_LEN(" "));
- buffer_append_string(b, get_http_status_name(con->http_status));
-
- /* add the connection header if
- * HTTP/1.1 -> close
- * HTTP/1.0 -> keep-alive
- */
- if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
- BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
- if (con->keep_alive) {
- BUFFER_APPEND_STRING_CONST(b, "keep-alive");
- } else {
- BUFFER_APPEND_STRING_CONST(b, "close");
- }
- }
-
- if ((con->parsed_response & HTTP_DATE) == 0) {
- /* HTTP/1.1 requires a Date: header */
- BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
-
- /* cache the generated timestamp */
- if (srv->cur_ts != srv->last_generated_date_ts) {
- buffer_prepare_copy(srv->ts_date_str, 255);
-
- strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
- "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
-
- srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
-
- srv->last_generated_date_ts = srv->cur_ts;
- }
-
- buffer_append_string_buffer(b, srv->ts_date_str);
- }
-
- if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
- BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
- }
-
- /* add all headers */
- for (i = 0; i < con->response.headers->used; i++) {
- data_string *ds;
-
- ds = (data_string *)con->response.headers->data[i];
-
- if (ds->value->used && ds->key->used &&
- 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
- /* headers we send */
- !buffer_is_equal_string(ds->key, CONST_STR_LEN("Server")) &&
- !buffer_is_equal_string(ds->key, CONST_STR_LEN("Date")) &&
- !buffer_is_equal_string(ds->key, CONST_STR_LEN("Transfer-Encoding")) &&
- !buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) {
- BUFFER_APPEND_STRING_CONST(b, "\r\n");
- buffer_append_string_buffer(b, ds->key);
- BUFFER_APPEND_STRING_CONST(b, ": ");
- buffer_append_string_buffer(b, ds->value);
- }
- }
-
- if (buffer_is_empty(con->conf.server_tag)) {
- BUFFER_APPEND_STRING_CONST(b, "\r\nServer: " PACKAGE_NAME "/" PACKAGE_VERSION);
- } else {
- BUFFER_APPEND_STRING_CONST(b, "\r\nServer: ");
- buffer_append_string_buffer(b, con->conf.server_tag);
- }
-
- BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
-
- if (con->conf.log_response_header) {
- log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
- "fd:", con->fd,
- "response-header-len:", b->used - 1,
- "\n", b);
- }
-
- con->bytes_header = b->used - 1;
-
- return 0;
-}
-
-
-int http_response_write_header(server *srv, connection *con,
- off_t file_size,
- time_t last_mod) {
+int http_response_write_header(server *srv, connection *con) {
buffer *b;
size_t i;
@@ -151,9 +48,6 @@ int http_response_write_header(server *srv, connection *con,
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
- } else if (file_size >= 0 && con->http_status != 304) {
- BUFFER_APPEND_STRING_CONST(b, "\r\nContent-Length: ");
- buffer_append_off_t(b, file_size);
}
/* HTTP/1.1 requires a Date: header */
@@ -173,51 +67,6 @@ int http_response_write_header(server *srv, connection *con,
buffer_append_string_buffer(b, srv->ts_date_str);
- /* no Last-Modified specified */
- if (last_mod && NULL == array_get_element(con->response.headers, "Last-Modified")) {
- struct tm *tm;
-
- for (i = 0; i < FILE_CACHE_MAX; i++) {
- if (srv->mtime_cache[i].mtime == last_mod) break;
-
- if (srv->mtime_cache[i].mtime == 0) {
- srv->mtime_cache[i].mtime = last_mod;
-
- buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
-
- tm = gmtime(&(srv->mtime_cache[i].mtime));
- srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
- srv->mtime_cache[i].str->size - 1,
- "%a, %d %b %Y %H:%M:%S GMT", tm);
-
- srv->mtime_cache[i].str->used++;
- break;
- }
- }
-
- if (i == FILE_CACHE_MAX) {
- i = 0;
-
- srv->mtime_cache[i].mtime = last_mod;
- buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
- tm = gmtime(&(srv->mtime_cache[i].mtime));
- srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
- srv->mtime_cache[i].str->size - 1,
- "%a, %d %b %Y %H:%M:%S GMT", tm);
- srv->mtime_cache[i].str->used++;
- }
-
- BUFFER_APPEND_STRING_CONST(b, "\r\nLast-Modified: ");
- buffer_append_string_buffer(b, srv->mtime_cache[i].str);
- }
-
- if (con->physical.path->used && con->physical.etag->used) {
- BUFFER_APPEND_STRING_CONST(b, "\r\nETag: ");
- buffer_append_string_buffer(b, con->physical.etag);
- }
-
- BUFFER_APPEND_STRING_CONST(b, "\r\nAccept-Ranges: bytes");
-
/* add all headers */
for (i = 0; i < con->response.headers->used; i++) {
data_string *ds;
@@ -246,6 +95,7 @@ int http_response_write_header(server *srv, connection *con,
BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
+
con->bytes_header = b->used - 1;
if (con->conf.log_response_header) {
@@ -255,703 +105,11 @@ int http_response_write_header(server *srv, connection *con,
return 0;
}
-static int http_response_parse_range(server *srv, connection *con) {
- struct stat st;
- int multipart = 0;
- int error;
- off_t start, end;
- const char *s, *minus;
- char *boundary = "fkj49sn38dcn3";
- const char *content_type = NULL;
- data_string *ds;
-
- if (-1 == stat(con->physical.path->ptr, &st)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "stat failed: ", strerror(errno));
- return -1;
- }
-
- start = 0;
- end = st.st_size - 1;
-
- con->response.content_length = 0;
-
- if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
- content_type = ds->value->ptr;
- }
-
- for (s = con->request.http_range, error = 0;
- !error && *s && NULL != (minus = strchr(s, '-')); ) {
- char *err;
- off_t la, le;
-
- if (s == minus) {
- /* -<stop> */
-
- le = strtoll(s, &err, 10);
-
- if (le == 0) {
- /* RFC 2616 - 14.35.1 */
-
- con->http_status = 416;
- error = 1;
- } else if (*err == '\0') {
- /* end */
- s = err;
-
- end = st.st_size - 1;
- start = st.st_size + le;
- } else if (*err == ',') {
- multipart = 1;
- s = err + 1;
-
- end = st.st_size - 1;
- start = st.st_size + le;
- } else {
- error = 1;
- }
-
- } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
- /* <start>- */
-
- la = strtoll(s, &err, 10);
-
- if (err == minus) {
- /* ok */
-
- if (*(err + 1) == '\0') {
- s = err + 1;
-
- end = st.st_size - 1;
- start = la;
-
- } else if (*(err + 1) == ',') {
- multipart = 1;
- s = err + 2;
-
- end = st.st_size - 1;
- start = la;
- } else {
- error = 1;
- }
- } else {
- /* error */
- error = 1;
- }
- } else {
- /* <start>-<stop> */
-
- la = strtoll(s, &err, 10);
-
- if (err == minus) {
- le = strtoll(minus+1, &err, 10);
-
- /* RFC 2616 - 14.35.1 */
- if (la > le) {
- error = 1;
- }
-
- if (*err == '\0') {
- /* ok, end*/
- s = err;
-
- end = le;
- start = la;
- } else if (*err == ',') {
- multipart = 1;
- s = err + 1;
-
- end = le;
- start = la;
- } else {
- /* error */
-
- error = 1;
- }
- } else {
- /* error */
-
- error = 1;
- }
- }
-
- if (!error) {
- if (start < 0) start = 0;
-
- /* RFC 2616 - 14.35.1 */
- if (end > st.st_size - 1) end = st.st_size - 1;
-
- if (start > st.st_size - 1) {
- error = 1;
-
- con->http_status = 416;
- }
- }
-
- if (!error) {
- if (multipart) {
- /* write boundary-header */
- buffer *b;
-
- b = chunkqueue_get_append_buffer(con->write_queue);
-
- buffer_copy_string(b, "\r\n--");
- buffer_append_string(b, boundary);
-
- /* write Content-Range */
- buffer_append_string(b, "\r\nContent-Range: bytes ");
- buffer_append_off_t(b, start);
- buffer_append_string(b, "-");
- buffer_append_off_t(b, end);
- buffer_append_string(b, "/");
- buffer_append_off_t(b, st.st_size);
-
- buffer_append_string(b, "\r\nContent-Type: ");
- buffer_append_string(b, content_type);
-
- /* write END-OF-HEADER */
- buffer_append_string(b, "\r\n\r\n");
-
- con->response.content_length += b->used - 1;
-
- }
-
- chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
- con->response.content_length += end - start + 1;
- }
- }
-
- /* something went wrong */
- if (error) {
- return 0;
- }
-
- if (multipart) {
- /* add boundary end */
- buffer *b;
-
- b = chunkqueue_get_append_buffer(con->write_queue);
-
- buffer_copy_string_len(b, "\r\n--", 4);
- buffer_append_string(b, boundary);
- buffer_append_string_len(b, "--\r\n", 4);
-
- con->response.content_length += b->used - 1;
-
- /* set header-fields */
-
- buffer_copy_string(srv->range_buf, "multipart/byteranges; boundary=");
- buffer_append_string(srv->range_buf, boundary);
-
- /* overwrite content-type */
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(srv->range_buf));
- } else {
- /* add Content-Range-header */
-
- buffer_copy_string(srv->range_buf, "bytes ");
- buffer_append_off_t(srv->range_buf, start);
- buffer_append_string(srv->range_buf, "-");
- buffer_append_off_t(srv->range_buf, end);
- buffer_append_string(srv->range_buf, "/");
- buffer_append_off_t(srv->range_buf, st.st_size);
-
- response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(srv->range_buf));
- }
-
- /* ok, the file is set-up */
- con->http_status = 206;
-
- return 0;
-}
-
-typedef struct {
- size_t namelen;
- time_t mtime;
- off_t size;
-} dirls_entry_t;
-
-typedef struct {
- dirls_entry_t **ent;
- int used;
- int size;
-} dirls_list_t;
-
-#define DIRLIST_ENT_NAME(ent) (char*) ent + sizeof(dirls_entry_t)
-#define DIRLIST_BLOB_SIZE 16
-
-/* simple combsort algorithm */
-static void http_dirls_sort(dirls_entry_t **ent, int num) {
- int gap = num;
- int i, j;
- int swapped;
- dirls_entry_t *tmp;
-
- do {
- gap = (gap * 10) / 13;
- if (gap == 9 || gap == 10)
- gap = 11;
- if (gap < 1)
- gap = 1;
- swapped = 0;
-
- for (i = 0; i < num - gap; i++) {
- j = i + gap;
- if (strcmp(DIRLIST_ENT_NAME(ent[i]), DIRLIST_ENT_NAME(ent[j])) > 0) {
- tmp = ent[i];
- ent[i] = ent[j];
- ent[j] = tmp;
- swapped = 1;
- }
- }
-
- } while (gap > 1 || swapped);
-}
-
-/* buffer must be able to hold "999.9K"
- * conversion is simple but not perfect
- */
-static int http_list_directory_sizefmt(char *buf, off_t size) {
- const char unit[] = "KMGTPE"; /* Kilo, Mega, Tera, Peta, Exa */
- const char *u = unit - 1; /* u will always increment at least once */
- int remain;
- char *out = buf;
-
- if (size < 100)
- size += 99;
- if (size < 100)
- size = 0;
-
- while (1) {
- remain = (int) size & 1023;
- size >>= 10;
- u++;
- if ((size & (~0 ^ 1023)) == 0)
- break;
- }
-
- remain /= 100;
- if (remain > 9)
- remain = 9;
- if (size > 999) {
- size = 0;
- remain = 9;
- u++;
- }
-
- out += ltostr(out, size);
- out[0] = '.';
- out[1] = remain + '0';
- out[2] = *u;
- out[3] = '\0';
- return (out + 3 - buf);
-}
-
-static void http_list_directory_header(buffer *out, connection *con) {
- BUFFER_APPEND_STRING_CONST(out,
- "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
- "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
- "<head>\n"
- "<title>Index of "
- );
- buffer_append_string_html_encoded(out, con->uri.path->ptr);
- BUFFER_APPEND_STRING_CONST(out, "</title>\n");
-
- if (con->conf.dirlist_css->used > 1) {
- BUFFER_APPEND_STRING_CONST(out, "<link rel=\"stylesheet\" type=\"text/css\" href=\"");
- buffer_append_string_buffer(out, con->conf.dirlist_css);
- BUFFER_APPEND_STRING_CONST(out, "\" />\n");
- } else {
- BUFFER_APPEND_STRING_CONST(out,
- "<style type=\"text/css\">\n"
- "a, a:active {text-decoration: none; color: blue;}\n"
- "a:visited {color: #48468F;}\n"
- "a:hover, a:focus {text-decoration: underline; color: red;}\n"
- "body {background-color: #F5F5F5;}\n"
- "h2 {margin-bottom: 12px;}\n"
- "table {margin-left: 12px;}\n"
- "th, td {"
- " font-family: \"Courier New\", Courier, monospace;"
- " font-size: 10pt;"
- " text-align: left;"
- "}\n"
- "th {"
- " font-weight: bold;"
- " padding-right: 14px;"
- " padding-bottom: 3px;"
- "}\n"
- );
- BUFFER_APPEND_STRING_CONST(out,
- "td {padding-right: 14px;}\n"
- "td.s, th.s {text-align: right;}\n"
- "div.list {"
- " background-color: white;"
- " border-top: 1px solid #646464;"
- " border-bottom: 1px solid #646464;"
- " padding-top: 10px;"
- " padding-bottom: 14px;"
- "}\n"
- "div.foot {"
- " font-family: \"Courier New\", Courier, monospace;"
- " font-size: 10pt;"
- " color: #787878;"
- " padding-top: 4px;"
- "}\n"
- "</style>\n"
- );
- }
-
- BUFFER_APPEND_STRING_CONST(out, "</head>\n<body>\n<h2>Index of ");
- buffer_append_string_html_encoded(out, con->uri.path->ptr);
- BUFFER_APPEND_STRING_CONST(out,
- "</h2>\n"
- "<div class=\"list\">\n"
- "<table cellpadding=\"0\" cellspacing=\"0\">\n"
- "<thead>"
- "<tr>"
- "<th class=\"n\">Name</th>"
- "<th class=\"m\">Last Modified</th>"
- "<th class=\"s\">Size</th>"
- "<th class=\"t\">Type</th>"
- "</tr>"
- "</thead>\n"
- "<tbody>\n"
- "<tr>"
- "<td class=\"n\"><a href=\"../\">Parent Directory</a>/</td>"
- "<td class=\"m\">&nbsp;</td>"
- "<td class=\"s\">- &nbsp;</td>"
- "<td class=\"t\">Directory</td>"
- "</tr>\n"
- );
-}
-
-static void http_list_directory_footer(buffer *out, connection *con) {
- BUFFER_APPEND_STRING_CONST(out,
- "</tbody>\n"
- "</table>\n"
- "</div>\n"
- "<div class=\"foot\">"
- );
-
- if (buffer_is_empty(con->conf.server_tag)) {
- BUFFER_APPEND_STRING_CONST(out, PACKAGE_NAME "/" PACKAGE_VERSION);
- } else {
- buffer_append_string_buffer(out, con->conf.server_tag);
- }
-
- BUFFER_APPEND_STRING_CONST(out,
- "</div>\n"
- "</body>\n"
- "</html>\n"
- );
-}
-
-static int http_list_directory(server *srv, connection *con, buffer *dir) {
- DIR *dp;
- buffer *out;
- struct dirent *dent;
- struct stat st;
- char *path, *path_file;
- int i;
- int hide_dotfiles = con->conf.hide_dotfiles;
- dirls_list_t dirs, files, *list;
- dirls_entry_t *tmp;
- char sizebuf[sizeof("999.9K")];
- char datebuf[sizeof("2005-Jan-01 22:23:24")];
- size_t k;
- const char *content_type;
- long name_max;
-#ifdef HAVE_XATTR
- char attrval[128];
- int attrlen;
-#endif
-#ifdef HAVE_LOCALTIME_R
- struct tm tm;
-#endif
-
- i = dir->used - 1;
- if (i <= 0) return -1;
-
-#ifdef HAVE_PATHCONF
- name_max = pathconf(dir->ptr, _PC_NAME_MAX);
-#else
- name_max = NAME_MAX;
-#endif
-
- path = malloc(i + name_max + 1);
- assert(path);
- strcpy(path, dir->ptr);
- path_file = path + i;
-
- if (NULL == (dp = opendir(path))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "opendir failed:", dir, strerror(errno));
-
- free(path);
- return -1;
- }
-
- dirs.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
- assert(dirs.ent);
- dirs.size = DIRLIST_BLOB_SIZE;
- dirs.used = 0;
- files.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
- assert(files.ent);
- files.size = DIRLIST_BLOB_SIZE;
- files.used = 0;
-
- while ((dent = readdir(dp)) != NULL) {
- if (dent->d_name[0] == '.') {
- if (hide_dotfiles)
- continue;
- if (dent->d_name[1] == '\0')
- continue;
- if (dent->d_name[1] == '.' && dent->d_name[2] == '\0')
- continue;
- }
-
- /* NOTE: the manual says, d_name is never more than NAME_MAX
- * so this should actually not be a buffer-overflow-risk
- */
- i = strlen(dent->d_name);
- if (i > name_max)
- continue;
- memcpy(path_file, dent->d_name, i + 1);
- if (stat(path, &st) != 0)
- continue;
-
- list = &files;
- if (S_ISDIR(st.st_mode))
- list = &dirs;
-
- if (list->used == list->size) {
- list->size += DIRLIST_BLOB_SIZE;
- list->ent = (dirls_entry_t**) realloc(list->ent, sizeof(dirls_entry_t*) * list->size);
- assert(list->ent);
- }
-
- tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i);
- tmp->mtime = st.st_mtime;
- tmp->size = st.st_size;
- tmp->namelen = i;
- memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, i + 1);
-
- list->ent[list->used++] = tmp;
- }
- closedir(dp);
-
- if (dirs.used) http_dirls_sort(dirs.ent, dirs.used);
-
- if (files.used) http_dirls_sort(files.ent, files.used);
-
- out = chunkqueue_get_append_buffer(con->write_queue);
-
- if (buffer_is_empty(con->conf.dirlist_encoding)) {
- BUFFER_COPY_STRING_CONST(out, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n");
- } else {
- BUFFER_COPY_STRING_CONST(out, "<?xml version=\"1.0\" encoding=\"");
- buffer_append_string_buffer(out, con->conf.dirlist_encoding);
- BUFFER_APPEND_STRING_CONST(out, "\"?>\n");
- }
-
- http_list_directory_header(out, con);
-
- /* directories */
- for (i = 0; i < dirs.used; i++) {
- tmp = dirs.ent[i];
-
-#ifdef HAVE_LOCALTIME_R
- localtime_r(&(tmp->mtime), &tm);
- strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
-#else
- strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
-#endif
-
- BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
- buffer_append_string_url_encoded(out, DIRLIST_ENT_NAME(tmp));
- BUFFER_APPEND_STRING_CONST(out, "/\">");
- buffer_append_string_html_encoded(out, DIRLIST_ENT_NAME(tmp));
- BUFFER_APPEND_STRING_CONST(out, "</a>/</td><td class=\"m\">");
- buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
- BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">- &nbsp;</td><td class=\"t\">Directory</td></tr>\n");
-
- free(tmp);
- }
-
- /* files */
- for (i = 0; i < files.used; i++) {
- tmp = files.ent[i];
-
-#ifdef HAVE_XATTR
- content_type = NULL;
- if (con->conf.use_xattr) {
- memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
- attrlen = sizeof(attrval) - 1;
- if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
- attrval[attrlen] = '\0';
- content_type = attrval;
- }
- }
- if (content_type == NULL) {
-#else
- if (1) {
-#endif
- content_type = "application/octet-stream";
- for (k = 0; k < con->conf.mimetypes->used; k++) {
- data_string *ds = (data_string *)con->conf.mimetypes->data[k];
- size_t ct_len;
-
- if (ds->key->used == 0)
- continue;
-
- ct_len = ds->key->used - 1;
- if (tmp->namelen < ct_len)
- continue;
-
- if (0 == strncmp(DIRLIST_ENT_NAME(tmp) + tmp->namelen - ct_len, ds->key->ptr, ct_len)) {
- content_type = ds->value->ptr;
- break;
- }
- }
- }
-
-#ifdef HAVE_LOCALTIME_R
- localtime_r(&(tmp->mtime), &tm);
- strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
-#else
- strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
-#endif
- http_list_directory_sizefmt(sizebuf, tmp->size);
-
- BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
- buffer_append_string_url_encoded(out, DIRLIST_ENT_NAME(tmp));
- BUFFER_APPEND_STRING_CONST(out, "\">");
- buffer_append_string_html_encoded(out, DIRLIST_ENT_NAME(tmp));
- BUFFER_APPEND_STRING_CONST(out, "</a></td><td class=\"m\">");
- buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
- BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">");
- buffer_append_string(out, sizebuf);
- BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"t\">");
- buffer_append_string(out, content_type);
- BUFFER_APPEND_STRING_CONST(out, "</td></tr>\n");
-
- free(tmp);
- }
-
- free(files.ent);
- free(dirs.ent);
- free(path);
-
- http_list_directory_footer(out, con);
- response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
- con->file_finished = 1;
-
- return 0;
-}
-
-
-int http_response_handle_cachable(server *srv, connection *con, time_t mtime) {
- if (con->http_status != 0) return 0;
-
- /*
- * 14.26 If-None-Match
- * [...]
- * If none of the entity tags match, then the server MAY perform the
- * requested method as if the If-None-Match header field did not exist,
- * but MUST also ignore any If-Modified-Since header field(s) in the
- * request. That is, if no entity tags match, then the server MUST NOT
- * return a 304 (Not Modified) response.
- */
-
- /* last-modified handling */
- if (con->request.http_if_none_match) {
- if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
- if (con->request.http_method == HTTP_METHOD_GET ||
- con->request.http_method == HTTP_METHOD_HEAD) {
-
- /* check if etag + last-modified */
- if (con->request.http_if_modified_since) {
- char buf[64];
- struct tm tm;
- size_t used_len;
- char *semicolon;
-
- strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
-
- if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
- used_len = strlen(con->request.http_if_modified_since);
- } else {
- used_len = semicolon - con->request.http_if_modified_since;
- }
-
- if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) {
- con->http_status = 304;
- return 1;
- } else {
- /* convert to timestamp */
- if (used_len < sizeof(buf) - 1) {
- time_t t;
- strncpy(buf, con->request.http_if_modified_since, used_len);
- buf[used_len] = '\0';
-
- strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
-
- if (-1 != (t = mktime(&tm)) &&
- t <= mtime) {
- con->http_status = 304;
- return 1;
- }
- } else {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- con->request.http_if_modified_since, buf);
-
- con->http_status = 412;
- return 1;
- }
- }
- } else {
- con->http_status = 304;
- return 1;
- }
- } else {
- con->http_status = 412;
- return 1;
- }
- }
- } else if (con->request.http_if_modified_since) {
- char buf[64];
- struct tm *tm;
- size_t used_len;
- char *semicolon;
-
- tm = gmtime(&(mtime));
- strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", tm);
-
- if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
- used_len = strlen(con->request.http_if_modified_since);
- } else {
- used_len = semicolon - con->request.http_if_modified_since;
- }
-
- if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) {
- con->http_status = 304;
- return 1;
- }
- }
-
- return 0;
-}
handler_t http_response_prepare(server *srv, connection *con) {
handler_t r;
- if (con->loops_per_request++ > 1000) {
- /* protect us again endless loops in a single request */
-
- log_error_write(srv, __FILE__, __LINE__, "s", "ENDLESS LOOP DETECTED ... aborting request");
-
- return HANDLER_ERROR;
- }
-
/* looks like someone has already done a decision */
if (con->mode == DIRECT &&
(con->http_status != 0 && con->http_status != 200)) {
@@ -962,14 +120,15 @@ handler_t http_response_prepare(server *srv, connection *con) {
return HANDLER_FINISHED;
}
-
+
if (con->request.http_method == HTTP_METHOD_OPTIONS) {
+ /* option requests are handled directly without checking of the path */
+ con->http_status = 200;
con->file_finished = 1;
- con->file_started = 1;
return HANDLER_FINISHED;
}
-
+
/* no decision yet, build conf->filename */
if (con->mode == DIRECT && con->physical.path->used == 0) {
char *qstr;
@@ -1003,6 +162,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
+ buffer_to_lower(con->uri.authority);
config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */
config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */
@@ -1069,7 +229,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
buffer_path_simplify(con->uri.path, srv->tmp_buf);
if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "-- sanitising URI");
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- sanatising URI");
log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path);
}
@@ -1129,14 +289,12 @@ handler_t http_response_prepare(server *srv, connection *con) {
buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
- buffer_reset(con->physical.path);
-
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- before doc_root");
log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
}
-
/* the docroot plugin should set the doc_root and might also set the physical.path
* for us (all vhost-plugins are supposed to set the doc_root)
* */
@@ -1153,20 +311,12 @@ handler_t http_response_prepare(server *srv, connection *con) {
break;
}
- if (buffer_is_empty(con->physical.path)) {
- /**
- * create physical filename
- * -> physical.path = docroot + rel_path
- *
- */
-
- buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
- BUFFER_APPEND_SLASH(con->physical.path);
- if (con->physical.rel_path->ptr[0] == '/') {
- buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
- } else {
- buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
- }
+ /* MacOS X and Windows can't distiguish between upper and lower-case
+ *
+ * convert to lower-case
+ */
+ if (con->conf.force_lower_case) {
+ buffer_to_lower(con->physical.rel_path);
}
/* the docroot plugins might set the servername, if they don't we take http-host */
@@ -1214,20 +364,19 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path);
log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
- log_error_write(srv, __FILE__, __LINE__, "sb", "Server-Name :", con->server_name);
}
}
/*
- * only if we are still in DIRECT mode we check for the real existence of the file
+ * Noone catched away the file from normal path of execution yet (like mod_access)
*
+ * Go on and check of the file exists at all
*/
if (con->mode == DIRECT) {
char *slash = NULL;
char *pathinfo = NULL;
int found = 0;
- size_t k;
stat_cache_entry *sce = NULL;
if (con->conf.log_request_handling) {
@@ -1235,19 +384,40 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
}
- switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- case HANDLER_ERROR:
- if (errno == EACCES) {
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ /* file exists */
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- file found");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ }
+
+ if (S_ISDIR(sce->st.st_mode)) {
+ if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
+ /* redirect to .../ */
+
+ http_response_redirect_to_directory(srv, con);
+
+ return HANDLER_FINISHED;
+ }
+ }
+ } else {
+ switch (errno) {
+ case EACCES:
con->http_status = 403;
buffer_reset(con->physical.path);
return HANDLER_FINISHED;
- }
-
- if (errno != ENOENT &&
- errno != ENOTDIR) {
+ case ENOENT:
+ con->http_status = 404;
+ buffer_reset(con->physical.path);
+
+ return HANDLER_FINISHED;
+ case ENOTDIR:
+ /* PATH_INFO ! :) */
+ break;
+ default:
/* we have no idea what happend. let's tell the user so. */
-
con->http_status = 500;
buffer_reset(con->physical.path);
@@ -1260,19 +430,8 @@ handler_t http_response_prepare(server *srv, connection *con) {
}
/* not found, perhaps PATHINFO */
- buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
- /*
- *
- * FIXME:
- *
- * Check for PATHINFO fall to dir of
- *
- * /a is a dir and
- *
- * /a/b/c is requested
- *
- */
+ buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
do {
struct stat st;
@@ -1308,8 +467,8 @@ handler_t http_response_prepare(server *srv, connection *con) {
if (con->conf.log_file_not_found) {
log_error_write(srv, __FILE__, __LINE__, "sbsb",
- "file not found:", con->uri.path,
- "->", con->physical.path);
+ "file not found:", con->uri.path,
+ "->", con->physical.path);
}
buffer_reset(con->physical.path);
@@ -1317,7 +476,6 @@ handler_t http_response_prepare(server *srv, connection *con) {
return HANDLER_FINISHED;
}
-
/* we have a PATHINFO */
if (pathinfo) {
buffer_copy_string(con->request.pathinfo, pathinfo);
@@ -1326,7 +484,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
* shorten uri.path
*/
- con->uri.path->used -= con->request.pathinfo->used - 1;
+ con->uri.path->used -= strlen(pathinfo);
con->uri.path->ptr[con->uri.path->used - 1] = '\0';
}
@@ -1336,168 +494,36 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo);
}
-
- /* setup the right file cache entry (FCE) */
- switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- case HANDLER_ERROR:
- con->http_status = 404;
-
- if (con->conf.log_file_not_found) {
- log_error_write(srv, __FILE__, __LINE__, "sbsb",
- "file not found:", con->uri.path,
- "->", con->physical.path);
- }
-
- return HANDLER_FINISHED;
- case HANDLER_GO_ON:
- default:
- break;
- }
-
- break;
- case HANDLER_GO_ON:
- if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "-- file found");
- log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
- }
-
- if (S_ISDIR(sce->st.st_mode)) {
- if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
- /* redirect to .../ */
-
- http_response_redirect_to_directory(srv, con);
-
- return HANDLER_FINISHED;
- } else {
- found = 0;
- /* indexfile */
-
- for (k = 0; !found && (k < con->conf.indexfiles->used); k++) {
- data_string *ds = (data_string *)con->conf.indexfiles->data[k];
-
- buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
- buffer_append_string_buffer(srv->tmp_buf, ds->value);
-
- switch (stat_cache_get_entry(srv, con, srv->tmp_buf, &sce)) {
- case HANDLER_COMEBACK:
- case HANDLER_GO_ON:
- /* rewrite uri.path to the real path (/ -> /index.php) */
- buffer_append_string_buffer(con->uri.path, ds->value);
-
- found = 1;
- break;
- case HANDLER_ERROR:
-
- if (errno == EACCES) {
- con->http_status = 403;
- buffer_reset(con->physical.path);
-
- return HANDLER_FINISHED;
- }
-
- if (errno != ENOENT &&
- errno != ENOTDIR) {
- /* we have no idea what happend. let's tell the user so. */
-
- con->http_status = 500;
- buffer_reset(con->physical.path);
-
- log_error_write(srv, __FILE__, __LINE__, "ssbsb",
- "file not found ... or so: ", strerror(errno),
- con->uri.path,
- "->", con->physical.path);
-
- return HANDLER_FINISHED;
- }
-
- break;
- default:
- break;
- }
- }
-
- if (!found &&
- (k == con->conf.indexfiles->used)) {
- /* directory listing ? */
-
- buffer_reset(srv->tmp_buf);
-
- if (con->conf.dir_listing == 0) {
- /* dirlisting disabled */
- con->http_status = 403;
- } else if (0 != http_list_directory(srv, con, con->physical.path)) {
- /* dirlisting failed */
- con->http_status = 403;
- }
-
- buffer_reset(con->physical.path);
-
- return HANDLER_FINISHED;
- }
-
- buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
- }
- }
- break;
- default:
- break;
}
- if (!S_ISREG(sce->st.st_mode)) {
- con->http_status = 404;
-
- if (con->conf.log_file_not_found) {
- log_error_write(srv, __FILE__, __LINE__, "sbsb",
- "not a regular file:", con->uri.path,
- "->", sce->name);
- }
-
- return HANDLER_FINISHED;
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
}
/* call the handlers */
switch(r = plugins_call_handle_subrequest_start(srv, con)) {
- case HANDLER_FINISHED:
- /* request was handled */
- break;
case HANDLER_GO_ON:
/* request was not handled */
break;
+ case HANDLER_FINISHED:
default:
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished");
+ }
+
/* something strange happend */
return r;
}
- /* ok, noone has handled the file up to now, so we do the fileserver-stuff */
- if (r == HANDLER_GO_ON) {
- /* DIRECT */
-
- /* set response content-type */
-
- if (buffer_is_empty(sce->content_type)) {
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/octet-stream"));
- } else {
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
- }
+ /* if we are still here, no one wanted the file, status 403 is ok I think */
+
+ if (con->mode == DIRECT) {
+ con->http_status = 403;
- /* generate e-tag */
- etag_mutate(con->physical.etag, sce->etag);
-
- http_response_handle_cachable(srv, con, sce->st.st_mtime);
-
- if (con->conf.range_requests &&
- con->http_status == 0 &&
- con->request.http_range) {
- http_response_parse_range(srv, con);
- } else if (con->http_status == 0) {
- switch(r = plugins_call_handle_physical_path(srv, con)) {
- case HANDLER_GO_ON:
- break;
- default:
- return r;
- }
- }
+ return HANDLER_FINISHED;
}
+
}
switch(r = plugins_call_handle_subrequest(srv, con)) {
diff --git a/src/response.h b/src/response.h
index 2dfbf440..eda07653 100644
--- a/src/response.h
+++ b/src/response.h
@@ -4,10 +4,7 @@
#include "server.h"
int http_response_parse(server *srv, connection *con);
-int http_response_write_basic_header(server *srv, connection *con);
-int http_response_write_header(server *srv, connection *con,
- off_t file_size,
- time_t last_mod);
+int http_response_write_header(server *srv, connection *con);
int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
diff --git a/src/server.c b/src/server.c
index 266bb2b6..aafa7333 100644
--- a/src/server.c
+++ b/src/server.c
@@ -124,10 +124,7 @@ static server *server_init(void) {
CLEAN(errorlog_buf);
CLEAN(response_range);
CLEAN(tmp_buf);
- CLEAN(range_buf);
- CLEAN(empty_string);
-
- buffer_copy_string(srv->empty_string, "");
+ CLEAN(cond_check_buf);
CLEAN(srvconf.errorlog_file);
CLEAN(srvconf.groupname);
@@ -194,8 +191,7 @@ static void server_free(server *srv) {
CLEAN(errorlog_buf);
CLEAN(response_range);
CLEAN(tmp_buf);
- CLEAN(range_buf);
- CLEAN(empty_string);
+ CLEAN(cond_check_buf);
CLEAN(srvconf.errorlog_file);
CLEAN(srvconf.groupname);
@@ -229,9 +225,6 @@ static void server_free(server *srv) {
buffer_free(s->ssl_ca_file);
buffer_free(s->error_handler);
buffer_free(s->errorfile_prefix);
- buffer_free(s->dirlist_css);
- buffer_free(s->dirlist_encoding);
- array_free(s->indexfiles);
array_free(s->mimetypes);
free(s);