diff options
author | Krzysztof Krzyżaniak <eloy@debian.org> | 2006-03-10 09:21:16 +0000 |
---|---|---|
committer | Krzysztof Krzyżaniak <eloy@debian.org> | 2006-03-10 09:21:16 +0000 |
commit | d44b89c43443081ef5eef2ca373573dddb665882 (patch) | |
tree | 557cac3628b5d97672b0443d0b5e0257bd19a97f /src | |
parent | 257c390ace0d9ba29c0ff2026eb90150d7598190 (diff) | |
download | lighttpd-d44b89c43443081ef5eef2ca373573dddb665882.tar.gz |
eloy: new upstream version
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/Makefile.in | 70 | ||||
-rw-r--r-- | src/configfile-glue.c | 2 | ||||
-rw-r--r-- | src/connections.c | 2 | ||||
-rw-r--r-- | src/keyvalue.c | 4 | ||||
-rw-r--r-- | src/keyvalue.h | 4 | ||||
-rw-r--r-- | src/mod_alias.c | 4 | ||||
-rw-r--r-- | src/mod_auth.c | 36 | ||||
-rw-r--r-- | src/mod_cgi.c | 24 | ||||
-rw-r--r-- | src/mod_fastcgi.c | 685 | ||||
-rw-r--r-- | src/mod_flv_streaming.c | 278 | ||||
-rw-r--r-- | src/mod_scgi.c | 4 | ||||
-rw-r--r-- | src/mod_ssi.c | 14 | ||||
-rw-r--r-- | src/mod_webdav.c | 4 | ||||
-rw-r--r-- | src/network.c | 16 | ||||
-rw-r--r-- | src/network_linux_sendfile.c | 39 | ||||
-rw-r--r-- | src/network_writev.c | 4 | ||||
-rw-r--r-- | src/request.c | 53 | ||||
-rw-r--r-- | src/response.c | 36 | ||||
-rw-r--r-- | src/server.c | 4 | ||||
-rw-r--r-- | src/spawn-fcgi.c | 17 |
21 files changed, 840 insertions, 472 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 7e9fc9e..ffec47e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,5 @@ +AM_CFLAGS = $(FAM_CFLAGS) + noinst_PROGRAMS=proc_open lemon # simple-fcgi #graphic evalo bench ajp ssl error_test adserver gen-license sbin_PROGRAMS=lighttpd bin_PROGRAMS=spawn-fcgi @@ -59,7 +61,7 @@ if NO_RDYNAMIC # everything lib_LTLIBRARIES += liblightcomp.la liblightcomp_la_SOURCES=$(common_src) -liblightcomp_la_CFLAGS=$(AM_CFLAGS) $(FAM_CFLAGS) +liblightcomp_la_CFLAGS=$(AM_CFLAGS) liblightcomp_la_LDFLAGS = -avoid-version -no-undefined liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS) common_libadd = liblightcomp.la @@ -68,15 +70,19 @@ src += $(common_src) common_libadd = endif +lib_LTLIBRARIES += mod_flv_streaming.la +mod_flv_streaming_la_SOURCES = mod_flv_streaming.c +mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined +mod_flv_streaming_la_LIBADD = $(common_libadd) + lib_LTLIBRARIES += mod_evasive.la mod_evasive_la_SOURCES = mod_evasive.c mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_evasive_la_LIBADD = $(common_libadd) - lib_LTLIBRARIES += mod_webdav.la mod_webdav_la_SOURCES = mod_webdav.c -mod_webdav_la_CFLAGS = $(XML_CFLAGS) +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) diff --git a/src/Makefile.in b/src/Makefile.in index cc6fab9..5b7e8c2 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -16,7 +16,7 @@ -SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES) +SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -157,6 +157,9 @@ mod_expire_la_OBJECTS = $(am_mod_expire_la_OBJECTS) mod_fastcgi_la_DEPENDENCIES = $(am__DEPENDENCIES_2) am_mod_fastcgi_la_OBJECTS = mod_fastcgi.lo mod_fastcgi_la_OBJECTS = $(am_mod_fastcgi_la_OBJECTS) +mod_flv_streaming_la_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_mod_flv_streaming_la_OBJECTS = mod_flv_streaming.lo +mod_flv_streaming_la_OBJECTS = $(am_mod_flv_streaming_la_OBJECTS) mod_indexfile_la_DEPENDENCIES = $(am__DEPENDENCIES_2) am_mod_indexfile_la_OBJECTS = mod_indexfile.lo mod_indexfile_la_OBJECTS = $(am_mod_indexfile_la_OBJECTS) @@ -287,24 +290,7 @@ SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) \ $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) \ $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) \ $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) \ - $(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) \ - $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) \ - $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) \ - $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) \ - $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) \ - $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) \ - $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) \ - $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) \ - $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) \ - $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) \ - $(spawn_fcgi_SOURCES) -DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \ - $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) \ - $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) \ - $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) \ - $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) \ - $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) \ - $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) \ + $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_la_SOURCES) \ $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) \ $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) \ $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) \ @@ -313,9 +299,26 @@ DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \ $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) \ $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) \ $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) \ - $(mod_webdav_la_SOURCES) $(lemon_SOURCES) \ - $(am__lighttpd_SOURCES_DIST) $(proc_open_SOURCES) \ - $(spawn_fcgi_SOURCES) + $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) \ + $(proc_open_SOURCES) $(spawn_fcgi_SOURCES) +DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \ + $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) \ + $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) \ + $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) \ + $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) \ + $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) \ + $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) \ + $(mod_flv_streaming_la_SOURCES) $(mod_indexfile_la_SOURCES) \ + $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) \ + $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) \ + $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) \ + $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) \ + $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) \ + $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) \ + $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) \ + $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) \ + $(lemon_SOURCES) $(am__lighttpd_SOURCES_DIST) \ + $(proc_open_SOURCES) $(spawn_fcgi_SOURCES) HEADERS = $(noinst_HEADERS) ETAGS = etags CTAGS = ctags @@ -456,6 +459,7 @@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ +AM_CFLAGS = $(FAM_CFLAGS) LEMON = $(top_builddir)/src/lemon lemon_SOURCES = lemon.c common_src = buffer.c log.c \ @@ -485,26 +489,29 @@ spawn_fcgi_SOURCES = spawn-fcgi.c #mod_httptls_la_SOURCES = mod_httptls.c #mod_httptls_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined #mod_httptls_la_LIBADD = $(common_libadd) -lib_LTLIBRARIES = $(am__append_1) mod_evasive.la mod_webdav.la \ - mod_cml.la mod_trigger_b4_dl.la mod_mysql_vhost.la mod_cgi.la \ - mod_scgi.la mod_staticfile.la mod_dirlisting.la \ - mod_indexfile.la mod_setenv.la mod_alias.la mod_userdir.la \ - mod_rrdtool.la mod_usertrack.la mod_proxy.la mod_ssi.la \ - mod_secdownload.la mod_expire.la mod_evhost.la \ +lib_LTLIBRARIES = $(am__append_1) mod_flv_streaming.la mod_evasive.la \ + mod_webdav.la mod_cml.la mod_trigger_b4_dl.la \ + mod_mysql_vhost.la mod_cgi.la mod_scgi.la mod_staticfile.la \ + mod_dirlisting.la mod_indexfile.la mod_setenv.la mod_alias.la \ + mod_userdir.la mod_rrdtool.la mod_usertrack.la mod_proxy.la \ + mod_ssi.la mod_secdownload.la mod_expire.la mod_evhost.la \ mod_simple_vhost.la mod_fastcgi.la mod_access.la \ mod_compress.la mod_auth.la mod_rewrite.la mod_redirect.la \ mod_status.la mod_accesslog.la @NO_RDYNAMIC_TRUE@liblightcomp_la_SOURCES = $(common_src) -@NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS) $(FAM_CFLAGS) +@NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS) @NO_RDYNAMIC_TRUE@liblightcomp_la_LDFLAGS = -avoid-version -no-undefined @NO_RDYNAMIC_TRUE@liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS) @NO_RDYNAMIC_FALSE@common_libadd = @NO_RDYNAMIC_TRUE@common_libadd = liblightcomp.la +mod_flv_streaming_la_SOURCES = mod_flv_streaming.c +mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined +mod_flv_streaming_la_LIBADD = $(common_libadd) mod_evasive_la_SOURCES = mod_evasive.c mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_evasive_la_LIBADD = $(common_libadd) mod_webdav_la_SOURCES = mod_webdav.c -mod_webdav_la_CFLAGS = $(XML_CFLAGS) +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c @@ -710,6 +717,8 @@ mod_expire.la: $(mod_expire_la_OBJECTS) $(mod_expire_la_DEPENDENCIES) $(LINK) -rpath $(libdir) $(mod_expire_la_LDFLAGS) $(mod_expire_la_OBJECTS) $(mod_expire_la_LIBADD) $(LIBS) mod_fastcgi.la: $(mod_fastcgi_la_OBJECTS) $(mod_fastcgi_la_DEPENDENCIES) $(LINK) -rpath $(libdir) $(mod_fastcgi_la_LDFLAGS) $(mod_fastcgi_la_OBJECTS) $(mod_fastcgi_la_LIBADD) $(LIBS) +mod_flv_streaming.la: $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(mod_flv_streaming_la_LDFLAGS) $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_la_LIBADD) $(LIBS) mod_indexfile.la: $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_DEPENDENCIES) $(LINK) -rpath $(libdir) $(mod_indexfile_la_LDFLAGS) $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_LIBADD) $(LIBS) mod_mysql_vhost.la: $(mod_mysql_vhost_la_OBJECTS) $(mod_mysql_vhost_la_DEPENDENCIES) @@ -912,6 +921,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evhost.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_expire.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_fastcgi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_flv_streaming.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_indexfile.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_proxy.Plo@am__quote@ diff --git a/src/configfile-glue.c b/src/configfile-glue.c index 5c3c68b..6401854 100644 --- a/src/configfile-glue.c +++ b/src/configfile-glue.c @@ -372,8 +372,8 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0, cache->matches, elementsof(cache->matches)); + cache->patterncount = n; if (n > 0) { - cache->patterncount = n; cache->comp_value = l; return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE; } else { diff --git a/src/connections.c b/src/connections.c index e4db410..3690448 100644 --- a/src/connections.c +++ b/src/connections.c @@ -394,6 +394,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) { case 408: case 411: case 416: + case 423: case 500: case 501: case 503: @@ -458,6 +459,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) { /* fall through */ case 207: case 200: /* class: header + body */ + case 201: case 301: case 302: break; diff --git a/src/keyvalue.c b/src/keyvalue.c index b26588f..2b21d55 100644 --- a/src/keyvalue.c +++ b/src/keyvalue.c @@ -27,6 +27,10 @@ static keyvalue http_methods[] = { { HTTP_METHOD_LABEL, "LABEL" }, { HTTP_METHOD_CHECKOUT, "CHECKOUT" }, { HTTP_METHOD_CHECKIN, "CHECKIN" }, + { HTTP_METHOD_MERGE, "MERGE" }, + { HTTP_METHOD_LOCK, "LOCK" }, + { HTTP_METHOD_UNLOCK, "UNLOCK" }, + { HTTP_METHOD_MKACTIVITY, "MKACTIVITY" }, { HTTP_METHOD_UNCHECKOUT, "UNCHECKOUT" }, { HTTP_METHOD_VERSION_CONTROL, "VERSION-CONTROL" }, { HTTP_METHOD_CONNECT, "CONNECT" }, diff --git a/src/keyvalue.h b/src/keyvalue.h index e1c940f..5caca63 100644 --- a/src/keyvalue.h +++ b/src/keyvalue.h @@ -27,6 +27,10 @@ typedef enum { HTTP_METHOD_CHECKIN, HTTP_METHOD_VERSION_CONTROL, HTTP_METHOD_UNCHECKOUT, + HTTP_METHOD_MKACTIVITY, + HTTP_METHOD_MERGE, + HTTP_METHOD_LOCK, + HTTP_METHOD_UNLOCK, HTTP_METHOD_LABEL, HTTP_METHOD_CONNECT } http_method_t; diff --git a/src/mod_alias.c b/src/mod_alias.c index 23570e4..f56afeb 100644 --- a/src/mod_alias.c +++ b/src/mod_alias.c @@ -166,7 +166,9 @@ PHYSICALPATH_FUNC(mod_alias_physical_handler) { if (alias_len > uri_len) continue; if (ds->key->used == 0) continue; - if (0 == strncmp(uri_ptr, ds->key->ptr, alias_len)) { + if (0 == (con->conf.force_lowercase_filenames ? + strncasecmp(uri_ptr, ds->key->ptr, alias_len) : + strncmp(uri_ptr, ds->key->ptr, alias_len))) { /* matched */ buffer_copy_string_buffer(con->physical.basedir, ds->value); diff --git a/src/mod_auth.c b/src/mod_auth.c index 9b791d4..7810437 100644 --- a/src/mod_auth.c +++ b/src/mod_auth.c @@ -399,9 +399,10 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { const char *method, *realm, *require; if (da->value->data[n]->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sssbs", - "unexpected type for key: ", "auth.require", "[", da->value->data[n]->key, "](string)"); - + log_error_write(srv, __FILE__, __LINE__, "ss", + "auth.require should contain an array as in:", + "auth.require = ( \"...\" => ( ..., ...) )"); + return HANDLER_ERROR; } @@ -416,34 +417,51 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) { require = ((data_string *)(da_file->value->data[m]))->value->ptr; } else { - log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", "auth.require", "[", da_file->value->data[m]->key, "](string)"); + log_error_write(srv, __FILE__, __LINE__, "ssbs", + "the field is unknown in:", + "auth.require = ( \"...\" => ( ..., -> \"", + da_file->value->data[m]->key, + "\" <- => \"...\" ) )"); + return HANDLER_ERROR; } } else { - log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", "auth.require", "[", da_file->value->data[m]->key, "](string)"); + log_error_write(srv, __FILE__, __LINE__, "ssbs", + "a string was expected for:", + "auth.require = ( \"...\" => ( ..., -> \"", + da_file->value->data[m]->key, + "\" <- => \"...\" ) )"); return HANDLER_ERROR; } } if (method == NULL) { - log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "method", "](string)"); + log_error_write(srv, __FILE__, __LINE__, "ss", + "the require field is missing in:", + "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )"); return HANDLER_ERROR; } else { if (0 != strcmp(method, "basic") && 0 != strcmp(method, "digest")) { - log_error_write(srv, __FILE__, __LINE__, "s", "auth.require->method has to be either 'basic' or 'digest'"); + log_error_write(srv, __FILE__, __LINE__, "ss", + "method has to be either \"basic\" or \"digest\" in", + "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )"); return HANDLER_ERROR; } } if (realm == NULL) { - log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "realm", "](string)"); + log_error_write(srv, __FILE__, __LINE__, "ss", + "the require field is missing in:", + "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )"); return HANDLER_ERROR; } if (require == NULL) { - log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "require", "](string)"); + log_error_write(srv, __FILE__, __LINE__, "ss", + "the require field is missing in:", + "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )"); return HANDLER_ERROR; } diff --git a/src/mod_cgi.c b/src/mod_cgi.c index 883bf98..15aca3c 100644 --- a/src/mod_cgi.c +++ b/src/mod_cgi.c @@ -809,8 +809,12 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)); } cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); - cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)); - cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)); + if (!buffer_is_empty(con->uri.query)) { + cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)); + } + if (!buffer_is_empty(con->request.orig_uri)) { + cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)); + } #ifdef HAVE_IPV6 @@ -967,6 +971,9 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * default: { handler_ctx *hctx; /* father */ + + close(from_cgi_fds[1]); + close(to_cgi_fds[0]); if (con->request.content_length) { chunkqueue *cq = con->request_content_queue; @@ -987,6 +994,8 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); + close(from_cgi_fds[0]); + close(to_cgi_fds[1]); return -1; } @@ -996,6 +1005,8 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", strerror(errno), c->file.name, c->file.fd); + close(from_cgi_fds[0]); + close(to_cgi_fds[1]); return -1; } @@ -1043,12 +1054,9 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * chunkqueue_remove_finished_chunks(cq); } } - - close(from_cgi_fds[1]); - - close(to_cgi_fds[0]); + close(to_cgi_fds[1]); - + /* register PID and wait for them asyncronously */ con->mode = p->id; buffer_reset(con->physical.path); @@ -1128,7 +1136,7 @@ URIHANDLER_FUNC(cgi_is_handled) { plugin_data *p = p_d; buffer *fn = con->physical.path; - if (fn->used == 0) return HANDLER_ERROR; + if (fn->used == 0) return HANDLER_GO_ON; mod_cgi_patch_connection(srv, con, p); diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c index da20c76..e64351a 100644 --- a/src/mod_fastcgi.c +++ b/src/mod_fastcgi.c @@ -57,8 +57,10 @@ typedef struct fcgi_proc { size_t id; /* id will be between 1 and max_procs */ - buffer *socket; /* config.socket + "-" + id */ + buffer *unixsocket; /* config.socket + "-" + id */ unsigned port; /* config.port + pno */ + + buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */ pid_t pid; /* PID of the spawned process (0 if not spawned locally) */ @@ -74,12 +76,13 @@ typedef struct fcgi_proc { int is_local; enum { - PROC_STATE_UNSET, /* init-phase */ - PROC_STATE_RUNNING, /* alive */ - PROC_STATE_DIED_WAIT_FOR_PID, - PROC_STATE_KILLED, /* was killed as we don't have the load anymore */ - PROC_STATE_DIED, /* marked as dead, should be restarted */ - PROC_STATE_DISABLED /* proc disabled as it resulted in an error */ + PROC_STATE_UNSET, /* init-phase */ + PROC_STATE_RUNNING, /* alive */ + PROC_STATE_OVERLOADED, /* listen-queue is full, + don't send something to this proc for the next 2 seconds */ + PROC_STATE_DIED_WAIT_FOR_PID, /* */ + PROC_STATE_DIED, /* marked as dead, should be restarted */ + PROC_STATE_KILLED /* was killed as we don't have the load anymore */ } state; } fcgi_proc; @@ -262,6 +265,8 @@ typedef struct { typedef struct { buffer *key; /* like .php */ + int note_is_sent; + fcgi_extension_host **hosts; size_t used; @@ -358,8 +363,6 @@ typedef struct { /* ok, we need a prototype */ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents); -int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc); - data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) { data_integer *di; @@ -406,8 +409,10 @@ int status_counter_set(server *srv, const char *s, size_t len, int val) { int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) { buffer_copy_string(b, "fastcgi.backend."); buffer_append_string_buffer(b, host->id); - buffer_append_string(b, "."); - buffer_append_long(b, proc->id); + if (proc) { + buffer_append_string(b, "."); + buffer_append_long(b, proc->id); + } return 0; } @@ -426,6 +431,15 @@ int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_ #undef CLEAN +#define CLEAN(x) \ + fastcgi_status_copy_procname(b, host, NULL); \ + buffer_append_string(b, x); \ + status_counter_set(srv, CONST_BUF_LEN(b), 0); + + CLEAN(".load"); + +#undef CLEAN + return 0; } @@ -472,7 +486,8 @@ fcgi_proc *fastcgi_process_init() { fcgi_proc *f; f = calloc(1, sizeof(*f)); - f->socket = buffer_init(); + f->unixsocket = buffer_init(); + f->connection_name = buffer_init(); f->prev = NULL; f->next = NULL; @@ -485,7 +500,8 @@ void fastcgi_process_free(fcgi_proc *f) { fastcgi_process_free(f->next); - buffer_free(f->socket); + buffer_free(f->unixsocket); + buffer_free(f->connection_name); free(f); } @@ -669,8 +685,8 @@ FREE_FUNC(mod_fastcgi_free) { if (proc->pid != 0) kill(proc->pid, SIGTERM); if (proc->is_local && - !buffer_is_empty(proc->socket)) { - unlink(proc->socket->ptr); + !buffer_is_empty(proc->unixsocket)) { + unlink(proc->unixsocket->ptr); } } @@ -678,8 +694,8 @@ FREE_FUNC(mod_fastcgi_free) { if (proc->pid != 0) kill(proc->pid, SIGTERM); if (proc->is_local && - !buffer_is_empty(proc->socket)) { - unlink(proc->socket->ptr); + !buffer_is_empty(proc->unixsocket)) { + unlink(proc->unixsocket->ptr); } } } @@ -799,24 +815,28 @@ static int fcgi_spawn_connection(server *srv, if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sdb", - "new proc, socket:", proc->port, proc->socket); + "new proc, socket:", proc->port, proc->unixsocket); } - if (!buffer_is_empty(proc->socket)) { + if (!buffer_is_empty(proc->unixsocket)) { memset(&fcgi_addr, 0, sizeof(fcgi_addr)); #ifdef HAVE_SYS_UN_H fcgi_addr_un.sun_family = AF_UNIX; - strcpy(fcgi_addr_un.sun_path, proc->socket->ptr); + strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr); #ifdef SUN_LEN servlen = SUN_LEN(&fcgi_addr_un); #else /* stevens says: */ - servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family); + servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family); #endif socket_type = AF_UNIX; fcgi_addr = (struct sockaddr *) &fcgi_addr_un; + + buffer_copy_string(proc->connection_name, "unix:"); + buffer_append_string_buffer(proc->connection_name, proc->unixsocket); + #else log_error_write(srv, __FILE__, __LINE__, "s", "ERROR: Unix Domain sockets are not supported."); @@ -859,6 +879,11 @@ static int fcgi_spawn_connection(server *srv, socket_type = AF_INET; fcgi_addr = (struct sockaddr *) &fcgi_addr_in; + + buffer_copy_string(proc->connection_name, "tcp:"); + buffer_append_string_buffer(proc->connection_name, host->host); + buffer_append_string(proc->connection_name, ":"); + buffer_append_long(proc->connection_name, proc->port); } if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { @@ -872,8 +897,9 @@ static int fcgi_spawn_connection(server *srv, pid_t child; int val; - if (!buffer_is_empty(proc->socket)) { - unlink(proc->socket->ptr); + if (errno != ENOENT && + !buffer_is_empty(proc->unixsocket)) { + unlink(proc->unixsocket->ptr); } close(fcgi_fd); @@ -894,10 +920,9 @@ static int fcgi_spawn_connection(server *srv, /* create socket */ if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { - log_error_write(srv, __FILE__, __LINE__, "sbds", + log_error_write(srv, __FILE__, __LINE__, "sbs", "bind failed for:", - proc->socket, - proc->port, + proc->connection_name, strerror(errno)); return -1; } @@ -1040,7 +1065,7 @@ static int fcgi_spawn_connection(server *srv, WTERMSIG(status)); if (WTERMSIG(status) == 11) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "s", "to be exact: it seg-fault, crashed, died, ... you get the idea." ); log_error_write(srv, __FILE__, __LINE__, "s", "If this is PHP try to remove the byte-code caches for now and try again."); @@ -1068,7 +1093,7 @@ static int fcgi_spawn_connection(server *srv, if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) socket is already used, won't spawn:", - proc->socket); + proc->connection_name); } } @@ -1240,9 +1265,12 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { if ((!buffer_is_empty(host->host) || host->port) && !buffer_is_empty(host->unixsocket)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "either host+port or socket"); - + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + "either host/port or socket have to be set in:", + da->key, "= (", + da_ext->key, " => (", + da_host->key, " ( ..."); + return HANDLER_ERROR; } @@ -1250,8 +1278,12 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { /* unix domain socket */ if (host->unixsocket->used > UNIX_PATH_MAX - 2) { - log_error_write(srv, __FILE__, __LINE__, "s", - "path of the unixdomain socket is too large"); + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + "unixsocket is too long in:", + da->key, "= (", + da_ext->key, " => (", + da_host->key, " ( ..."); + return HANDLER_ERROR; } } else { @@ -1259,21 +1291,20 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { if (buffer_is_empty(host->host) && buffer_is_empty(host->bin_path)) { - log_error_write(srv, __FILE__, __LINE__, "sbbbs", - "missing key (string):", - da->key, - da_ext->key, - da_host->key, - "host"); + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + "host or binpath have to be set in:", + da->key, "= (", + da_ext->key, " => (", + da_host->key, " ( ..."); return HANDLER_ERROR; } else if (host->port == 0) { - log_error_write(srv, __FILE__, __LINE__, "sbbbs", - "missing key (short):", - da->key, - da_ext->key, - da_host->key, - "port"); + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + "port has to be set in:", + da->key, "= (", + da_ext->key, " => (", + da_host->key, " ( ..."); + return HANDLER_ERROR; } } @@ -1308,9 +1339,9 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { if (buffer_is_empty(host->unixsocket)) { proc->port = host->port + pno; } else { - buffer_copy_string_buffer(proc->socket, host->unixsocket); - buffer_append_string(proc->socket, "-"); - buffer_append_long(proc->socket, pno); + buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); + buffer_append_string(proc->unixsocket, "-"); + buffer_append_long(proc->unixsocket, pno); } if (s->debug) { @@ -1346,7 +1377,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { if (buffer_is_empty(host->unixsocket)) { proc->port = host->port; } else { - buffer_copy_string_buffer(proc->socket, host->unixsocket); + buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); } fastcgi_status_init(srv, p->statuskey, host, proc); @@ -1477,14 +1508,13 @@ void fcgi_connection_close(server *srv, handler_ctx *hctx) { status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load); if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sddb", - "release proc:", - hctx->fd, - hctx->proc->pid, hctx->proc->socket); + log_error_write(srv, __FILE__, __LINE__, "ssdsbsd", + "released proc:", + "pid:", hctx->proc->pid, + "socket:", hctx->proc->connection_name, + "load:", hctx->proc->load); } } - - fcgi_proclist_sort_down(srv, hctx->host, hctx->proc); } @@ -1519,6 +1549,7 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) { fdevent_unregister(srv->ev, hctx->fd); close(hctx->fd); srv->cur_fds--; + hctx->fd = -1; } fcgi_requestid_del(srv, p, hctx->request_id); @@ -1528,16 +1559,20 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) { hctx->request_id = 0; hctx->reconnects++; - if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sddb", - "release proc:", - hctx->fd, - hctx->proc->pid, hctx->proc->socket); + if (p->conf.debug > 2) { + if (hctx->proc) { + log_error_write(srv, __FILE__, __LINE__, "sdb", + "release proc for reconnect:", + hctx->proc->pid, hctx->proc->connection_name); + } else { + log_error_write(srv, __FILE__, __LINE__, "sb", + "release proc for reconnect:", + hctx->host->unixsocket); + } } - if (hctx->proc) { + if (hctx->proc && hctx->got_proc) { hctx->proc->load--; - fcgi_proclist_sort_down(srv, hctx->host, hctx->proc); } /* perhaps another host gives us more luck */ @@ -1637,18 +1672,24 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h memset(&fcgi_addr, 0, sizeof(fcgi_addr)); - if (!buffer_is_empty(proc->socket)) { + if (!buffer_is_empty(proc->unixsocket)) { #ifdef HAVE_SYS_UN_H /* use the unix domain socket */ fcgi_addr_un.sun_family = AF_UNIX; - strcpy(fcgi_addr_un.sun_path, proc->socket->ptr); + strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr); #ifdef SUN_LEN servlen = SUN_LEN(&fcgi_addr_un); #else /* stevens says: */ - servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family); + servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family); #endif fcgi_addr = (struct sockaddr *) &fcgi_addr_un; + + if (buffer_is_empty(proc->connection_name)) { + /* on remote spawing we have to set the connection-name now */ + buffer_copy_string(proc->connection_name, "unix:"); + buffer_append_string_buffer(proc->connection_name, proc->unixsocket); + } #else return -1; #endif @@ -1665,32 +1706,40 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h servlen = sizeof(fcgi_addr_in); fcgi_addr = (struct sockaddr *) &fcgi_addr_in; + + if (buffer_is_empty(proc->connection_name)) { + /* on remote spawing we have to set the connection-name now */ + buffer_copy_string(proc->connection_name, "tcp:"); + buffer_append_string_buffer(proc->connection_name, host->host); + buffer_append_string(proc->connection_name, ":"); + buffer_append_long(proc->connection_name, proc->port); + } } if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { if (errno == EINPROGRESS || errno == EALREADY || errno == EINTR) { - if (hctx->conf.debug) { + if (hctx->conf.debug > 2) { log_error_write(srv, __FILE__, __LINE__, "sb", - "connect delayed, will continue later:", host->host); + "connect delayed, will continue later:", proc->connection_name); } return CONNECTION_DELAYED; } else if (errno == EAGAIN) { if (hctx->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sbsd", "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. " "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections." - "The load for this fastcgi backend is:", proc->load); + "The load for this fastcgi backend", proc->connection_name, "is", proc->load); } return CONNECTION_OVERLOADED; } else { - log_error_write(srv, __FILE__, __LINE__, "ssdb", + log_error_write(srv, __FILE__, __LINE__, "sssb", "connect failed:", - strerror(errno), - proc->port, proc->socket); + strerror(errno), "on", + proc->connection_name); return CONNECTION_DEAD; } @@ -2378,12 +2427,10 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { b->used = r + 1; /* one extra for the fake \0 */ b->ptr[b->used - 1] = '\0'; } else { - log_error_write(srv, __FILE__, __LINE__, "ssdsbsbsd", + log_error_write(srv, __FILE__, __LINE__, "ssdsb", "unexpected end-of-file (perhaps the fastcgi process died):", "pid:", proc->pid, - "socket:", proc->socket, - "host:", host->host, - "port:", proc->port); + "socket:", proc->connection_name); return -1; } @@ -2514,222 +2561,97 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { return fin; } -int fcgi_proclist_sort_up(server *srv, fcgi_extension_host *host, fcgi_proc *proc) { - fcgi_proc *p; - - UNUSED(srv); - - /* we have been the smallest of the current list - * and we want to insert the node sorted as soon - * possible - * - * 1 0 0 0 1 1 1 - * | ^ - * | | - * +------+ - * - */ - - /* nothing to sort, only one element */ - if (host->first == proc && proc->next == NULL) return 0; - - for (p = proc; p->next && p->next->load < proc->load; p = p->next); - - /* no need to move something - * - * 1 2 2 2 3 3 3 - * ^ - * | - * + - * - */ - if (p == proc) return 0; - - if (host->first == proc) { - /* we have been the first elememt */ - - host->first = proc->next; - host->first->prev = NULL; - } - - /* disconnect proc */ - - if (proc->prev) proc->prev->next = proc->next; - if (proc->next) proc->next->prev = proc->prev; - - /* proc should be right of p */ - - proc->next = p->next; - proc->prev = p; - if (p->next) p->next->prev = proc; - p->next = proc; -#if 0 - for(p = host->first; p; p = p->next) { - log_error_write(srv, __FILE__, __LINE__, "dd", - p->pid, p->load); - } -#else - UNUSED(srv); -#endif - - return 0; -} - -int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc) { - fcgi_proc *p; - - UNUSED(srv); - - /* we have been the smallest of the current list - * and we want to insert the node sorted as soon - * possible - * - * 0 0 0 0 1 0 1 - * ^ | - * | | - * +----------+ - * - * - * the basic is idea is: - * - the last active fastcgi process should be still - * in ram and is not swapped out yet - * - processes that are not reused will be killed - * after some time by the trigger-handler - * - remember it as: - * everything > 0 is hot - * all unused procs are colder the more right they are - * ice-cold processes are propably unused since more - * than 'unused-timeout', are swaped out and won't be - * reused in the next seconds anyway. - * - */ - - /* nothing to sort, only one element */ - if (host->first == proc && proc->next == NULL) return 0; - - for (p = host->first; p != proc && p->load < proc->load; p = p->next); - - - /* no need to move something - * - * 1 2 2 2 3 3 3 - * ^ - * | - * + - * - */ - if (p == proc) return 0; - - /* we have to move left. If we are already the first element - * we are done */ - if (host->first == proc) return 0; - - /* release proc */ - if (proc->prev) proc->prev->next = proc->next; - if (proc->next) proc->next->prev = proc->prev; - - /* proc should be left of p */ - proc->next = p; - proc->prev = p->prev; - if (p->prev) p->prev->next = proc; - p->prev = proc; - - if (proc->prev == NULL) host->first = proc; -#if 0 - for(p = host->first; p; p = p->next) { - log_error_write(srv, __FILE__, __LINE__, "dd", - p->pid, p->load); - } -#else - UNUSED(srv); -#endif - - return 0; -} - static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) { fcgi_proc *proc; for (proc = host->first; proc; proc = proc->next) { - if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sbdbdddd", + int status; + + if (p->conf.debug > 2) { + log_error_write(srv, __FILE__, __LINE__, "sbdddd", "proc:", - host->host, proc->port, - proc->socket, + proc->connection_name, proc->state, proc->is_local, proc->load, proc->pid); } - if (!proc->is_local) { - /* - * external servers might get disabled - * - * enable the server again, perhaps it is back again - */ - - if ((proc->state == PROC_STATE_DISABLED) && - (srv->cur_ts > proc->disabled_until)) { - proc->state = PROC_STATE_RUNNING; - host->active_procs++; - - fastcgi_status_copy_procname(p->statuskey, host, proc); - buffer_append_string(p->statuskey, ".disabled"); + /* + * if the remote side is overloaded, we check back after <n> seconds + * + */ + switch (proc->state) { + case PROC_STATE_KILLED: + case PROC_STATE_UNSET: + /* this should never happen as long as adaptive spawing is disabled */ + assert(0); - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 0); + break; + case PROC_STATE_RUNNING: + break; + case PROC_STATE_OVERLOADED: + if (srv->cur_ts <= proc->disabled_until) break; + + proc->state = PROC_STATE_RUNNING; + host->active_procs++; + + log_error_write(srv, __FILE__, __LINE__, "sbdb", + "fcgi-server re-enabled:", + host->host, host->port, + host->unixsocket); + break; + case PROC_STATE_DIED_WAIT_FOR_PID: + /* non-local procs don't have PIDs to wait for */ + if (!proc->is_local) break; - log_error_write(srv, __FILE__, __LINE__, "sbdb", - "fcgi-server re-enabled:", - host->host, host->port, - host->unixsocket); - } - } else { /* the child should not terminate at all */ - int status; - if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) { - switch(waitpid(proc->pid, &status, WNOHANG)) { - case 0: - /* child is still alive */ - break; - case -1: - break; - default: - if (WIFEXITED(status)) { + switch(waitpid(proc->pid, &status, WNOHANG)) { + case 0: + /* child is still alive */ + break; + case -1: + break; + default: + if (WIFEXITED(status)) { #if 0 - log_error_write(srv, __FILE__, __LINE__, "sdsd", - "child exited, pid:", proc->pid, - "status:", WEXITSTATUS(status)); + log_error_write(srv, __FILE__, __LINE__, "sdsd", + "child exited, pid:", proc->pid, + "status:", WEXITSTATUS(status)); #endif - } else if (WIFSIGNALED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child signaled:", - WTERMSIG(status)); - } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", - status); - } - - proc->state = PROC_STATE_DIED; - break; + } else if (WIFSIGNALED(status)) { + log_error_write(srv, __FILE__, __LINE__, "sd", + "child signaled:", + WTERMSIG(status)); + } else { + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", + status); } + + proc->state = PROC_STATE_DIED; + break; } + + /* fall through if we have a dead proc now */ + if (proc->state != PROC_STATE_DIED) break; + + case PROC_STATE_DIED: + /* local proc get restarted by us, + * remote ones hopefully by the admin */ + + if (proc->is_local) { + /* we still have connections bound to this proc, + * let them terminate first */ + if (proc->load != 0) break; - /* - * local servers might died, but we restart them - * - */ - if (proc->state == PROC_STATE_DIED && - proc->load == 0) { /* restart the child */ if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd", + log_error_write(srv, __FILE__, __LINE__, "ssbsdsd", "--- fastcgi spawning", - "\n\tport:", host->port, - "\n\tsocket", host->unixsocket, + "\n\tsocket", proc->connection_name, "\n\tcurrent:", 1, "/", host->min_procs); } @@ -2738,9 +2660,17 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h "ERROR: spawning fcgi failed."); return HANDLER_ERROR; } - - fcgi_proclist_sort_down(srv, host, proc); + } else { + if (srv->cur_ts <= proc->disabled_until) break; + + proc->state = PROC_STATE_RUNNING; + host->active_procs++; + + log_error_write(srv, __FILE__, __LINE__, "sb", + "fcgi-server re-enabled:", + proc->connection_name); } + break; } } @@ -2751,6 +2681,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { plugin_data *p = hctx->plugin_data; fcgi_extension_host *host= hctx->host; connection *con = hctx->remote_conn; + fcgi_proc *proc; int ret; @@ -2763,6 +2694,10 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { host->host->used, host->port, host->unixsocket->used); + + hctx->proc->disabled_until = srv->cur_ts + 10; + hctx->proc->state = PROC_STATE_DIED; + return HANDLER_ERROR; } @@ -2776,18 +2711,29 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { log_error_write(srv, __FILE__, __LINE__, "ss", "getsockopt failed:", strerror(errno)); + hctx->proc->disabled_until = srv->cur_ts + 10; + hctx->proc->state = PROC_STATE_DIED; + return HANDLER_ERROR; } if (socket_error != 0) { if (!hctx->proc->is_local || p->conf.debug) { /* local procs get restarted */ - log_error_write(srv, __FILE__, __LINE__, "sssd", + log_error_write(srv, __FILE__, __LINE__, "sssb", "establishing connection failed:", strerror(socket_error), - "port:", hctx->proc->port); + "socket:", hctx->proc->connection_name); } - hctx->proc->disabled_until = srv->cur_ts + 10; + hctx->proc->disabled_until = srv->cur_ts + 5; + + if (hctx->proc->is_local) { + hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID; + } else { + hctx->proc->state = PROC_STATE_DIED; + } + + hctx->proc->state = PROC_STATE_DIED; fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string(p->statuskey, ".died"); @@ -2807,18 +2753,27 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { break; case FCGI_STATE_INIT: /* do we have a running process for this host (max-procs) ? */ + hctx->proc = NULL; - for (hctx->proc = hctx->host->first; - hctx->proc && hctx->proc->state != PROC_STATE_RUNNING; - hctx->proc = hctx->proc->next); + for (proc = hctx->host->first; + proc && proc->state != PROC_STATE_RUNNING; + proc = proc->next); /* all childs are dead */ - if (hctx->proc == NULL) { + if (proc == NULL) { hctx->fde_ndx = -1; return HANDLER_ERROR; } + hctx->proc = proc; + + /* check the other procs if they have a lower load */ + for (proc = proc->next; proc; proc = proc->next) { + if (proc->state != PROC_STATE_RUNNING) continue; + if (proc->load < hctx->proc->load) hctx->proc = proc; + } + ret = host->unixsocket->used ? AF_UNIX : AF_INET; if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) { @@ -2863,14 +2818,14 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { /* cool down the backend, it is overloaded * -> EAGAIN */ - log_error_write(srv, __FILE__, __LINE__, "ssdsdb", + log_error_write(srv, __FILE__, __LINE__, "ssdsd", "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:", "reconnects:", hctx->reconnects, - "load:", host->load, - host->unixsocket); + "load:", host->load); hctx->proc->disabled_until = srv->cur_ts + 2; + hctx->proc->state = PROC_STATE_OVERLOADED; fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string(p->statuskey, ".overloaded"); @@ -2883,11 +2838,21 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { * - ECONNREFUSED for tcp-ip sockets * - ENOENT for unix-domain-sockets * - * for check if the host is back in 10 seconds + * for check if the host is back in 5 seconds * */ - hctx->proc->disabled_until = srv->cur_ts + 10; - + hctx->proc->disabled_until = srv->cur_ts + 5; + if (hctx->proc->is_local) { + hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID; + } else { + hctx->proc->state = PROC_STATE_DIED; + } + + log_error_write(srv, __FILE__, __LINE__, "ssdsd", + "backend died, we disable it for a 5 seconds and send the request to another backend instead:", + "reconnects:", hctx->reconnects, + "load:", host->load); + fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string(p->statuskey, ".died"); @@ -2919,24 +2884,27 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { status_counter_inc(srv, CONST_BUF_LEN(p->statuskey)); + /* the proc-load */ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string(p->statuskey, ".load"); status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load); + /* the host-load */ + fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL); + buffer_append_string(p->statuskey, ".load"); + + status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load); + if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sddbdd", + log_error_write(srv, __FILE__, __LINE__, "ssdsbsd", "got proc:", - hctx->fd, - hctx->proc->pid, - hctx->proc->socket, - hctx->proc->port, - hctx->proc->load); + "pid:", hctx->proc->pid, + "socket:", hctx->proc->connection_name, + "load:", hctx->proc->load); } /* move the proc-list entry down the list */ - fcgi_proclist_sort_up(srv, hctx->host, hctx->proc); - if (hctx->request_id == 0) { hctx->request_id = fcgi_requestid_new(srv, p); } else { @@ -3098,43 +3066,7 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { if (hctx->state == FCGI_STATE_INIT || hctx->state == FCGI_STATE_CONNECT_DELAYED) { - /* connect() or getsockopt() failed, - * restart the request-handling - */ - if (proc) { - if (proc->is_local) { - - if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sbdb", - "connect() to fastcgi failed, restarting the request-handling:", - host->host, - proc->port, - proc->socket); - } - - /* - * several hctx might reference the same proc - * - * Only one of them should mark the proc as dead all the other - * ones should just take a new one. - * - * If a new proc was started with the old struct this might lead - * the mark a perfect proc as dead otherwise - * - */ - if (proc->state == PROC_STATE_RUNNING && - hctx->pid == proc->pid) { - proc->state = PROC_STATE_DIED_WAIT_FOR_PID; - } - } else { - proc->state = PROC_STATE_DISABLED; - } - host->active_procs--; - fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); - buffer_append_string(p->statuskey, ".disabled"); - - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 1); - } + if (proc) host->active_procs--; fcgi_restart_dead_procs(srv, p, host); @@ -3247,18 +3179,18 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { } if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd", + log_error_write(srv, __FILE__, __LINE__, "ssbsdsd", "--- fastcgi spawning", - "\n\tport:", host->port, - "\n\tsocket", host->unixsocket, + "\n\tsocket", proc->connection_name, "\n\tcurrent:", 1, "/", host->min_procs); } if (fcgi_spawn_connection(srv, p, host, proc)) { - /* child died */ + /* respawning failed, retry later */ proc->state = PROC_STATE_DIED; - } else { - fcgi_proclist_sort_down(srv, host, proc); + + log_error_write(srv, __FILE__, __LINE__, "s", + "respawning failed, will retry later"); } break; @@ -3272,18 +3204,18 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { hctx->reconnects < 5) { fcgi_reconnect(srv, hctx); - log_error_write(srv, __FILE__, __LINE__, "ssdsd", - "response not received, request not sent, reconnecting.", - "connection-fd:", con->fd, - "fcgi-fd:", hctx->fd); + log_error_write(srv, __FILE__, __LINE__, "ssbsbs", + "response not received, request not sent", + "on socket:", proc->connection_name, + "for", con->uri.path, ", reconnecting"); return HANDLER_WAIT_FOR_FD; } - - log_error_write(srv, __FILE__, __LINE__, "sosdsd", + + log_error_write(srv, __FILE__, __LINE__, "sosbsbs", "response not received, request sent:", hctx->wb->bytes_out, - "connection-fd:", con->fd, - "fcgi-fd:", hctx->fd); + "on socket:", proc->connection_name, + "for", con->uri.path, ", closing connection"); fcgi_connection_close(srv, hctx); @@ -3295,10 +3227,10 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { /* response might have been already started, kill the connection */ fcgi_connection_close(srv, hctx); - log_error_write(srv, __FILE__, __LINE__, "ssdsd", - "response already sent out, termination connection", - "connection-fd:", con->fd, - "fcgi-fd:", hctx->fd); + log_error_write(srv, __FILE__, __LINE__, "ssbsbs", + "response already sent out, but backend returned error", + "on socket:", proc->connection_name, + "for", con->uri.path, ", terminating connection"); connection_set_state(srv, con, CON_STATE_ERROR); } @@ -3351,7 +3283,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", "error: unexpected close of fastcgi connection for", con->uri.path, - "(no fastcgi process on host: ", + "(no fastcgi process on host:", host->host, ", port: ", host->port, @@ -3425,9 +3357,7 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i fn = uri_path_handler ? con->uri.path : con->physical.path; - if (fn->used == 0) { - return HANDLER_ERROR; - } + if (buffer_is_empty(fn)) return HANDLER_GO_ON; s_len = fn->used - 1; @@ -3519,14 +3449,23 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i /* sorry, we don't have a server alive for this ext */ buffer_reset(con->physical.path); con->http_status = 500; - - log_error_write(srv, __FILE__, __LINE__, "sb", - "no fcgi-handler found for:", - fn); + + /* only send the 'no handler' once */ + if (!extension->note_is_sent) { + extension->note_is_sent = 1; + + log_error_write(srv, __FILE__, __LINE__, "sbsbs", + "all handlers for ", con->uri.path, + "on", extension->key, + "are down."); + } return HANDLER_FINISHED; } + /* a note about no handler is not sent yey */ + extension->note_is_sent = 0; + /* * if check-local is disabled, use the uri.path handler * @@ -3708,48 +3647,46 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { host->num_procs < host->max_procs && (sum_load / host->num_procs) > host->max_load_per_proc) { /* overload, spawn new child */ - fcgi_proc *fp = NULL; - if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "overload detected, spawning a new child"); } - for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next); + for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next); - if (fp) { - if (fp == host->unused_procs) host->unused_procs = fp->next; + if (proc) { + if (proc == host->unused_procs) host->unused_procs = proc->next; - if (fp->next) fp->next->prev = NULL; + if (proc->next) proc->next->prev = NULL; host->max_id++; } else { - fp = fastcgi_process_init(); - fp->id = host->max_id++; + proc = fastcgi_process_init(); + proc->id = host->max_id++; } host->num_procs++; if (buffer_is_empty(host->unixsocket)) { - fp->port = host->port + fp->id; + proc->port = host->port + proc->id; } else { - buffer_copy_string_buffer(fp->socket, host->unixsocket); - buffer_append_string(fp->socket, "-"); - buffer_append_long(fp->socket, fp->id); + buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); + buffer_append_string(proc->unixsocket, "-"); + buffer_append_long(proc->unixsocket, proc->id); } - if (fcgi_spawn_connection(srv, p, host, fp)) { + if (fcgi_spawn_connection(srv, p, host, proc)) { log_error_write(srv, __FILE__, __LINE__, "s", "ERROR: spawning fcgi failed."); return HANDLER_ERROR; } - fp->prev = NULL; - fp->next = host->first; + proc->prev = NULL; + proc->next = host->first; if (host->first) { - host->first->prev = fp; + host->first->prev = proc; } - host->first = fp; + host->first = proc; } for (proc = host->first; proc; proc = proc->next) { @@ -3764,7 +3701,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "ssbsd", "idle-timeout reached, terminating child:", - "socket:", proc->socket, + "socket:", proc->connection_name, "pid", proc->pid); } @@ -3786,7 +3723,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { log_error_write(srv, __FILE__, __LINE__, "ssbsd", "killed:", - "socket:", proc->socket, + "socket:", proc->connection_name, "pid", proc->pid); host->num_procs--; @@ -3827,7 +3764,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { if (proc->state != PROC_STATE_KILLED) { log_error_write(srv, __FILE__, __LINE__, "sdb", "child exited:", - WEXITSTATUS(status), proc->socket); + WEXITSTATUS(status), proc->connection_name); } } else if (WIFSIGNALED(status)) { if (WTERMSIG(status) != SIGTERM) { diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c new file mode 100644 index 0000000..c557bd4 --- /dev/null +++ b/src/mod_flv_streaming.c @@ -0,0 +1,278 @@ +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "base.h" +#include "log.h" +#include "buffer.h" +#include "response.h" +#include "http_chunk.h" +#include "stat_cache.h" + +#include "plugin.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* plugin config for all request/connections */ + +typedef struct { + array *extensions; +} plugin_config; + +typedef struct { + PLUGIN_DATA; + + buffer *query_str; + array *get_params; + + plugin_config **config_storage; + + plugin_config conf; +} plugin_data; + +/* init the plugin data */ +INIT_FUNC(mod_flv_streaming_init) { + plugin_data *p; + + p = calloc(1, sizeof(*p)); + + p->query_str = buffer_init(); + p->get_params = array_init(); + + return p; +} + +/* detroy the plugin data */ +FREE_FUNC(mod_flv_streaming_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; + + array_free(s->extensions); + + free(s); + } + free(p->config_storage); + } + + buffer_free(p->query_str); + array_free(p->get_params); + + free(p); + + return HANDLER_GO_ON; +} + +/* handle plugin config and check values */ + +SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) { + plugin_data *p = p_d; + size_t i = 0; + + config_values_t cv[] = { + { "flv-streaming.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->extensions = array_init(); + + cv[0].destination = s->extensions; + + 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_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) { + size_t i, j; + plugin_config *s = p->config_storage[0]; + + PATCH(extensions); + + /* 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("flv-streaming.extensions"))) { + PATCH(extensions); + } + } + } + + return 0; +} +#undef PATCH + +static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) { + size_t is_key = 1; + size_t i; + char *key = NULL, *val = NULL; + + key = qrystr->ptr; + + /* we need the \0 */ + for (i = 0; i < qrystr->used; i++) { + switch(qrystr->ptr[i]) { + case '=': + if (is_key) { + val = qrystr->ptr + i + 1; + + qrystr->ptr[i] = '\0'; + + is_key = 0; + } + + break; + case '&': + case '\0': /* fin symbol */ + if (!is_key) { + data_string *ds; + /* we need at least a = since the last & */ + + /* terminate the value */ + qrystr->ptr[i] = '\0'; + + if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { + ds = data_string_init(); + } + buffer_copy_string_len(ds->key, key, strlen(key)); + buffer_copy_string_len(ds->value, val, strlen(val)); + + array_insert_unique(get_params, (data_unset *)ds); + } + + key = qrystr->ptr + i + 1; + val = NULL; + is_key = 1; + break; + } + } + + return 0; +} + +URIHANDLER_FUNC(mod_flv_streaming_path_handler) { + plugin_data *p = p_d; + int s_len; + size_t k; + + UNUSED(srv); + + if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON; + + mod_flv_streaming_patch_connection(srv, con, p); + + s_len = con->physical.path->used - 1; + + for (k = 0; k < p->conf.extensions->used; k++) { + data_string *ds = (data_string *)p->conf.extensions->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->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) { + data_string *get_param; + stat_cache_entry *sce = NULL; + buffer *b; + int start; + char *err = NULL; + /* if there is a start=[0-9]+ in the header use it as start, + * otherwise send the full file */ + + array_reset(p->get_params); + buffer_copy_string_buffer(p->query_str, con->uri.query); + split_get_params(srv, con, p->get_params, p->query_str); + + if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) { + return HANDLER_GO_ON; + } + + /* too short */ + if (get_param->value->used < 2) return HANDLER_GO_ON; + + /* check if it is a number */ + start = strtol(get_param->value->ptr, &err, 10); + if (*err != '\0') { + return HANDLER_GO_ON; + } + + if (start <= 0) return HANDLER_GO_ON; + + /* check if start is > filesize */ + if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { + return HANDLER_GO_ON; + } + + if (start > sce->st.st_size) { + return HANDLER_GO_ON; + } + + /* we are safe now, let's build a flv header */ + b = chunkqueue_get_append_buffer(con->write_queue); + BUFFER_COPY_STRING_CONST(b, "FLV\x1\x1\0\0\0\x9\0\0\0\x9"); + + http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start); + + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv")); + + con->file_finished = 1; + + return HANDLER_FINISHED; + } + } + + /* not found */ + return HANDLER_GO_ON; +} + +/* this function is called at dlopen() time and inits the callbacks */ + +int mod_flv_streaming_plugin_init(plugin *p) { + p->version = LIGHTTPD_VERSION_ID; + p->name = buffer_init_string("flv_streaming"); + + p->init = mod_flv_streaming_init; + p->handle_physical = mod_flv_streaming_path_handler; + p->set_defaults = mod_flv_streaming_set_defaults; + p->cleanup = mod_flv_streaming_free; + + p->data = NULL; + + return 0; +} diff --git a/src/mod_scgi.c b/src/mod_scgi.c index 2c1df2f..88c80eb 100644 --- a/src/mod_scgi.c +++ b/src/mod_scgi.c @@ -645,7 +645,7 @@ static int scgi_spawn_connection(server *srv, servlen = SUN_LEN(&scgi_addr_un); #else /* stevens says: */ - servlen = proc->socket->used - 1 + sizeof(scgi_addr_un.sun_family); + servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family); #endif socket_type = AF_UNIX; scgi_addr = (struct sockaddr *) &scgi_addr_un; @@ -1296,7 +1296,7 @@ static int scgi_establish_connection(server *srv, handler_ctx *hctx) { servlen = SUN_LEN(&scgi_addr_un); #else /* stevens says: */ - servlen = proc->socket->used - 1 + sizeof(scgi_addr_un.sun_family); + servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family); #endif scgi_addr = (struct sockaddr *) &scgi_addr_un; #else diff --git a/src/mod_ssi.c b/src/mod_ssi.c index b6a19d7..d1e1b25 100644 --- a/src/mod_ssi.c +++ b/src/mod_ssi.c @@ -518,13 +518,11 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, } else { buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1); } - - /* fn */ - if (NULL == (sl = strrchr(file_path, '/'))) { - buffer_append_string(p->stat_fn, file_path); - } else { - buffer_append_string(p->stat_fn, sl + 1); - } + + buffer_copy_string(srv->tmp_buf, file_path); + buffer_urldecode_path(srv->tmp_buf); + buffer_path_simplify(srv->tmp_buf, srv->tmp_buf); + buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); } else { /* virtual */ @@ -974,7 +972,7 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) #ifdef HAVE_PCRE_H for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) { const char **l; - /* take every think from last offset to current match pos */ + /* take everything from last offset to current match pos */ if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i); diff --git a/src/mod_webdav.c b/src/mod_webdav.c index 3306c73..c78e609 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -1294,6 +1294,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { } } else { con->http_status = 201; + con->file_finished = 1; } return HANDLER_FINISHED; @@ -1390,6 +1391,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { chunk *c; con->http_status = 201; /* created */ + con->file_finished = 1; for (c = cq->first; c; c = cq->first) { int r = 0; @@ -1606,6 +1608,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { rmdir(con->physical.path->ptr); } con->http_status = 201; + con->file_finished = 1; } else { /* it is just a file, good */ int r; @@ -1625,6 +1628,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { if (-1 == r) { con->http_status = 201; /* we will create a new one */ + con->file_finished = 1; switch(errno) { case ENOTDIR: diff --git a/src/network.c b/src/network.c index 922009f..fe52bc2 100644 --- a/src/network.c +++ b/src/network.c @@ -252,7 +252,7 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { addr_len = SUN_LEN(&srv_socket->addr.un); #else /* stevens says: */ - addr_len = strlen(host) + sizeof(srv_socket->addr.un.sun_family); + addr_len = strlen(host) + 1 + sizeof(srv_socket->addr.un.sun_family); #endif /* check if the socket exists and try to connect to it. */ @@ -540,6 +540,7 @@ int network_init(server *srv) { for (i = 1; i < srv->config_context->used; i++) { data_config *dc = (data_config *)srv->config_context->data[i]; specific_config *s = srv->config_storage[i]; + size_t j; /* not our stage */ if (COMP_SERVER_SOCKET != dc->comp) continue; @@ -549,13 +550,20 @@ int network_init(server *srv) { return -1; } + + /* check if we already know this socket, + * if yes, don't init it */ + for (j = 0; j < srv->srv_sockets.used; j++) { + if (buffer_is_equal(srv->srv_sockets.ptr[j]->srv_token, dc->string)) { + break; + } + } - if (0 != network_server_init(srv, dc->string, s)) { - return -1; + if (j == srv->srv_sockets.used) { + if (0 != network_server_init(srv, dc->string, s)) return -1; } } - return 0; } diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c index 6426568..580ba87 100644 --- a/src/network_linux_sendfile.c +++ b/src/network_linux_sendfile.c @@ -23,6 +23,9 @@ #include "log.h" #include "stat_cache.h" +/* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */ +#undef HAVE_POSIX_FADVISE + int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) { chunk *c; size_t chunks_written = 0; @@ -129,23 +132,11 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, size_t toSend; stat_cache_entry *sce = NULL; - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { - log_error_write(srv, __FILE__, __LINE__, "sb", - strerror(errno), c->file.name); - return -1; - } - offset = c->file.start + c->offset; /* limit the toSend to 2^31-1 bytes in a chunk */ toSend = c->file.length - c->offset > ((1 << 30) - 1) ? ((1 << 30) - 1) : c->file.length - c->offset; - if (offset > sce->st.st_size) { - log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); - - return -1; - } - /* open file if not already opened */ if (-1 == c->file.fd) { if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { @@ -159,14 +150,14 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, #ifdef HAVE_POSIX_FADVISE /* tell the kernel that we want to stream the file */ if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) { - log_error_write(srv, __FILE__, __LINE__, "ssd", - "posix_fadvise failed:", strerror(errno), c->file.fd); + if (ENOSYS != errno) { + log_error_write(srv, __FILE__, __LINE__, "ssd", + "posix_fadvise failed:", strerror(errno), c->file.fd); + } } #endif } - - /* Linux sendfile() */ if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) { switch (errno) { case EAGAIN: @@ -184,7 +175,21 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, } if (r == 0) { - /* we got a event to write put we couldn't. remote side closed ? */ + /* We got an event to write but we wrote nothing + * + * - the file shrinked -> error + * - the remote side closed inbetween -> remote-close */ + + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { + /* file is gone ? */ + return -1; + } + + if (offset > sce->st.st_size) { + /* file shrinked, close the connection */ + return -1; + } + return -2; } diff --git a/src/network_writev.c b/src/network_writev.c index 578048e..96a2a4a 100644 --- a/src/network_writev.c +++ b/src/network_writev.c @@ -255,14 +255,14 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq #ifdef LOCAL_BUFFERING buffer_copy_string_len(c->mem, c->file.mmap.start, c->file.mmap.length); #else -#ifdef HAVE_POSIX_MADVISE +#ifdef HAVE_MADVISE /* don't advise files < 64Kb */ if (c->file.mmap.length > (64 KByte)) { /* darwin 7 is returning EINVAL all the time and I don't know how to * detect this at runtime.i * * ignore the return value for now */ - posix_madvise(c->file.mmap.start, c->file.mmap.length, POSIX_MADV_WILLNEED); + madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED); } #endif #endif diff --git a/src/request.c b/src/request.c index 020333e..f539c80 100644 --- a/src/request.c +++ b/src/request.c @@ -368,11 +368,53 @@ int http_request_parse(server *srv, connection *con) { } con->request.http_method = r; - - if (0 == strncmp(proto, "HTTP/1.", sizeof("HTTP/1.") - 1)) { - if (proto[7] == '1') { + + /* + * RFC2616 says: + * + * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT + * + * */ + if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) { + char * major = proto + sizeof("HTTP/") - 1; + char * minor = strchr(major, '.'); + char *err = NULL; + int major_num = 0, minor_num = 0; + + int invalid_version = 0; + + if (NULL == minor || /* no dot */ + minor == major || /* no major */ + *(minor + 1) == '\0' /* no minor */) { + invalid_version = 1; + } else { + *minor = '\0'; + major_num = strtol(major, &err, 10); + + if (*err != '\0') invalid_version = 1; + + *minor++ = '.'; + minor_num = strtol(minor, &err, 10); + + if (*err != '\0') invalid_version = 1; + } + + if (invalid_version) { + con->http_status = 400; + con->keep_alive = 0; + + if (srv->srvconf.log_request_header_on_error) { + log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400"); + log_error_write(srv, __FILE__, __LINE__, "Sb", + "request-header:\n", + con->request.request); + } + return 0; + } + + if (major_num == 1 && minor_num == 1) { con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0; - } else if (proto[7] == '0') { + } else if (major_num == 1 && minor_num == 0) { con->request.http_version = HTTP_VERSION_1_0; } else { con->http_status = 505; @@ -1003,12 +1045,11 @@ int http_request_parse(server *srv, connection *con) { switch(con->request.http_method) { case HTTP_METHOD_GET: case HTTP_METHOD_HEAD: - case HTTP_METHOD_OPTIONS: /* content-length is forbidden for those */ if (con_length_set && con->request.content_length != 0) { /* content-length is missing */ log_error_write(srv, __FILE__, __LINE__, "s", - "GET/HEAD/OPTIONS with content-length -> 400"); + "GET/HEAD with content-length -> 400"); con->keep_alive = 0; con->http_status = 400; diff --git a/src/response.c b/src/response.c index d955cec..4f23ea9 100644 --- a/src/response.c +++ b/src/response.c @@ -320,6 +320,42 @@ 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); +#if defined(__WIN32) || defined(__CYGWIN__) + /* strip dots from the end and spaces + * + * windows/dos handle those filenames as the same file + * + * foo == foo. == foo..... == "foo... " == "foo.. ./" + * + * This will affect in some cases PATHINFO + * + * on native windows we could prepend the filename with \\?\ to circumvent + * this behaviour. I have no idea how to push this through cygwin + * + * */ + + if (con->physical.rel_path->used > 1) { + buffer *b = con->physical.rel_path; + size_t i; + + if (b->used > 2 && + b->ptr[b->used-2] == '/' && + (b->ptr[b->used-3] == ' ' || + b->ptr[b->used-3] == '.')) { + b->ptr[b->used--] = '\0'; + } + + for (i = b->used - 2; b->used > 1; i--) { + if (b->ptr[i] == ' ' || + b->ptr[i] == '.') { + b->ptr[b->used--] = '\0'; + } else { + break; + } + } + } +#endif + 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); diff --git a/src/server.c b/src/server.c index f33100c..d4f9eba 100644 --- a/src/server.c +++ b/src/server.c @@ -118,8 +118,6 @@ static void daemonize(void) { if (0 != fork()) exit(0); if (0 != chdir("/")) exit(0); - - umask(0); } #endif @@ -218,6 +216,7 @@ static void server_free(server *srv) { CLEAN(srvconf.event_handler); CLEAN(srvconf.pid_file); CLEAN(srvconf.modules_dir); + CLEAN(srvconf.network_backend); CLEAN(tmp_chunk_len); #undef CLEAN @@ -256,6 +255,7 @@ static void server_free(server *srv) { CLEAN(config_context); CLEAN(config_touched); CLEAN(status); + CLEAN(srvconf.upload_tempdirs); #undef CLEAN joblist_free(srv, srv->joblist); diff --git a/src/spawn-fcgi.c b/src/spawn-fcgi.c index 99fc31a..fd869a2 100644 --- a/src/spawn-fcgi.c +++ b/src/spawn-fcgi.c @@ -41,7 +41,7 @@ typedef int socklen_t; #endif #ifdef HAVE_SYS_UN_H -int fcgi_spawn_connection(char *appPath, unsigned short port, const char *unixsocket, int child_count, int pid_fd, int nofork) { +int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const char *unixsocket, int child_count, int pid_fd, int nofork) { int fcgi_fd; int socket_type, status; struct timeval tv = { 0, 100 * 1000 }; @@ -77,7 +77,11 @@ int fcgi_spawn_connection(char *appPath, unsigned short port, const char *unixso fcgi_addr = (struct sockaddr *) &fcgi_addr_un; } else { fcgi_addr_in.sin_family = AF_INET; - fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); + if (addr != NULL) { + fcgi_addr_in.sin_addr.s_addr = inet_addr(addr); + } else { + fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); + } fcgi_addr_in.sin_port = htons(port); servlen = sizeof(fcgi_addr_in); @@ -243,6 +247,7 @@ void show_help () { " - spawns fastcgi processes\n" \ "usage:\n" \ " -f <fcgiapp> filename of the fcgi-application\n" \ +" -a <addr> bind to ip address\n" \ " -p <port> bind to tcp-port\n" \ " -s <path> bind to unix-domain socket\n" \ " -C <childs> (PHP only) numbers of childs to spawn (default 5)\n" \ @@ -261,7 +266,8 @@ void show_help () { int main(int argc, char **argv) { char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, - *groupname = NULL, *unixsocket = NULL, *pid_file = NULL; + *groupname = NULL, *unixsocket = NULL, *pid_file = NULL, + *addr = NULL; unsigned short port = 0; int child_count = 5; int i_am_root, o; @@ -270,9 +276,10 @@ int main(int argc, char **argv) { i_am_root = (getuid() == 0); - while(-1 != (o = getopt(argc, argv, "c:f:g:hnp:u:vC:s:P:"))) { + while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) { switch(o) { case 'f': fcgi_app = optarg; break; + case 'a': addr = optarg;/* ip addr */ break; case 'p': port = strtol(optarg, NULL, 10);/* port */ break; case 'C': child_count = strtol(optarg, NULL, 10);/* */ break; case 's': unixsocket = optarg; /* unix-domain socket */ break; @@ -422,7 +429,7 @@ int main(int argc, char **argv) { if (username) setuid(pwd->pw_uid); } - return fcgi_spawn_connection(fcgi_app, port, unixsocket, child_count, pid_fd, nofork); + return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork); } #else int main() { |