diff options
author | Stefan Fritsch <sf@sfritsch.de> | 2015-04-28 22:06:31 +0200 |
---|---|---|
committer | Stefan Fritsch <sf@sfritsch.de> | 2015-04-28 22:06:31 +0200 |
commit | 080d5e16db802902200a9ce5b6c40f8f1fdc1f73 (patch) | |
tree | 69845ca856fe6817f103544e88541d80411fe9a8 /modules | |
parent | cb35beef2a938b80c9e4b5d6a408eca437aa74db (diff) | |
download | apache2-080d5e16db802902200a9ce5b6c40f8f1fdc1f73.tar.gz |
Imported Upstream version 2.4.12
Diffstat (limited to 'modules')
59 files changed, 943 insertions, 537 deletions
diff --git a/modules/aaa/mod_auth_basic.c b/modules/aaa/mod_auth_basic.c index 75044d48..5ef40f75 100644 --- a/modules/aaa/mod_auth_basic.c +++ b/modules/aaa/mod_auth_basic.c @@ -315,8 +315,8 @@ static int authenticate_basic_user(request_rec *r) /* We need an authentication realm. */ if (!ap_auth_name(r)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, - 0, r, APLOGNO(01615) "need AuthName: %s", r->uri); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01615) + "need AuthName: %s", r->uri); return HTTP_INTERNAL_SERVER_ERROR; } @@ -428,7 +428,7 @@ static int authenticate_basic_user(request_rec *r) break; } - /* If we're returning 403, tell them to try again. */ + /* If we're returning 401, tell them to try again. */ if (return_code == HTTP_UNAUTHORIZED) { note_basic_auth_failure(r); } diff --git a/modules/aaa/mod_auth_form.c b/modules/aaa/mod_auth_form.c index cfb4a7f2..263c8e63 100644 --- a/modules/aaa/mod_auth_form.c +++ b/modules/aaa/mod_auth_form.c @@ -903,16 +903,16 @@ static int authenticate_form_authn(request_rec * r) * never be secure. Abort the auth attempt in this case. */ if (PROXYREQ_PROXY == r->proxyreq) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, - 0, r, APLOGNO(01809) "form auth cannot be used for proxy " + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01809) + "form auth cannot be used for proxy " "requests due to XSS risk, access denied: %s", r->uri); return HTTP_INTERNAL_SERVER_ERROR; } /* We need an authentication realm. */ if (!ap_auth_name(r)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, - 0, r, APLOGNO(01810) "need AuthName: %s", r->uri); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01810) + "need AuthName: %s", r->uri); return HTTP_INTERNAL_SERVER_ERROR; } diff --git a/modules/aaa/mod_authnz_fcgi.c b/modules/aaa/mod_authnz_fcgi.c index 673b0e77..51b15edd 100644 --- a/modules/aaa/mod_authnz_fcgi.c +++ b/modules/aaa/mod_authnz_fcgi.c @@ -406,13 +406,12 @@ enum { * * Returns 0 if it can't find the end of the headers, and 1 if it found the * end of the headers. */ -static int handle_headers(request_rec *r, - int *state, - char *readbuf) +static int handle_headers(request_rec *r, int *state, + const char *readbuf, apr_size_t readlen) { const char *itr = readbuf; - while (*itr) { + while (readlen--) { if (*itr == '\r') { switch (*state) { case HDR_STATE_GOT_CRLF: @@ -472,7 +471,7 @@ static apr_status_t handle_response(const fcgi_provider_conf *conf, { apr_bucket *b; apr_bucket_brigade *ob; - apr_size_t orspbuflen; + apr_size_t orspbuflen = 0; apr_status_t rv = APR_SUCCESS; const char *fn = "handle_response"; int header_state = HDR_STATE_READING_HEADERS; @@ -555,7 +554,8 @@ static apr_status_t handle_response(const fcgi_provider_conf *conf, APR_BRIGADE_INSERT_TAIL(ob, b); if (!seen_end_of_headers) { - int st = handle_headers(r, &header_state, readbuf); + int st = handle_headers(r, &header_state, + readbuf, readbuflen); if (st == 1) { int status; @@ -642,6 +642,10 @@ static apr_status_t handle_response(const fcgi_provider_conf *conf, "%d", fn, type); break; } + /* Leave on above switch's inner error. */ + if (rv != APR_SUCCESS) { + break; + } /* * Read/discard any trailing padding. diff --git a/modules/aaa/mod_authz_core.c b/modules/aaa/mod_authz_core.c index c9ed22ff..c68b56bd 100644 --- a/modules/aaa/mod_authz_core.c +++ b/modules/aaa/mod_authz_core.c @@ -168,6 +168,13 @@ static void *merge_authz_core_dir_config(apr_pool_t *p, return (void*)conf; } +/* Only per-server directive we have is GLOBAL_ONLY */ +static void *merge_authz_core_svr_config(apr_pool_t *p, + void *basev, void *newv) +{ + return basev; +} + static void *create_authz_core_svr_config(apr_pool_t *p, server_rec *s) { authz_core_srv_conf *authcfg; @@ -1140,7 +1147,7 @@ AP_DECLARE_MODULE(authz_core) = create_authz_core_dir_config, /* dir config creater */ merge_authz_core_dir_config, /* dir merger */ create_authz_core_svr_config, /* server config */ - NULL, /* merge server config */ + merge_authz_core_svr_config , /* merge server config */ authz_cmds, register_hooks /* register hooks */ }; diff --git a/modules/arch/netware/mod_nw_ssl.c b/modules/arch/netware/mod_nw_ssl.c index a6e15e7f..d3443002 100644 --- a/modules/arch/netware/mod_nw_ssl.c +++ b/modules/arch/netware/mod_nw_ssl.c @@ -1086,7 +1086,7 @@ char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, else if (strcEQ(var, "SERVER_SOFTWARE")) result = ap_get_server_banner(); else if (strcEQ(var, "API_VERSION")) { - result = apr_itoa(p, MODULE_MAGIC_NUMBER); + result = apr_itoa(p, MODULE_MAGIC_NUMBER_MAJOR); resdup = FALSE; } else if (strcEQ(var, "TIME_YEAR")) { @@ -1192,8 +1192,8 @@ static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f, /* Send the interim 101 response. */ upgradebb = apr_brigade_create(r->pool, f->c->bucket_alloc); - ap_fputstrs(f->next, upgradebb, SWITCH_STATUS_LINE, CRLF, - UPGRADE_HEADER, CRLF, CONNECTION_HEADER, CRLF, CRLF, NULL); + ap_fputs(f->next, upgradebb, SWITCH_STATUS_LINE CRLF + UPGRADE_HEADER CRLF CONNECTION_HEADER CRLF CRLF); b = apr_bucket_flush_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(upgradebb, b); diff --git a/modules/arch/win32/mod_isapi.c b/modules/arch/win32/mod_isapi.c index 801c7dea..ce0875a5 100644 --- a/modules/arch/win32/mod_isapi.c +++ b/modules/arch/win32/mod_isapi.c @@ -955,7 +955,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, return 1; } else if (cid->dconf.log_unsupported) { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02671) "ServerSupportFunction " "HSE_REQ_DONE_WITH_SESSION is not supported: %s", r->filename); @@ -1000,7 +1000,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, case HSE_REQ_GET_SSPI_INFO: if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02672) "ServerSupportFunction HSE_REQ_GET_SSPI_INFO " "is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); @@ -1035,7 +1035,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, return 1; } if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02673) "ServerSupportFunction HSE_REQ_IO_COMPLETION " "is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); @@ -1055,7 +1055,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, if (!cid->dconf.fake_async && (tf->dwFlags & HSE_IO_ASYNC)) { if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02674) "ServerSupportFunction HSE_REQ_TRANSMIT_FILE " "as HSE_IO_ASYNC is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); @@ -1170,7 +1170,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, case HSE_REQ_REFRESH_ISAPI_ACL: if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02675) "ServerSupportFunction " "HSE_REQ_REFRESH_ISAPI_ACL " "is not supported: %s", r->filename); @@ -1227,7 +1227,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, case HSE_REQ_GET_IMPERSONATION_TOKEN: /* Added in ISAPI 4.0 */ if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02676) "ServerSupportFunction " "HSE_REQ_GET_IMPERSONATION_TOKEN " "is not supported: %s", r->filename); @@ -1306,7 +1306,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, case HSE_REQ_ABORTIVE_CLOSE: if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02677) "ServerSupportFunction HSE_REQ_ABORTIVE_CLOSE" " is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); @@ -1314,7 +1314,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, case HSE_REQ_GET_CERT_INFO_EX: /* Added in ISAPI 4.0 */ if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02678) "ServerSupportFunction " "HSE_REQ_GET_CERT_INFO_EX " "is not supported: %s", r->filename); @@ -1363,7 +1363,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, case HSE_REQ_CLOSE_CONNECTION: /* Added after ISAPI 4.0 */ if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02679) "ServerSupportFunction " "HSE_REQ_CLOSE_CONNECTION " "is not supported: %s", r->filename); @@ -1381,7 +1381,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, /* Undocumented - defined by the Microsoft Jan '00 Platform SDK */ if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02680) "ServerSupportFunction " "HSE_REQ_EXTENSION_TRIGGER " "is not supported: %s", r->filename); @@ -1390,7 +1390,7 @@ static int APR_THREAD_FUNC regfnServerSupportFunction(isapi_cid *cid, default: if (cid->dconf.log_unsupported) - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02681) "ServerSupportFunction (%d) not supported: " "%s", HSE_code, r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); @@ -1702,7 +1702,7 @@ static int isapi_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte rv = apr_thread_mutex_create(&loaded.lock, APR_THREAD_MUTEX_DEFAULT, loaded.pool); if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, + ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO(02682) "Failed to create module cache lock"); return rv; } diff --git a/modules/cache/cache_util.c b/modules/cache/cache_util.c index bf450931..b7454ad6 100644 --- a/modules/cache/cache_util.c +++ b/modules/cache/cache_util.c @@ -443,7 +443,7 @@ int ap_cache_check_no_cache(cache_request_rec *cache, request_rec *r) return 0; } else { - ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02657) "Incoming request is asking for an uncached version of " "%s, but we have been configured to ignore it and serve " "cached content anyway", r->unparsed_uri); @@ -483,7 +483,7 @@ int ap_cache_check_no_store(cache_request_rec *cache, request_rec *r) return 0; } else { - ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02658) "Incoming request is asking for a no-store version of " "%s, but we have been configured to ignore it and serve " "cached content anyway", r->unparsed_uri); @@ -1258,8 +1258,10 @@ apr_table_t *cache_merge_headers_out(request_rec *r) if (r->content_type && !apr_table_get(headers_out, "Content-Type")) { - apr_table_setn(headers_out, "Content-Type", - ap_make_content_type(r, r->content_type)); + const char *ctype = ap_make_content_type(r, r->content_type); + if (ctype) { + apr_table_setn(headers_out, "Content-Type", ctype); + } } if (r->content_encoding diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c index cd839ed7..b95f0a8a 100644 --- a/modules/cache/mod_cache.c +++ b/modules/cache/mod_cache.c @@ -234,6 +234,11 @@ static int cache_quick_handler(request_rec *r, int lookup) ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(00752) "Cache locked for url, not caching " "response: %s", r->uri); + /* cache_select() may have added conditional headers */ + if (cache->stale_headers) { + r->headers_in = cache->stale_headers; + } + } } else { @@ -636,7 +641,6 @@ static int cache_handler(request_rec *r) static apr_status_t cache_out_filter(ap_filter_t *f, apr_bucket_brigade *in) { request_rec *r = f->r; - apr_bucket *e; cache_request_rec *cache = (cache_request_rec *)f->ctx; if (!cache) { @@ -652,10 +656,8 @@ static apr_status_t cache_out_filter(ap_filter_t *f, apr_bucket_brigade *in) "cache: running CACHE_OUT filter"); /* clean out any previous response up to EOS, if any */ - for (e = APR_BRIGADE_FIRST(in); - e != APR_BRIGADE_SENTINEL(in); - e = APR_BUCKET_NEXT(e)) - { + while (!APR_BRIGADE_EMPTY(in)) { + apr_bucket *e = APR_BRIGADE_FIRST(in); if (APR_BUCKET_IS_EOS(e)) { apr_bucket_brigade *bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); @@ -1201,6 +1203,8 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) apr_table_unset(r->headers_in, "If-Range"); apr_table_unset(r->headers_in, "If-Unmodified-Since"); + /* Currently HTTP_NOT_MODIFIED, and after the redirect, handlers won't think to set status to HTTP_OK */ + r->status = HTTP_OK; ap_internal_redirect(r->unparsed_uri, r); return APR_SUCCESS; diff --git a/modules/cache/mod_cache_socache.c b/modules/cache/mod_cache_socache.c index a138e6b8..6bd9466b 100644 --- a/modules/cache/mod_cache_socache.c +++ b/modules/cache/mod_cache_socache.c @@ -22,6 +22,7 @@ #include "http_config.h" #include "http_log.h" #include "http_core.h" +#include "http_protocol.h" #include "ap_provider.h" #include "ap_socache.h" #include "util_filter.h" @@ -30,6 +31,7 @@ #include "util_mutex.h" #include "mod_cache.h" +#include "mod_status.h" #include "cache_socache_common.h" @@ -1375,6 +1377,56 @@ static apr_status_t destroy_cache(void *data) return APR_SUCCESS; } +static int socache_status_hook(request_rec *r, int flags) +{ + apr_status_t status = APR_SUCCESS; + cache_socache_conf *conf = ap_get_module_config(r->server->module_config, + &cache_socache_module); + if (!conf->provider || !conf->provider->socache_provider || + !conf->provider->socache_instance) { + return DECLINED; + } + + ap_rputs("<hr>\n" + "<table cellspacing=0 cellpadding=0>\n" + "<tr><td bgcolor=\"#000000\">\n" + "<b><font color=\"#ffffff\" face=\"Arial,Helvetica\">" + "mod_cache_socache Status:</font></b>\n" + "</td></tr>\n" + "<tr><td bgcolor=\"#ffffff\">\n", r); + + if (socache_mutex) { + status = apr_global_mutex_lock(socache_mutex); + if (status != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02816) + "could not acquire lock for cache status"); + } + } + + if (status != APR_SUCCESS) { + ap_rputs("No cache status data available\n", r); + } else { + conf->provider->socache_provider->status(conf->provider->socache_instance, + r, flags); + } + + if (socache_mutex && status == APR_SUCCESS) { + status = apr_global_mutex_unlock(socache_mutex); + if (status != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02817) + "could not release lock for cache status"); + } + } + + ap_rputs("</td></tr>\n</table>\n", r); + return OK; +} + +static void socache_status_register(apr_pool_t *p) +{ + APR_OPTIONAL_HOOK(ap, status_hook, socache_status_hook, NULL, NULL, APR_HOOK_MIDDLE); +} + static int socache_precfg(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptmp) { apr_status_t rv = ap_mutex_register(pconf, cache_socache_id, NULL, @@ -1384,6 +1436,10 @@ static int socache_precfg(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptmp) "failed to register %s mutex", cache_socache_id); return 500; /* An HTTP status would be a misnomer! */ } + + /* Register to handle mod_status status page generation */ + socache_status_register(pconf); + return OK; } @@ -1394,7 +1450,7 @@ static int socache_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_status_t rv; const char *errmsg; static struct ap_socache_hints socache_hints = - { 64, 32, 60000000 }; + { 64, 2048, 60000000 }; for (s = base_server; s; s = s->next) { cache_socache_conf *conf = diff --git a/modules/cache/mod_cache_socache.dsp b/modules/cache/mod_cache_socache.dsp index e5d582e2..1dd82145 100644 --- a/modules/cache/mod_cache_socache.dsp +++ b/modules/cache/mod_cache_socache.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fd"Release\mod_cache_socache_src" /FD /c +# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /I "../generators" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fd"Release\mod_cache_socache_src" /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -75,7 +75,7 @@ PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).ma # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fd"Debug\mod_cache_socache_src" /FD /c +# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../srclib/apr-util/include" /I "../../srclib/apr/include" /I "../../include" /I "../generators" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fd"Debug\mod_cache_socache_src" /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" diff --git a/modules/core/mod_macro.c b/modules/core/mod_macro.c index 75180930..016f5f49 100644 --- a/modules/core/mod_macro.c +++ b/modules/core/mod_macro.c @@ -15,7 +15,7 @@ */ /* - $Id: mod_macro.c 1562134 2014-01-28 18:11:59Z jim $ + $Id: mod_macro.c 1631118 2014-10-11 21:12:18Z jailletc36 $ */ #include "httpd.h" @@ -115,17 +115,16 @@ static apr_array_header_t *get_arguments(apr_pool_t * pool, const char *line) /* warn if anything non blank appears, but ignore comments... */ -static void warn_if_non_blank( - const char * what, - char * ptr, - ap_configfile_t * cfg) +static void warn_if_non_blank(const char * what, + char * ptr, + ap_configfile_t * cfg) { char * p; for (p=ptr; *p; p++) { if (*p == '#') break; if (*p != ' ' && *p != '\t') { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "%s on line %d of %s: %s", what, cfg->line_number, cfg->name, ptr); break; @@ -164,8 +163,8 @@ static char *get_lines_till_end_token(apr_pool_t * pool, if (!strncmp(first, "</", 2)) { any_nesting--; if (any_nesting < 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, - 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, + 0, NULL, APLOGNO(02793) "bad (negative) nesting on line %d of %s", config_file->line_number - line_number_start, where); @@ -185,14 +184,14 @@ static char *get_lines_till_end_token(apr_pool_t * pool, } warn_if_non_blank( - "non blank chars found after directive closing", + APLOGNO(02794) "non blank chars found after directive closing", endp+1, config_file); macro_nesting--; if (!macro_nesting) { if (any_nesting) { ap_log_error(APLOG_MARK, - APLOG_NOERRNO | APLOG_WARNING, 0, NULL, + APLOG_WARNING, 0, NULL, APLOGNO(02795) "bad cumulated nesting (%+d) in %s", any_nesting, where); } @@ -257,7 +256,7 @@ static const char *check_macro_arguments(apr_pool_t * pool, macro->name, macro->location, i + 1); } else if (!looks_like_an_argument(tab[i])) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02796) "macro '%s' (%s) " "argument name '%s' (#%d) without expected prefix, " "better prefix argument names with one of '%s'.", @@ -271,7 +270,7 @@ static const char *check_macro_arguments(apr_pool_t * pool, /* must not use the same argument name twice */ if (!strcmp(tab[i], tab[j])) { return apr_psprintf(pool, - "argument name conflict in macro '%s' (%s): " + "argument name conflict in macro '%s' (%s): " "argument '%s': #%d and #%d, " "change argument names!", macro->name, macro->location, @@ -281,11 +280,11 @@ static const char *check_macro_arguments(apr_pool_t * pool, /* warn about common prefix, but only if non empty names */ if (ltabi && ltabj && !strncmp(tab[i], tab[j], ltabi < ltabj ? ltabi : ltabj)) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, - 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, + 0, NULL, APLOGNO(02797) "macro '%s' (%s): " - "argument name prefix conflict (%s #%d and %s #%d)," - " be careful about your macro definition!", + "argument name prefix conflict (%s #%d and %s #%d), " + "be careful about your macro definition!", macro->name, macro->location, tab[i], i + 1, tab[j], j + 1); } @@ -305,7 +304,7 @@ static void check_macro_use_arguments(const char *where, int i; for (i = 0; i < array->nelts; i++) { if (empty_string_p(tab[i])) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02798) "%s: empty argument #%d", where, i + 1); } } @@ -506,7 +505,7 @@ static const char *check_macro_contents(apr_pool_t * pool, const char *errmsg; if (macro->contents->nelts == 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02799) "macro '%s' (%s): empty contents!", macro->name, macro->location); return NULL; /* no need to further warnings... */ @@ -526,7 +525,7 @@ static const char *check_macro_contents(apr_pool_t * pool, for (i = 0; i < nelts; i++) { if (!used->elts[i]) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02800) "macro '%s' (%s): argument '%s' (#%d) never used", macro->name, macro->location, names[i], i + 1); } @@ -719,7 +718,8 @@ static const char *macro_section(cmd_parms * cmd, return BEGIN_MACRO " macro definition: empty name"; } - warn_if_non_blank("non blank chars found after " BEGIN_MACRO " closing '>'", + warn_if_non_blank(APLOGNO(02801) "non blank chars found after " + BEGIN_MACRO " closing '>'", endp+1, cmd->config_file); /* coldly drop '>[^>]*$' out */ @@ -736,7 +736,7 @@ static const char *macro_section(cmd_parms * cmd, if (macro != NULL) { /* already defined: warn about the redefinition */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02802) "macro '%s' multiply defined: " "%s, redefined on line %d of \"%s\"", macro->name, macro->location, @@ -761,7 +761,7 @@ static const char *macro_section(cmd_parms * cmd, apr_psprintf(pool, "macro '%s' (%s)", macro->name, macro->location); if (looks_like_an_argument(name)) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02803) "%s better prefix a macro name with any of '%s'", where, ARG_PREFIX); } diff --git a/modules/core/mod_so.c b/modules/core/mod_so.c index 6df596a9..eeacec67 100644 --- a/modules/core/mod_so.c +++ b/modules/core/mod_so.c @@ -209,8 +209,8 @@ static const char *load_module(cmd_parms *cmd, void *dummy, for (i = 0; i < sconf->loaded_modules->nelts; i++) { modi = &modie[i]; if (modi->name != NULL && strcmp(modi->name, modname) == 0) { - ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, - cmd->pool, APLOGNO(01574) "module %s is already loaded, skipping", + ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, cmd->pool, APLOGNO(01574) + "module %s is already loaded, skipping", modname); return NULL; } diff --git a/modules/core/mod_watchdog.h b/modules/core/mod_watchdog.h index 13d23ba9..8e7112cf 100644 --- a/modules/core/mod_watchdog.h +++ b/modules/core/mod_watchdog.h @@ -21,9 +21,9 @@ * @file mod_watchdog.h * @brief Watchdog module for Apache * - * @defgroup MOD_WATCHDOG watchdog + * @defgroup MOD_WATCHDOG mod_watchdog * @ingroup APACHE_MODS - * \@{ + * @{ */ #include "httpd.h" @@ -210,4 +210,4 @@ APR_DECLARE_EXTERNAL_HOOK(ap, AP_WD, int, watchdog_step, ( #endif #endif /* MOD_WATCHDOG_H */ -/** \@} */ +/** @} */ diff --git a/modules/database/mod_dbd.c b/modules/database/mod_dbd.c index 5ff1ea20..72126652 100644 --- a/modules/database/mod_dbd.c +++ b/modules/database/mod_dbd.c @@ -327,7 +327,7 @@ DBD_DECLARE_NONSTD(void) ap_dbd_prepare(server_rec *s, const char *query, if (apr_hash_get(svr->cfg->queries, label, APR_HASH_KEY_STRING) && strcmp(query, "")) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02653) "conflicting SQL statements with label %s", label); } @@ -799,7 +799,8 @@ DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s) /* If nothing is configured, we shouldn't be here */ if (cfg->name == no_dbdriver) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "not configured"); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02654) + "not configured"); return NULL; } @@ -822,7 +823,7 @@ DBD_DECLARE_NONSTD(ap_dbd_t*) ap_dbd_open(apr_pool_t *pool, server_rec *s) rv = apr_reslist_acquire(group->reslist, (void*) &rec); if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02655) "Failed to acquire DBD connection from pool!"); return NULL; } diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c index 6c4c44b1..950646ee 100644 --- a/modules/dav/fs/repos.c +++ b/modules/dav/fs/repos.c @@ -874,12 +874,13 @@ static int dav_fs_is_parent_resource( && ctx2->pathname[len1] == '/'); } -static apr_status_t tmpfile_cleanup(void *data) { - dav_stream *ds = data; - if (ds->temppath) { - apr_file_remove(ds->temppath, ds->p); - } - return APR_SUCCESS; +static apr_status_t tmpfile_cleanup(void *data) +{ + dav_stream *ds = data; + if (ds->temppath) { + apr_file_remove(ds->temppath, ds->p); + } + return APR_SUCCESS; } /* custom mktemp that creates the file with APR_OS_DEFAULT permissions */ diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c index 07a4e2c5..2af117d2 100644 --- a/modules/dav/main/mod_dav.c +++ b/modules/dav/main/mod_dav.c @@ -315,6 +315,7 @@ static const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config, static int dav_error_response(request_rec *r, int status, const char *body) { r->status = status; + r->status_line = ap_get_status_line(status); ap_set_content_type(r, "text/html; charset=ISO-8859-1"); @@ -711,8 +712,8 @@ static dav_error *dav_get_resource(request_rec *r, int label_allowed, if (conf->provider == NULL) { return dav_new_error(r->pool, HTTP_METHOD_NOT_ALLOWED, 0, 0, apr_psprintf(r->pool, - "DAV not enabled for %s", - ap_escape_html(r->pool, r->uri))); + "DAV not enabled for %s", + ap_escape_html(r->pool, r->uri))); } /* resolve the resource */ diff --git a/modules/examples/mod_example_hooks.c b/modules/examples/mod_example_hooks.c index 1c8ca4c1..1130f7eb 100644 --- a/modules/examples/mod_example_hooks.c +++ b/modules/examples/mod_example_hooks.c @@ -15,7 +15,7 @@ */ /* - * Apache example module. Provide demonstrations of how modules do things. + * Apache example_hooks module. Provide demonstrations of how modules do things. * It is not meant to be used in a production server. Since it participates * in all of the processing phases, it could conceivable interfere with * the proper operation of other modules -- particularly the ones related @@ -26,7 +26,7 @@ * prefixed with 'x_' instead of 'example_'. * * To use mod_example_hooks, configure the Apache build with - * --enable-example and compile. Set up a <Location> block in your + * --enable-example-hooks and compile. Set up a <Location> block in your * configuration file like so: * * <Location /example> @@ -328,11 +328,11 @@ static x_cfg *our_cconfig(const conn_rec *c) static void example_log_each(apr_pool_t *p, server_rec *s, const char *note) { if (s != NULL) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_example: %s", note); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "mod_example_hooks: %s", note); } else { apr_file_t *out = NULL; apr_file_open_stderr(&out, p); - apr_file_printf(out, "mod_example traced in non-loggable " + apr_file_printf(out, "mod_example_hooks traced in non-loggable " "context: %s\n", note); } } @@ -703,7 +703,7 @@ static void *x_merge_server_config(apr_pool_t *p, void *server1_conf, * declaration near the bottom of this file.) Note that these may be * * called for situations that don't relate primarily to our function - in * * other words, the fixup handler shouldn't assume that the request has * - * to do with "example" stuff. * + * to do with "example_hooks" stuff. * * * * With the exception of the content handler, all of our routines will be * * called for each request, unless an earlier handler from another module * diff --git a/modules/filters/mod_include.c b/modules/filters/mod_include.c index af90db67..e8d8ea78 100644 --- a/modules/filters/mod_include.c +++ b/modules/filters/mod_include.c @@ -697,7 +697,7 @@ static const char *include_expr_var_fn(ap_expr_eval_ctx_t *eval_ctx, { const char *res, *name = data; include_ctx_t *ctx = eval_ctx->data; - if (name[0] == 'e') { + if ((name[0] == 'e') || (name[0] == 'E')) { /* keep legacy "env" semantics */ if ((res = apr_table_get(ctx->r->notes, arg)) != NULL) return res; @@ -968,8 +968,8 @@ static APR_INLINE int re_check(include_ctx_t *ctx, const char *string, compiled = ap_pregcomp(ctx->dpool, rexp, AP_REG_EXTENDED); if (!compiled) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, "unable to " - "compile pattern \"%s\"", rexp); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, APLOGNO(02667) + "unable to compile pattern \"%s\"", rexp); return -1; } @@ -1698,7 +1698,7 @@ static int find_file(request_rec *r, const char *directive, const char *tag, APR_FILEPATH_NOTABSOLUTE, r->pool); if (rv != APR_SUCCESS) { - error_fmt = "unable to access file \"%s\" " + error_fmt = APLOGNO(02668) "unable to access file \"%s\" " "in parsed file %s"; } else { @@ -1711,13 +1711,13 @@ static int find_file(request_rec *r, const char *directive, const char *tag, if ((rv = apr_stat(finfo, to_send, APR_FINFO_GPROT | APR_FINFO_MIN, rr->pool)) != APR_SUCCESS && rv != APR_INCOMPLETE) { - error_fmt = "unable to get information about \"%s\" " - "in parsed file %s"; + error_fmt = APLOGNO(02669) "unable to get information " + "about \"%s\" in parsed file %s"; } } else { - error_fmt = "unable to lookup information about \"%s\" " - "in parsed file %s"; + error_fmt = APLOGNO(02670) "unable to lookup information " + "about \"%s\" in parsed file %s"; } } diff --git a/modules/filters/mod_ratelimit.c b/modules/filters/mod_ratelimit.c index 939ab8e9..59e130e7 100644 --- a/modules/filters/mod_ratelimit.c +++ b/modules/filters/mod_ratelimit.c @@ -146,7 +146,7 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) if (rv != APR_SUCCESS) { ctx->state = RATE_ERROR; - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01455) + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01455) "rl: full speed brigade pass failed."); } } @@ -218,7 +218,7 @@ rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) if (rv != APR_SUCCESS) { ctx->state = RATE_ERROR; - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01457) + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01457) "rl: brigade pass failed."); break; } diff --git a/modules/filters/mod_substitute.c b/modules/filters/mod_substitute.c index 15cd8ee4..9326348c 100644 --- a/modules/filters/mod_substitute.c +++ b/modules/filters/mod_substitute.c @@ -33,6 +33,13 @@ #define APR_WANT_STRFUNC #include "apr_want.h" +/* + * We want to limit the memory usage in a way that is predictable. + * Therefore we limit the resulting length of the line. + * This is the default value. + */ +#define AP_SUBST_MAX_LINE_LENGTH (1024*1024) + static const char substitute_filter_name[] = "SUBSTITUTE"; module AP_MODULE_DECLARE_DATA substitute_module; @@ -48,6 +55,8 @@ typedef struct subst_pattern_t { typedef struct { apr_array_header_t *patterns; + apr_size_t max_line_length; + int max_line_length_set; } subst_dir_conf; typedef struct { @@ -64,6 +73,7 @@ static void *create_substitute_dcfg(apr_pool_t *p, char *d) (subst_dir_conf *) apr_pcalloc(p, sizeof(subst_dir_conf)); dcfg->patterns = apr_array_make(p, 10, sizeof(subst_pattern_t)); + dcfg->max_line_length = AP_SUBST_MAX_LINE_LENGTH; return dcfg; } @@ -76,15 +86,14 @@ static void *merge_substitute_dcfg(apr_pool_t *p, void *basev, void *overv) a->patterns = apr_array_append(p, over->patterns, base->patterns); + a->max_line_length = over->max_line_length_set ? + over->max_line_length : base->max_line_length; + a->max_line_length_set = over->max_line_length_set ? + over->max_line_length_set : base->max_line_length_set; return a; } #define AP_MAX_BUCKETS 1000 -/* - * We want to limit the memory usage in a way that is predictable. Therefore - * we limit the resulting length of the line to this value. - */ -#define AP_SUBST_MAX_LINE_LENGTH (128*MAX_STRING_LEN) #define SEDRMPATBCKT(b, offset, tmp_b, patlen) do { \ apr_bucket_split(b, offset); \ @@ -143,9 +152,9 @@ static apr_status_t do_pattmatch(ap_filter_t *f, apr_bucket *inb, const char *repl; /* * space_left counts how many bytes we have left until the - * line length reaches AP_SUBST_MAX_LINE_LENGTH. + * line length reaches max_line_length. */ - apr_size_t space_left = AP_SUBST_MAX_LINE_LENGTH; + apr_size_t space_left = cfg->max_line_length; apr_size_t repl_len = strlen(script->replacement); while ((repl = apr_strmatch(script->pattern, buff, bytes))) { @@ -161,7 +170,7 @@ static apr_status_t do_pattmatch(ap_filter_t *f, apr_bucket *inb, * are constanting allocing space and copying * strings. */ - if (vb.strlen + len + repl_len > AP_SUBST_MAX_LINE_LENGTH) + if (vb.strlen + len + repl_len > cfg->max_line_length) return APR_ENOMEM; ap_varbuf_strmemcat(&vb, buff, len); ap_varbuf_strmemcat(&vb, script->replacement, repl_len); @@ -228,19 +237,25 @@ static apr_status_t do_pattmatch(ap_filter_t *f, apr_bucket *inb, int left = bytes; const char *pos = buff; char *repl; - apr_size_t space_left = AP_SUBST_MAX_LINE_LENGTH; + apr_size_t space_left = cfg->max_line_length; while (!ap_regexec_len(script->regexp, pos, left, AP_MAX_REG_MATCH, regm, 0)) { apr_status_t rv; have_match = 1; if (script->flatten && !force_quick) { + /* check remaining buffer size */ + /* Note that the last param in ap_varbuf_regsub below + * must stay positive. If it gets 0, it would mean + * unlimited space available. */ + if (vb.strlen + regm[0].rm_so >= cfg->max_line_length) + return APR_ENOMEM; /* copy bytes before the match */ if (regm[0].rm_so > 0) ap_varbuf_strmemcat(&vb, pos, regm[0].rm_so); - /* add replacement string */ + /* add replacement string, last argument is unsigned! */ rv = ap_varbuf_regsub(&vb, script->replacement, pos, AP_MAX_REG_MATCH, regm, - AP_SUBST_MAX_LINE_LENGTH - vb.strlen); + cfg->max_line_length - vb.strlen); if (rv != APR_SUCCESS) return rv; } @@ -309,6 +324,9 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb) apr_bucket *tmp_b; apr_bucket_brigade *tmp_bb = NULL; apr_status_t rv; + subst_dir_conf *cfg = + (subst_dir_conf *) ap_get_module_config(f->r->per_dir_config, + &substitute_module); substitute_module_ctx *ctx = f->ctx; @@ -381,7 +399,7 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb) &fbytes, ctx->tpool); if (rv != APR_SUCCESS) goto err; - if (fbytes > AP_SUBST_MAX_LINE_LENGTH) { + if (fbytes > cfg->max_line_length) { rv = APR_ENOMEM; goto err; } @@ -447,7 +465,7 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb) &fbytes, ctx->tpool); if (rv != APR_SUCCESS) goto err; - if (fbytes > AP_SUBST_MAX_LINE_LENGTH) { + if (fbytes > cfg->max_line_length) { /* Avoid pflattening further lines, we will * abort later on anyway. */ @@ -627,6 +645,44 @@ static const char *set_pattern(cmd_parms *cmd, void *cfg, const char *line) return NULL; } +#define KBYTE 1024 +#define MBYTE 1048576 +#define GBYTE 1073741824 + +static const char *set_max_line_length(cmd_parms *cmd, void *cfg, const char *arg) +{ + subst_dir_conf *dcfg = (subst_dir_conf *)cfg; + apr_off_t max; + char *end; + apr_status_t rv; + + rv = apr_strtoff(&max, arg, &end, 10); + if (rv == APR_SUCCESS) { + if ((*end == 'K' || *end == 'k') && !end[1]) { + max *= KBYTE; + } + else if ((*end == 'M' || *end == 'm') && !end[1]) { + max *= MBYTE; + } + else if ((*end == 'G' || *end == 'g') && !end[1]) { + max *= GBYTE; + } + else if (*end && /* neither empty nor [Bb] */ + ((*end != 'B' && *end != 'b') || end[1])) { + rv = APR_EGENERAL; + } + } + + if (rv != APR_SUCCESS || max < 0) + { + return "SubstituteMaxLineLength must be a non-negative integer optionally " + "suffixed with 'b', 'k', 'm' or 'g'."; + } + dcfg->max_line_length = (apr_size_t)max; + dcfg->max_line_length_set = 1; + return NULL; +} + #define PROTO_FLAGS AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH static void register_hooks(apr_pool_t *pool) { @@ -635,8 +691,10 @@ static void register_hooks(apr_pool_t *pool) } static const command_rec substitute_cmds[] = { - AP_INIT_TAKE1("Substitute", set_pattern, NULL, OR_ALL, + AP_INIT_TAKE1("Substitute", set_pattern, NULL, OR_FILEINFO, "Pattern to filter the response content (s/foo/bar/[inf])"), + AP_INIT_TAKE1("SubstituteMaxLineLength", set_max_line_length, NULL, OR_FILEINFO, + "Maximum line length"), {NULL} }; diff --git a/modules/filters/mod_xml2enc.c b/modules/filters/mod_xml2enc.c index a4202a28..d28c97d1 100644 --- a/modules/filters/mod_xml2enc.c +++ b/modules/filters/mod_xml2enc.c @@ -142,8 +142,7 @@ static void fix_skipto(request_rec* r, xml2ctx* ctx) &bstart); ap_assert(rv == APR_SUCCESS); while (b = APR_BRIGADE_FIRST(ctx->bbsave), b != bstart) { - APR_BUCKET_REMOVE(b); - apr_bucket_destroy(b); + apr_bucket_delete(b); } ctx->bytes -= (p-ctx->buf); ctx->buf = p ; @@ -228,8 +227,7 @@ static void sniff_encoding(request_rec* r, xml2ctx* ctx) /* cut out the <meta> we're invalidating */ while (cutb != cute) { b = APR_BUCKET_NEXT(cutb); - APR_BUCKET_REMOVE(cutb); - apr_bucket_destroy(cutb); + apr_bucket_delete(cutb); cutb = b; } /* and leave a string */ @@ -435,8 +433,7 @@ static apr_status_t xml2enc_ffunc(ap_filter_t* f, apr_bucket_brigade* bb) /* remove the data we've just read */ rv = apr_brigade_partition(bb, bytes, &bstart); while (b = APR_BRIGADE_FIRST(bb), b != bstart) { - APR_BUCKET_REMOVE(b); - apr_bucket_destroy(b); + apr_bucket_delete(b); } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, APLOGNO(01438) "xml2enc: consuming %" APR_SIZE_T_FMT diff --git a/modules/generators/mod_autoindex.c b/modules/generators/mod_autoindex.c index 3d36c77b..5e86e407 100644 --- a/modules/generators/mod_autoindex.c +++ b/modules/generators/mod_autoindex.c @@ -1416,7 +1416,7 @@ static char *terminate_description(autoindex_config_rec *d, char *desc, apr_int32_t autoindex_opts, int desc_width) { int maxsize = desc_width; - register int x; + int x; /* * If there's no DescriptionWidth in effect, default to the old @@ -1782,7 +1782,7 @@ static void output_directories(struct ent **ar, int n, } } else { - ap_rputs("</td><td> ", r); + ap_rvputs(r, "</td><td", (d->style_sheet != NULL) ? " class=\"indexcoldesc\">" : ">", " ", NULL); } } ap_rputs("</td></tr>\n", r); diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c index 7808262f..beb02f27 100644 --- a/modules/generators/mod_cgi.c +++ b/modules/generators/mod_cgi.c @@ -162,7 +162,7 @@ AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, }; static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret, - apr_status_t rv, char *error) + apr_status_t rv, char *logno, char *error) { apr_file_t *f = NULL; apr_finfo_t finfo; @@ -170,7 +170,7 @@ static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret, int log_flags = rv ? APLOG_ERR : APLOG_ERR; ap_log_rerror(APLOG_MARK, log_flags, rv, r, - "%s: %s", error, r->filename); + "%s%s: %s", logno ? logno : "", error, r->filename); /* XXX Very expensive mainline case! Open, then getfileinfo! */ if (!conf->logname || @@ -203,6 +203,7 @@ static apr_status_t log_script_err(request_rec *r, apr_file_t *script_err) char argsbuffer[HUGE_STRING_LEN]; char *newline; apr_status_t rv; + cgi_server_conf *conf = ap_get_module_config(r->server->module_config, &cgi_module); while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN, script_err)) == APR_SUCCESS) { @@ -210,8 +211,7 @@ static apr_status_t log_script_err(request_rec *r, apr_file_t *script_err) if (newline) { *newline = '\0'; } - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01215) - "%s", argsbuffer); + log_scripterror(r, conf, r->status, 0, APLOGNO(01215), argsbuffer); } return rv; @@ -774,24 +774,24 @@ static int cgi_handler(request_rec *r) conf = ap_get_module_config(r->server->module_config, &cgi_module); if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, + return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(02809), "Options ExecCGI is off in this directory"); if (nph && is_included) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, + return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(02810), "attempt to include NPH CGI script"); if (r->finfo.filetype == APR_NOFILE) - return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, + return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(02811), "script not found or unable to stat"); if (r->finfo.filetype == APR_DIR) - return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, + return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, APLOGNO(02812), "attempt to invoke directory as script"); if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) && r->path_info && *r->path_info) { /* default to accept */ - return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, + return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, APLOGNO(02813), "AcceptPathInfo off disallows user's path"); } /* diff --git a/modules/http/byterange_filter.c b/modules/http/byterange_filter.c index 09f19565..de585c57 100644 --- a/modules/http/byterange_filter.c +++ b/modules/http/byterange_filter.c @@ -380,8 +380,7 @@ static apr_status_t copy_brigade_range(apr_bucket_brigade *bb, return rv; } out_first = APR_BUCKET_NEXT(copy); - APR_BUCKET_REMOVE(copy); - apr_bucket_destroy(copy); + apr_bucket_delete(copy); } else { out_first = copy; @@ -400,8 +399,7 @@ static apr_status_t copy_brigade_range(apr_bucket_brigade *bb, } copy = APR_BUCKET_NEXT(copy); if (copy != APR_BRIGADE_SENTINEL(bbout)) { - APR_BUCKET_REMOVE(copy); - apr_bucket_destroy(copy); + apr_bucket_delete(copy); } } break; diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index 2a0a979d..733e9c82 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -231,6 +231,49 @@ static apr_status_t get_chunk_line(http_ctx_t *ctx, apr_bucket_brigade *b, } +static apr_status_t read_chunked_trailers(http_ctx_t *ctx, ap_filter_t *f, + apr_bucket_brigade *b, int merge) +{ + int rv; + apr_bucket *e; + request_rec *r = f->r; + apr_table_t *saved_headers_in = r->headers_in; + int saved_status = r->status; + + r->status = HTTP_OK; + r->headers_in = r->trailers_in; + apr_table_clear(r->headers_in); + ctx->state = BODY_NONE; + ap_get_mime_headers(r); + + if(r->status == HTTP_OK) { + r->status = saved_status; + e = apr_bucket_eos_create(f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + ctx->eos_sent = 1; + rv = APR_SUCCESS; + } + else { + const char *error_notes = apr_table_get(r->notes, + "error-notes"); + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, + "Error while reading HTTP trailer: %i%s%s", + r->status, error_notes ? ": " : "", + error_notes ? error_notes : ""); + rv = APR_EINVAL; + } + + if(!merge) { + r->headers_in = saved_headers_in; + } + else { + r->headers_in = apr_table_overlay(r->pool, saved_headers_in, + r->trailers_in); + } + + return rv; +} + /* This is the HTTP_INPUT filter for HTTP requests and responses from * proxied servers (mod_proxy). It handles chunked and content-length * bodies. This can only be inserted/used after the headers @@ -240,6 +283,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { + core_server_config *conf; apr_bucket *e; http_ctx_t *ctx = f->ctx; apr_status_t rv; @@ -247,6 +291,9 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, int http_error = HTTP_REQUEST_ENTITY_TOO_LARGE; apr_bucket_brigade *bb; + conf = (core_server_config *) + ap_get_module_config(f->r->server->module_config, &core_module); + /* just get out of the way of things we don't want. */ if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) { return ap_get_brigade(f->next, b, mode, block, readbytes); @@ -364,7 +411,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, * in a state of expecting one. */ f->r->expecting_100 = 0; - tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL, " ", + tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL " ", ap_get_status_line(HTTP_CONTINUE), CRLF CRLF, NULL); len = strlen(tmp); @@ -425,13 +472,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, } if (!ctx->remaining) { - /* Handle trailers by calling ap_get_mime_headers again! */ - ctx->state = BODY_NONE; - ap_get_mime_headers(f->r); - e = apr_bucket_eos_create(f->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(b, e); - ctx->eos_sent = 1; - return APR_SUCCESS; + return read_chunked_trailers(ctx, f, b, + conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE); } } } @@ -534,13 +576,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, } if (!ctx->remaining) { - /* Handle trailers by calling ap_get_mime_headers again! */ - ctx->state = BODY_NONE; - ap_get_mime_headers(f->r); - e = apr_bucket_eos_create(f->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(b, e); - ctx->eos_sent = 1; - return APR_SUCCESS; + return read_chunked_trailers(ctx, f, b, + conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE); } } break; diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index fe2cc208..a7f30fcf 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -1608,8 +1608,8 @@ AP_DECLARE(void) ap_method_list_add(ap_method_list_t *l, const char *method) * bitmask. */ methnum = ap_method_number_of(method); - l->method_mask |= (AP_METHOD_BIT << methnum); if (methnum != M_INVALID) { + l->method_mask |= (AP_METHOD_BIT << methnum); return; } /* @@ -1641,15 +1641,15 @@ AP_DECLARE(void) ap_method_list_remove(ap_method_list_t *l, * by a module, use the bitmask. */ methnum = ap_method_number_of(method); - l->method_mask |= ~(AP_METHOD_BIT << methnum); if (methnum != M_INVALID) { + l->method_mask &= ~(AP_METHOD_BIT << methnum); return; } /* * Otherwise, see if the method name is in the array of string names. */ if (l->method_list->nelts != 0) { - register int i, j, k; + int i, j, k; methods = (char **)l->method_list->elts; for (i = 0; i < l->method_list->nelts; ) { if (strcmp(method, methods[i]) == 0) { diff --git a/modules/http/http_request.c b/modules/http/http_request.c index 796d506e..cdfec8b5 100644 --- a/modules/http/http_request.c +++ b/modules/http/http_request.c @@ -463,6 +463,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, new->main = r->main; new->headers_in = r->headers_in; + new->trailers_in = r->trailers_in; new->headers_out = apr_table_make(r->pool, 12); if (ap_is_HTTP_REDIRECT(new->status)) { const char *location = apr_table_get(r->headers_out, "Location"); @@ -470,6 +471,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, apr_table_setn(new->headers_out, "Location", location); } new->err_headers_out = r->err_headers_out; + new->trailers_out = apr_table_make(r->pool, 5); new->subprocess_env = rename_original_env(r->pool, r->subprocess_env); new->notes = apr_table_make(r->pool, 5); @@ -583,6 +585,8 @@ AP_DECLARE(void) ap_internal_fast_redirect(request_rec *rr, request_rec *r) r->headers_out); r->err_headers_out = apr_table_overlay(r->pool, rr->err_headers_out, r->err_headers_out); + r->trailers_out = apr_table_overlay(r->pool, rr->trailers_out, + r->trailers_out); r->subprocess_env = apr_table_overlay(r->pool, rr->subprocess_env, r->subprocess_env); diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c index 0cc51c40..7440d9eb 100644 --- a/modules/ldap/util_ldap.c +++ b/modules/ldap/util_ldap.c @@ -1824,7 +1824,7 @@ start_over: * combination, which might be reused unintentionally next time this * connection is used from the connection pool. */ - ldc->must_rebind = 0; + ldc->must_rebind = 1; ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "LDC %pp used for authn, must be rebound", ldc); } diff --git a/modules/ldap/util_ldap_cache_mgr.c b/modules/ldap/util_ldap_cache_mgr.c index ae7e652a..2389b5d0 100644 --- a/modules/ldap/util_ldap_cache_mgr.c +++ b/modules/ldap/util_ldap_cache_mgr.c @@ -359,9 +359,11 @@ util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st, cache->maxentries = cache_size; cache->numentries = 0; cache->size = cache_size / 3; - if (cache->size < 64) cache->size = 64; - for (i = 0; primes[i] && primes[i] < cache->size; ++i) ; - cache->size = primes[i]? primes[i] : primes[i-1]; + if (cache->size < 64) + cache->size = 64; + for (i = 0; primes[i] && primes[i] < cache->size; ++i) + ; + cache->size = primes[i] ? primes[i] : primes[i-1]; cache->nodes = (util_cache_node_t **)util_ald_alloc(cache, cache->size * sizeof(util_cache_node_t *)); if (!cache->nodes) { diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c index 792756db..c1b0e1ba 100644 --- a/modules/loggers/mod_log_config.c +++ b/modules/loggers/mod_log_config.c @@ -431,6 +431,12 @@ static const char *log_header_in(request_rec *r, char *a) return ap_escape_logitem(r->pool, apr_table_get(r->headers_in, a)); } +static const char *log_trailer_in(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, apr_table_get(r->trailers_in, a)); +} + + static APR_INLINE char *find_multiple_headers(apr_pool_t *pool, const apr_table_t *table, const char *key) @@ -514,6 +520,11 @@ static const char *log_header_out(request_rec *r, char *a) return ap_escape_logitem(r->pool, cp); } +static const char *log_trailer_out(request_rec *r, char *a) +{ + return ap_escape_logitem(r->pool, apr_table_get(r->trailers_out, a)); +} + static const char *log_note(request_rec *r, char *a) { return ap_escape_logitem(r->pool, apr_table_get(r->notes, a)); @@ -916,7 +927,7 @@ static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it, static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa) { const char *s = *sa; - ap_log_handler *handler; + ap_log_handler *handler = NULL; if (*s != '%') { return parse_log_misc_string(p, it, sa); @@ -986,7 +997,16 @@ static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa) break; default: - handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1); + /* check for '^' + two character format first */ + if (*s == '^' && *(s+1) && *(s+2)) { + handler = (ap_log_handler *)apr_hash_get(log_hash, s, 3); + if (handler) { + s += 3; + } + } + if (!handler) { + handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1); + } if (!handler) { char dummy[2]; @@ -1516,7 +1536,7 @@ static void ap_register_log_handler(apr_pool_t *p, char *tag, log_struct->func = handler; log_struct->want_orig_default = def; - apr_hash_set(log_hash, tag, 1, (const void *)log_struct); + apr_hash_set(log_hash, tag, strlen(tag), (const void *)log_struct); } static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle) { @@ -1694,6 +1714,9 @@ static int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) log_pfn_register(p, "U", log_request_uri, 1); log_pfn_register(p, "s", log_status, 1); log_pfn_register(p, "R", log_handler, 1); + + log_pfn_register(p, "^ti", log_trailer_in, 0); + log_pfn_register(p, "^to", log_trailer_out, 0); } /* reset to default conditions */ diff --git a/modules/loggers/mod_logio.c b/modules/loggers/mod_logio.c index ad387a9b..359d4673 100644 --- a/modules/loggers/mod_logio.c +++ b/modules/loggers/mod_logio.c @@ -52,7 +52,8 @@ typedef struct logio_config_t { * Optional function for the core to add to bytes_out */ -static void ap_logio_add_bytes_out(conn_rec *c, apr_off_t bytes){ +static void ap_logio_add_bytes_out(conn_rec *c, apr_off_t bytes) +{ logio_config_t *cf = ap_get_module_config(c->conn_config, &logio_module); cf->bytes_out += bytes; @@ -62,7 +63,8 @@ static void ap_logio_add_bytes_out(conn_rec *c, apr_off_t bytes){ * Optional function for modules to adjust bytes_in */ -static void ap_logio_add_bytes_in(conn_rec *c, apr_off_t bytes){ +static void ap_logio_add_bytes_in(conn_rec *c, apr_off_t bytes) +{ logio_config_t *cf = ap_get_module_config(c->conn_config, &logio_module); cf->bytes_in += bytes; @@ -132,7 +134,8 @@ static apr_status_t logio_in_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, - apr_off_t readbytes) { + apr_off_t readbytes) +{ apr_off_t length; apr_status_t status; logio_config_t *cf = ap_get_module_config(f->c->conn_config, &logio_module); @@ -151,7 +154,8 @@ static apr_status_t logio_in_filter(ap_filter_t *f, * The hooks... */ -static int logio_pre_conn(conn_rec *c, void *csd) { +static int logio_pre_conn(conn_rec *c, void *csd) +{ logio_config_t *cf = apr_pcalloc(c->pool, sizeof(*cf)); ap_set_module_config(c->conn_config, &logio_module, cf); diff --git a/modules/lua/lua_apr.c b/modules/lua/lua_apr.c index 94761ba4..fd3ba20e 100644 --- a/modules/lua/lua_apr.c +++ b/modules/lua/lua_apr.c @@ -52,8 +52,8 @@ static int lua_table_set(lua_State *L) while ( (badchar = ap_strchr(badchar, '\n')) ) { *badchar = ' '; } - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, t->r, - APLOGNO(02614) "mod_lua: Value for '%s' in table '%s' contains newline!", + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, t->r, APLOGNO(02614) + "mod_lua: Value for '%s' in table '%s' contains newline!", key, t->n); apr_table_set(t->t, key, replacement); } diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c index 8b740c22..6dc6b9f5 100644 --- a/modules/lua/lua_request.c +++ b/modules/lua/lua_request.c @@ -2086,13 +2086,13 @@ static int lua_set_cookie(lua_State *L) if (expires > 0) { rv = apr_rfc822_date(cdate, apr_time_from_sec(expires)); if (rv == APR_SUCCESS) { - strexpires = apr_psprintf(r->pool, "Expires=\"%s\";", cdate); + strexpires = apr_psprintf(r->pool, "Expires=%s;", cdate); } } /* Create path segment */ if (path != NULL && strlen(path) > 0) { - strpath = apr_psprintf(r->pool, "Path=\"%s\";", path); + strpath = apr_psprintf(r->pool, "Path=%s;", path); } /* Create domain segment */ @@ -2171,13 +2171,13 @@ static int lua_websocket_greet(lua_State *L) r->read_chunked = 0; ap_rflush(r); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "Websocket: Upgraded from HTTP to Websocket"); + "Websocket: Upgraded from HTTP to Websocket"); lua_pushboolean(L, 1); return 1; } } - ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, - "Websocket: Upgrade from HTTP to Websocket failed"); + ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02666) + "Websocket: Upgrade from HTTP to Websocket failed"); return 0; } diff --git a/modules/lua/mod_lua.c b/modules/lua/mod_lua.c index 90f34cda..e6d2cfcc 100644 --- a/modules/lua/mod_lua.c +++ b/modules/lua/mod_lua.c @@ -66,9 +66,13 @@ typedef struct { const char *file_name; const char *function_name; ap_lua_vm_spec *spec; - apr_array_header_t *args; } lua_authz_provider_spec; +typedef struct { + lua_authz_provider_spec *spec; + apr_array_header_t *args; +} lua_authz_provider_func; + apr_hash_t *lua_authz_providers; typedef struct @@ -500,9 +504,9 @@ static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade ap_remove_output_filter(f); apr_brigade_cleanup(pbbIn); apr_brigade_cleanup(ctx->tmpBucket); - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "lua: Error while executing filter: %s", - lua_tostring(L, -1)); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02663) + "lua: Error while executing filter: %s", + lua_tostring(L, -1)); return HTTP_INTERNAL_SERVER_ERROR; } } @@ -1692,6 +1696,7 @@ static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line, { const char *provider_name; lua_authz_provider_spec *spec; + lua_authz_provider_func *func = apr_pcalloc(cmd->pool, sizeof(lua_authz_provider_func)); apr_pool_userdata_get((void**)&provider_name, AUTHZ_PROVIDER_NAME_NOTE, cmd->temp_pool); @@ -1699,16 +1704,17 @@ static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line, spec = apr_hash_get(lua_authz_providers, provider_name, APR_HASH_KEY_STRING); ap_assert(spec != NULL); + func->spec = spec; if (require_line && *require_line) { const char *arg; - spec->args = apr_array_make(cmd->pool, 2, sizeof(const char *)); + func->args = apr_array_make(cmd->pool, 2, sizeof(const char *)); while ((arg = ap_getword_conf(cmd->pool, &require_line)) && *arg) { - APR_ARRAY_PUSH(spec->args, const char *) = arg; + APR_ARRAY_PUSH(func->args, const char *) = arg; } } - *parsed_require_line = spec; + *parsed_require_line = func; return NULL; } @@ -1722,7 +1728,8 @@ static authz_status lua_authz_check(request_rec *r, const char *require_line, &lua_module); const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config, &lua_module); - const lua_authz_provider_spec *prov_spec = parsed_require_line; + const lua_authz_provider_func *prov_func = parsed_require_line; + const lua_authz_provider_spec *prov_spec = prov_func->spec; int result; int nargs = 0; @@ -1744,19 +1751,19 @@ static authz_status lua_authz_check(request_rec *r, const char *require_line, return AUTHZ_GENERAL_ERROR; } ap_lua_run_lua_request(L, r); - if (prov_spec->args) { + if (prov_func->args) { int i; - if (!lua_checkstack(L, prov_spec->args->nelts)) { + if (!lua_checkstack(L, prov_func->args->nelts)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02315) "Error: authz provider %s: too many arguments", prov_spec->name); ap_lua_release_state(L, spec, r); return AUTHZ_GENERAL_ERROR; } - for (i = 0; i < prov_spec->args->nelts; i++) { - const char *arg = APR_ARRAY_IDX(prov_spec->args, i, const char *); + for (i = 0; i < prov_func->args->nelts; i++) { + const char *arg = APR_ARRAY_IDX(prov_func->args, i, const char *); lua_pushstring(L, arg); } - nargs = prov_spec->args->nelts; + nargs = prov_func->args->nelts; } if (lua_pcall(L, 1 + nargs, 1, 0)) { const char *err = lua_tostring(L, -1); @@ -2003,7 +2010,7 @@ static int lua_post_config(apr_pool_t *pconf, apr_pool_t *plog, /* Create shared memory space */ rs = apr_temp_dir_get(&tempdir, pconf); if (rs != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, + ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, APLOGNO(02664) "mod_lua IVM: Failed to find temporary directory"); return HTTP_INTERNAL_SERVER_ERROR; } @@ -2012,7 +2019,7 @@ static int lua_post_config(apr_pool_t *pconf, apr_pool_t *plog, rs = apr_shm_create(&lua_ivm_shm, sizeof(apr_pool_t**), (const char *) lua_ivm_shmfile, pconf); if (rs != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, + ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, APLOGNO(02665) "mod_lua: Failed to create shared memory segment on file %s", lua_ivm_shmfile); return HTTP_INTERNAL_SERVER_ERROR; diff --git a/modules/mappers/mod_dir.c b/modules/mappers/mod_dir.c index 2a359c7f..542236b5 100644 --- a/modules/mappers/mod_dir.c +++ b/modules/mappers/mod_dir.c @@ -262,7 +262,7 @@ static int fixup_dir(request_rec *r) if (r->args != NULL) { ifile = apr_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri), - "/", "?", r->args, NULL); + "/?", r->args, NULL); } else { ifile = apr_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri), diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c index 5ec0d4d0..0089a6c9 100644 --- a/modules/mappers/mod_negotiation.c +++ b/modules/mappers/mod_negotiation.c @@ -1707,7 +1707,7 @@ static void set_language_quality(negotiation_state *neg, var_rec *variant) * we are allowed to use the prefix of in HTTP/1.1 */ char *lang = ((char **) (variant->content_languages->elts))[j]; - int idx = -1; + int idx; /* If we wish to fallback or * we use our own LanguagePriority index. diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 2fe9bf9e..de0c11ba 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -4161,7 +4161,6 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) r->filename)); r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL); - apr_table_setn(r->notes, "rewrite-proxy", "1"); return 1; } diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index b331a6c5..885a2c9e 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -174,6 +174,15 @@ static const char *set_worker_param(apr_pool_t *p, return "DisableReuse must be On|Off"; worker->s->disablereuse_set = 1; } + else if (!strcasecmp(key, "enablereuse")) { + if (!strcasecmp(val, "on")) + worker->s->disablereuse = 0; + else if (!strcasecmp(val, "off")) + worker->s->disablereuse = 1; + else + return "EnableReuse must be On|Off"; + worker->s->disablereuse_set = 1; + } else if (!strcasecmp(key, "route")) { /* Worker route. */ @@ -548,9 +557,9 @@ static const char *proxy_interpolate(request_rec *r, const char *str) return str; } /* OK, this is syntax we want to interpolate. Is there such a var ? */ - var = apr_pstrndup(r->pool, start+2, end-(start+2)); + var = apr_pstrmemdup(r->pool, start+2, end-(start+2)); val = apr_table_get(r->subprocess_env, var); - firstpart = apr_pstrndup(r->pool, str, (start-str)); + firstpart = apr_pstrmemdup(r->pool, str, (start-str)); if (val == NULL) { return apr_pstrcat(r->pool, firstpart, @@ -938,7 +947,6 @@ static int proxy_handler(request_rec *r) strncmp(r->filename, "proxy:", 6) != 0) { r->proxyreq = PROXYREQ_REVERSE; r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL); - apr_table_setn(r->notes, "rewrite-proxy", "1"); } else { return DECLINED; @@ -1044,7 +1052,7 @@ static int proxy_handler(request_rec *r) return HTTP_MOVED_PERMANENTLY; } - scheme = apr_pstrndup(r->pool, uri, p - uri); + scheme = apr_pstrmemdup(r->pool, uri, p - uri); /* Check URI's destination host against NoProxy hosts */ /* Bypass ProxyRemote server lookup if configured as NoProxy */ for (direct_connect = i = 0; i < conf->dirconn->nelts && @@ -1461,23 +1469,23 @@ static const char * return add_proxy(cmd, dummy, f1, r1, 1); } -static char *de_socketfy(apr_pool_t *p, char *url) +PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url) { - char *ptr; + const char *ptr; /* * We could be passed a URL during the config stage that contains * the UDS path... ignore it */ if (!strncasecmp(url, "unix:", 5) && - ((ptr = ap_strchr(url, '|')) != NULL)) { + ((ptr = ap_strchr_c(url, '|')) != NULL)) { /* move past the 'unix:...|' UDS path info */ - char *ret, *c; + const char *ret, *c; ret = ptr + 1; /* special case: "unix:....|scheme:" is OK, expand * to "unix:....|scheme://localhost" * */ - c = ap_strchr(ret, ':'); + c = ap_strchr_c(ret, ':'); if (c == NULL) { return NULL; } @@ -1582,7 +1590,7 @@ static const char * } new->fake = apr_pstrdup(cmd->pool, f); - new->real = apr_pstrdup(cmd->pool, de_socketfy(cmd->pool, r)); + new->real = apr_pstrdup(cmd->pool, ap_proxy_de_socketfy(cmd->pool, r)); new->flags = flags; if (use_regex) { new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED); @@ -1631,7 +1639,7 @@ static const char * new->balancer = balancer; } else { - proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->pool, r)); + proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->pool, r)); int reuse = 0; if (!worker) { const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0); @@ -2110,7 +2118,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) } /* Try to find existing worker */ - worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, de_socketfy(cmd->temp_pool, name)); + worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, ap_proxy_de_socketfy(cmd->temp_pool, name)); if (!worker) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147) "Defining worker '%s' for balancer '%s'", @@ -2196,7 +2204,7 @@ static const char * } } else { - worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->temp_pool, name)); + worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->temp_pool, name)); if (!worker) { if (in_proxy_section) { err = ap_proxy_define_worker(cmd->pool, &worker, NULL, @@ -2336,7 +2344,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) } else { worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf, - de_socketfy(cmd->temp_pool, (char*)conf->p)); + ap_proxy_de_socketfy(cmd->temp_pool, (char*)conf->p)); if (!worker) { err = ap_proxy_define_worker(cmd->pool, &worker, NULL, sconf, conf->p, 0); diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 4ead22e7..89f5c095 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -865,6 +865,17 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, proxy_conn_rec *conn, proxy_worker *worker, server_rec *s); + +/** + * Make a connection to a Unix Domain Socket (UDS) path + * @param sock UDS to connect + * @param uds_path UDS path to connect to + * @param p pool to make the sock addr + * @return APR_SUCCESS or error status + */ +PROXY_DECLARE(apr_status_t) ap_proxy_connect_uds(apr_socket_t *sock, + const char *uds_path, + apr_pool_t *p); /** * Make a connection record for backend connection * @param proxy_function calling proxy scheme (http, ajp, ...) @@ -1012,6 +1023,14 @@ int ap_proxy_lb_workers(void); */ PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme); +/** + * Strip a unix domain socket (UDS) prefix from the input URL + * @param p pool to allocate result from + * @param url a URL potentially prefixed with a UDS path + * @return URL with the UDS prefix removed + */ +PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url); + extern module PROXY_DECLARE_DATA proxy_module; #endif /*MOD_PROXY_H*/ diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index cf52a7d9..6a83aa2f 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -123,10 +123,7 @@ static apr_off_t get_content_length(request_rec * r) { apr_off_t len = 0; - if (r->clength > 0) { - return r->clength; - } - else if (r->main == NULL) { + if (r->main == NULL) { const char *clp = apr_table_get(r->headers_in, "Content-Length"); if (clp) { diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index acfd3861..f33aa936 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -98,7 +98,7 @@ static int proxy_balancer_canon(request_rec *r, char *url) if (path == NULL) return HTTP_BAD_REQUEST; - r->filename = apr_pstrcat(r->pool, "proxy:", BALANCER_PREFIX, host, + r->filename = apr_pstrcat(r->pool, "proxy:" BALANCER_PREFIX, host, "/", path, (search) ? "?" : "", (search) ? search : "", NULL); r->path_info = apr_pstrcat(r->pool, "/", path, NULL); diff --git a/modules/proxy/mod_proxy_connect.c b/modules/proxy/mod_proxy_connect.c index 9a1bfefb..2a34a15b 100644 --- a/modules/proxy/mod_proxy_connect.c +++ b/modules/proxy/mod_proxy_connect.c @@ -210,7 +210,6 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, char buffer[HUGE_STRING_LEN]; apr_socket_t *client_socket = ap_get_conn_socket(c); int failed, rc; - int client_error = 0; apr_pollset_t *pollset; apr_pollfd_t pollfd; const apr_pollfd_t *signalled; @@ -320,7 +319,7 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, /* Add client side to the poll */ pollfd.p = r->pool; pollfd.desc_type = APR_POLL_SOCKET; - pollfd.reqevents = APR_POLLIN; + pollfd.reqevents = APR_POLLIN | APR_POLLHUP; pollfd.desc.s = client_socket; pollfd.client_data = NULL; apr_pollset_add(pollset, &pollfd); @@ -434,31 +433,35 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, if (cur->desc.s == sock) { pollevent = cur->rtnevents; - if (pollevent & APR_POLLIN) { + if (pollevent & (APR_POLLIN | APR_POLLHUP)) { #ifdef DEBUGGING ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01025) "sock was readable"); #endif rv = proxy_connect_transfer(r, backconn, c, bb, "sock"); - } - else if ((pollevent & APR_POLLERR) - || (pollevent & APR_POLLHUP)) { - rv = APR_EPIPE; - ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(01026) - "err/hup on backconn"); } - if (rv != APR_SUCCESS) - client_error = 1; + else if (pollevent & APR_POLLERR) { + rv = APR_EPIPE; + backconn->aborted = 1; + ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(01026) + "err on backconn"); + } } else if (cur->desc.s == client_socket) { pollevent = cur->rtnevents; - if (pollevent & APR_POLLIN) { + if (pollevent & (APR_POLLIN | APR_POLLHUP)) { #ifdef DEBUGGING ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01027) "client was readable"); #endif rv = proxy_connect_transfer(r, c, backconn, bb, "client"); } + else if (pollevent & APR_POLLERR) { + rv = APR_EPIPE; + c->aborted = 1; + ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(01026) + "err on client"); + } } else { rv = APR_EBADF; @@ -481,12 +484,11 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, * Close the socket and clean up */ - if (client_error) + if (backconn->aborted) apr_socket_close(sock); else ap_lingering_close(backconn); - c->aborted = 1; c->keepalive = AP_CONN_CLOSE; return OK; diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c index e2fb59cd..f528b3df 100644 --- a/modules/proxy/mod_proxy_fcgi.c +++ b/modules/proxy/mod_proxy_fcgi.c @@ -20,6 +20,10 @@ module AP_MODULE_DECLARE_DATA proxy_fcgi_module; +typedef struct { + int need_dirwalk; +} fcgi_req_config_t; + /* * Canonicalise http-like URLs. * scheme is the scheme for the URL @@ -29,8 +33,11 @@ module AP_MODULE_DECLARE_DATA proxy_fcgi_module; static int proxy_fcgi_canon(request_rec *r, char *url) { char *host, sport[7]; - const char *err, *path; + const char *err; + char *path; apr_port_t port, def_port; + fcgi_req_config_t *rconf = NULL; + const char *pathinfo_type = NULL; if (strncasecmp(url, "fcgi:", 5) == 0) { url += 5; @@ -76,11 +83,51 @@ static int proxy_fcgi_canon(request_rec *r, char *url) ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01060) "set r->filename to %s", r->filename); - if (apr_table_get(r->subprocess_env, "proxy-fcgi-pathinfo")) { - r->path_info = apr_pstrcat(r->pool, "/", path, NULL); + rconf = ap_get_module_config(r->request_config, &proxy_fcgi_module); + if (rconf == NULL) { + rconf = apr_pcalloc(r->pool, sizeof(fcgi_req_config_t)); + ap_set_module_config(r->request_config, &proxy_fcgi_module, rconf); + } - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01061) - "set r->path_info to %s", r->path_info); + if (NULL != (pathinfo_type = apr_table_get(r->subprocess_env, "proxy-fcgi-pathinfo"))) { + /* It has to be on disk for this to work */ + if (!strcasecmp(pathinfo_type, "full")) { + rconf->need_dirwalk = 1; + ap_unescape_url_keep2f(path, 0); + } + else if (!strcasecmp(pathinfo_type, "first-dot")) { + char *split = ap_strchr(path, '.'); + if (split) { + char *slash = ap_strchr(split, '/'); + if (slash) { + r->path_info = apr_pstrdup(r->pool, slash); + ap_unescape_url_keep2f(r->path_info, 0); + *slash = '\0'; /* truncate path */ + } + } + } + else if (!strcasecmp(pathinfo_type, "last-dot")) { + char *split = ap_strrchr(path, '.'); + if (split) { + char *slash = ap_strchr(split, '/'); + if (slash) { + r->path_info = apr_pstrdup(r->pool, slash); + ap_unescape_url_keep2f(r->path_info, 0); + *slash = '\0'; /* truncate path */ + } + } + } + else { + /* before proxy-fcgi-pathinfo had multi-values. This requires the + * the FCGI server to fixup PATH_INFO because it's the entire path + */ + r->path_info = apr_pstrcat(r->pool, "/", path, NULL); + if (!strcasecmp(pathinfo_type, "unescape")) { + ap_unescape_url_keep2f(r->path_info, 0); + } + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01061) + "set r->path_info to %s", r->path_info); + } } return OK; @@ -204,9 +251,26 @@ static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, apr_status_t rv; apr_size_t avail_len, len, required_len; int next_elem, starting_elem; + char *proxyfilename = r->filename; + fcgi_req_config_t *rconf = ap_get_module_config(r->request_config, &proxy_fcgi_module); + + if (rconf) { + if (rconf->need_dirwalk) { + ap_directory_walk(r); + } + } + + /* Strip balancer prefix */ + if (r->filename && !strncmp(r->filename, "proxy:balancer://", 17)) { + char *newfname = apr_pstrdup(r->pool, r->filename+17); + newfname = ap_strchr(newfname, '/'); + r->filename = newfname; + } ap_add_common_vars(r); ap_add_cgi_vars(r); + + r->filename = proxyfilename; /* XXX are there any FastCGI specific env vars we need to send? */ @@ -308,13 +372,12 @@ enum { * * Returns 0 if it can't find the end of the headers, and 1 if it found the * end of the headers. */ -static int handle_headers(request_rec *r, - int *state, - char *readbuf) +static int handle_headers(request_rec *r, int *state, + const char *readbuf, apr_size_t readlen) { const char *itr = readbuf; - while (*itr) { + while (readlen--) { if (*itr == '\r') { switch (*state) { case HDR_STATE_GOT_CRLF: @@ -368,7 +431,7 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, const char **err) { apr_bucket_brigade *ib, *ob; - int seen_end_of_headers = 0, done = 0; + int seen_end_of_headers = 0, done = 0, ignore_body = 0; apr_status_t rv = APR_SUCCESS; int script_error_status = HTTP_OK; conn_rec *c = r->connection; @@ -561,7 +624,8 @@ recv_again: APR_BRIGADE_INSERT_TAIL(ob, b); if (! seen_end_of_headers) { - int st = handle_headers(r, &header_state, iobuf); + int st = handle_headers(r, &header_state, + iobuf, readbuflen); if (st == 1) { int status; @@ -577,9 +641,16 @@ recv_again: APR_BRIGADE_INSERT_TAIL(ob, tmp_b); r->status = status; ap_pass_brigade(r->output_filters, ob); - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01070) - "Error parsing script headers"); - rv = APR_EINVAL; + if (status == HTTP_NOT_MODIFIED) { + /* The 304 response MUST NOT contain + * a message-body, ignore it. */ + ignore_body = 1; + } + else { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01070) + "Error parsing script headers"); + rv = APR_EINVAL; + } break; } @@ -598,7 +669,7 @@ recv_again: } if (script_error_status == HTTP_OK - && !APR_BRIGADE_EMPTY(ob)) { + && !APR_BRIGADE_EMPTY(ob) && !ignore_body) { /* Send the part of the body that we read while * reading the headers. */ @@ -626,7 +697,7 @@ recv_again: * but that could be a huge amount of data; so we pass * along smaller chunks */ - if (script_error_status == HTTP_OK) { + if (script_error_status == HTTP_OK && !ignore_body) { rv = ap_pass_brigade(r->output_filters, ob); if (rv != APR_SUCCESS) { *err = "passing brigade to output filters"; @@ -636,7 +707,7 @@ recv_again: apr_brigade_cleanup(ob); } - /* If we didn't read all the data go back and get the + /* If we didn't read all the data, go back and get the * rest of it. */ if (clen > readbuflen) { clen -= readbuflen; @@ -663,7 +734,7 @@ recv_again: /* TODO: Should probably clean up this logging a bit... */ if (clen) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01071) - "Got error '%s'", iobuf); + "Got error '%.*s'", (int)readbuflen, iobuf); } if (clen > readbuflen) { @@ -681,12 +752,16 @@ recv_again: "Got bogus record %d", type); break; } + /* Leave on above switch's inner error. */ + if (rv != APR_SUCCESS) { + break; + } if (plen) { rv = get_data_full(conn, iobuf, plen); if (rv != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - APLOGNO(02537) "Error occurred reading padding"); + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02537) + "Error occurred reading padding"); break; } } @@ -714,7 +789,7 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r, char *url, char *server_portstr) { /* Request IDs are arbitrary numbers that we assign to a - * single request. This would allow multiplex/pipelinig of + * single request. This would allow multiplex/pipelining of * multiple requests to the same FastCGI connection, but * we don't support that, and always use a value of '1' to * keep things simple. */ @@ -814,11 +889,15 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, goto cleanup; } - /* XXX Setting close to 0 is a great way to end up with - * timeouts at this point, since we lack good ways to manage the - * back end fastcgi processes. This should be revisited when we - * have a better story on that part of things. */ + /* This scheme handler does not reuse connections by default, to + * avoid tieing up a fastcgi that isn't expecting to work on + * parallel requests. But if the user went out of their way to + * type the default value of disablereuse=off, we'll allow it. + */ backend->close = 1; + if (worker->s->disablereuse_set && !worker->s->disablereuse) { + backend->close = 0; + } /* Step Two: Make the Connection */ if (ap_proxy_connect_backend(FCGI_SCHEME, backend, worker, r->server)) { diff --git a/modules/proxy/mod_proxy_fdpass.c b/modules/proxy/mod_proxy_fdpass.c index 26a7b13e..63cf4696 100644 --- a/modules/proxy/mod_proxy_fdpass.c +++ b/modules/proxy/mod_proxy_fdpass.c @@ -24,12 +24,6 @@ #error This module only works on unix platforms with the correct OS support #endif -#include "apr_version.h" -#if APR_MAJOR_VERSION < 2 -/* for apr_wait_for_io_or_timeout */ -#include "apr_support.h" -#endif - #include "mod_proxy_fdpass.h" module AP_MODULE_DECLARE_DATA proxy_fdpass_module; @@ -54,54 +48,10 @@ static int proxy_fdpass_canon(request_rec *r, char *url) return OK; } -/* TODO: In APR 2.x: Extend apr_sockaddr_t to possibly be a path !!! */ -static apr_status_t socket_connect_un(apr_socket_t *sock, - struct sockaddr_un *sa) -{ - apr_status_t rv; - apr_os_sock_t rawsock; - apr_interval_time_t t; - - rv = apr_os_sock_get(&rawsock, sock); - if (rv != APR_SUCCESS) { - return rv; - } - - rv = apr_socket_timeout_get(sock, &t); - if (rv != APR_SUCCESS) { - return rv; - } - - do { - rv = connect(rawsock, (struct sockaddr*)sa, - sizeof(*sa) + strlen(sa->sun_path)); - } while (rv == -1 && errno == EINTR); - - if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY) - && (t > 0)) { -#if APR_MAJOR_VERSION < 2 - rv = apr_wait_for_io_or_timeout(NULL, sock, 0); -#else - rv = apr_socket_wait(sock, APR_WAIT_WRITE); -#endif - - if (rv != APR_SUCCESS) { - return rv; - } - } - - if (rv == -1 && errno != EISCONN) { - return errno; - } - - return APR_SUCCESS; -} - static apr_status_t get_socket_from_path(apr_pool_t *p, const char* path, apr_socket_t **out_sock) { - struct sockaddr_un sa; apr_socket_t *s; apr_status_t rv; *out_sock = NULL; @@ -112,10 +62,7 @@ static apr_status_t get_socket_from_path(apr_pool_t *p, return rv; } - sa.sun_family = AF_UNIX; - apr_cpystrn(sa.sun_path, path, sizeof(sa.sun_path)); - - rv = socket_connect_un(s, &sa); + rv = ap_proxy_connect_uds(s, path, p); if (rv != APR_SUCCESS) { return rv; } diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c index cf5d5130..5c689aa1 100644 --- a/modules/proxy/mod_proxy_ftp.c +++ b/modules/proxy/mod_proxy_ftp.c @@ -275,8 +275,7 @@ static apr_status_t ftp_string_read(conn_rec *c, apr_bucket_brigade *bb, pos += len; } } - APR_BUCKET_REMOVE(e); - apr_bucket_destroy(e); + apr_bucket_delete(e); } *pos = '\0'; } @@ -448,7 +447,7 @@ static apr_status_t proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *out = apr_brigade_create(p, c->bucket_alloc); apr_status_t rv; - register int n; + int n; char *dir, *path, *reldir, *site, *str, *type; const char *pwd = apr_table_get(r->notes, "Directory-PWD"); @@ -634,8 +633,7 @@ static apr_status_t proxy_send_dir_filter(ap_filter_t *f, /* len+1 to leave space for the trailing nil char */ apr_cpystrn(ctx->buffer+strlen(ctx->buffer), response, len+1); - APR_BUCKET_REMOVE(e); - apr_bucket_destroy(e); + apr_bucket_delete(e); } /* EOS? jump to footer */ @@ -1767,39 +1765,39 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, r, origin, bb, &ftpmessage); /* then extract the Last-Modified time from it (YYYYMMDDhhmmss or YYYYMMDDhhmmss.xxx GMT). */ if (rc == 213) { - struct { - char YYYY[4+1]; - char MM[2+1]; - char DD[2+1]; - char hh[2+1]; - char mm[2+1]; - char ss[2+1]; - } time_val; - if (6 == sscanf(ftpmessage, "%4[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]", - time_val.YYYY, time_val.MM, time_val.DD, time_val.hh, time_val.mm, time_val.ss)) { + struct { + char YYYY[4+1]; + char MM[2+1]; + char DD[2+1]; + char hh[2+1]; + char mm[2+1]; + char ss[2+1]; + } time_val; + if (6 == sscanf(ftpmessage, "%4[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]", + time_val.YYYY, time_val.MM, time_val.DD, time_val.hh, time_val.mm, time_val.ss)) { struct tm tms; - memset (&tms, '\0', sizeof tms); - tms.tm_year = atoi(time_val.YYYY) - 1900; - tms.tm_mon = atoi(time_val.MM) - 1; - tms.tm_mday = atoi(time_val.DD); - tms.tm_hour = atoi(time_val.hh); - tms.tm_min = atoi(time_val.mm); - tms.tm_sec = atoi(time_val.ss); + memset (&tms, '\0', sizeof tms); + tms.tm_year = atoi(time_val.YYYY) - 1900; + tms.tm_mon = atoi(time_val.MM) - 1; + tms.tm_mday = atoi(time_val.DD); + tms.tm_hour = atoi(time_val.hh); + tms.tm_min = atoi(time_val.mm); + tms.tm_sec = atoi(time_val.ss); #ifdef HAVE_TIMEGM /* Does system have timegm()? */ - mtime = timegm(&tms); - mtime *= APR_USEC_PER_SEC; + mtime = timegm(&tms); + mtime *= APR_USEC_PER_SEC; #elif HAVE_GMTOFF /* does struct tm have a member tm_gmtoff? */ /* mktime will subtract the local timezone, which is not what we want. - * Add it again because the MDTM string is GMT - */ - mtime = mktime(&tms); - mtime += tms.tm_gmtoff; - mtime *= APR_USEC_PER_SEC; + * Add it again because the MDTM string is GMT + */ + mtime = mktime(&tms); + mtime += tms.tm_gmtoff; + mtime *= APR_USEC_PER_SEC; #else - mtime = 0L; + mtime = 0L; #endif } - } + } #endif /* USE_MDTM */ /* FIXME: Handle range requests - send REST */ buf = apr_pstrcat(p, "RETR ", ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL); diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 141452bf..98a93dd2 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -687,7 +687,6 @@ static apr_status_t proxy_buckets_lifetime_transform(request_rec *r, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00964) "Unhandled bucket type of type %s in" " proxy_buckets_lifetime_transform", e->type->name); - apr_bucket_delete(e); rv = APR_EGENERAL; } } @@ -750,14 +749,8 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, if (!r->kept_body && r->main) { /* XXX: Why DON'T sub-requests use keepalives? */ p_conn->close = 1; - if (old_cl_val) { - old_cl_val = NULL; - apr_table_unset(r->headers_in, "Content-Length"); - } - if (old_te_val) { - old_te_val = NULL; - apr_table_unset(r->headers_in, "Transfer-Encoding"); - } + old_cl_val = NULL; + old_te_val = NULL; rb_method = RB_STREAM_CL; e = apr_bucket_eos_create(input_brigade->bucket_alloc); APR_BRIGADE_INSERT_TAIL(input_brigade, e); @@ -783,7 +776,6 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, "client %s (%s) requested Transfer-Encoding " "chunked body with Content-Length (C-L ignored)", c->client_ip, c->remote_host ? c->remote_host: ""); - apr_table_unset(r->headers_in, "Content-Length"); old_cl_val = NULL; origin->keepalive = AP_CONN_CLOSE; p_conn->close = 1; @@ -1011,8 +1003,11 @@ static request_rec *make_fake_req(conn_rec *c, request_rec *r) rp->status = HTTP_OK; rp->headers_in = apr_table_make(pool, 50); + rp->trailers_in = apr_table_make(pool, 5); + rp->subprocess_env = apr_table_make(pool, 50); rp->headers_out = apr_table_make(pool, 12); + rp->trailers_out = apr_table_make(pool, 5); rp->err_headers_out = apr_table_make(pool, 5); rp->notes = apr_table_make(pool, 5); @@ -1093,6 +1088,7 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr, psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); r->headers_out = apr_table_make(r->pool, 20); + r->trailers_out = apr_table_make(r->pool, 5); *pread_len = 0; /* @@ -1223,6 +1219,14 @@ apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec #define AP_MAX_INTERIM_RESPONSES 10 #endif +static int add_trailers(void *data, const char *key, const char *val) +{ + if (val) { + apr_table_add((apr_table_t*)data, key, val); + } + return 1; +} + static apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, proxy_conn_rec **backend_ptr, @@ -1640,6 +1644,18 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, if (!r->header_only && /* not HEAD request */ (proxy_status != HTTP_NO_CONTENT) && /* not 204 */ (proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */ + const char *tmp; + /* Add minimal headers needed to allow http_in filter + * detecting end of body without waiting for a timeout. */ + if ((tmp = apr_table_get(r->headers_out, "Transfer-Encoding"))) { + apr_table_set(backend->r->headers_in, "Transfer-Encoding", tmp); + } + else if ((tmp = apr_table_get(r->headers_out, "Content-Length"))) { + apr_table_set(backend->r->headers_in, "Content-Length", tmp); + } + else if (te) { + apr_table_set(backend->r->headers_in, "Transfer-Encoding", te); + } ap_discard_request_body(backend->r); } return proxy_status; @@ -1735,6 +1751,12 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, /* next time try a non-blocking read */ mode = APR_NONBLOCK_READ; + if (!apr_is_empty_table(backend->r->trailers_in)) { + apr_table_do(add_trailers, r->trailers_out, + backend->r->trailers_in, NULL); + apr_table_clear(backend->r->trailers_in); + } + apr_brigade_length(bb, 0, &readbytes); backend->worker->s->read += readbytes; #if DEBUGGING diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c index a2172fe2..1eb6ac89 100644 --- a/modules/proxy/mod_proxy_wstunnel.c +++ b/modules/proxy/mod_proxy_wstunnel.c @@ -141,40 +141,17 @@ static int proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o, return rv; } -/* Search thru the input filters and remove the reqtimeout one */ -static void remove_reqtimeout(ap_filter_t *next) -{ - ap_filter_t *reqto = NULL; - ap_filter_rec_t *filter; - - filter = ap_get_input_filter_handle("reqtimeout"); - if (!filter) { - return; - } - - while (next) { - if (next->frec == filter) { - reqto = next; - break; - } - next = next->next; - } - if (reqto) { - ap_remove_input_filter(reqto); - } -} - /* * process the request and write the response. */ -static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, +static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, proxy_conn_rec *conn, proxy_worker *worker, proxy_server_conf *conf, apr_uri_t *uri, char *url, char *server_portstr) { - apr_status_t rv = APR_SUCCESS; + apr_status_t rv; apr_pollset_t *pollset; apr_pollfd_t pollfd; const apr_pollfd_t *signalled; @@ -236,7 +213,7 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, pollfd.desc.s = client_socket; apr_pollset_add(pollset, &pollfd); - remove_reqtimeout(c->input_filters); + ap_remove_input_filter_byhandle(c->input_filters, "reqtimeout"); r->output_filters = c->output_filters; r->proto_output_filters = c->output_filters; @@ -271,6 +248,7 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, } else if (pollevent & APR_POLLERR) { rv = APR_EPIPE; + backconn->aborted = 1; ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447) "error on backconn"); } @@ -394,7 +372,7 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, /* Step Three: Process the Request */ - status = ap_proxy_wstunnel_request(p, r, backend, worker, conf, uri, locurl, + status = proxy_wstunnel_request(p, r, backend, worker, conf, uri, locurl, server_portstr); break; } diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index bc840499..83131c12 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -940,7 +940,7 @@ PROXY_DECLARE(const char *) ap_proxy_location_reverse_map(request_rec *r, part = url; } } - if (l1 >= l2 && strncasecmp(real, part, l2) == 0) { + if (l2 > 0 && l1 >= l2 && strncasecmp(real, part, l2) == 0) { u = apr_pstrcat(r->pool, ent[i].fake, &part[l2], NULL); return ap_is_url(u) ? u : ap_construct_url(r->pool, u, r); } @@ -1528,6 +1528,8 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, return NULL; } + url = ap_proxy_de_socketfy(p, url); + c = ap_strchr_c(url, ':'); if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') { return NULL; @@ -1683,9 +1685,13 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, memset(wshared, 0, sizeof(proxy_worker_shared)); + if (uri.port && uri.port == ap_proxy_port_of_scheme(uri.scheme)) { + uri.port = 0; + } ptr = apr_uri_unparse(p, &uri, APR_URI_UNP_REVEALPASSWORD); if (PROXY_STRNCPY(wshared->name, ptr) != APR_SUCCESS) { - return apr_psprintf(p, "worker name (%s) too long", ptr); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(02808) + "Alert! worker name (%s) too long; truncated to: %s", ptr, wshared->name); } if (PROXY_STRNCPY(wshared->scheme, uri.scheme) != APR_SUCCESS) { return apr_psprintf(p, "worker scheme (%s) too long", uri.scheme); @@ -1897,6 +1903,40 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke } } +/* + * In the case of the reverse proxy, we need to see if we + * were passed a UDS url (eg: from mod_proxy) and adjust uds_path + * as required. + */ +static void fix_uds_filename(request_rec *r, char **url) +{ + char *ptr, *ptr2; + if (!r || !r->filename) return; + + if (!strncmp(r->filename, "proxy:", 6) && + (ptr2 = ap_strcasestr(r->filename, "unix:")) && + (ptr = ap_strchr(ptr2, '|'))) { + apr_uri_t urisock; + apr_status_t rv; + *ptr = '\0'; + rv = apr_uri_parse(r->pool, ptr2, &urisock); + if (rv == APR_SUCCESS) { + char *rurl = ptr+1; + char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path); + apr_table_setn(r->notes, "uds_path", sockpath); + *url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */ + /* r->filename starts w/ "proxy:", so add after that */ + memmove(r->filename+6, rurl, strlen(rurl)+1); + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "*: rewrite of url due to UDS(%s): %s (%s)", + sockpath, *url, r->filename); + } + else { + *ptr = '|'; + } + } +} + PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, proxy_balancer **balancer, request_rec *r, @@ -1911,8 +1951,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "%s: found worker %s for %s", (*worker)->s->scheme, (*worker)->s->name, *url); - *balancer = NULL; + fix_uds_filename(r, url); access_status = OK; } else if (r->proxyreq == PROXYREQ_PROXY) { @@ -1932,10 +1972,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, } else if (r->proxyreq == PROXYREQ_REVERSE) { if (conf->reverse) { - char *ptr; - char *ptr2; ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, - "*: found reverse proxy worker for %s", *url); + "*: using default reverse proxy worker for %s (no keepalive)", *url); *balancer = NULL; *worker = conf->reverse; access_status = OK; @@ -1945,36 +1983,7 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, * regarding the Connection header in the request. */ apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1"); - /* - * In the case of the generic reverse proxy, we need to see if we - * were passed a UDS url (eg: from mod_proxy) and adjust uds_path - * as required. - * - * NOTE: Here we use a quick note lookup, but we could also - * check to see if r->filename starts with 'proxy:' - */ - if (apr_table_get(r->notes, "rewrite-proxy") && - (ptr2 = ap_strcasestr(r->filename, "unix:")) && - (ptr = ap_strchr(ptr2, '|'))) { - apr_uri_t urisock; - apr_status_t rv; - *ptr = '\0'; - rv = apr_uri_parse(r->pool, ptr2, &urisock); - if (rv == APR_SUCCESS) { - char *rurl = ptr+1; - char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path); - apr_table_setn(r->notes, "uds_path", sockpath); - *url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */ - /* r->filename starts w/ "proxy:", so add after that */ - memmove(r->filename+6, rurl, strlen(rurl)+1); - ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, - "*: rewrite of url due to UDS(%s): %s (%s)", - sockpath, *url, r->filename); - } - else { - *ptr = '|'; - } - } + fix_uds_filename(r, url); } } } @@ -2493,6 +2502,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes, "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); + ap_xlate_proto_to_ascii(buffer, nbytes); apr_socket_send(backend->sock, buffer, &nbytes); /* Receive the whole CONNECT response */ @@ -2504,7 +2514,8 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, len += nbytes; left -= nbytes; buffer[len] = '\0'; - if (strstr(buffer + len - nbytes, "\r\n\r\n") != NULL) { + if (strstr(buffer + len - nbytes, CRLF_ASCII CRLF_ASCII) != NULL) { + ap_xlate_proto_from_ascii(buffer, len); complete = 1; break; } @@ -2516,7 +2527,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, status = apr_socket_recv(backend->sock, drain_buffer, &nbytes); drain_buffer[nbytes] = '\0'; nbytes = sizeof(drain_buffer) - 1; - if (strstr(drain_buffer, "\r\n\r\n") != NULL) { + if (strstr(drain_buffer, CRLF_ASCII CRLF_ASCII) != NULL) { break; } } @@ -2524,7 +2535,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, /* Check for HTTP_OK response status */ if (status == APR_SUCCESS) { - int major, minor; + unsigned int major, minor; /* Only scan for three character status code */ char code_str[4]; @@ -2542,7 +2553,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00950) "send_http_connect: the forward proxy returned code is '%s'", code_str); - status = APR_INCOMPLETE; + status = APR_INCOMPLETE; } } } @@ -2552,13 +2563,16 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, #if APR_HAVE_SYS_UN_H -/* lifted from mod_proxy_fdpass.c; tweaked addrlen in connect() call */ -static apr_status_t socket_connect_un(apr_socket_t *sock, - struct sockaddr_un *sa) +/* TODO: In APR 2.x: Extend apr_sockaddr_t to possibly be a path !!! */ +PROXY_DECLARE(apr_status_t) ap_proxy_connect_uds(apr_socket_t *sock, + const char *uds_path, + apr_pool_t *p) { apr_status_t rv; apr_os_sock_t rawsock; apr_interval_time_t t; + struct sockaddr_un *sa; + apr_socklen_t addrlen, pathlen; rv = apr_os_sock_get(&rawsock, sock); if (rv != APR_SUCCESS) { @@ -2570,29 +2584,30 @@ static apr_status_t socket_connect_un(apr_socket_t *sock, return rv; } + pathlen = strlen(uds_path); + /* copy the UDS path (including NUL) to the sockaddr_un */ + addrlen = APR_OFFSETOF(struct sockaddr_un, sun_path) + pathlen; + sa = (struct sockaddr_un *)apr_palloc(p, addrlen + 1); + memcpy(sa->sun_path, uds_path, pathlen + 1); + sa->sun_family = AF_UNIX; + do { - const socklen_t addrlen = APR_OFFSETOF(struct sockaddr_un, sun_path) - + strlen(sa->sun_path) + 1; rv = connect(rawsock, (struct sockaddr*)sa, addrlen); - } while (rv == -1 && errno == EINTR); + } while (rv == -1 && (rv = errno) == EINTR); - if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY) - && (t > 0)) { + if (rv && rv != EISCONN) { + if ((rv == EINPROGRESS || rv == EALREADY) && (t > 0)) { #if APR_MAJOR_VERSION < 2 - rv = apr_wait_for_io_or_timeout(NULL, sock, 0); + rv = apr_wait_for_io_or_timeout(NULL, sock, 0); #else - rv = apr_socket_wait(sock, APR_WAIT_WRITE); + rv = apr_socket_wait(sock, APR_WAIT_WRITE); #endif - + } if (rv != APR_SUCCESS) { return rv; } } - if (rv == -1 && errno != EISCONN) { - return errno; - } - return APR_SUCCESS; } #endif @@ -2625,8 +2640,6 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, #if APR_HAVE_SYS_UN_H if (conn->uds_path) { - struct sockaddr_un sa; - rv = apr_socket_create(&newsock, AF_UNIX, SOCK_STREAM, 0, conn->scpool); if (rv != APR_SUCCESS) { @@ -2640,10 +2653,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, } conn->connection = NULL; - sa.sun_family = AF_UNIX; - apr_cpystrn(sa.sun_path, conn->uds_path, sizeof(sa.sun_path)); - - rv = socket_connect_un(newsock, &sa); + rv = ap_proxy_connect_uds(newsock, conn->uds_path, conn->scpool); if (rv != APR_SUCCESS) { apr_socket_close(newsock); ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02454) @@ -2654,6 +2664,13 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, worker->s->hostname); break; } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02823) + "%s: connection established with Unix domain socket " + "%s (%s)", + proxy_function, + conn->uds_path, + worker->s->hostname); } else #endif @@ -2746,6 +2763,12 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, backend_addr = backend_addr->next; continue; } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02824) + "%s: connection established with %pI (%s)", + proxy_function, + backend_addr, + worker->s->hostname); } /* Set a timeout on the socket */ @@ -2817,6 +2840,33 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, return connected ? OK : DECLINED; } +static apr_status_t connection_shutdown(void *theconn) +{ + proxy_conn_rec *conn = (proxy_conn_rec *)theconn; + conn_rec *c = conn->connection; + if (c) { + if (!c->aborted) { + apr_interval_time_t saved_timeout = 0; + apr_socket_timeout_get(conn->sock, &saved_timeout); + if (saved_timeout) { + apr_socket_timeout_set(conn->sock, 0); + } + + (void)ap_shutdown_conn(c, 0); + c->aborted = 1; + + if (saved_timeout) { + apr_socket_timeout_set(conn->sock, saved_timeout); + } + } + + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02642) + "proxy: connection shutdown"); + } + return APR_SUCCESS; +} + + PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, proxy_conn_rec *conn, conn_rec *c, @@ -2889,6 +2939,11 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, } apr_socket_timeout_set(conn->sock, current_timeout); + /* Shutdown the connection before closing it (eg. SSL connections + * need to be close-notify-ed). + */ + apr_pool_pre_cleanup_register(conn->scpool, conn, connection_shutdown); + return OK; } @@ -3202,7 +3257,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, char *buf; const apr_array_header_t *headers_in_array; const apr_table_entry_t *headers_in; - apr_table_t *headers_in_copy; + apr_table_t *saved_headers_in; apr_bucket *e; int do_100_continue; conn_rec *origin = p_conn->connection; @@ -3274,6 +3329,21 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); + /* + * Save the original headers in here and restore them when leaving, since + * we will apply proxy purpose only modifications (eg. clearing hop-by-hop + * headers, add Via or X-Forwarded-* or Expect...), whereas the originals + * will be needed later to prepare the correct response and logging. + * + * Note: We need to take r->pool for apr_table_copy as the key / value + * pairs in r->headers_in have been created out of r->pool and + * p might be (and actually is) a longer living pool. + * This would trigger the bad pool ancestry abort in apr_table_copy if + * apr is compiled with APR_POOL_DEBUG. + */ + saved_headers_in = r->headers_in; + r->headers_in = apr_table_copy(r->pool, saved_headers_in); + /* handle Via */ if (conf->viaopt == via_block) { /* Block all outgoing Via: headers */ @@ -3372,21 +3442,10 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, } proxy_run_fixups(r); - /* - * Make a copy of the headers_in table before clearing the connection - * headers as we need the connection headers later in the http output - * filter to prepare the correct response headers. - * - * Note: We need to take r->pool for apr_table_copy as the key / value - * pairs in r->headers_in have been created out of r->pool and - * p might be (and actually is) a longer living pool. - * This would trigger the bad pool ancestry abort in apr_table_copy if - * apr is compiled with APR_POOL_DEBUG. - */ - headers_in_copy = apr_table_copy(r->pool, r->headers_in); - ap_proxy_clear_connection(r, headers_in_copy); + ap_proxy_clear_connection(r, r->headers_in); + /* send request headers */ - headers_in_array = apr_table_elts(headers_in_copy); + headers_in_array = apr_table_elts(r->headers_in); headers_in = (const apr_table_entry_t *) headers_in_array->elts; for (counter = 0; counter < headers_in_array->nelts; counter++) { if (headers_in[counter].key == NULL @@ -3432,7 +3491,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, /* for sub-requests, ignore freshness/expiry headers */ if (r->main) { - if ( !strcasecmp(headers_in[counter].key, "If-Match") + if ( !strcasecmp(headers_in[counter].key, "If-Match") || !strcasecmp(headers_in[counter].key, "If-Modified-Since") || !strcasecmp(headers_in[counter].key, "If-Range") || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since") @@ -3448,6 +3507,11 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(header_brigade, e); } + + /* Restore the original headers in (see comment above), + * we won't modify them anymore. + */ + r->headers_in = saved_headers_in; return OK; } diff --git a/modules/slotmem/mod_slotmem_shm.c b/modules/slotmem/mod_slotmem_shm.c index b6cfa0a2..d0106992 100644 --- a/modules/slotmem/mod_slotmem_shm.c +++ b/modules/slotmem/mod_slotmem_shm.c @@ -213,19 +213,19 @@ static apr_status_t restore_slotmem(void *ptr, const char *name, apr_size_t size rv = APR_SUCCESS; apr_md5(digest2, ptr, nbytes); if (memcmp(digest, digest2, APR_MD5_DIGESTSIZE)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(02551) "bad md5 match"); rv = APR_EGENERAL; } } } else { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(02552) "at EOF... bypassing md5 match check (old persist file?)"); } } else if (nbytes != size) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(02553) "Expected %" APR_SIZE_T_FMT ": Read %" APR_SIZE_T_FMT, size, nbytes); rv = APR_EGENERAL; diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index 316dc650..63852d07 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -138,6 +138,9 @@ static const command_rec ssl_config_cmds[] = { SSL_CMD_SRV(Compression, FLAG, "Enable SSL level compression " "(`on', `off')") + SSL_CMD_SRV(SessionTickets, FLAG, + "Enable or disable TLS session tickets" + "(`on', `off')") SSL_CMD_SRV(InsecureRenegotiation, FLAG, "Enable support for insecure renegotiation") SSL_CMD_ALL(UserName, TAKE1, @@ -299,9 +302,12 @@ static apr_status_t ssl_cleanup_pre_config(void *data) #endif ERR_remove_state(0); - /* Don't call ERR_free_strings here; ERR_load_*_strings only - * actually load the error strings once per process due to static + /* Don't call ERR_free_strings in earlier versions, ERR_load_*_strings only + * actually loaded the error strings once per process due to static * variable abuse in OpenSSL. */ +#if (OPENSSL_VERSION_NUMBER >= 0x00090805f) + ERR_free_strings(); +#endif /* Also don't call CRYPTO_cleanup_all_ex_data here; any registered * ex_data indices may have been cached in static variables in diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index e1470d1b..e3c147ad 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -222,6 +222,7 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) #ifndef OPENSSL_NO_COMP sc->compression = UNSET; #endif + sc->session_tickets = UNSET; modssl_ctx_init_proxy(sc, p); @@ -394,6 +395,7 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) #ifndef OPENSSL_NO_COMP cfgMergeBool(compression); #endif + cfgMergeBool(session_tickets); modssl_ctx_cfg_merge_proxy(p, base->proxy, add->proxy, mrg->proxy); @@ -760,6 +762,17 @@ const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag) #endif } +const char *ssl_cmd_SSLSessionTickets(cmd_parms *cmd, void *dcfg, int flag) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); +#ifndef SSL_OP_NO_TICKET + return "This version of OpenSSL does not support using " + "SSLSessionTickets."; +#endif + sc->session_tickets = flag ? TRUE : FALSE; + return NULL; +} + const char *ssl_cmd_SSLInsecureRenegotiation(cmd_parms *cmd, void *dcfg, int flag) { #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index ef2185d2..63e89578 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -272,7 +272,7 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, return HTTP_INTERNAL_SERVER_ERROR; } #ifdef HAVE_OCSP_STAPLING - ssl_stapling_ex_init(); + ssl_stapling_certinfo_hash_init(p); #endif /* @@ -553,6 +553,16 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, } #endif +#ifdef SSL_OP_NO_TICKET + /* + * Configure using RFC 5077 TLS session tickets + * for session resumption. + */ + if (sc->session_tickets == FALSE) { + SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); + } +#endif + #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION if (sc->insecure_reneg == TRUE) { SSL_CTX_set_options(ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); @@ -1039,7 +1049,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s, if (!(cert = SSL_CTX_get0_certificate(mctx->ssl_ctx))) { #else ssl = SSL_new(mctx->ssl_ctx); - if (ssl) { + if (ssl) { /* Workaround bug in SSL_get_certificate in OpenSSL 0.9.8y */ SSL_set_connect_state(ssl); cert = SSL_get_certificate(ssl); @@ -1067,7 +1077,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s, * later, we defer to the code in ssl_init_server_ctx. */ if ((mctx->stapling_enabled == TRUE) && - !ssl_stapling_init_cert(s, mctx, cert)) { + !ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02567) "Unable to configure certificate %s for stapling", key_id); @@ -1425,7 +1435,8 @@ static apr_status_t ssl_init_server_ctx(server_rec *s, SSL_CERT_SET_FIRST); while (ret) { cert = SSL_CTX_get0_certificate(sc->server->ssl_ctx); - if (!cert || !ssl_stapling_init_cert(s, sc->server, cert)) { + if (!cert || !ssl_stapling_init_cert(s, p, ptemp, sc->server, + cert)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02604) "Unable to configure certificate %s:%d " "for stapling", sc->vhost_id, i); @@ -1542,7 +1553,7 @@ apr_status_t ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) klen = strlen(key); if ((ps = (server_rec *)apr_hash_get(table, key, klen))) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(02662) "Init: SSL server IP/port conflict: " "%s (%s:%d) vs. %s (%s:%d)", ssl_util_vhostid(p, s), diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index 7f60cc27..9dd181e0 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -1090,7 +1090,7 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) "request to '%s'", hostname_note); ssl_log_ssl_error(SSLLOG_MARK, APLOG_WARNING, server); } - } + } #endif if ((n = SSL_connect(filter_ctx->pssl)) <= 0) { @@ -1928,8 +1928,14 @@ void ssl_io_filter_init(conn_rec *c, request_rec *r, SSL *ssl) ssl_io_filter_cleanup, apr_pool_cleanup_null); if (APLOG_CS_IS_LEVEL(c, mySrvFromConn(c), APLOG_TRACE4)) { - BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb); - BIO_set_callback_arg(SSL_get_rbio(ssl), (void *)ssl); + BIO *rbio = SSL_get_rbio(ssl), + *wbio = SSL_get_wbio(ssl); + BIO_set_callback(rbio, ssl_io_data_cb); + BIO_set_callback_arg(rbio, (void *)ssl); + if (wbio && wbio != rbio) { + BIO_set_callback(wbio, ssl_io_data_cb); + BIO_set_callback_arg(wbio, (void *)ssl); + } } return; @@ -1954,8 +1960,8 @@ void ssl_io_filter_register(apr_pool_t *p) #define DUMP_WIDTH 16 -static void ssl_io_data_dump(server_rec *srvr, - const char *s, +static void ssl_io_data_dump(server_rec *s, + const char *b, long len) { char buf[256]; @@ -1964,12 +1970,12 @@ static void ssl_io_data_dump(server_rec *srvr, unsigned char ch; trunc = 0; - for(; (len > 0) && ((s[len-1] == ' ') || (s[len-1] == '\0')); len--) + for(; (len > 0) && ((b[len-1] == ' ') || (b[len-1] == '\0')); len--) trunc++; rows = (len / DUMP_WIDTH); if ((rows * DUMP_WIDTH) < len) rows++; - ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, srvr, + ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, s, "+-------------------------------------------------------------------------+"); for(i = 0 ; i< rows; i++) { #if APR_CHARSET_EBCDIC @@ -1979,7 +1985,7 @@ static void ssl_io_data_dump(server_rec *srvr, j = len % DUMP_WIDTH; if (j == 0) j = DUMP_WIDTH; - memcpy(ebcdic_text,(char *)(s) + i * DUMP_WIDTH, j); + memcpy(ebcdic_text,(char *)(b) + i * DUMP_WIDTH, j); ap_xlate_proto_from_ascii(ebcdic_text, j); #endif /* APR_CHARSET_EBCDIC */ apr_snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH); @@ -1988,7 +1994,7 @@ static void ssl_io_data_dump(server_rec *srvr, if (((i * DUMP_WIDTH) + j) >= len) apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); else { - ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff; + ch = ((unsigned char)*((char *)(b) + i * DUMP_WIDTH + j)) & 0xff; apr_snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' '); apr_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf)); } @@ -1998,7 +2004,7 @@ static void ssl_io_data_dump(server_rec *srvr, if (((i * DUMP_WIDTH) + j) >= len) apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf)); else { - ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff; + ch = ((unsigned char)*((char *)(b) + i * DUMP_WIDTH + j)) & 0xff; #if APR_CHARSET_EBCDIC apr_snprintf(tmp, sizeof(tmp), "%c", (ch >= 0x20 && ch <= 0x7F) ? ebcdic_text[j] : '.'); #else /* APR_CHARSET_EBCDIC */ @@ -2008,13 +2014,12 @@ static void ssl_io_data_dump(server_rec *srvr, } } apr_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf)); - ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, srvr, - "%s", buf); + ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, s, "%s", buf); } if (trunc > 0) - ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, srvr, + ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, s, "| %04ld - <SPACES/NULS>", len + trunc); - ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, srvr, + ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, s, "+-------------------------------------------------------------------------+"); return; } diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index 3f905e7b..14afbf4a 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -54,8 +54,8 @@ static apr_status_t upgrade_connection(request_rec *r) bb = apr_brigade_create(r->pool, conn->bucket_alloc); - rv = ap_fputstrs(conn->output_filters, bb, SWITCH_STATUS_LINE, CRLF, - UPGRADE_HEADER, CRLF, CONNECTION_HEADER, CRLF, CRLF, NULL); + rv = ap_fputs(conn->output_filters, bb, SWITCH_STATUS_LINE CRLF + UPGRADE_HEADER CRLF CONNECTION_HEADER CRLF CRLF); if (rv == APR_SUCCESS) { APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_flush_create(conn->bucket_alloc)); @@ -2049,8 +2049,14 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s) * we need to set that callback here. */ if (APLOGtrace4(s)) { - BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb); - BIO_set_callback_arg(SSL_get_rbio(ssl), (void *)ssl); + BIO *rbio = SSL_get_rbio(ssl), + *wbio = SSL_get_wbio(ssl); + BIO_set_callback(rbio, ssl_io_data_cb); + BIO_set_callback_arg(rbio, (void *)ssl); + if (wbio && wbio != rbio) { + BIO_set_callback(wbio, ssl_io_data_cb); + BIO_set_callback_arg(wbio, (void *)ssl); + } } return 1; diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c index a1f8734c..e158a476 100644 --- a/modules/ssl/ssl_engine_pphrase.c +++ b/modules/ssl/ssl_engine_pphrase.c @@ -415,12 +415,10 @@ static apr_status_t ssl_pipe_child_create(apr_pool_t *p, const char *progname) APR_FULL_BLOCK, APR_NO_PIPE)) == APR_SUCCESS)) { char **args; - const char *pname; apr_tokenize_to_argv(progname, &args, p); - pname = apr_pstrdup(p, args[0]); procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew)); - rc = apr_proc_create(procnew, pname, (const char * const *)args, + rc = apr_proc_create(procnew, args[0], (const char * const *)args, NULL, procattr, p); if (rc == APR_SUCCESS) { /* XXX: not sure if we aught to... diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index 922bf7c1..695bc14b 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -73,7 +73,9 @@ static apr_array_header_t *expr_peer_ext_list_fn(ap_expr_eval_ctx_t *ctx, static const char *expr_var_fn(ap_expr_eval_ctx_t *ctx, const void *data) { char *var = (char *)data; - return ssl_var_lookup_ssl(ctx->p, ctx->c, ctx->r, var); + SSLConnRec *sslconn = myConnConfig(ctx->c); + + return sslconn ? ssl_var_lookup_ssl(ctx->p, ctx->c, ctx->r, var) : NULL; } static int ssl_expr_lookup(ap_expr_lookup_parms *parms) @@ -261,7 +263,7 @@ char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, else if (strcEQ(var, "SERVER_SOFTWARE")) result = ap_get_server_banner(); else if (strcEQ(var, "API_VERSION")) { - result = apr_itoa(p, MODULE_MAGIC_NUMBER); + result = apr_itoa(p, MODULE_MAGIC_NUMBER_MAJOR); resdup = FALSE; } else if (strcEQ(var, "TIME_YEAR")) { diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index e8e2cff0..98e9d35a 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -151,6 +151,13 @@ /* OCSP stapling */ #if !defined(OPENSSL_NO_OCSP) && defined(SSL_CTX_set_tlsext_status_cb) #define HAVE_OCSP_STAPLING +/* backward compatibility with OpenSSL < 1.0 */ +#ifndef sk_OPENSSL_STRING_num +#define sk_OPENSSL_STRING_num sk_num +#endif +#ifndef sk_OPENSSL_STRING_value +#define sk_OPENSSL_STRING_value sk_value +#endif #ifndef sk_OPENSSL_STRING_pop #define sk_OPENSSL_STRING_pop sk_pop #endif @@ -640,6 +647,7 @@ struct SSLSrvConfigRec { #ifndef OPENSSL_NO_COMP BOOL compression; #endif + BOOL session_tickets; }; /** @@ -694,6 +702,7 @@ const char *ssl_cmd_SSLCARevocationFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCARevocationCheck(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag); const char *ssl_cmd_SSLCompression(cmd_parms *, void *, int flag); +const char *ssl_cmd_SSLSessionTickets(cmd_parms *, void *, int flag); const char *ssl_cmd_SSLVerifyClient(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLVerifyDepth(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLSessionCache(cmd_parms *, void *, const char *); @@ -812,10 +821,11 @@ const char *ssl_cmd_SSLStaplingErrorCacheTimeout(cmd_parms *, void *, const char const char *ssl_cmd_SSLStaplingReturnResponderErrors(cmd_parms *, void *, int); const char *ssl_cmd_SSLStaplingFakeTryLater(cmd_parms *, void *, int); const char *ssl_cmd_SSLStaplingResponderTimeout(cmd_parms *, void *, const char *); -const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *, void *, const char *); apr_status_t modssl_init_stapling(server_rec *, apr_pool_t *, apr_pool_t *, modssl_ctx_t *); -void ssl_stapling_ex_init(void); -int ssl_stapling_init_cert(server_rec *s, modssl_ctx_t *mctx, X509 *x); +void ssl_stapling_certinfo_hash_init(apr_pool_t *); +int ssl_stapling_init_cert(server_rec *, apr_pool_t *, apr_pool_t *, + modssl_ctx_t *, X509 *); #endif #ifdef HAVE_SRP int ssl_callback_SRPServerParams(SSL *, int *, void *); diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c index 0bf37768..b6183e8b 100644 --- a/modules/ssl/ssl_util_ssl.c +++ b/modules/ssl/ssl_util_ssl.c @@ -125,6 +125,7 @@ int SSL_smart_shutdown(SSL *ssl) { int i; int rc; + int flush; /* * Repeat the calls, because SSL_shutdown internally dispatches through a @@ -134,8 +135,20 @@ int SSL_smart_shutdown(SSL *ssl) * connection and OpenSSL cannot recognize it. */ rc = 0; + flush = !(SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN); for (i = 0; i < 4 /* max 2x pending + 2x data = 4 */; i++) { - if ((rc = SSL_shutdown(ssl))) + rc = SSL_shutdown(ssl); + if (rc >= 0 && flush && (SSL_get_shutdown(ssl) & SSL_SENT_SHUTDOWN)) { + /* Once the close notity is sent through the output filters, + * ensure it is flushed through the socket. + */ + if (BIO_flush(SSL_get_wbio(ssl)) <= 0) { + rc = -1; + break; + } + flush = 0; + } + if (rc != 0) break; } return rc; diff --git a/modules/ssl/ssl_util_stapling.c b/modules/ssl/ssl_util_stapling.c index 2dc8fcea..0e83baf3 100644 --- a/modules/ssl/ssl_util_stapling.c +++ b/modules/ssl/ssl_util_stapling.c @@ -43,36 +43,32 @@ #define MAX_STAPLING_DER 10240 -/* Cached info stored in certificate ex_info. */ +/* Cached info stored in the global stapling_certinfo hash. */ typedef struct { - /* Index in session cache SHA1 hash of certificate */ - UCHAR idx[20]; - /* Certificate ID for OCSP requests or NULL if ID cannot be determined */ + /* Index in session cache (SHA-1 digest of DER encoded certificate) */ + UCHAR idx[SHA_DIGEST_LENGTH]; + /* Certificate ID for OCSP request */ OCSP_CERTID *cid; - /* Responder details */ + /* URI of the OCSP responder */ char *uri; } certinfo; -static void certinfo_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, - int idx, long argl, void *argp) +static apr_status_t ssl_stapling_certid_free(void *data) { - certinfo *cinf = ptr; + OCSP_CERTID *cid = data; - if (!cinf) - return; - if (cinf->uri) - OPENSSL_free(cinf->uri); - OPENSSL_free(cinf); + if (cid) { + OCSP_CERTID_free(cid); + } + + return APR_SUCCESS; } -static int stapling_ex_idx = -1; +static apr_hash_t *stapling_certinfo; -void ssl_stapling_ex_init(void) +void ssl_stapling_certinfo_hash_init(apr_pool_t *p) { - if (stapling_ex_idx != -1) - return; - stapling_ex_idx = X509_get_ex_new_index(0, "X509 cached OCSP info", 0, 0, - certinfo_free); + stapling_certinfo = apr_hash_make(p); } static X509 *stapling_get_issuer(modssl_ctx_t *mctx, X509 *x) @@ -106,70 +102,96 @@ static X509 *stapling_get_issuer(modssl_ctx_t *mctx, X509 *x) } -int ssl_stapling_init_cert(server_rec *s, modssl_ctx_t *mctx, X509 *x) +int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, + modssl_ctx_t *mctx, X509 *x) { - certinfo *cinf; + UCHAR idx[SHA_DIGEST_LENGTH]; + certinfo *cinf = NULL; X509 *issuer = NULL; + OCSP_CERTID *cid = NULL; STACK_OF(OPENSSL_STRING) *aia = NULL; - if (x == NULL) + if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1)) return 0; - cinf = X509_get_ex_data(x, stapling_ex_idx); + + cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx)); if (cinf) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02215) - "ssl_stapling_init_cert: certificate already initialized!"); - return 0; - } - cinf = OPENSSL_malloc(sizeof(certinfo)); - if (!cinf) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02216) - "ssl_stapling_init_cert: error allocating memory!"); - return 0; + /* + * We already parsed the certificate, and no OCSP URI was found. + * The certificate might be used for multiple vhosts, though, + * so we check for a ForceURL for this vhost. + */ + if (!cinf->uri && !mctx->stapling_force_url) { + ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, + APLOGNO(02814) "ssl_stapling_init_cert: no OCSP URI " + "in certificate and no SSLStaplingForceURL " + "configured for server %s", mctx->sc->vhost_id); + return 0; + } + return 1; } - cinf->cid = NULL; - cinf->uri = NULL; - X509_set_ex_data(x, stapling_ex_idx, cinf); - - issuer = stapling_get_issuer(mctx, x); - if (issuer == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02217) - "ssl_stapling_init_cert: Can't retrieve issuer certificate!"); + if (!(issuer = stapling_get_issuer(mctx, x))) { + ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02217) + "ssl_stapling_init_cert: can't retrieve issuer " + "certificate!"); return 0; } - cinf->cid = OCSP_cert_to_id(NULL, x, issuer); + cid = OCSP_cert_to_id(NULL, x, issuer); X509_free(issuer); - if (!cinf->cid) + if (!cid) { + ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02815) + "ssl_stapling_init_cert: can't create CertID " + "for OCSP request"); return 0; - X509_digest(x, EVP_sha1(), cinf->idx, NULL); + } aia = X509_get1_ocsp(x); - if (aia) { - cinf->uri = sk_OPENSSL_STRING_pop(aia); - X509_email_free(aia); - } - if (!cinf->uri && !mctx->stapling_force_url) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02218) - "ssl_stapling_init_cert: no responder URL"); + if (!aia && !mctx->stapling_force_url) { + OCSP_CERTID_free(cid); + ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, + APLOGNO(02218) "ssl_stapling_init_cert: no OCSP URI " + "in certificate and no SSLStaplingForceURL set"); return 0; } + + /* At this point, we have determined that there's something to store */ + cinf = apr_pcalloc(p, sizeof(certinfo)); + memcpy (cinf->idx, idx, sizeof(idx)); + cinf->cid = cid; + /* make sure cid is also freed at pool cleanup */ + apr_pool_cleanup_register(p, cid, ssl_stapling_certid_free, + apr_pool_cleanup_null); + if (aia) { + /* allocate uri from the pconf pool */ + cinf->uri = apr_pstrdup(p, sk_OPENSSL_STRING_value(aia, 0)); + X509_email_free(aia); + } + + ssl_log_xerror(SSLLOG_MARK, APLOG_TRACE1, 0, ptemp, s, x, + "ssl_stapling_init_cert: storing certinfo for server %s", + mctx->sc->vhost_id); + + apr_hash_set(stapling_certinfo, cinf->idx, sizeof(cinf->idx), cinf); + return 1; } -static certinfo *stapling_get_cert_info(server_rec *s, modssl_ctx_t *mctx, +static certinfo *stapling_get_certinfo(server_rec *s, modssl_ctx_t *mctx, SSL *ssl) { certinfo *cinf; X509 *x; + UCHAR idx[SHA_DIGEST_LENGTH]; x = SSL_get_certificate(ssl); - if (x == NULL) + if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1)) return NULL; - cinf = X509_get_ex_data(x, stapling_ex_idx); + cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx)); if (cinf && cinf->cid) return cinf; ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01926) - "stapling_get_cert_info: stapling not supported for certificate"); + "stapling_get_certinfo: stapling not supported for certificate"); return NULL; } @@ -188,13 +210,13 @@ static BOOL stapling_cache_response(server_rec *s, modssl_ctx_t *mctx, BOOL ok, apr_pool_t *pool) { SSLModConfigRec *mc = myModConfig(s); - unsigned char resp_der[MAX_STAPLING_DER]; + unsigned char resp_der[MAX_STAPLING_DER]; /* includes one-byte flag + response */ unsigned char *p; - int resp_derlen; + int resp_derlen, stored_len; BOOL rv; apr_time_t expiry; - resp_derlen = i2d_OCSP_RESPONSE(rsp, NULL) + 1; + resp_derlen = i2d_OCSP_RESPONSE(rsp, NULL); if (resp_derlen <= 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01927) @@ -202,7 +224,8 @@ static BOOL stapling_cache_response(server_rec *s, modssl_ctx_t *mctx, return FALSE; } - if (resp_derlen > sizeof resp_der) { + stored_len = resp_derlen + 1; /* response + ok flag */ + if (stored_len > sizeof resp_der) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01928) "OCSP stapling response too big (%u bytes)", resp_derlen); return FALSE; @@ -226,7 +249,7 @@ static BOOL stapling_cache_response(server_rec *s, modssl_ctx_t *mctx, rv = mc->stapling_cache->store(mc->stapling_cache_context, s, cinf->idx, sizeof(cinf->idx), - expiry, resp_der, resp_derlen, pool); + expiry, resp_der, stored_len, pool); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01929) "stapling_cache_response: OCSP response session store error!"); @@ -585,7 +608,7 @@ static int stapling_cb(SSL *ssl, void *arg) ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951) "stapling_cb: OCSP Stapling callback called"); - cinf = stapling_get_cert_info(s, mctx, ssl); + cinf = stapling_get_certinfo(s, mctx, ssl); if (cinf == NULL) { return SSL_TLSEXT_ERR_NOACK; } |