<li><a href="#timeout">TimeOut</a></li>
+ <li><a href="#timeout">TraceEnable</a></li>
+
<li><a href="#usecanonicalname">UseCanonicalName</a></li>
<li><a href="#user">User</a></li>
the timer is not reset when a packet is sent.
<hr />
+ <h2><a id="traceenable"
+ name="traceenable">TraceEnable</a></h2>
+ <a href="directive-dict.html#Syntax"
+ rel="Help"><strong>Syntax:</strong></a> TraceEnable
+ <em>[on|off|extended]</em><br />
+ <a href="directive-dict.html#Default"
+ rel="Help"><strong>Default:</strong></a> <code>TraceEnable
+ on</code><br />
+ <a href="directive-dict.html#Context"
+ rel="Help"><strong>Context:</strong></a> server config<br />
+ <a href="directive-dict.html#Status"
+ rel="Help"><strong>Status:</strong></a> core (Windows,
+ NetWare)<br />
+ <strong>Compatibility:</strong> Available only in Apache 1.3.34
+ and later
+
+ <p>This directive overrides the behavior of TRACE for both
+ the core server and mod_proxy. The default <code>TraceEnable
+ on</code> permits TRACE requests per RFC 2616, which disallows
+ any request body to accompany the request. <code>TraceEnable
+ off</code> causes the core server and mod_proxy to return
+ a 405 FORBIDDEN error to the client.</p>
+
+ <p>Finally, for testing and diagnostic purposes only, request
+ bodies may be allowed using the non-compliant <code>TraceEnable
+ extended</code> directive. The core (as an origin server) will
+ restrict the request body to 64k (plus 8k for chunk headers if
+ Transfer-Encoding: chunked is used). The core will reflect the
+ full headers and all chunk headers with the request body. As a
+ proxy server, the request body is not restricted to 64k. At this
+ time the Apache 1.3 mod_proxy does not permit chunked request
+ bodies for any request, including the extended TRACE request.</p>
+ <hr />
+
<h2><a id="usecanonicalname"
name="usecanonicalname">UseCanonicalName directive</a></h2>
<li><a href="core.html#timeout">TimeOut</a></li>
+ <li><a href="core.html#timeout">TraceEnable</a></li>
+
<li><a
href="mod_log_config.html#transferlog">TransferLog</a></li>
Changes with Apache 1.3.34
+ *) Added TraceEnable [on|off|extended] per-server directive to alter
+ the behavior of the TRACE method. This addresses a flaw in proxy
+ conformance to RFC 2616 - previously the proxy server would accept
+ a TRACE request body although the RFC prohibited it. The default
+ remains 'TraceEnable on'.
+ [William Rowe]
+
*) mod_digest: Fix another nonce string calculation issue.
[Eric Covener]
* 19990320.16 - ap_escape_errorlog_item()
* 19990320.17 - ap_auth_nonce() and ap_auth_nonce added
* in core_dir_config.
+ * 19990320.18 - trace_enable member added to core server_config
*/
#define MODULE_MAGIC_COOKIE 0x41503133UL /* "AP13" */
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 19990320
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 17 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 18 /* 0...n */
/* Useful for testing for features. */
#define AP_MODULE_MAGIC_AT_LEAST(major,minor) \
int recursion_limit_set; /* boolean */
int redirect_limit; /* maximum number of internal redirects */
int subreq_limit; /* maximum nesting level of subrequests */
+
+ /* TRACE control */
+ int trace_enable; /* see AP_TRACE_ below */
+
} core_server_config;
+/* trace_enable options */
+#define AP_TRACE_UNSET -1
+#define AP_TRACE_DISABLE 0
+#define AP_TRACE_ENABLE 1
+#define AP_TRACE_EXTENDED 2
+
/* for http_config.c */
CORE_EXPORT(void) ap_core_reorder_directories(pool *, server_rec *);
conf->subreq_limit = 0;
conf->recursion_limit_set = 0;
+ conf->trace_enable = AP_TRACE_UNSET;
+
return (void *)conf;
}
? virt->subreq_limit
: base->subreq_limit;
+ conf->trace_enable = (virt->trace_enable != AP_TRACE_UNSET)
+ ? virt->trace_enable
+ : base->trace_enable;
+
return conf;
}
int methnum = ap_method_number_of(method);
if (methnum == M_TRACE && !tog) {
- return "TRACE cannot be controlled by <Limit>";
+ return "TRACE cannot be controlled by <Limit>, see TraceEnable";
}
else if (methnum == M_INVALID) {
return ap_pstrcat(cmd->pool, "unknown method \"", method,
return NULL;
}
+static const char *set_trace_enable(cmd_parms *cmd, void *dummy,
+ const char *arg1)
+{
+ core_server_config *conf = ap_get_module_config(cmd->server->module_config,
+ &core_module);
+
+ if (strcasecmp(arg1, "on") == 0) {
+ conf->trace_enable = AP_TRACE_ENABLE;
+ }
+ else if (strcasecmp(arg1, "off") == 0) {
+ conf->trace_enable = AP_TRACE_DISABLE;
+ }
+ else if (strcasecmp(arg1, "extended") == 0) {
+ conf->trace_enable = AP_TRACE_EXTENDED;
+ }
+ else {
+ return "TraceEnable must be one of 'on', 'off', or 'extended'";
+ }
+
+ return NULL;
+}
+
static void log_backtrace(const request_rec *r)
{
const request_rec *top = r;
{ "LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF, TAKE12,
"maximum recursion depth of internal redirects and subrequests"},
+{ "TraceEnable", set_trace_enable, NULL, RSRC_CONF, TAKE1,
+ "'on' (default), 'off' or 'extended' to trace request body content"},
{ NULL }
};
ap_bputs(CRLF, client); /* Send the terminating empty line */
}
-/* Build the Allow field-value from the request handler method mask.
- * Note that we always allow TRACE, since it is handled below.
+/* Build the Allow header from the request handler method mask.
+ * Note TRACE is tested on a per-server basis.
*/
-static char *make_allow(request_rec *r)
+static void set_allow_header(request_rec *r)
{
- return 2 + ap_pstrcat(r->pool,
+ core_server_config *conf =
+ ap_get_module_config(r->server->module_config, &core_module);
+
+ char *res = ap_pstrcat(r->pool,
(r->allowed & (1 << M_GET)) ? ", GET, HEAD" : "",
(r->allowed & (1 << M_POST)) ? ", POST" : "",
(r->allowed & (1 << M_PUT)) ? ", PUT" : "",
(r->allowed & (1 << M_MOVE)) ? ", MOVE" : "",
(r->allowed & (1 << M_LOCK)) ? ", LOCK" : "",
(r->allowed & (1 << M_UNLOCK)) ? ", UNLOCK" : "",
- ", TRACE",
+ (conf->trace_enable != AP_TRACE_DISABLE) ? ", TRACE" : "",
NULL);
+
+ /* Cowardly attempt to avoid returning an empty Allow: header,
+ * but no matter how inaccurate, result code 405 demands it.
+ */
+ if (*res)
+ ap_table_setn(r->headers_out, "Allow", res + 2);
+ else if (r->status == METHOD_NOT_ALLOWED)
+ ap_table_setn(r->headers_out, "Allow", "");
}
API_EXPORT(int) ap_send_http_trace(request_rec *r)
{
+ core_server_config *conf;
int rv;
+ int body;
+ char *bodyread, *bodyoff;
+ long bodylen = 0;
+ long bodybuf;
+ long res;
/* Get the original request */
while (r->prev)
r = r->prev;
+ conf = ap_get_module_config(r->server->module_config, &core_module);
+
+ if (conf->trace_enable == AP_TRACE_DISABLE) {
+ ap_table_setn(r->notes, "error-notes",
+ "TRACE denied by server configuration");
+ return HTTP_FORBIDDEN;
+ }
+
+ if (conf->trace_enable == AP_TRACE_EXTENDED)
+ body = REQUEST_CHUNKED_PASS;
+ else
+ body = REQUEST_NO_BODY;
- if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY)))
+ if ((rv = ap_setup_client_block(r, body))) {
+ if (rv == HTTP_REQUEST_ENTITY_TOO_LARGE)
+ ap_table_setn(r->notes, "error-notes",
+ "TRACE with a request body is not allowed");
return rv;
+ }
+
+ if (ap_should_client_block(r)) {
+
+ if (r->remaining > 0) {
+ if (r->remaining > 65536) {
+ ap_table_setn(r->notes, "error-notes",
+ "Extended TRACE request bodies cannot exceed 64k\n");
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+ /* always 32 extra bytes to catch chunk header exceptions */
+ bodybuf = r->remaining + 32;
+ }
+ else {
+ /* Add an extra 8192 for chunk headers */
+ bodybuf = 73730;
+ }
+
+ bodyoff = bodyread = ap_palloc(r->pool, bodybuf);
+
+ /* only while we have enough for a chunked header */
+ while ((!bodylen || bodybuf >= 32) &&
+ (res = ap_get_client_block(r, bodyoff, bodybuf)) > 0) {
+ bodylen += res;
+ bodybuf -= res;
+ bodyoff += res;
+ }
+ if (res > 0 && bodybuf < 32) {
+ /* discard_rest_of_request_body into our buffer */
+ while (ap_get_client_block(r, bodyread, bodylen) > 0)
+ ;
+ ap_table_setn(r->notes, "error-notes",
+ "Extended TRACE request bodies cannot exceed 64k\n");
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+
+ if (res < 0) {
+ return HTTP_BAD_REQUEST;
+ }
+ }
ap_hard_timeout("send TRACE", r);
r->content_type = "message/http";
+
ap_send_http_header(r);
#ifdef CHARSET_EBCDIC
/* Server-generated response, converted */
ap_send_header_field, (void *) r, r->headers_in, NULL);
ap_rputs(CRLF, r);
+ /* If configured to accept a body, echo the body including chunks */
+ if (bodylen)
+ ap_rwrite(bodyread, bodylen, r);
+
ap_kill_timeout(r);
return OK;
}
ap_basic_http_header(r);
ap_table_setn(r->headers_out, "Content-Length", "0");
- ap_table_setn(r->headers_out, "Allow", make_allow(r));
+ set_allow_header(r);
ap_set_keepalive(r);
ap_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
}
if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED))
- ap_table_setn(r->headers_out, "Allow", make_allow(r));
+ set_allow_header(r);
ap_send_http_header(r);
/* HTTP routines for Apache proxy */
+#define CORE_PRIVATE /* To inspect core_server_conf->trace_enable */
#include "mod_proxy.h"
#include "http_log.h"
#include "http_main.h"
memset(&server, '\0', sizeof(server));
server.sin_family = AF_INET;
+ if (r->method_number == M_TRACE) {
+ core_server_config *coreconf = (core_server_config *)
+ ap_get_module_config(r->server->module_config, &core_module);
+
+ if (coreconf->trace_enable == AP_TRACE_DISABLE)
+ return ap_proxyerror(r, HTTP_FORBIDDEN,
+ "TRACE denied by server configuration");
+
+ /* Can't test ap_should_client_block, we aren't ready to send
+ * the client a 100 Continue response till the connection has
+ * been established
+ */
+ if (coreconf->trace_enable != AP_TRACE_EXTENDED
+ && (r->read_length || (!r->read_chunked && (r->remaining <= 0))))
+ return ap_proxyerror(r, HTTP_REQUEST_ENTITY_TOO_LARGE,
+ "TRACE with request body is not allowed");
+ }
+
/* We break the URL into host, port, path-search */
urlptr = strstr(url, "://");