#include "mod_core.h"
#include "mod_proxy.h"
#include "ap_listen.h"
+#include "ap_provider.h"
#include "mod_so.h" /* for ap_find_loaded_module_symbol */
conf->d_is_fnmatch = new->d_is_fnmatch;
conf->d_components = new->d_components;
conf->r = new->r;
+ conf->refs = new->refs;
conf->condition = new->condition;
if (new->opts & OPT_UNSET) {
conf->enable_sendfile = new->enable_sendfile;
}
- conf->allow_encoded_slashes = new->allow_encoded_slashes;
- conf->decode_encoded_slashes = new->decode_encoded_slashes;
+ if (new->allow_encoded_slashes_set) {
+ conf->allow_encoded_slashes = new->allow_encoded_slashes;
+ }
+ if (new->decode_encoded_slashes_set) {
+ conf->decode_encoded_slashes = new->decode_encoded_slashes;
+ }
if (new->log) {
if (!conf->log) {
if (virt->http09_enable != AP_HTTP09_UNSET)
conf->http09_enable = virt->http09_enable;
+ if (virt->http_conformance != AP_HTTP_CONFORMANCE_UNSET)
+ conf->http_conformance = virt->http_conformance;
+
+ if (virt->http_cl_head_zero != AP_HTTP_CL_HEAD_ZERO_UNSET)
+ conf->http_cl_head_zero = virt->http_cl_head_zero;
+
+ if (virt->http_expect_strict != AP_HTTP_EXPECT_STRICT_UNSET)
+ conf->http_expect_strict = virt->http_expect_strict;
+
/* no action for virt->accf_map, not allowed per-vhost */
if (virt->protocol)
conf->ap_document_root = arg;
}
else {
- return "DocumentRoot must be a directory";
+ return apr_psprintf(cmd->pool,
+ "DocumentRoot '%s' is not a directory, or is not readable",
+ arg);
}
}
return NULL;
if (error_number == 401 && what == REMOTE_PATH) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, cmd->server, APLOGNO(00113)
- "cannot use a full URL in a 401 ErrorDocument "
- "directive --- ignoring!");
+ "%s:%d cannot use a full URL in a 401 ErrorDocument "
+ "directive --- ignoring!", cmd->directive->filename, cmd->directive->line_num);
}
else { /* Store it... */
if (conf->response_code_strings == NULL) {
RESPONSE_CODES);
}
- if (strcmp(msg, "default") == 0) {
+ if (strcasecmp(msg, "default") == 0) {
/* special case: ErrorDocument 404 default restores the
* canned server error response
*/
conf->d = cmd->path;
conf->d_is_fnmatch = (apr_fnmatch_test(conf->d) != 0);
+ if (r) {
+ conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
+ ap_regname(r, conf->refs, AP_REG_MATCH, 1);
+ }
+
/* Make this explicit - the "/" root has 0 elements, that is, we
* will always merge it, and it will always sort and merge first.
* All others are sorted and tested by the number of slashes.
conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
conf->r = r;
+ if (r) {
+ conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
+ ap_regname(r, conf->refs, AP_REG_MATCH, 1);
+ }
+
ap_add_per_url_conf(cmd->server, new_url_conf);
if (*arg != '\0') {
conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
conf->r = r;
+ if (r) {
+ conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
+ ap_regname(r, conf->refs, AP_REG_MATCH, 1);
+ }
+
ap_add_file_conf(cmd->pool, (core_dir_config *)mconfig, new_file_conf);
if (*arg != '\0') {
cmd->cmd->name, " must be On, Off, or NoDecode",
NULL);
}
+
+ d->allow_encoded_slashes_set = 1;
+ d->decode_encoded_slashes_set = 1;
+
return NULL;
}
SrvTk_MINIMAL, /* eg: Apache/2.0.41 */
SrvTk_OS, /* eg: Apache/2.0.41 (UNIX) */
SrvTk_FULL, /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */
- SrvTk_PRODUCT_ONLY /* eg: Apache */
+ SrvTk_PRODUCT_ONLY /* eg: Apache */
};
static enum server_token_type ap_server_tokens = SrvTk_FULL;
}
static const char *set_serv_tokens(cmd_parms *cmd, void *dummy,
- const char *arg1, const char *arg2)
+ const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
return err;
}
- if (!strcasecmp(arg1, "OS")) {
+ if (!strcasecmp(arg, "OS")) {
ap_server_tokens = SrvTk_OS;
}
- else if (!strcasecmp(arg1, "Min") || !strcasecmp(arg1, "Minimal")) {
+ else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) {
ap_server_tokens = SrvTk_MINIMAL;
}
- else if (!strcasecmp(arg1, "Major")) {
+ else if (!strcasecmp(arg, "Major")) {
ap_server_tokens = SrvTk_MAJOR;
}
- else if (!strcasecmp(arg1, "Minor") ) {
+ else if (!strcasecmp(arg, "Minor") ) {
ap_server_tokens = SrvTk_MINOR;
}
- else if (!strcasecmp(arg1, "Prod") || !strcasecmp(arg1, "ProductOnly")) {
+ else if (!strcasecmp(arg, "Prod") || !strcasecmp(arg, "ProductOnly")) {
ap_server_tokens = SrvTk_PRODUCT_ONLY;
}
- else if (!strcasecmp(arg1, "Full")) {
+ else if (!strcasecmp(arg, "Full")) {
ap_server_tokens = SrvTk_FULL;
}
else {
- return "ServerTokens takes 1 argument, 'Prod', 'Major', 'Minor', 'Min', 'OS', or 'Full'";
+ return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', or 'Full'";
}
return NULL;
else if (strcmp(arg, "1.0") == 0)
conf->http09_enable = AP_HTTP09_DISABLE;
else
- return "HttpProtocol min must be one of '0.9' and '1.0'";
- return NULL;
+ return "HttpProtocol 'min' must be one of '0.9' and '1.0'";
+ return NULL;
+ }
+
+ if (strcmp(arg, "strict") == 0)
+ conf->http_conformance = AP_HTTP_CONFORMANCE_STRICT;
+ else if (strcmp(arg, "strict,log-only") == 0)
+ conf->http_conformance = AP_HTTP_CONFORMANCE_STRICT|
+ AP_HTTP_CONFORMANCE_LOGONLY;
+ else if (strcmp(arg, "liberal") == 0)
+ conf->http_conformance = AP_HTTP_CONFORMANCE_LIBERAL;
+ else
+ return "HttpProtocol accepts 'min=0.9', 'min=1.0', 'liberal', "
+ "'strict', 'strict,log-only'";
+
+ if ((conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) &&
+ (conf->http_conformance & AP_HTTP_CONFORMANCE_LIBERAL)) {
+ return "HttpProtocol 'strict' and 'liberal' are mutually exclusive";
}
- return "HttpProtocol must be min=0.9|1.0";
+
+ return NULL;
}
static const char *set_http_method(cmd_parms *cmd, void *conf, const char *arg)
return NULL;
}
+static const char *set_cl_head_zero(cmd_parms *cmd, void *dummy, int arg)
+{
+ core_server_config *conf =
+ ap_get_core_module_config(cmd->server->module_config);
+
+ if (arg) {
+ conf->http_cl_head_zero = AP_HTTP_CL_HEAD_ZERO_ENABLE;
+ } else {
+ conf->http_cl_head_zero = AP_HTTP_CL_HEAD_ZERO_DISABLE;
+ }
+ return NULL;
+}
+
+static const char *set_expect_strict(cmd_parms *cmd, void *dummy, int arg)
+{
+ core_server_config *conf =
+ ap_get_core_module_config(cmd->server->module_config);
+
+ if (arg) {
+ conf->http_expect_strict = AP_HTTP_EXPECT_STRICT_ENABLE;
+ } else {
+ conf->http_expect_strict = AP_HTTP_EXPECT_STRICT_DISABLE;
+ }
+ return NULL;
+}
+
static apr_hash_t *errorlog_hash;
static int log_constant_item(const ap_errorlog_info *info, const char *arg,
return a;
}
+static const char *set_errorlog(cmd_parms *cmd, void *dummy, const char *arg1,
+ const char *arg2)
+{
+ ap_errorlog_provider *provider;
+ const char *err;
+ cmd->server->errorlog_provider = NULL;
+
+ if (!arg2) {
+ /* Stay backward compatible and check for "syslog" */
+ if (strncmp("syslog", arg1, 6) == 0) {
+ arg2 = arg1 + 7; /* skip the ':' if any */
+ arg1 = "syslog";
+ }
+ else {
+ /* Admin can define only "ErrorLog provider" and we should
+ * still handle that using the defined provider, but with empty
+ * error_fname. */
+ provider = ap_lookup_provider(AP_ERRORLOG_PROVIDER_GROUP, arg1,
+ AP_ERRORLOG_PROVIDER_VERSION);
+ if (provider) {
+ arg2 = "";
+ }
+ else {
+ return set_server_string_slot(cmd, dummy, arg1);
+ }
+ }
+ }
+
+ if (strcmp("file", arg1) == 0) {
+ return set_server_string_slot(cmd, dummy, arg2);
+ }
+
+ provider = ap_lookup_provider(AP_ERRORLOG_PROVIDER_GROUP, arg1,
+ AP_ERRORLOG_PROVIDER_VERSION);
+ if (!provider) {
+ return apr_psprintf(cmd->pool,
+ "Unknown ErrorLog provider: %s",
+ arg1);
+ }
+
+ err = provider->parse_errorlog_arg(cmd, arg2);
+ if (err) {
+ return err;
+ }
+
+ cmd->server->errorlog_provider = provider;
+ return set_server_string_slot(cmd, dummy, arg2);
+}
+
static const char *set_errorlog_format(cmd_parms *cmd, void *dummy,
const char *arg1, const char *arg2)
{
"Common directory of server-related files (logs, confs, etc.)"),
AP_INIT_TAKE1("DefaultRuntimeDir", set_runtime_dir, NULL, RSRC_CONF | EXEC_ON_READ,
"Common directory for run-time files (shared memory, locks, etc.)"),
-AP_INIT_TAKE1("ErrorLog", set_server_string_slot,
+AP_INIT_TAKE12("ErrorLog", set_errorlog,
(void *)APR_OFFSETOF(server_rec, error_fname), RSRC_CONF,
"The filename of the error log"),
AP_INIT_TAKE12("ErrorLogFormat", set_errorlog_format, NULL, RSRC_CONF,
"Override LogLevel for clients with certain IPs"),
AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF,
"A numeric IP address:port, or the name of a host"),
-AP_INIT_TAKE12("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
+AP_INIT_TAKE1("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
"Determine tokens displayed in the Server: header - Min(imal), "
- "Major, Minor, Prod, OS or Full"),
+ "Major, Minor, Prod(uctOnly), OS, or Full"),
AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF,
"Limit on maximum size of an HTTP request line"),
AP_INIT_TAKE1("LimitRequestFieldsize", set_limit_req_fieldsize, NULL,
#endif
AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF,
"'on' (default), 'off' or 'extended' to trace request body content"),
-AP_INIT_TAKE1("HttpProtocol", set_http_protocol, NULL, RSRC_CONF,
- "'min=0.9' (default) or 'min=1.0' to allow/deny HTTP/0.9"),
+AP_INIT_ITERATE("HttpProtocol", set_http_protocol, NULL, RSRC_CONF,
+ "'min=0.9' (default) or 'min=1.0' to allow/deny HTTP/0.9; "
+ "'liberal', 'strict', 'strict,log-only'"),
AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF,
"Registers non-standard HTTP methods"),
+AP_INIT_FLAG("HttpContentLengthHeadZero", set_cl_head_zero, NULL, OR_OPTIONS,
+ "whether to permit Content-Length of 0 responses to HEAD requests"),
+AP_INIT_FLAG("HttpExpectStrict", set_expect_strict, NULL, OR_OPTIONS,
+ "whether to return a 417 if a client doesn't send 100-Continue"),
{ NULL }
};
if (r->method_number == M_GET || r->method_number == M_POST) {
if (r->finfo.filetype == APR_NOFILE) {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00128)
- "File does not exist: %s", r->filename);
+ "File does not exist: %s",
+ apr_pstrcat(r->pool, r->filename, r->path_info, NULL));
return HTTP_NOT_FOUND;
}
static int check_errorlog_dir(apr_pool_t *p, server_rec *s)
{
if (!s->error_fname || s->error_fname[0] == '|'
- || strcmp(s->error_fname, "syslog") == 0) {
+ || s->errorlog_provider != NULL) {
return APR_SUCCESS;
}
else {
apr_bucket_alloc_t *alloc)
{
apr_status_t rv;
+ apr_pool_t *pool;
conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
core_server_config *sconf = ap_get_core_module_config(s->module_config);
/* Got a connection structure, so initialize what fields we can
* (the rest are zeroed out by pcalloc).
*/
- c->conn_config = ap_create_conn_config(ptrans);
- c->notes = apr_table_make(ptrans, 5);
+ apr_pool_create(&pool, ptrans);
+ apr_pool_tag(pool, "master_conn");
+ c->pool = pool;
+
+ c->conn_config = ap_create_conn_config(c->pool);
+ c->notes = apr_table_make(c->pool, 5);
+ c->slaves = apr_array_make(c->pool, 20, sizeof(conn_slave_rec *));
+
- c->pool = ptrans;
if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(00137)
net->client_socket = csd;
ap_set_core_module_config(net->c->conn_config, csd);
- ap_add_input_filter_handle(ap_core_input_filter_handle, net, NULL, net->c);
- ap_add_output_filter_handle(ap_core_output_filter_handle, net, NULL, net->c);
+ /* only the master connection talks to the network */
+ if (c->master == NULL) {
+ ap_add_input_filter_handle(ap_core_input_filter_handle, net, NULL,
+ net->c);
+ ap_add_output_filter_handle(ap_core_output_filter_handle, net, NULL,
+ net->c);
+ }
return DONE;
}
+AP_CORE_DECLARE(conn_rec *) ap_create_slave_connection(conn_rec *c)
+{
+ apr_pool_t *pool;
+ conn_slave_rec *new;
+ conn_rec *sc = (conn_rec *) apr_palloc(c->pool, sizeof(conn_rec));
+
+ apr_pool_create(&pool, c->pool);
+ apr_pool_tag(pool, "slave_conn");
+ memcpy(sc, c, sizeof(conn_rec));
+ sc->slaves = NULL;
+ sc->master = c;
+ sc->input_filters = NULL;
+ sc->output_filters = NULL;
+ sc->pool = pool;
+ new = apr_array_push(c->slaves);
+ new->c = sc;
+ return sc;
+}
+
AP_DECLARE(int) ap_state_query(int query)
{
switch (query) {
AP_DECLARE(apr_uint32_t) ap_random_pick(apr_uint32_t min, apr_uint32_t max)
{
apr_uint32_t number;
+#if (!__GNUC__ || __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || \
+ !__sparc__ || APR_SIZEOF_VOIDP != 8)
+ /* This triggers a gcc bug on sparc/64bit with gcc < 4.8, PR 52900 */
if (max < 16384) {
apr_uint16_t num16;
ap_random_insecure_bytes(&num16, sizeof(num16));
RAND_RANGE(num16, min, max, APR_UINT16_MAX);
number = num16;
}
- else {
+ else
+#endif
+ {
ap_random_insecure_bytes(&number, sizeof(number));
RAND_RANGE(number, min, max, APR_UINT32_MAX);
}
apr_file_printf(out, "ServerRoot: \"%s\"\n", ap_server_root);
tmp = ap_server_root_relative(p, sconf->ap_document_root);
apr_file_printf(out, "Main DocumentRoot: \"%s\"\n", tmp);
- if (s->error_fname[0] != '|' && strcmp(s->error_fname, "syslog") != 0)
+ if (s->error_fname[0] != '|' && s->errorlog_provider == NULL)
tmp = ap_server_root_relative(p, s->error_fname);
else
tmp = s->error_fname;
ap_hook_insert_network_bucket(core_insert_network_bucket, NULL, NULL,
APR_HOOK_REALLY_LAST);
ap_hook_dirwalk_stat(core_dirwalk_stat, NULL, NULL, APR_HOOK_REALLY_LAST);
+ ap_hook_open_htaccess(ap_open_htaccess, NULL, NULL, APR_HOOK_REALLY_LAST);
/* register the core's insert_filter hook and register core-provided
* filters