Index: configure.in =================================================================== Index: src/configfile-glue.c =================================================================== --- src/configfile-glue.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/configfile-glue.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -277,7 +277,7 @@ } break; } - case COMP_HTTP_REMOTEIP: { + case COMP_HTTP_REMOTE_IP: { char *nm_slash; /* handle remoteip limitations * @@ -341,11 +341,15 @@ } break; } + case COMP_HTTP_SCHEME: + l = con->uri.scheme; + break; + case COMP_HTTP_URL: l = con->uri.path; break; - case COMP_HTTP_QUERYSTRING: + case COMP_HTTP_QUERY_STRING: l = con->uri.query; break; @@ -372,7 +376,7 @@ } break; } - case COMP_HTTP_USERAGENT: { + case COMP_HTTP_USER_AGENT: { data_string *ds; if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) { l = ds->value; @@ -381,7 +385,17 @@ } break; } + case COMP_HTTP_REQUEST_METHOD: { + const char *method = get_http_method_name(con->request.http_method); + /* we only have the request method as const char but we need a buffer for comparing */ + + buffer_copy_string(srv->tmp_buf, method); + + l = srv->tmp_buf; + + break; + } default: return COND_RESULT_FALSE; } Index: src/mod_cgi.c =================================================================== --- src/mod_cgi.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_cgi.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1004,6 +1004,7 @@ case -1: /* error */ log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno)); + return -1; break; default: { handler_ctx *hctx; @@ -1227,8 +1228,14 @@ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", p->cgi_pid.ptr[ndx]); #endif + } else if (WIFSIGNALED(status)) { + /* FIXME: what if we killed the CGI script with a kill(..., SIGTERM) ? + */ + if (WTERMSIG(status) != SIGTERM) { + log_error_write(srv, __FILE__, __LINE__, "sd", "cleaning up CGI: process died with signal", WTERMSIG(status)); + } } else { - log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?"); + log_error_write(srv, __FILE__, __LINE__, "s", "cleaning up CGI: ended unexpectedly"); } cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]); Index: src/mod_secure_download.c =================================================================== --- src/mod_secure_download.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_secure_download.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -245,7 +245,8 @@ /* timed-out */ if (srv->cur_ts - ts > p->conf.timeout || srv->cur_ts - ts < -p->conf.timeout) { - con->http_status = 408; + /* "Gone" as the url will never be valid again instead of "408 - Timeout" where the request may be repeated */ + con->http_status = 410; return HANDLER_FINISHED; } Index: src/base.h =================================================================== --- src/base.h (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/base.h (.../branches/lighttpd-1.4.x) (revision 2118) @@ -515,6 +515,7 @@ #ifdef USE_OPENSSL SSL_CTX *ssl_ctx; #endif + unsigned short is_proxy_ssl; } server_socket; typedef struct { Index: src/connections.c =================================================================== --- src/connections.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/connections.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -394,10 +394,13 @@ * 403 is from the response handler when noone else catched it * * */ - if (con->uri.path->used && + if ((!con->http_status || con->http_status == 200) && con->uri.path->used && con->uri.path->ptr[0] != '*') { response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); + con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; + con->parsed_response &= ~HTTP_CONTENT_LENGTH; + con->http_status = 200; con->file_finished = 1; @@ -498,9 +501,11 @@ case 207: case 200: /* class: header + body */ case 201: + case 300: case 301: case 302: case 303: + case 307: break; case 206: /* write_queue is already prepared */ @@ -511,13 +516,13 @@ default: /* disable chunked encoding again as we have no body */ con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; + con->parsed_response &= ~HTTP_CONTENT_LENGTH; chunkqueue_reset(con->write_queue); con->file_finished = 1; break; } - if (con->file_finished) { /* we have all the content and chunked encoding is not used, set a content-length */ @@ -536,12 +541,16 @@ if ((con->http_status >= 100 && con->http_status < 200) || con->http_status == 204 || con->http_status == 304) { + data_string *ds; /* no Content-Body, no Content-Length */ - } else if (qlen >= 0) { + if (NULL != (ds = (data_string*) array_get_element(con->response.headers, "Content-Length"))) { + buffer_reset(ds->value); // Headers with empty values are ignored for output + } + } else if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) { /* qlen = 0 is important for Redirects (301, ...) as they MAY have * a content. Browsers are waiting for a Content otherwise */ - buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue)); + buffer_copy_off_t(srv->tmp_buf, qlen); response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf)); } @@ -582,6 +591,8 @@ * a HEAD request has the same as a GET * without the content */ + con->file_finished = 1; + chunkqueue_reset(con->write_queue); con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; } @@ -834,14 +845,8 @@ con->plugin_ctx[pd->id] = NULL; } -#if COND_RESULT_UNSET - for (i = srv->config_context->used - 1; i >= 0; i --) { - con->cond_cache[i].result = COND_RESULT_UNSET; - con->cond_cache[i].patterncount = 0; - } -#else - memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used); -#endif + /* The cond_cache gets reset in response.c */ +// config_cond_cache_reset(srv, con); #ifdef USE_OPENSSL if (con->ssl_error_want_reuse_buffer) { Index: src/array.h =================================================================== --- src/array.h (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/array.h (.../branches/lighttpd-1.4.x) (revision 2118) @@ -86,10 +86,12 @@ COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, - COMP_HTTP_USERAGENT, + COMP_HTTP_USER_AGENT, COMP_HTTP_COOKIE, - COMP_HTTP_REMOTEIP, - COMP_HTTP_QUERYSTRING, + COMP_HTTP_REMOTE_IP, + COMP_HTTP_QUERY_STRING, + COMP_HTTP_SCHEME, + COMP_HTTP_REQUEST_METHOD, COMP_LAST_ELEMENT } comp_key_t; Index: src/mod_staticfile.c =================================================================== --- src/mod_staticfile.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_staticfile.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -352,7 +352,7 @@ size_t k; int s_len; stat_cache_entry *sce = NULL; - buffer *mtime; + buffer *mtime = NULL; data_string *ds; int allow_caching = 1; @@ -450,7 +450,9 @@ } } - response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes")); + if (con->conf.range_requests) { + response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes")); + } if (allow_caching) { if (p->conf.etags_used && con->etag_flags != 0 && !buffer_is_empty(sce->etag)) { @@ -483,8 +485,24 @@ /* if the value is the same as our ETag, we do a Range-request, * otherwise a full 200 */ - if (!buffer_is_equal(ds->value, con->physical.etag)) { + if (ds->value->ptr[0] == '"') { + /** + * client wants a ETag + */ + if (!con->physical.etag) { + do_range_request = 0; + } else if (!buffer_is_equal(ds->value, con->physical.etag)) { + do_range_request = 0; + } + } else if (!mtime) { + /** + * we don't have a Last-Modified and can match the If-Range: + * + * sending all + */ do_range_request = 0; + } else if (!buffer_is_equal(ds->value, mtime)) { + do_range_request = 0; } } Index: src/fdevent_solaris_devpoll.c =================================================================== --- src/fdevent_solaris_devpoll.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/fdevent_solaris_devpoll.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -67,7 +67,7 @@ int ret; dopoll.dp_timeout = timeout_ms; - dopoll.dp_nfds = ev->maxfds; + dopoll.dp_nfds = ev->maxfds - 1; dopoll.dp_fds = ev->devpollfds; ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll); Index: src/etag.c =================================================================== --- src/etag.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/etag.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,5 +1,14 @@ #include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined HAVE_STDINT_H #include +#elif defined HAVE_INTTYPES_H +#include +#endif #include "buffer.h" #include "etag.h" Index: src/mod_scgi.c =================================================================== --- src/mod_scgi.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_scgi.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1057,6 +1057,9 @@ /* a local socket + self spawning */ size_t pno; + /* HACK: just to make sure the adaptive spawing is disabled */ + df->min_procs = df->max_procs; + if (df->min_procs > df->max_procs) df->max_procs = df->min_procs; if (df->max_load_per_proc < 1) df->max_load_per_proc = 0; @@ -2694,8 +2697,9 @@ if (s_len < ct_len) continue; /* check extension in the form "/scgi_pattern" */ - if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { - break; + if (*(extension->key->ptr) == '/') { + if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) + break; } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) { /* check extension in the form ".fcg" */ break; Index: src/response.c =================================================================== --- src/response.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/response.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -19,6 +19,7 @@ #include "stat_cache.h" #include "chunk.h" +#include "configfile.h" #include "connections.h" #include "plugin.h" @@ -59,7 +60,8 @@ 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)) { + 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) && + 0 != strncmp(ds->key->ptr, "X-Sendfile", sizeof("X-Sendfile") - 1)) { if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1; if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1; @@ -149,6 +151,9 @@ * * */ + config_cond_cache_reset(srv, con); + config_setup_connection(srv, con); // Perhaps this could be removed at other places. + if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "run condition"); } @@ -180,11 +185,13 @@ buffer_copy_string_buffer(con->uri.authority, con->request.http_host); buffer_to_lower(con->uri.authority); + config_patch_connection(srv, con, COMP_HTTP_SCHEME); /* Scheme: */ config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */ - config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */ + config_patch_connection(srv, con, COMP_HTTP_REMOTE_IP); /* Client-IP */ config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */ - config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */ + config_patch_connection(srv, con, COMP_HTTP_USER_AGENT);/* User-Agent: */ config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */ + config_patch_connection(srv, con, COMP_HTTP_REQUEST_METHOD); /* REQUEST_METHOD */ /** their might be a fragment which has to be cut away */ if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) { @@ -270,7 +277,7 @@ */ config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */ - config_patch_connection(srv, con, COMP_HTTP_QUERYSTRING); /* HTTPqs */ + config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */ /* do we have to downgrade to 1.0 ? */ if (!con->conf.allow_http11) { @@ -547,17 +554,14 @@ buffer_copy_string_buffer(srv->tmp_buf, con->physical.path); do { - struct stat st; - if (slash) { buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr); } else { buffer_copy_string_buffer(con->physical.path, srv->tmp_buf); } - if (0 == stat(con->physical.path->ptr, &(st)) && - S_ISREG(st.st_mode)) { - found = 1; + if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { + found = S_ISREG(sce->st.st_mode); break; } @@ -589,6 +593,20 @@ return HANDLER_FINISHED; } +#ifdef HAVE_LSTAT + if ((sce->is_symlink != 0) && !con->conf.follow_symlink) { + con->http_status = 403; + + if (con->conf.log_request_handling) { + log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); + log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); + } + + buffer_reset(con->physical.path); + return HANDLER_FINISHED; + }; +#endif + /* we have a PATHINFO */ if (pathinfo) { buffer_copy_string(con->request.pathinfo, pathinfo); @@ -631,8 +649,14 @@ /* if we are still here, no one wanted the file, status 403 is ok I think */ - if (con->mode == DIRECT) { - con->http_status = 403; + if (con->mode == DIRECT && con->http_status == 0) { + switch (con->request.http_method) { + case HTTP_METHOD_OPTIONS: + con->http_status = 200; + break; + default: + con->http_status = 403; + } return HANDLER_FINISHED; } Index: src/mod_userdir.c =================================================================== --- src/mod_userdir.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_userdir.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -21,6 +21,7 @@ array *include_user; buffer *path; buffer *basepath; + unsigned short letterhomes; } plugin_config; typedef struct { @@ -87,6 +88,7 @@ { "userdir.exclude-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "userdir.include-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { "userdir.basepath", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ + { "userdir.letterhomes", NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION }, /* 4 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -102,11 +104,13 @@ s->include_user = array_init(); s->path = buffer_init(); s->basepath = buffer_init(); + s->letterhomes = 0; cv[0].destination = s->path; cv[1].destination = s->exclude_user; cv[2].destination = s->include_user; cv[3].destination = s->basepath; + cv[4].destination = &(s->letterhomes); p->config_storage[i] = s; @@ -128,6 +132,7 @@ PATCH(exclude_user); PATCH(include_user); PATCH(basepath); + PATCH(letterhomes); /* skip the first, the global context */ for (i = 1; i < srv->config_context->used; i++) { @@ -149,6 +154,8 @@ PATCH(include_user); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) { PATCH(basepath); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.letterhomes"))) { + PATCH(letterhomes); } } } @@ -253,6 +260,10 @@ buffer_copy_string_buffer(p->temp_path, p->conf.basepath); BUFFER_APPEND_SLASH(p->temp_path); + if (p->conf.letterhomes) { + buffer_append_string_len(p->temp_path, p->username->ptr, 1); + BUFFER_APPEND_SLASH(p->temp_path); + } buffer_append_string_buffer(p->temp_path, p->username); } BUFFER_APPEND_SLASH(p->temp_path); Index: src/mod_proxy.c =================================================================== --- src/mod_proxy.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_proxy.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1093,15 +1093,17 @@ if (s_len < ct_len) continue; /* check extension in the form "/proxy_pattern" */ - if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { - if (s_len > ct_len + 1) { - char *pi_offset; + if (*(extension->key->ptr) == '/') { + if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { + if (s_len > ct_len + 1) { + char *pi_offset; - if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) { - path_info_offset = pi_offset - fn->ptr; + if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) { + path_info_offset = pi_offset - fn->ptr; + } } + break; } - break; } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) { /* check extension in the form ".fcg" */ break; @@ -1203,7 +1205,7 @@ } /* didn't found a higher id, wrap to the start */ - if (ndx != -1 && max_usage != INT_MAX) { + if (ndx == -1 && max_usage != INT_MAX) { ndx = max_usage; } Index: src/mod_extforward.c =================================================================== --- src/mod_extforward.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_extforward.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -20,6 +20,7 @@ /** * mod_extforward.c for lighttpd, by comman.kang gmail com * extended, modified by Lionel Elie Mamane (LEM), lionel mamane lu + * support chained proxies by glen@delfi.ee, #1528 * * Config example: * @@ -33,6 +34,10 @@ * Note that "all" has precedence over specific entries, * so "all except" setups will not work. * + * In case you have chained proxies, you can add all their IP's to the + * config. However "all" has effect only on connecting IP, as the + * X-Forwarded-For header can not be trusted. + * * Note: The effect of this module is variable on $HTTP["remotip"] directives and * other module's remote ip dependent actions. * Things done by modules before we change the remoteip or after we reset it will match on the proxy's IP. @@ -225,18 +230,16 @@ char *base, *curr; /* state variable, 0 means not in string, 1 means in string */ int in_str = 0; - for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) - { + for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) { if (in_str) { - if ( (*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':' ) { + if ((*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':') { /* found an separator , insert value into result array */ - put_string_into_array_len(result, base, curr-base); + put_string_into_array_len(result, base, curr - base); /* change state to not in string */ in_str = 0; } } else { - if (*curr >= '0' && *curr <= '9') - { + if (*curr >= '0' && *curr <= '9') { /* found leading char of an IP address, move base pointer and change state */ base = curr; in_str = 1; @@ -244,9 +247,8 @@ } } /* if breaking out while in str, we got to the end of string, so add it */ - if (in_str) - { - put_string_into_array_len(result, base, curr-base); + if (in_str) { + put_string_into_array_len(result, base, curr - base); } } return result; @@ -255,20 +257,42 @@ #define IP_TRUSTED 1 #define IP_UNTRUSTED 0 /* - check whether ip is trusted, return 1 for trusted , 0 for untrusted -*/ + * check whether ip is trusted, return 1 for trusted , 0 for untrusted + */ static int is_proxy_trusted(const char *ipstr, plugin_data *p) { - data_string* allds = (data_string *) array_get_element(p->conf.forwarder,"all"); + data_string* allds = (data_string *)array_get_element(p->conf.forwarder, "all"); + if (allds) { - if (strcasecmp(allds->value->ptr,"trust") == 0) + if (strcasecmp(allds->value->ptr, "trust") == 0) { return IP_TRUSTED; - else + } else { return IP_UNTRUSTED; + } } - return (data_string *)array_get_element(p->conf.forwarder,ipstr) ? IP_TRUSTED : IP_UNTRUSTED ; + + return (data_string *)array_get_element(p->conf.forwarder, ipstr) ? IP_TRUSTED : IP_UNTRUSTED; } +/* + * Return char *ip of last address of proxy that is not trusted. + * Do not accept "all" keyword here. + */ +static const char *last_not_in_array(array *a, plugin_data *p) +{ + array *forwarder = p->conf.forwarder; + + for (int i = a->used - 1; i >= 0; i--) { + data_string *ds = (data_string *)a->data[i]; + const char *ip = ds->value->ptr; + + if (!array_get_element(forwarder, ip)) { + return ip; + } + } + return NULL; +} + struct addrinfo *ipstr_to_sockaddr(const char *host) { struct addrinfo hints, *res0; @@ -305,7 +329,7 @@ static void clean_cond_cache(server *srv, connection *con) { - config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTEIP); + config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTE_IP); } URIHANDLER_FUNC(mod_extforward_uri_handler) { @@ -316,9 +340,8 @@ struct addrinfo *addrlist = NULL; #endif const char *dst_addr_str = NULL; - int i; array *forward_array = NULL; - char *real_remote_addr = NULL; + const char *real_remote_addr = NULL; #ifdef HAVE_IPV6 #endif @@ -342,7 +365,6 @@ return HANDLER_GO_ON; } - /* if the remote ip itself is not trusted , then do nothing */ #ifdef HAVE_IPV6 dst_addr_str = inet_ntop(con->dst_addr.plain.sa_family, con->dst_addr.plain.sa_family == AF_INET6 ? @@ -353,7 +375,9 @@ #else dst_addr_str = inet_ntoa(con->dst_addr.ipv4.sin_addr); #endif - if (IP_UNTRUSTED == is_proxy_trusted (dst_addr_str, p) ) { + + /* if the remote ip itself is not trusted, then do nothing */ + if (IP_UNTRUSTED == is_proxy_trusted(dst_addr_str, p)) { if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "remote address is NOT a trusted proxy, skipping"); @@ -362,40 +386,34 @@ return HANDLER_GO_ON; } + /* build forward_array from forwarded data_string */ forward_array = extract_forward_array(forwarded->value); + real_remote_addr = last_not_in_array(forward_array, p); - /* Testing shows that multiple headers and multiple values in one header - come in _reverse_ order. So the first one we get is the last one in the request. */ - for (i = forward_array->used - 1; i >= 0; i--) { - data_string *ds = (data_string *) forward_array->data[i]; - if (ds) { - real_remote_addr = ds->value->ptr; - break; - } else { - /* bug ? bailing out here */ - break; - } - } - if (real_remote_addr != NULL) { /* parsed */ sock_addr sock; - struct addrinfo *addrs_left; + server_socket *srv_sock = con->srv_socket; + data_string *forwarded_proto = (data_string *)array_get_element(con->request.headers, "X-Forwarded-Proto"); + if (forwarded_proto && !strcmp(forwarded_proto->value->ptr, "https")) { + srv_sock->is_proxy_ssl = 1; + } else { + srv_sock->is_proxy_ssl = 0; + } + if (con->conf.log_request_handling) { - log_error_write(srv, __FILE__, __LINE__, "ss", - "using address:", real_remote_addr); + log_error_write(srv, __FILE__, __LINE__, "ss", "using address:", real_remote_addr); } #ifdef HAVE_IPV6 addrlist = ipstr_to_sockaddr(real_remote_addr); sock.plain.sa_family = AF_UNSPEC; - for (addrs_left = addrlist; addrs_left != NULL; - addrs_left = addrs_left -> ai_next) { + for (addrs_left = addrlist; addrs_left != NULL; addrs_left = addrs_left -> ai_next) { sock.plain.sa_family = addrs_left->ai_family; - if ( sock.plain.sa_family == AF_INET ) { + if (sock.plain.sa_family == AF_INET) { sock.ipv4.sin_addr = ((struct sockaddr_in*)addrs_left->ai_addr)->sin_addr; break; - } else if ( sock.plain.sa_family == AF_INET6 ) { + } else if (sock.plain.sa_family == AF_INET6) { sock.ipv6.sin6_addr = ((struct sockaddr_in6*)addrs_left->ai_addr)->sin6_addr; break; } @@ -430,7 +448,7 @@ if (addrlist != NULL ) freeaddrinfo(addrlist); #endif } - array_free(forward_array); + array_free(forward_array); /* not found */ return HANDLER_GO_ON; Index: src/Makefile.am =================================================================== --- src/Makefile.am (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/Makefile.am (.../branches/lighttpd-1.4.x) (revision 2118) @@ -16,20 +16,20 @@ configparser.c configparser.h: mod_ssi_exprparser.c mod_ssi_exprparser.h: else -configparser.y: lemon -mod_ssi_exprparser.y: lemon +$(srcdir)/configparser.y: lemon +$(srcdir)/mod_ssi_exprparser.y: lemon -configparser.c configparser.h: configparser.y +configparser.c configparser.h: $(srcdir)/configparser.y rm -f configparser.h $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c -mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y +mod_ssi_exprparser.c mod_ssi_exprparser.h: $(srcdir)/mod_ssi_exprparser.y rm -f mod_ssi_exprparser.h $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c endif -configfile.c: configparser.h -mod_ssi_expr.c: mod_ssi_exprparser.h +$(srcdir)/configfile.c: configparser.h +$(srcdir)/mod_ssi_expr.c: mod_ssi_exprparser.h common_src=buffer.c log.c \ keyvalue.c chunk.c \ @@ -281,4 +281,4 @@ #ajp_SOURCES = ajp.c noinst_HEADERS = $(hdr) -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c SConscript Index: src/network_openssl.c =================================================================== --- src/network_openssl.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/network_openssl.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -58,31 +58,6 @@ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); } - /* evil hack for opera 9.01 and 8.54 and earlier - * - * opera hangs if the trainling 0\r\n\r\n is in a seperate SSL-packet - * - * we try to move the packet into the previous mem-chunk if possible - */ - if ((cq == con->write_queue) && - (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) && - (con->file_finished)) { - /* merge the last chunk into the previous chunk */ - - for(c = cq->first; c && c->next && c->next->next; c = c->next); - - if (c && - c->type == MEM_CHUNK && - c->next && - c->next->type == MEM_CHUNK && - c->next->mem->used == sizeof("0\r\n\r\n") && - 0 == strcmp(c->next->mem->ptr, "0\r\n\r\n")) { - buffer_append_string_buffer(c->mem, c->next->mem); - - c->next->mem->used = 0; - } - } - for(c = cq->first; c; c = c->next) { int chunk_finished = 0; @@ -128,6 +103,7 @@ /* no, but we have errno */ switch(errno) { case EPIPE: + case ECONNRESET: return -2; default: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", @@ -230,6 +206,7 @@ /* no, but we have errno */ switch(errno) { case EPIPE: + case ECONNRESET: return -2; default: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", Index: src/http_auth.c =================================================================== --- src/http_auth.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/http_auth.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -29,6 +29,7 @@ #include "log.h" #include "http_auth.h" #include "http_auth_digest.h" +#include "inet_ntop_cache.h" #include "stream.h" #ifdef USE_OPENSSL @@ -862,7 +863,7 @@ /* password doesn't match */ if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) { - log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username); + log_error_write(srv, __FILE__, __LINE__, "sbbss", "password doesn't match for ", con->uri.path, username, ", IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr))); buffer_free(username); buffer_free(password); @@ -1130,7 +1131,7 @@ } log_error_write(srv, __FILE__, __LINE__, "sss", - "digest: auth failed for", username, "wrong password"); + "digest: auth failed for ", username, ": wrong password, IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr))); buffer_free(b); return 0; Index: src/configparser.y =================================================================== --- src/configparser.y (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/configparser.y (.../branches/lighttpd-1.4.x) (revision 2118) @@ -51,7 +51,7 @@ return NULL; } -/* op1 is to be eat/return by this function, op1->key is not cared +/* op1 is to be eat/return by this function if success, op1->key is not cared op2 is left untouch, unreferenced */ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { @@ -69,7 +69,6 @@ return (data_unset *)ds; } else { fprintf(stderr, "data type mismatch, cannot be merge\n"); - op1->free(op1); return NULL; } } @@ -123,6 +122,7 @@ %type aelement {data_unset *} %type condline {data_config *} %type condlines {data_config *} +%type global {data_config *} %type aelements {array *} %type array {array *} %type key {buffer *} @@ -142,22 +142,24 @@ %token_destructor { buffer_free($$); } varline ::= key(A) ASSIGN expression(B). { - buffer_copy_string_buffer(B->key, A); - if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) { - fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", - ctx->current->context_ndx, - ctx->current->key->ptr, A->ptr); - ctx->ok = 0; - } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) { - array_insert_unique(ctx->current->value, B); - B = NULL; - } else { - fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", - ctx->current->context_ndx, - ctx->current->key->ptr, B->key->ptr); - ctx->ok = 0; - B->free(B); - B = NULL; + if (ctx->ok) { + buffer_copy_string_buffer(B->key, A); + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) { + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", + ctx->current->context_ndx, + ctx->current->key->ptr, A->ptr); + ctx->ok = 0; + } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) { + array_insert_unique(ctx->current->value, B); + B = NULL; + } else { + fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", + ctx->current->context_ndx, + ctx->current->key->ptr, B->key->ptr); + ctx->ok = 0; + B->free(B); + B = NULL; + } } buffer_free(A); A = NULL; @@ -187,6 +189,7 @@ du = configparser_merge_data(du, B); if (NULL == du) { ctx->ok = 0; + du->free(du); } else { buffer_copy_string_buffer(du->key, A); @@ -418,10 +421,15 @@ { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) }, { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) }, { COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) }, - { COMP_HTTP_USERAGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) }, + { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) }, + { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) }, { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) }, - { COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) }, - { COMP_HTTP_QUERYSTRING, CONST_STR_LEN("HTTP[\"querystring\"]") }, + { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) }, + { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) }, + { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") }, + { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") }, + { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") }, + { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) }, { COMP_UNSET, NULL, 0 }, }; size_t i; Index: src/mod_status.c =================================================================== --- src/mod_status.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_status.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -560,6 +560,8 @@ double avg; time_t ts; char buf[32]; + unsigned int k; + unsigned int l; b = chunkqueue_get_append_buffer(con->write_queue); @@ -588,6 +590,22 @@ buffer_append_long(b, srv->conns->used); BUFFER_APPEND_STRING_CONST(b, "\n"); + BUFFER_APPEND_STRING_CONST(b, "IdleServers: "); + buffer_append_long(b, srv->conns->size - srv->conns->used); + BUFFER_APPEND_STRING_CONST(b, "\n"); + + /* output scoreboard */ + BUFFER_APPEND_STRING_CONST(b, "Scoreboard: "); + for (k = 0; k < srv->conns->used; k++) { + connection *c = srv->conns->ptr[k]; + const char *state = connection_get_short_state(c->state); + buffer_append_string_len(b, state, 1); + } + for (l = 0; l < srv->conns->size - srv->conns->used; l++) { + BUFFER_APPEND_STRING_CONST(b, "_"); + } + BUFFER_APPEND_STRING_CONST(b, "\n"); + /* set text/plain output */ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain")); Index: src/mod_compress.c =================================================================== --- src/mod_compress.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_compress.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -102,6 +102,50 @@ return HANDLER_GO_ON; } +// 0 on success, -1 for error +int mkdir_recursive(char *dir) { + char *p = dir; + + if (!dir || !dir[0]) + return 0; + + while ((p = strchr(p + 1, '/')) != NULL) { + + *p = '\0'; + if ((mkdir(dir, 0700) != 0) && (errno != EEXIST)) { + *p = '/'; + return -1; + } + + *p++ = '/'; + if (!*p) return 0; // Ignore trailing slash + } + + return (mkdir(dir, 0700) != 0) && (errno != EEXIST) ? -1 : 0; +} + +// 0 on success, -1 for error +int mkdir_for_file(char *filename) { + char *p = filename; + + if (!filename || !filename[0]) + return -1; + + while ((p = strchr(p + 1, '/')) != NULL) { + + *p = '\0'; + if ((mkdir(filename, 0700) != 0) && (errno != EEXIST)) { + *p = '/'; + return -1; + } + + *p++ = '/'; + if (!*p) return -1; // Unexpected trailing slash in filename + } + + return 0; +} + SETDEFAULTS_FUNC(mod_compress_setdefaults) { plugin_data *p = p_d; size_t i = 0; @@ -134,6 +178,8 @@ } if (!buffer_is_empty(s->compress_cache_dir)) { + mkdir_recursive(s->compress_cache_dir->ptr); + struct stat st; if (0 != stat(s->compress_cache_dir->ptr, &st)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir", @@ -342,27 +388,8 @@ BUFFER_APPEND_SLASH(p->ofn); if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) { - size_t offset = p->ofn->used - 1; - char *dir, *nextdir; - buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1); - buffer_copy_string_buffer(p->b, p->ofn); - - /* mkdir -p ... */ - for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) { - *nextdir = '\0'; - - if (-1 == mkdir(p->b->ptr, 0700)) { - if (errno != EEXIST) { - log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno)); - - return -1; - } - } - - *nextdir = '/'; - } } else { buffer_append_string_buffer(p->ofn, con->uri.path); } @@ -384,6 +411,11 @@ buffer_append_string_buffer(p->ofn, sce->etag); + if (-1 == mkdir_for_file(p->ofn->ptr)) { + log_error_write(srv, __FILE__, __LINE__, "sb", "couldn't create directory for file", p->ofn); + return -1; + } + if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) { if (errno == EEXIST) { /* cache-entry exists */ @@ -407,6 +439,11 @@ close(ofd); + /* Remove the incomplete cache file, so that later hits aren't served from it */ + if (-1 == unlink(p->ofn->ptr)) { + log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno)); + } + return -1; } @@ -416,6 +453,12 @@ close(ofd); close(ifd); + + /* Remove the incomplete cache file, so that later hits aren't served from it */ + if (-1 == unlink(p->ofn->ptr)) { + log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno)); + } + return -1; } @@ -438,23 +481,30 @@ break; } - if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) { - munmap(start, sce->st.st_size); - close(ofd); - close(ifd); - return -1; + if (ret == 0) { + r = write(ofd, p->b->ptr, p->b->used); + if (-1 == r) { + log_error_write(srv, __FILE__, __LINE__, "sbss", "writing cachefile", p->ofn, "failed:", strerror(errno)); + ret = -1; + } else if ((size_t)r != p->b->used) { + log_error_write(srv, __FILE__, __LINE__, "sbs", "writing cachefile", p->ofn, "failed: not enough bytes written"); + ret = -1; + } } - if ((size_t)r != p->b->used) { - - } - munmap(start, sce->st.st_size); close(ofd); close(ifd); - if (ret != 0) return -1; + if (ret != 0) { + /* Remove the incomplete cache file, so that later hits aren't served from it */ + if (-1 == unlink(p->ofn->ptr)) { + log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno)); + } + return -1; + } + buffer_copy_string_buffer(con->physical.path, p->ofn); return 0; @@ -570,6 +620,8 @@ off_t max_fsize; stat_cache_entry *sce = NULL; + if (con->mode != DIRECT || con->http_status) return HANDLER_GO_ON; + /* only GET and POST can get compressed */ if (con->request.http_method != HTTP_METHOD_GET && con->request.http_method != HTTP_METHOD_POST) { @@ -678,8 +730,16 @@ } } else if (0 == deflate_file_to_buffer(srv, con, p, con->physical.path, sce, compression_type)) { + buffer *mtime; response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name)); + + mtime = strftime_cache_get(srv, sce->st.st_mtime); + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime)); + + 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("Content-Type"), CONST_BUF_LEN(sce->content_type)); return HANDLER_FINISHED; Index: src/mod_ssi.c =================================================================== --- src/mod_ssi.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_ssi.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -36,6 +36,11 @@ #include #endif +#include "etag.h" + +/* The newest modified time of included files for include statement */ +static volatile time_t include_file_last_mtime = 0; + /* init the plugin data */ INIT_FUNC(mod_ssi_init) { plugin_data *p; @@ -575,6 +580,11 @@ break; case SSI_INCLUDE: chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size); + + /* Keep the newest mtime of included files */ + if (st.st_mtime > include_file_last_mtime) + include_file_last_mtime = st.st_mtime; + break; } } else { @@ -912,6 +922,9 @@ build_ssi_cgi_vars(srv, con, p); p->if_is_false = 0; + /* Reset the modified time of included files */ + include_file_last_mtime = 0; + if (-1 == stream_open(&s, con->physical.path)) { log_error_write(srv, __FILE__, __LINE__, "sb", "stream-open: ", con->physical.path); @@ -1010,6 +1023,30 @@ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); + { + /* Generate "ETag" & "Last-Modified" headers */ + + stat_cache_entry *sce = NULL; + time_t lm_time = 0; + buffer *mtime = NULL; + + stat_cache_get_entry(srv, con, con->physical.path, &sce); + + etag_mutate(con->physical.etag, sce->etag); + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag)); + + if (sce->st.st_mtime > include_file_last_mtime) + lm_time = sce->st.st_mtime; + else + lm_time = include_file_last_mtime; + + mtime = strftime_cache_get(srv, lm_time); + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime)); + } + + /* Reset the modified time of included files */ + include_file_last_mtime = 0; + /* reset physical.path */ buffer_reset(con->physical.path); Index: src/spawn-fcgi.c =================================================================== --- src/spawn-fcgi.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/spawn-fcgi.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -37,7 +37,7 @@ #endif #ifdef HAVE_SYS_UN_H -int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const char *unixsocket, int child_count, int pid_fd, int nofork) { +int fcgi_spawn_connection(char *appPath, char **appArgv, 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 }; @@ -48,6 +48,9 @@ socklen_t servlen; + pid_t child; + int val; + if (child_count < 2) { child_count = 5; } @@ -71,6 +74,25 @@ #endif socket_type = AF_UNIX; fcgi_addr = (struct sockaddr *) &fcgi_addr_un; + + /* check if some backend is listening on the socket + * as if we delete the socket-file and rebind there will be no "socket already in use" error + */ + if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { + fprintf(stderr, "%s.%d\n", + __FILE__, __LINE__); + return -1; + } + + if (-1 != connect(fcgi_fd, fcgi_addr, servlen)) { + fprintf(stderr, "%s.%d: socket is already used, can't spawn\n", + __FILE__, __LINE__); + return -1; + } + + /* cleanup previous socket if it exists */ + unlink(unixsocket); + close(fcgi_fd); } else { fcgi_addr_in.sin_family = AF_INET; if (addr != NULL) { @@ -85,144 +107,128 @@ fcgi_addr = (struct sockaddr *) &fcgi_addr_in; } + /* open socket */ if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { fprintf(stderr, "%s.%d\n", __FILE__, __LINE__); return -1; } - if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { - /* server is not up, spawn in */ - pid_t child; - int val; + val = 1; + if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { + fprintf(stderr, "%s.%d\n", + __FILE__, __LINE__); + return -1; + } - if (unixsocket) unlink(unixsocket); + /* create socket */ + if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { + fprintf(stderr, "%s.%d: bind failed: %s\n", + __FILE__, __LINE__, + strerror(errno)); + return -1; + } - close(fcgi_fd); + if (-1 == listen(fcgi_fd, 1024)) { + fprintf(stderr, "%s.%d: fd = -1\n", + __FILE__, __LINE__); + return -1; + } - /* reopen socket */ - if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - fprintf(stderr, "%s.%d\n", - __FILE__, __LINE__); - return -1; - } + if (!nofork) { + child = fork(); + } else { + child = 0; + } - val = 1; - if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { - fprintf(stderr, "%s.%d\n", - __FILE__, __LINE__); - return -1; - } + switch (child) { + case 0: { + char cgi_childs[64]; - /* create socket */ - if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { - fprintf(stderr, "%s.%d: bind failed: %s\n", - __FILE__, __LINE__, - strerror(errno)); - return -1; - } + int i = 0; - if (-1 == listen(fcgi_fd, 1024)) { - fprintf(stderr, "%s.%d: fd = -1\n", - __FILE__, __LINE__); - return -1; + /* is safe as we limit to 256 childs */ + sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count); + + if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { + close(FCGI_LISTENSOCK_FILENO); + dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); + close(fcgi_fd); } - if (!nofork) { - child = fork(); - } else { - child = 0; + /* we don't need the client socket */ + for (i = 3; i < 256; i++) { + close(i); } - switch (child) { - case 0: { - char cgi_childs[64]; - char *b; + /* create environment */ - int i = 0; + putenv(cgi_childs); - /* is save as we limit to 256 childs */ - sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count); + /* fork and replace shell */ + if (appArgv) { + execv(appArgv[0], appArgv); - if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { - close(FCGI_LISTENSOCK_FILENO); - dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); - close(fcgi_fd); - } - - /* we don't need the client socket */ - for (i = 3; i < 256; i++) { - close(i); - } - - /* create environment */ - - putenv(cgi_childs); - - /* fork and replace shell */ - b = malloc(strlen("exec ") + strlen(appPath) + 1); + } else { + char *b = malloc(strlen("exec ") + strlen(appPath) + 1); strcpy(b, "exec "); strcat(b, appPath); /* exec the cgi */ execl("/bin/sh", "sh", "-c", b, (char *)NULL); + } - exit(errno); + exit(errno); - break; - } - case -1: - /* error */ - break; - default: - /* father */ + break; + } + case -1: + /* error */ + break; + default: + /* father */ - /* wait */ - select(0, NULL, NULL, NULL, &tv); + /* wait */ + select(0, NULL, NULL, NULL, &tv); - switch (waitpid(child, &status, WNOHANG)) { - case 0: - fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", - __FILE__, __LINE__, - child); + switch (waitpid(child, &status, WNOHANG)) { + case 0: + fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", + __FILE__, __LINE__, + child); - /* write pid file */ - if (pid_fd != -1) { - /* assume a 32bit pid_t */ - char pidbuf[12]; + /* write pid file */ + if (pid_fd != -1) { + /* assume a 32bit pid_t */ + char pidbuf[12]; - snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); + snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); - write(pid_fd, pidbuf, strlen(pidbuf)); - close(pid_fd); - pid_fd = -1; - } - - break; - case -1: - break; - default: - if (WIFEXITED(status)) { - fprintf(stderr, "%s.%d: child exited with: %d, %s\n", - __FILE__, __LINE__, - WEXITSTATUS(status), strerror(WEXITSTATUS(status))); - } else if (WIFSIGNALED(status)) { - fprintf(stderr, "%s.%d: child signaled: %d\n", - __FILE__, __LINE__, - WTERMSIG(status)); - } else { - fprintf(stderr, "%s.%d: child died somehow: %d\n", - __FILE__, __LINE__, - status); - } + write(pid_fd, pidbuf, strlen(pidbuf)); + close(pid_fd); + pid_fd = -1; } break; + case -1: + break; + default: + if (WIFEXITED(status)) { + fprintf(stderr, "%s.%d: child exited with: %d, %s\n", + __FILE__, __LINE__, + WEXITSTATUS(status), strerror(WEXITSTATUS(status))); + } else if (WIFSIGNALED(status)) { + fprintf(stderr, "%s.%d: child signaled: %d\n", + __FILE__, __LINE__, + WTERMSIG(status)); + } else { + fprintf(stderr, "%s.%d: child died somehow: %d\n", + __FILE__, __LINE__, + status); + } } - } else { - fprintf(stderr, "%s.%d: socket is already used, can't spawn\n", - __FILE__, __LINE__); - return -1; + + break; } close(fcgi_fd); @@ -239,9 +245,12 @@ } void show_help () { - char *b = "spawn-fcgi" "-" PACKAGE_VERSION \ -" - spawns fastcgi processes\n" \ -"usage:\n" \ + char *b = \ +"Usage: spawn-fcgi [options] -- [fcgi app arguments]\n" \ +"\n" \ +"spawn-fcgi v" PACKAGE_VERSION " - spawns fastcgi processes\n" \ +"\n" \ +"Options:\n" \ " -f filename of the fcgi-application\n" \ " -a bind to ip address\n" \ " -p bind to tcp-port\n" \ @@ -264,6 +273,7 @@ char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, *groupname = NULL, *unixsocket = NULL, *pid_file = NULL, *addr = NULL; + char **fcgi_app_argv = { NULL }; unsigned short port = 0; int child_count = 5; int i_am_root, o; @@ -274,10 +284,10 @@ i_am_root = (getuid() == 0); - while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p: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 '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; @@ -294,7 +304,11 @@ } } - if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) { + if (optind < argc) { + fcgi_app_argv = &argv[optind]; + } + + if ((fcgi_app == NULL && fcgi_app_argv == NULL) || (port == 0 && unixsocket == NULL)) { show_help(); return -1; } @@ -404,6 +418,18 @@ } } + /* + * Change group before chroot, when we have access + * to /etc/group + */ + if (groupname) { + setgid(grp->gr_gid); + setgroups(0, NULL); + if (username) { + initgroups(username, grp->gr_gid); + } + } + if (changeroot) { if (-1 == chroot(changeroot)) { fprintf(stderr, "%s.%d: %s %s\n", @@ -420,18 +446,12 @@ } /* drop root privs */ - if (groupname) { - setgid(grp->gr_gid); - } if (username) { - if (groupname) { - initgroups(username, grp->gr_gid); - } setuid(pwd->pw_uid); } } - return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork); + return fcgi_spawn_connection(fcgi_app, fcgi_app_argv, addr, port, unixsocket, child_count, pid_fd, nofork); } #else int main() { Index: src/mod_auth.c =================================================================== --- src/mod_auth.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_auth.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -238,13 +238,13 @@ int auth_type_len = auth_realm - http_authorization; if ((auth_type_len == 5) && - (0 == strncmp(http_authorization, "Basic", auth_type_len))) { + (0 == strncasecmp(http_authorization, "Basic", auth_type_len))) { if (0 == strcmp(method->value->ptr, "basic")) { auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1); } } else if ((auth_type_len == 6) && - (0 == strncmp(http_authorization, "Digest", auth_type_len))) { + (0 == strncasecmp(http_authorization, "Digest", auth_type_len))) { if (0 == strcmp(method->value->ptr, "digest")) { if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) { con->http_status = 400; Index: src/mod_fastcgi.c =================================================================== --- src/mod_fastcgi.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/mod_fastcgi.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -162,8 +162,8 @@ * if host is one of the local IP adresses the * whole connection is local * - * if tcp/ip should be used host AND port have - * to be specified + * if port is not 0, and host is not specified, + * "localhost" (INADDR_LOOPBACK) is assumed. * */ buffer *host; @@ -823,12 +823,12 @@ fcgi_addr_in.sin_family = AF_INET; if (buffer_is_empty(host->host)) { - fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); + fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } else { struct hostent *he; /* set a useful default */ - fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); + fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (NULL == (he = gethostbyname(host->host->ptr))) { @@ -858,7 +858,11 @@ fcgi_addr = (struct sockaddr *) &fcgi_addr_in; buffer_copy_string(proc->connection_name, "tcp:"); - buffer_append_string_buffer(proc->connection_name, host->host); + if (!buffer_is_empty(host->host)) { + buffer_append_string_buffer(proc->connection_name, host->host); + } else { + buffer_append_string(proc->connection_name, "localhost"); + } buffer_append_string(proc->connection_name, ":"); buffer_append_long(proc->connection_name, proc->port); } @@ -1687,12 +1691,16 @@ #endif } else { fcgi_addr_in.sin_family = AF_INET; - if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "converting IP address failed for", host->host, - "\nBe sure to specify an IP address here"); - - return -1; + if (!buffer_is_empty(host->host)) { + if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) { + log_error_write(srv, __FILE__, __LINE__, "sbs", + "converting IP address failed for", host->host, + "\nBe sure to specify an IP address here"); + + return -1; + } + } else { + fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } fcgi_addr_in.sin_port = htons(proc->port); servlen = sizeof(fcgi_addr_in); @@ -1702,7 +1710,11 @@ 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); + if (!buffer_is_empty(host->host)) { + buffer_append_string_buffer(proc->connection_name, host->host); + } else { + buffer_append_string(proc->connection_name, "localhost"); + } buffer_append_string(proc->connection_name, ":"); buffer_append_long(proc->connection_name, proc->port); } @@ -2045,13 +2057,10 @@ s = get_http_version_name(con->request.http_version); FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con) -#ifdef USE_OPENSSL - if (srv_sock->is_ssl) { + if (srv_sock->is_ssl || srv_sock->is_proxy_ssl) { FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")),con) } -#endif - FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con); fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0); @@ -2530,15 +2539,28 @@ } if (host->allow_xsendfile && - NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) { + (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file")) + || NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile")))) { stat_cache_entry *sce; if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) { + data_string *dcls = data_string_init(); /* found */ - http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size); hctx->send_content_body = 0; /* ignore the content */ joblist_append(srv, con); + + buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1); + buffer_copy_long(dcls->value, sce->st.st_size); + dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls); + if (dcls) dcls->free((data_unset*)dcls); + + con->parsed_response |= HTTP_CONTENT_LENGTH; + con->response.content_length = sce->st.st_size; + } else { + log_error_write(srv, __FILE__, __LINE__, "sb", + "send-file error: couldn't get stat_cache entry for:", + ds->value); } } @@ -2719,9 +2741,14 @@ int ret; - /* sanity check */ + /* sanity check: + * - host != NULL + * - either: + * - tcp socket (do not check host->host->uses, as it may be not set which means INADDR_LOOPBACK) + * - unix socket + */ if (!host || - ((!host->host->used || !host->port) && !host->unixsocket->used)) { + (!host->port && !host->unixsocket->used)) { log_error_write(srv, __FILE__, __LINE__, "sxddd", "write-req: error", host, @@ -3456,8 +3483,9 @@ if (s_len < ct_len) continue; /* check extension in the form "/fcgi_pattern" */ - if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { - break; + if (*(extension->key->ptr) == '/') { + if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) + break; } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) { /* check extension in the form ".fcg" */ break; @@ -3473,7 +3501,7 @@ for (k = 0; k < extension->used; k++) { host = extension->hosts[k]; - /* we should have at least one proc that can do somthing */ + /* we should have at least one proc that can do something */ if (host->active_procs == 0) { host = NULL; Index: src/stream.c =================================================================== --- src/stream.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/stream.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -64,6 +64,7 @@ NULL); if (!mh) { +/* LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | @@ -73,7 +74,7 @@ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); - +*/ return -1; } Index: src/server.c =================================================================== --- src/server.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/server.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -697,9 +697,6 @@ } } - /* #372: solaris need some fds extra for devpoll */ - if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10; - if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { @@ -759,6 +756,19 @@ return -1; } +#ifdef HAVE_PWD_H + /* + * Change group before chroot, when we have access + * to /etc/group + * */ + if (srv->srvconf.groupname->used) { + setgid(grp->gr_gid); + setgroups(0, NULL); + if (srv->srvconf.username->used) { + initgroups(srv->srvconf.username->ptr, grp->gr_gid); + } + } +#endif #ifdef HAVE_CHROOT if (srv->srvconf.changeroot->used) { tzset(); @@ -775,15 +785,7 @@ #endif #ifdef HAVE_PWD_H /* drop root privs */ - if (srv->srvconf.groupname->used) { - setgid(grp->gr_gid); - setgroups(0, NULL); - } - if (srv->srvconf.username->used) { - if (srv->srvconf.groupname->used) { - initgroups(srv->srvconf.username->ptr, grp->gr_gid); - } setuid(pwd->pw_uid); } #endif @@ -891,6 +893,17 @@ pid_fd = -1; } + // Close stderr ASAP in the child process to make sure that nothing + // is being written to that fd which may not be valid anymore. + if (-1 == log_error_open(srv)) { + log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down."); + + plugins_free(srv); + network_close(srv); + server_free(srv); + return -1; + } + if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); @@ -941,15 +954,7 @@ return -1; } - if (-1 == log_error_open(srv)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "opening errorlog failed, dying"); - plugins_free(srv); - network_close(srv); - server_free(srv); - return -1; - } #ifdef HAVE_SIGACTION Index: src/network_linux_sendfile.c =================================================================== --- src/network_linux_sendfile.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ src/network_linux_sendfile.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -162,6 +162,7 @@ switch (errno) { case EAGAIN: case EINTR: + /* ok, we can't send more, let's try later again */ r = 0; break; case EPIPE: @@ -172,9 +173,7 @@ "sendfile failed:", strerror(errno), fd); return -1; } - } - - if (r == 0) { + } else if (r == 0) { int oerrno = errno; /* We got an event to write but we wrote nothing * Index: tests/mod-access.t =================================================================== --- tests/mod-access.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/mod-access.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/mod-auth.t =================================================================== --- tests/mod-auth.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/mod-auth.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,14 +1,14 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; use IO::Socket; -use Test::More tests => 13; +use Test::More tests => 14; use LightyTest; my $tf = LightyTest->new(); @@ -48,6 +48,16 @@ $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (des)'); +$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (des) (lowercase)'); + + SKIP: { skip "no md5 for crypt under cygwin", 1 if $^O eq 'cygwin'; $t->{REQUEST} = ( < "text/html" ) + +cgi.assign = (".pl" => "/usr/bin/perl" ) + +extforward.forwarder = ( + "127.0.0.1" => "trust", + "127.0.30.1" => "trust", +) Index: tests/symlink.t =================================================================== Index: tests/request.t =================================================================== --- tests/request.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/request.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/mod-userdir.t =================================================================== --- tests/mod-userdir.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/mod-userdir.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/core-keepalive.t =================================================================== --- tests/core-keepalive.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/core-keepalive.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,10 +1,9 @@ #!/usr/bin/env perl - BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/mod-proxy.t =================================================================== Index: tests/env-variables.t =================================================================== Index: tests/core-var-include.t =================================================================== --- tests/core-var-include.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/core-var-include.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/mod-extforward.t =================================================================== --- tests/mod-extforward.t (.../tags/lighttpd-1.4.18) (revision 0) +++ tests/mod-extforward.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -0,0 +1,48 @@ +#!/usr/bin/env perl +BEGIN { + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; +} + +use strict; +use IO::Socket; +use Test::More tests => 5; +use LightyTest; + +my $tf = LightyTest->new(); +my $t; + +$tf->{CONFIGFILE} = 'mod-extforward.conf'; + +ok($tf->start_proc == 0, "Starting lighttpd") or die(); + +$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.10.1' } ]; +ok($tf->handle_http($t) == 0, 'expect 127.0.10.1, from single ip'); + +$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.20.1' } ]; +ok($tf->handle_http($t) == 0, 'expect 127.0.20.1, from two ips'); + +$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '127.0.20.1' } ]; +ok($tf->handle_http($t) == 0, 'expect 127.0.20.1, from chained proxies'); + +ok($tf->stop_proc == 0, "Stopping lighttpd"); Property changes on: tests/mod-extforward.t ___________________________________________________________________ Name: svn:executable + * Index: tests/core-request.t =================================================================== --- tests/core-request.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/core-request.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/mod-redirect.t =================================================================== --- tests/mod-redirect.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/mod-redirect.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/mod-cgi.t =================================================================== --- tests/mod-cgi.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/mod-cgi.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/mod-setenv.t =================================================================== --- tests/mod-setenv.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/mod-setenv.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,10 +1,9 @@ #!/usr/bin/env perl - BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/cachable.t =================================================================== --- tests/cachable.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/cachable.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/lowercase.t =================================================================== --- tests/lowercase.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/lowercase.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/fcgi-responder.c =================================================================== --- tests/fcgi-responder.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/fcgi-responder.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,4 +1,6 @@ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif #ifdef HAVE_FASTCGI_FASTCGI_H #include #else Index: tests/fcgi-auth.c =================================================================== --- tests/fcgi-auth.c (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/fcgi-auth.c (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,4 +1,6 @@ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif #ifdef HAVE_FASTCGI_FASTCGI_H #include #else Index: tests/core.t =================================================================== --- tests/core.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/core.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,10 +1,9 @@ #!/usr/bin/env perl - BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/mod-fastcgi.t =================================================================== --- tests/mod-fastcgi.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/mod-fastcgi.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,13 +1,13 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; -use Test::More tests => 46; +use Test::More tests => 47; use LightyTest; my $tf = LightyTest->new(); @@ -223,7 +223,7 @@ } SKIP: { - skip "no php found", 4 unless -x "/usr/bin/php-cgi"; + skip "no php found", 5 unless -x "/usr/bin/php-cgi"; $tf->{CONFIGFILE} = 'fastcgi-13.conf'; ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die(); $t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'FastCGI + local spawning'); + $t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-Content-Length' => '0' } ]; + # Of course a valid content-length != 0 would be ok, but we assume for now that such one is not generated. + ok($tf->handle_http($t) == 0, 'Check for buggy content length with HEAD'); + $t->{REQUEST} = ( < %s\n", $key, $value; + } +} + +0; Property changes on: tests/docroot/www/ip.pl ___________________________________________________________________ Name: svn:executable + * Index: tests/Makefile.am =================================================================== --- tests/Makefile.am (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/Makefile.am (.../branches/lighttpd-1.4.x) (revision 2118) @@ -31,14 +31,20 @@ core-response.t \ core-keepalive.t \ core.t \ + mod-proxy.t \ + proxy.conf \ + mod-secdownload.t \ mod-access.t \ mod-auth.t \ mod-cgi.t \ mod-compress.t \ mod-fastcgi.t \ mod-redirect.t \ + mod-rewrite.t \ mod-userdir.t \ - mod-rewrite.t \ + env-variables.t \ + env-variables.conf \ + symlink.t \ request.t \ mod-ssi.t \ LightyTest.pm \ @@ -49,12 +55,12 @@ core-404-handler.t \ 404-handler.conf - TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) EXTRA_DIST=wrapper.sh lighttpd.conf \ lighttpd.user \ lighttpd.htpasswd \ + SConscript \ $(CONFS) \ $(TESTS) Index: tests/core-404-handler.t =================================================================== --- tests/core-404-handler.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/core-404-handler.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -10,10 +10,10 @@ # returning no status -> 200 # BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/mod-compress.t =================================================================== --- tests/mod-compress.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/mod-compress.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/LightyTest.pm =================================================================== --- tests/LightyTest.pm (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/LightyTest.pm (.../branches/lighttpd-1.4.x) (revision 2118) @@ -72,7 +72,7 @@ if (defined $pid) { kill('TERM',$pid) or return -1; - select(undef, undef, undef, 0.01); + select(undef, undef, undef, 0.1); } return 0; Index: tests/mod-ssi.t =================================================================== --- tests/mod-ssi.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/mod-ssi.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/core-condition.t =================================================================== --- tests/core-condition.t (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/core-condition.t (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; Index: tests/run-tests.pl =================================================================== --- tests/run-tests.pl (.../tags/lighttpd-1.4.18) (revision 2118) +++ tests/run-tests.pl (.../branches/lighttpd-1.4.x) (revision 2118) @@ -3,7 +3,7 @@ use strict; use Test::Harness qw(&runtests $verbose); -$verbose=0; +$verbose = (defined $ENV{'VERBOSE'} ? $ENV{'VERBOSE'} : 0);; my $srcdir = (defined $ENV{'srcdir'} ? $ENV{'srcdir'} : '.'); Index: doc/configuration.txt =================================================================== --- doc/configuration.txt (.../tags/lighttpd-1.4.18) (revision 2118) +++ doc/configuration.txt (.../branches/lighttpd-1.4.x) (revision 2118) @@ -85,6 +85,8 @@ $HTTP["cookie"] match on cookie +$HTTP["scheme"] + match on scheme $HTTP["host"] match on host $HTTP["useragent"] Index: doc/lighttpd.conf =================================================================== --- doc/lighttpd.conf (.../tags/lighttpd-1.4.18) (revision 2118) +++ doc/lighttpd.conf (.../branches/lighttpd-1.4.x) (revision 2118) @@ -72,6 +72,7 @@ ".ogg" => "application/ogg", ".wav" => "audio/x-wav", ".gif" => "image/gif", + ".jar" => "application/x-java-archive", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".png" => "image/png", Index: SConstruct =================================================================== Index: Makefile.am =================================================================== --- Makefile.am (.../tags/lighttpd-1.4.18) (revision 2118) +++ Makefile.am (.../branches/lighttpd-1.4.x) (revision 2118) @@ -1,3 +1,3 @@ SUBDIRS=src doc tests cygwin openwrt -EXTRA_DIST=lighttpd.spec +EXTRA_DIST=lighttpd.spec autogen.sh SConstruct Index: NEWS =================================================================== --- NEWS (.../tags/lighttpd-1.4.18) (revision 2118) +++ NEWS (.../branches/lighttpd-1.4.x) (revision 2118) @@ -3,6 +3,52 @@ NEWS ==== +- 1.4.19 - + + * added support for If-Range: (#1346) + * added support for matching $HTTP["scheme"] in configs + * fixed initgroups() called after chroot (#1384) + * fixed case-sensitive check for Auth-Method (#1456) + * execute fcgi app without /bin/sh if used as argument to spawn-fcgi (#1428) + * fixed a bug that made /-prefixed extensions being handled also when + matching the end of the uri in fcgi,scgi and proxy modules (#1489) + * print error if X-LIGHTTPD-send-file cannot be done; reset header + Content-Length for send-file. Patches by Stefan Buehler + * prevent crash in certain php-fcgi configurations (#841) + * add IdleServers and Scoreboard directives in ?auto mode for mod_status (#1507) + * open log immediately after daemonizing, fixes SIGPIPEs on startup (#165) + * HTTPS env var should be "on" when using mod_extforward and the X-Forwarded-Proto header is set. (#1499) + * generate ETag and Last-Modified headers for mod_ssi based on newest modified include (#1491) + * support letterhomes in mod_userdir (#1473) + * support chained proxies in mod_extforward (#1528) + * fixed bogus "cgi died ?" if we kill the CGI process on shutdown + * fixed ECONNRESET handling in network-openssl + * fixed handling of EAGAIN in network-linux-sendfile (#657) + * reset conditional cache (#1164) + * create directories in mod_compress (was broken with alias/userdir) (#1027) + * fixed out of range access in fd array (#1562, #372) + * mod_compress should check if the request is already handled, e.g. by fastcgi (#1565) + * remove broken workaround for buggy Opera version with ssl/chunked encoding (#285) + * generate etag/last-modified header for on-the-fly-compressed files (#1171) + * req-method OPTIONS: do not insert default response if request was denied, do not deny OPTIONS by default (#1324) + * fixed memory leak on windows (#1347) + * fixed building outside of the src dir (#1349) + * fixed including of stdint.h/inttypes.h in etag.c (#1413) + * do not add Accept-Ranges header if range-request is disabled (#1449) + * log the ip of failed auth tries in error.log (enhancement #1544) + * fixed RoundRobin in mod_proxy (#516) + * check for symlinks after successful pathinfo matching (#1574) + * fixed mod-proxy.t to run with a builddir outside of the src dir + * do not suppress content on "307 Temporary Redirect" (#1412) + * fixed Content-Length header if response body gets removed in connections.c (#1412, part 2) + * do not generate a "Content-Length: 0" header for HEAD requests, added test too + * remove compress cache file if compression or write failed (#1150) + * fixed body handling of status 300 requests + * spawn-fcgi: only try to connect to unix socket (not tcp) before spawning (#1575) + * fix sending source of cgi script instead of 500 error if fork fails + * fix min-procs handling in mod_scgi.c, just set to max-procs (patch from #623) + * fix sending "408 - Timeout" instead of "410 - Gone" for timedout urls in mod_secdownload (#1440) + - 1.4.18 - 2007-09-09 * fixed compile error on IRIX 6.5.x on prctl() (#1333) Index: lighttpd.spec.in =================================================================== --- lighttpd.spec.in (.../tags/lighttpd-1.4.18) (revision 2118) +++ lighttpd.spec.in (.../branches/lighttpd-1.4.x) (revision 2118) @@ -6,21 +6,19 @@ Packager: Jan Kneschke License: BSD Group: Networking/Daemons -URL: http://jan.kneschke.de/projects/lighttpd/ +URL: http://www.lighttpd.net/ Requires: pcre >= 3.1 zlib -BuildPrereq: libtool zlib-devel +BuildRequires: libtool zlib-devel BuildRoot: %{_tmppath}/%{name}-root - %description lighttpd is intented to be a frontend for ad-servers which have to deliver small files concurrently to many connections. -Available rpmbuild rebuild options : ---with : ssl mysql lua memcache +Available rpmbuild rebuild options: +--with: ssl mysql lua memcache %prep - %setup -q %build @@ -33,14 +31,13 @@ make %install - %makeinstall mkdir -p %{buildroot}%{_sysconfdir}/{init.d,sysconfig} -if test -f /etc/redhat-release -o -f /etc/fedora-release; then - install -m 755 doc/rc.lighttpd.redhat %{buildroot}%{_sysconfdir}/init.d/lighttpd +if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then + install -m 755 doc/rc.lighttpd.redhat %{buildroot}%{_sysconfdir}/init.d/lighttpd else - install -m 755 doc/rc.lighttpd %{buildroot}%{_sysconfdir}/init.d/lighttpd + install -m 755 doc/rc.lighttpd %{buildroot}%{_sysconfdir}/init.d/lighttpd fi install -m 644 doc/sysconfig.lighttpd %{buildroot}%{_sysconfdir}/sysconfig/lighttpd @@ -49,16 +46,16 @@ %post ## read http://www.fedora.us/docs/spec.html next time :) -if test "$1" = "1"; then - # real install, not upgrade - /sbin/chkconfig --add lighttpd +if [ "$1" = "1" ]; then + # real install, not upgrade + /sbin/chkconfig --add lighttpd fi %preun -if test "$1" = "0"; then - # real uninstall, not upgrade - %{_sysconfdir}/init.d/lighttpd stop - /sbin/chkconfig --del lighttpd +if [ "$1" = "0"]; then + # real uninstall, not upgrade + %{_sysconfdir}/init.d/lighttpd stop + /sbin/chkconfig --del lighttpd fi %files Property changes on: . ___________________________________________________________________ Name: svk:merge - a98e19e4-a712-0410-8832-6551a15ffc53:/local/branches/lighttpd-1.4.x:1557 + 152afb58-edef-0310-8abb-c4023f1b3aa9:/branches/lighttpd-1.3.x:499 152afb58-edef-0310-8abb-c4023f1b3aa9:/branches/lighttpd-1.4.11-ssl-fixes:1346 152afb58-edef-0310-8abb-c4023f1b3aa9:/branches/lighttpd-merge-1.4.x:1041 152afb58-edef-0310-8abb-c4023f1b3aa9:/tags/lighttpd-1.4.11:1042 152afb58-edef-0310-8abb-c4023f1b3aa9:/tags/release-1.3.13:105 152afb58-edef-0310-8abb-c4023f1b3aa9:/trunk:104 a98e19e4-a712-0410-8832-6551a15ffc53:/local/branches/lighttpd-1.4.x:1557 ebd0e9cf-3e47-4385-9dd4-f0e25e97baa2:/local/lighttpd/branches/lighttpd-1.4.x:2154