</usage>
</directivesynopsis>
+<directivesynopsis>
+<name>HTTPProtocolOptions</name>
+<description>Modify restrictions on HTTP Request Messages</description>
+<syntax>HTTPProtocolOptions [Strict|Unsafe] [Allow0.9|Require1.0]
+[StrictWhitespace|LenientWhitespace] [RegisteredMethods|LenientMethods]</syntax>
+<default>HTTPProtocolOptions Strict Allow0.9 LenientWhitespace
+LenientMethods</default>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+<compatibility>2.2.32 or 2.4.24 and later</compatibility>
+
+<usage>
+ <p>This directive changes the rules applied to the HTTP Request Line
+ (<a href="https://tools.ietf.org/html/rfc7230#section-3.1.1"
+ >RFC 7230 §3.1.1</a>) and the HTTP Request Header Fields
+ (<a href="https://tools.ietf.org/html/rfc7230#section-3.2"
+ >RFC 7230 §3.2</a>), which are now applied by default or using
+ the <code>Strict</code> option. Due to legacy modules, applications or
+ custom user-agents which must be deperecated, an <code>Unsafe</code>
+ option has been added to revert to the legacy behavior. These rules are
+ applied prior to request processing, so must be configured at the global
+ or default (first) matching virtual host section, by interface and not
+ by name, to be honored.</p>
+
+ <p>Prior to the introduction of this directive, the Apache HTTP Server
+ request message parsers were tolerant of a number of forms of input
+ which did not conform to the protocol.
+ <a href="https://tools.ietf.org/html/rfc7230#section-9.4"
+ >RFC 7230 §9.4 Request Splitting</a> and
+ <a href="https://tools.ietf.org/html/rfc7230#section-9.5"
+ >§9.5 Response Smuggling</a> call out only two of the potential
+ risks of accepting non-conformant request messages. As of the introduction
+ of this directive, all grammer rules of the specification are enforced in
+ the default <code>Strict</code> operating mode.</p>
+
+ <p>Users are strongly cautioned against toggling the <code>Unsafe</code>
+ mode of operation for these reasons, most especially on outward-facing,
+ publicly accessible server deployments. Reviewing the messages within the
+ <directive>ErrorLog</directive>, configured with
+ <directive>LogLevel</directive> <code>info</code> level or below,
+ can help identify such faulty requests along with their origin.
+ Users should pay particular attention to any 400 responses in the access
+ log for indiciations that valid requests are unexpectedly rejected.</p>
+
+ <p><a href="https://tools.ietf.org/html/rfc2616#section-19.6"
+ >RFC 2616 §19.6</a> "Compatibility With Previous Versions" had
+ encouraged HTTP servers to support legacy HTTP/0.9 requests. RFC 7230
+ superceeds this with "The expectation to support HTTP/0.9 requests has
+ been removed" and offers additional comments in
+ <a href="https://tools.ietf.org/html/rfc7230#appendix-A"
+ >RFC 2616 Appendix A</a>. The <code>Require1.0</code> option allows
+ the user to remove support of the default <code>Allow0.9</code> option's
+ behavior.</p>
+
+ <p><a href="https://tools.ietf.org/html/rfc7230#section-3.5"
+ >RFC 7230 §3.5</a> "Message Parsing Robustness" permits, and
+ identifies potential risks of parsing messages containing non-space
+ character whitespace. While the spec defines that exactly one space
+ seperates the URI from the method, and the protocol from the URI, the
+ Apache HTTP Server has traditionally been lenient in accepting other
+ whitespace including one or more horizontal-tab or space characters.
+ The default <code>LenientWhitespace</code> continues to accept such
+ requests from non-conforming user-agents, but the administrator may toggle
+ the <code>StrictWhitespace</code> option to insist on precisely two spaces
+ in the request line. Other whitespace including vertical-tab, form-feed,
+ and carriage-return characters are rejected and cannot be supported.</p>
+
+ <p><a href="https://tools.ietf.org/html/rfc7231#section-4.1"
+ >RFC 7231 §4.1</a> "Request Methods" "Overview" requires that
+ origin servers shall respond with an error when an unsupported method
+ is encountered in the request line. This already happens when the
+ <code>LenientMethods</code> option is used, but administrators may wish
+ to toggle the <code>RegisteredMethods</code> option and register all
+ permitted method tokens using the <directive>RegisterHttpMethod</directive>
+ directive, particularly if the <code>Unsafe</code> option has been toggled.
+ The <code>RegisteredMethods</code> option should <strong>not</strong>
+ be toggled for forward proxy hosts, as the methods supported by the
+ origin servers are unknown to the proxy server.</p>
+</usage>
+</directivesynopsis>
+
<directivesynopsis>
<name>Error</name>
<description>Abort configuration parsing with a custom error message</description>
if (virt->http_conformance != AP_HTTP_CONFORMANCE_UNSET)
conf->http_conformance = virt->http_conformance;
+ if (virt->http_whitespace != AP_HTTP_WHITESPACE_UNSET)
+ conf->http_whitespace = virt->http_whitespace;
+
+ if (virt->http_methods != AP_HTTP_METHODS_UNSET)
+ conf->http_methods = virt->http_methods;
+
/* no action for virt->accf_map, not allowed per-vhost */
if (virt->protocol)
return NULL;
}
-static const char *set_http_protocol(cmd_parms *cmd, void *dummy,
- const char *arg)
+static const char *set_http_protocol_options(cmd_parms *cmd, void *dummy,
+ const char *arg)
{
core_server_config *conf =
ap_get_core_module_config(cmd->server->module_config);
- if (strncmp(arg, "min=", 4) == 0) {
- arg += 4;
- if (strcmp(arg, "0.9") == 0)
- conf->http09_enable = AP_HTTP09_ENABLE;
- 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;
- }
-
- 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;
+ if (strcasecmp(arg, "allow0.9") == 0)
+ conf->http09_enable |= AP_HTTP09_ENABLE;
+ else if (strcasecmp(arg, "require1.0") == 0)
+ conf->http09_enable |= AP_HTTP09_DISABLE;
+ else if (strcasecmp(arg, "strict") == 0)
+ conf->http_conformance |= AP_HTTP_CONFORMANCE_STRICT;
+ else if (strcasecmp(arg, "unsafe") == 0)
+ conf->http_conformance |= AP_HTTP_CONFORMANCE_UNSAFE;
+ else if (strcasecmp(arg, "strictwhitespace") == 0)
+ conf->http_whitespace |= AP_HTTP_WHITESPACE_STRICT;
+ else if (strcasecmp(arg, "lenientwhitespace") == 0)
+ conf->http_whitespace |= AP_HTTP_WHITESPACE_LENIENT;
+ else if (strcasecmp(arg, "registeredmethods") == 0)
+ conf->http_methods |= AP_HTTP_METHODS_REGISTERED;
+ else if (strcasecmp(arg, "lenientmethods") == 0)
+ conf->http_methods |= AP_HTTP_METHODS_LENIENT;
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 "HttpProtocolOptions accepts 'Allow0.9' (default) or "
+ "'Require1.0', 'Unsafe' or 'Strict' (default), "
+ "'StrictWhitespace' or 'LenientWhitespace (default), and "
+ "'RegisteredMethods' or 'LenientMethods (default)";
+
+ if ((conf->http09_enable & AP_HTTP09_ENABLE)
+ && (conf->http09_enable & AP_HTTP09_DISABLE))
+ return "HttpProtocolOptions 'Allow0.9' and 'Require1.0'"
+ " are mutually exclusive";
+
+ if ((conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT)
+ && (conf->http_conformance & AP_HTTP_CONFORMANCE_UNSAFE))
+ return "HttpProtocolOptions 'Strict' and 'Unsafe'"
+ " are mutually exclusive";
+
+ if ((conf->http_whitespace & AP_HTTP_WHITESPACE_STRICT)
+ && (conf->http_whitespace & AP_HTTP_WHITESPACE_LENIENT))
+ return "HttpProtocolOptions 'StrictWhitespace' and 'LenientWhitespace'"
+ " are mutually exclusive";
+
+ if ((conf->http_methods & AP_HTTP_METHODS_REGISTERED)
+ && (conf->http_methods & AP_HTTP_METHODS_LENIENT))
+ return "HttpProtocolOptions 'RegisteredMethods' and 'LenientMethods'"
+ " are mutually exclusive";
return NULL;
}
AP_INIT_TAKE1("ProtocolsHonorOrder", set_protocols_honor_order, NULL, RSRC_CONF,
"'off' (default) or 'on' to respect given order of protocols, "
"by default the client specified order determines selection"),
-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("HttpProtocolOptions", set_http_protocol_options, NULL, RSRC_CONF,
+ "'Allow0.9' or 'Require1.0' (default) to allow or deny HTTP/0.9; "
+ "'Unsafe' or 'Strict' (default) to process incorrect requests"),
AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF,
"Registers non-standard HTTP methods"),
{ NULL }
}
}
-static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
+/* get the length of the field name for logging, but no more than 80 bytes */
+#define LOG_NAME_MAX_LEN 80
+static int field_name_len(const char *field)
{
- const char *ll;
- const char *uri;
- const char *pro;
+ const char *end = ap_strchr_c(field, ':');
+ if (end == NULL || end - field > LOG_NAME_MAX_LEN)
+ return LOG_NAME_MAX_LEN;
+ return end - field;
+}
+static int read_request_line(request_rec *r, apr_bucket_brigade *bb)
+{
+ enum {
+ rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
+ rrl_missinguri, rrl_badprotocol, rrl_trailingtext
+ } deferred_error = rrl_none;
+ char *ll;
+ char *uri;
unsigned int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */
char http[5];
apr_size_t len;
int num_blank_lines = DEFAULT_LIMIT_BLANK_LINES;
core_server_config *conf = ap_get_core_module_config(r->server->module_config);
- int strict = conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT;
- int enforce_strict = !(conf->http_conformance & AP_HTTP_CONFORMANCE_LOGONLY);
+ int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
+ const char *badwhitespace = strict ? "\t\n\v\f\r" : "\n\v\f\r";
+ int strictspaces = (conf->http_whitespace == AP_HTTP_WHITESPACE_STRICT);
/* Read past empty lines until we get a real request line,
* a read error, the connection closes (EOF), or we timeout.
}
r->request_time = apr_time_now();
- ll = r->the_request;
- r->method = ap_getword_white(r->pool, &ll);
- uri = ap_getword_white(r->pool, &ll);
+ r->method = r->the_request;
+ if (apr_isspace(*r->method))
+ deferred_error = rrl_excesswhitespace;
+ for ( ; apr_isspace(*r->method); ++r->method)
+ ;
- if (!*r->method || !*uri) {
- r->status = HTTP_BAD_REQUEST;
- r->proto_num = HTTP_VERSION(1,0);
- r->protocol = apr_pstrdup(r->pool, "HTTP/1.0");
- return 0;
+ if (strict) {
+ ll = (char*) ap_scan_http_token(r->method);
+ if ((ll == r->method) || (*ll && !apr_isspace(*ll))) {
+ deferred_error = rrl_badmethod;
+ ll = strpbrk(ll, "\t\n\v\f\r ");
+ }
}
+ else {
+ ll = strpbrk(r->method, "\t\n\v\f\r ");
+ }
+ if (!ll) {
+ if (deferred_error == rrl_none)
+ deferred_error = rrl_missinguri;
+ r->protocol = uri = "";
+ len = 0;
+ goto rrl_done;
+ }
+
+ if (strictspaces && ll[0] && (ll[0] != ' ' || apr_isspace(ll[1]))
+ && deferred_error == rrl_none) {
+ deferred_error = rrl_excesswhitespace;
+ }
+ for (uri = ll; apr_isspace(*uri); ++uri)
+ if (strchr(badwhitespace, *uri) && deferred_error == rrl_none)
+ deferred_error = rrl_badwhitespace;
+ *ll = '\0';
+ if (!*uri && deferred_error == rrl_none)
+ deferred_error = rrl_missinguri;
+
+ if (!(ll = strpbrk(uri, " \t\n\v\f\r"))) {
+ r->protocol = "";
+ len = 0;
+ goto rrl_done;
+ }
+ for (r->protocol = ll; apr_isspace(*r->protocol); ++r->protocol)
+ if (strchr(badwhitespace, *r->protocol) && deferred_error == rrl_none
+ && deferred_error == rrl_none)
+ deferred_error = rrl_badwhitespace;
+ *ll = '\0';
+ if (!(ll = strpbrk(r->protocol, " \t\n\v\f\r"))) {
+ len = strlen(r->protocol);
+ goto rrl_done;
+ }
+ len = ll - r->protocol;
+ if (strictspaces && *ll)
+ deferred_error = rrl_excesswhitespace;
+ for ( ; apr_isspace(*ll); ++ll)
+ if (strchr(badwhitespace, *ll) && deferred_error == rrl_none)
+ deferred_error = rrl_badwhitespace;
+ if (*ll && deferred_error == rrl_none)
+ deferred_error = rrl_trailingtext;
+ ll = (char *)r->protocol + len;
+ *ll = '\0';
+
+rrl_done:
+ /* For internal integrety, reconstruct the_request
+ * using only single SP characters, per spec.
+ * Once the method, uri and protocol are processed,
+ * we can then resume deferred error reporting
+ */
+ r->the_request = apr_pstrcat(r->pool, r->method, *uri ? " " : NULL, uri,
+ *r->protocol ? " " : NULL, r->protocol, NULL);
- /* Provide quick information about the request method as soon as known */
+ if (len == 8
+ && r->protocol[0] == 'H' && r->protocol[1] == 'T'
+ && r->protocol[2] == 'T' && r->protocol[3] == 'P'
+ && r->protocol[4] == '/' && apr_isdigit(r->protocol[5])
+ && r->protocol[6] == '.' && apr_isdigit(r->protocol[7])
+ && r->protocol[5] != '0') {
+ r->assbackwards = 0;
+ r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - '0');
+ }
+ else if (len == 8
+ && (r->protocol[0] == 'H' || r->protocol[0] == 'h')
+ && (r->protocol[1] == 'T' || r->protocol[1] == 't')
+ && (r->protocol[2] == 'T' || r->protocol[2] == 't')
+ && (r->protocol[3] == 'P' || r->protocol[3] == 'p')
+ && r->protocol[4] == '/' && apr_isdigit(r->protocol[5])
+ && r->protocol[6] == '.' && apr_isdigit(r->protocol[7])
+ && r->protocol[5] != '0') {
+ r->assbackwards = 0;
+ r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - '0');
+ if (strict && deferred_error == rrl_none)
+ deferred_error = rrl_badprotocol;
+ else
+ memcpy((char*)r->protocol, "HTTP", 4);
+ }
+ else if (r->protocol[0]) {
+ r->assbackwards = 0;
+ r->proto_num = HTTP_VERSION(1,0);
+ /* Defer setting the r->protocol string till error msg is composed */
+ if (strict && deferred_error == rrl_none)
+ deferred_error = rrl_badprotocol;
+ else
+ r->protocol = "HTTP/1.0";
+ }
+ else {
+ r->assbackwards = 1;
+ r->protocol = "HTTP/0.9";
+ r->proto_num = HTTP_VERSION(0, 9);
+ }
+ /* Satisfy the method_number and uri fields prior to invoking error
+ * handling, such that these fields are available for subsitution
+ */
r->method_number = ap_method_number_of(r->method);
- if (r->method_number == M_GET && r->method[0] == 'H') {
+ if (r->method_number == M_GET && r->method[0] == 'H')
r->header_only = 1;
- }
ap_parse_uri(r, uri);
- if (r->status != HTTP_OK) {
- r->proto_num = HTTP_VERSION(1,0);
- r->protocol = apr_pstrdup(r->pool, "HTTP/1.0");
- return 0;
- }
- if (ll[0]) {
- r->assbackwards = 0;
- pro = ll;
- len = strlen(ll);
+ if (r->proto_num == HTTP_VERSION(0, 9)) {
+ if (conf->http09_enable == AP_HTTP09_DISABLE
+ && deferred_error == rrl_none) {
+ /* If we deny 0.9, send error message with 1.x behavior */
+ r->assbackwards = 0;
+ r->connection->keepalive = AP_CONN_CLOSE;
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02401)
+ "HTTP Request Line; Rejected HTTP/0.9 request");
+ r->status = HTTP_VERSION_NOT_SUPPORTED;
+ return 0;
+ }
+ if (strict && strcmp(r->method, "GET") && deferred_error == rrl_none) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03444)
+ "HTTP Request Line; Invalid method token: '%.*s'"
+ " (only GET is allowed for HTTP/0.9 requests)",
+ field_name_len(r->method), r->method);
+ r->status = HTTP_BAD_REQUEST;
+ return 0;
+ }
}
- else {
- r->assbackwards = 1;
- pro = "HTTP/0.9";
- len = 8;
- if (conf->http09_enable == AP_HTTP09_DISABLE) {
- r->status = HTTP_VERSION_NOT_SUPPORTED;
- r->protocol = apr_pstrmemdup(r->pool, pro, len);
- /* If we deny 0.9, send error message with 1.x */
- r->assbackwards = 0;
- r->proto_num = HTTP_VERSION(0, 9);
- r->connection->keepalive = AP_CONN_CLOSE;
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02401)
- "HTTP/0.9 denied by server configuration");
- return 0;
+
+ if (deferred_error != rrl_none) {
+ if (deferred_error == rrl_badmethod)
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03445)
+ "HTTP Request Line; Invalid method token: '%.*s'",
+ field_name_len(r->method), r->method);
+ else if (deferred_error == rrl_missinguri)
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03446)
+ "HTTP Request Line; Missing URI");
+ else if (deferred_error == rrl_badwhitespace)
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03447)
+ "HTTP Request Line; Invalid whitespace");
+ else if (deferred_error == rrl_excesswhitespace)
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03448)
+ "HTTP Request Line; Inappropriate whitespace "
+ "(disallowed by StrictWhitespace");
+ else if (deferred_error == rrl_trailingtext)
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03449)
+ "HTTP Request Line; Extraneous text found '%.*s' "
+ "(perhaps whitespace was injected?)",
+ field_name_len(ll), ll);
+ else if (deferred_error == rrl_badprotocol) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02418)
+ "HTTP Request Line; Unrecognized protocol '%.*s' "
+ "(perhaps whitespace was injected?)",
+ field_name_len(r->protocol), r->protocol);
+ r->protocol = "HTTP/1.0";
}
+ r->status = HTTP_BAD_REQUEST;
+ return 0;
}
- r->protocol = apr_pstrmemdup(r->pool, pro, len);
- /* Avoid sscanf in the common case */
- if (len == 8
- && pro[0] == 'H' && pro[1] == 'T' && pro[2] == 'T' && pro[3] == 'P'
- && pro[4] == '/' && apr_isdigit(pro[5]) && pro[6] == '.'
- && apr_isdigit(pro[7])) {
- r->proto_num = HTTP_VERSION(pro[5] - '0', pro[7] - '0');
+ if (conf->http_methods == AP_HTTP_METHODS_REGISTERED
+ && r->method_number == M_INVALID) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02423)
+ "HTTP Request Line; Unrecognized HTTP method: '%.*s' "
+ "(disallowed by RegisteredMethods)",
+ field_name_len(r->method), r->method);
+ r->status = HTTP_NOT_IMPLEMENTED;
+ return 0;
}
- else {
- if (strict) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02418)
- "Invalid protocol '%s'", r->protocol);
- if (enforce_strict) {
- r->proto_num = HTTP_VERSION(1,0);
- r->protocol = apr_pstrdup(r->pool, "HTTP/1.0");
- r->connection->keepalive = AP_CONN_CLOSE;
- r->status = HTTP_BAD_REQUEST;
- return 0;
- }
- }
- if (3 == sscanf(r->protocol, "%4s/%u.%u", http, &major, &minor)
- && (strcasecmp("http", http) == 0)
- && (minor < HTTP_VERSION(1, 0)) ) { /* don't allow HTTP/0.1000 */
- r->proto_num = HTTP_VERSION(major, minor);
- }
- else {
- r->proto_num = HTTP_VERSION(1, 0);
- }
+
+ if (r->status != HTTP_OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03450)
+ "HTTP Request Line; URI parsing failed");
+ return 0;
}
if (strict) {
- int err = 0;
if (ap_has_cntrl(r->the_request)) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02420)
- "Request line must not contain control characters");
- err = HTTP_BAD_REQUEST;
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02420)
+ "HTTP Request Line; URI must not contain control"
+ " characters");
+ r->status = HTTP_BAD_REQUEST;
+ return 0;
}
if (r->parsed_uri.fragment) {
/* RFC3986 3.5: no fragment */
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02421)
- "URI must not contain a fragment");
- err = HTTP_BAD_REQUEST;
- }
- else if (r->parsed_uri.user || r->parsed_uri.password) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02422)
- "URI must not contain a username/password");
- err = HTTP_BAD_REQUEST;
- }
- else if (r->method_number == M_INVALID) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02423)
- "Invalid HTTP method string: %s", r->method);
- err = HTTP_NOT_IMPLEMENTED;
- }
- else if (r->assbackwards == 0 && r->proto_num < HTTP_VERSION(1, 0)) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02424)
- "HTTP/0.x does not take a protocol");
- err = HTTP_BAD_REQUEST;
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02421)
+ "HTTP Request Line; URI must not contain a fragment");
+ r->status = HTTP_BAD_REQUEST;
+ return 0;
}
-
- if (err && enforce_strict) {
- r->status = err;
+ if (r->parsed_uri.user || r->parsed_uri.password) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02422)
+ "HTTP Request Line; URI must not contain a "
+ "username/password");
+ r->status = HTTP_BAD_REQUEST;
return 0;
}
}
return 1;
}
-/* get the length of the field name for logging, but no more than 80 bytes */
-#define LOG_NAME_MAX_LEN 80
-static int field_name_len(const char *field)
-{
- const char *end = ap_strchr_c(field, ':');
- if (end == NULL || end - field > LOG_NAME_MAX_LEN)
- return LOG_NAME_MAX_LEN;
- return end - field;
-}
-
static int table_do_fn_check_lengths(void *r_, const char *key,
const char *value)
{
int fields_read = 0;
char *tmp_field;
core_server_config *conf = ap_get_core_module_config(r->server->module_config);
+ int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
/*
* Read header lines until we get the empty separator line, a read error,
}
memcpy(last_field + last_len, field, len +1); /* +1 for nul */
/* Replace obs-fold w/ SP per RFC 7230 3.2.4 */
- if (conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) {
+ if (strict) {
last_field[last_len] = ' ';
}
last_len += len;
return;
}
- if (!(conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT))
- {
- /* Not Strict, using the legacy parser */
+ if (!strict) {
+ /* Not Strict ('Unsafe' mode), using the legacy parser */
if (!(value = strchr(last_field, ':'))) { /* Find ':' or */
r->status = HTTP_BAD_REQUEST; /* abort bad request */