</directivesynopsis>
<directivesynopsis>
-<name>HTTPProtocolOptions</name>
+<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>
+<syntax>HttpProtocolOptions [Strict|Unsafe] [StrictURL|UnsafeURL]
+ [RegisteredMethods|LenientMethods] [Allow0.9|Require1.0]</syntax>
+<default>HttpProtocolOptions Strict StrictURL LenientMethods Allow0.9</default>
<contextlist><context>server config</context>
<context>virtual host</context></contextlist>
<compatibility>2.2.32 or 2.4.24 and later</compatibility>
(<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>
+ custom user-agents which must be deperecated, <code>Unsafe</code>
+ and <code>UnsafeURL</code> options have been added to revert to the legacy
+ behaviors. These rules are applied prior to request processing, so must be
+ configured at the global or default (first) matching virtual host section,
+ by IP/port 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
>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>
-
+ risks of accepting non-conformant request messages, while
+ <a href="https://tools.ietf.org/html/rfc7230#section-3.5"
+ >RFC 7230 §3.5</a> "Message Parsing Robustness" identify the
+ risks of accepting obscure whitespace and request message formatting.
+ As of the introduction of this directive, all grammer rules of the
+ specification are enforced in the default <code>Strict</code> operating
+ mode, and the strict whitespace suggested by section 3.5 is enforced
+ and cannot be relaxed.</p>
+
+ <p><a href="https://tools.ietf.org/html/rfc3986#section-2.2"
+ >RFC 3986 §2.2 and 2.3</a> define "Reserved Characters" and
+ "Unreserved Characters". All other character octets are required to
+ be %XX encoded under this spec, and RFC7230 defers to these requirements.
+ By default the <code>StrictURI</code> option will reject all requests
+ containing invalid characters. This rule can be relaxed with the
+ <code>UnsafeURI</code> option to support badly written user-agents.</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,
+ or <code>UnsafeURI</code> modes of operation, particularly on
+ outward-facing, publicly accessible server deployments.
+ If an interface is required for faulty monitoring or other custom service
+ consumers running on an intranet, users should toggle only those Unsafe
+ options which are necessary, and only on a specific virtual host configured
+ to service only their internal private network.</p>
+
+ <p>Reviewing the messages logged to the <directive>ErrorLog</directive>,
+ configured with <directive>LogLevel</directive> <code>debug</code> level,
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>
+ Users should pay particular attention to the 400 responses in the access
+ log for invalid requests which were unexpectedly rejected.</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>
+ to toggle the <code>RegisteredMethods</code> option and register any
+ non-standard methods 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>
+
+ <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 7230 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>
</usage>
</directivesynopsis>
* APR_ENOSPC is returned if there is not enough buffer space.
* Other errors may be returned on other errors.
*
- * The LF is *not* returned in the buffer. Therefore, a *read of 0
+ * The [CR]LF are *not* returned in the buffer. Therefore, a *read of 0
* indicates that an empty line was read.
*
* Notes: Because the buffer uses 1 char for NUL, the most we can return is
*/
AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
apr_size_t *read, request_rec *r,
- int fold, apr_bucket_brigade *bb)
+ int flags, apr_bucket_brigade *bb)
{
apr_status_t rv;
apr_bucket *e;
apr_size_t bytes_handled = 0, current_alloc = 0;
char *pos, *last_char = *s;
int do_alloc = (*s == NULL), saw_eos = 0;
+ int fold = flags & AP_GETLINE_FOLD;
+ int crlf = flags & AP_GETLINE_CRLF;
/*
* Initialize last_char as otherwise a random value will be compared
}
}
+ if (crlf && (last_char <= *s || last_char[-1] != APR_ASCII_CR)) {
+ *last_char = '\0';
+ bytes_handled = last_char - *s;
+ *read = bytes_handled;
+ return APR_EINVAL;
+ }
+
/* Now NUL-terminate the string at the end of the line;
* if the last-but-one character is a CR, terminate there */
if (last_char > *s && last_char[-1] == APR_ASCII_CR) {
}
#endif
-AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold)
+AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags)
{
char *tmp_s = s;
apr_status_t rv;
apr_bucket_brigade *tmp_bb;
tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
- rv = ap_rgetline(&tmp_s, n, &len, r, fold, tmp_bb);
+ rv = ap_rgetline(&tmp_s, n, &len, r, flags, tmp_bb);
apr_brigade_destroy(tmp_bb);
/* Map the out-of-space condition to the old API. */
{
enum {
rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace,
- rrl_missinguri, rrl_badprotocol, rrl_trailingtext
+ rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext,
+ rrl_badmethod09, rrl_reject09
} deferred_error = rrl_none;
char *ll;
char *uri;
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_UNSAFE);
- const char *badwhitespace = strict ? "\t\n\v\f\r" : "\n\v\f\r";
- int strictspaces = (conf->http_whitespace == AP_HTTP_WHITESPACE_STRICT);
+ int stricturi = (conf->http_stricturi != AP_HTTP_URI_UNSAFE);
/* Read past empty lines until we get a real request line,
* a read error, the connection closes (EOF), or we timeout.
*/
r->the_request = NULL;
rv = ap_rgetline(&(r->the_request), (apr_size_t)(r->server->limit_req_line + 2),
- &len, r, 0, bb);
+ &len, r, strict ? AP_GETLINE_CRLF : 0, bb);
if (rv != APR_SUCCESS) {
r->request_time = apr_time_now();
r->request_time = apr_time_now();
r->method = r->the_request;
- if (apr_isspace(*r->method))
- deferred_error = rrl_excesswhitespace;
- for ( ; apr_isspace(*r->method); ++r->method)
- ;
+ /* If there is whitespace before a method, skip it and mark in error */
+ if (apr_isspace(*r->method)) {
+ deferred_error = rrl_badwhitespace;
+ for ( ; apr_isspace(*r->method); ++r->method)
+ ;
+ }
+
+ /* Scan the method up to the next whitespace, ensure it contains only
+ * valid http-token characters, otherwise mark in error
+ */
if (strict) {
ll = (char*) ap_scan_http_token(r->method);
- if ((ll == r->method) || (*ll && !apr_isspace(*ll))) {
+ if (((ll == r->method) || (*ll && !apr_isspace(*ll)))
+ && deferred_error == rrl_none) {
deferred_error = rrl_badmethod;
ll = strpbrk(ll, "\t\n\v\f\r ");
}
else {
ll = strpbrk(r->method, "\t\n\v\f\r ");
}
+
+ /* Verify method terminated with a single SP, or mark as specific error */
if (!ll) {
if (deferred_error == rrl_none)
deferred_error = rrl_missinguri;
len = 0;
goto rrl_done;
}
-
- if (strictspaces && ll[0] && (ll[0] != ' ' || apr_isspace(ll[1]))
- && deferred_error == rrl_none) {
+ else if (strict && ll[0] && (ll[0] != ' ' || apr_isspace(ll[1]))
+ && deferred_error == rrl_none) {
deferred_error = rrl_excesswhitespace;
}
+
+ /* Advance uri pointer over leading whitespace, NUL terminate the method
+ * If non-SP whitespace is encountered, mark as specific error
+ */
for (uri = ll; apr_isspace(*uri); ++uri)
- if (ap_strchr_c(badwhitespace, *uri) && deferred_error == rrl_none)
+ if (ap_strchr_c("\t\n\v\f\r", *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"))) {
+ /* Scan the URI up to the next whitespace, ensure it contains only
+ * valid RFC3986 characters, otherwise mark in error
+ */
+ if (stricturi) {
+ ll = (char*) ap_scan_http_uri_safe(uri);
+ if (ll == uri || (*ll && !apr_isspace(*ll))) {
+ deferred_error = rrl_baduri;
+ ll = strpbrk(ll, "\t\n\v\f\r ");
+ }
+ }
+ else {
+ ll = strpbrk(uri, "\t\n\v\f\r ");
+ }
+
+ /* Verify method terminated with a single SP, or mark as specific error */
+ if (!ll) {
r->protocol = "";
len = 0;
goto rrl_done;
}
+ else if (strict && ll[0] && (ll[0] != ' ' || apr_isspace(ll[1]))
+ && deferred_error == rrl_none) {
+ deferred_error = rrl_excesswhitespace;
+ }
+
+ /* Advance protocol pointer over leading whitespace, NUL terminate the uri
+ * If non-SP whitespace is encountered, mark as specific error
+ */
for (r->protocol = ll; apr_isspace(*r->protocol); ++r->protocol)
- if (ap_strchr_c(badwhitespace, *r->protocol) && deferred_error == rrl_none)
+ if (ap_strchr_c("\t\n\v\f\r", *r->protocol)
+ && deferred_error == rrl_none)
deferred_error = rrl_badwhitespace;
*ll = '\0';
+
+ /* Scan the protocol up to the next whitespace, validation comes later */
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 (ap_strchr_c(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';
+
+ /* Advance over trailing whitespace, if found mark in error,
+ * determine if trailing text is found, unconditionally mark in error,
+ * finally NUL terminate the protocol string
+ */
+ if (strict && *ll) {
+ deferred_error = rrl_excesswhitespace;
+ }
+ else {
+ for ( ; apr_isspace(*ll); ++ll)
+ if (ap_strchr_c("\t\n\v\f\r", *ll)
+ && deferred_error == rrl_none)
+ deferred_error = rrl_badwhitespace;
+ if (*ll && deferred_error == rrl_none)
+ deferred_error = rrl_trailingtext;
+ }
+ *((char *)r->protocol + len) = '\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
+ /* For internal integrety and palloc efficiency, reconstruct the_request
+ * in one palloc, using only single SP characters, per spec.
*/
r->the_request = apr_pstrcat(r->pool, r->method, *uri ? " " : NULL, uri,
*r->protocol ? " " : NULL, r->protocol, NULL);
r->proto_num = HTTP_VERSION(0, 9);
}
- /* Satisfy the method_number and uri fields prior to invoking error
+ /* Determine the method_number and parse the uri prior to invoking error
* handling, such that these fields are available for subsitution
*/
r->method_number = ap_method_number_of(r->method);
ap_parse_uri(r, uri);
- 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;
- }
+ /* With the request understood, we can consider HTTP/0.9 specific errors */
+ if (r->proto_num == HTTP_VERSION(0, 9) && deferred_error == rrl_none) {
+ if (conf->http09_enable == AP_HTTP09_DISABLE)
+ deferred_error = rrl_reject09;
+ else if (strict && (r->method_number != M_GET || r->header_only))
+ deferred_error = rrl_badmethod09;
}
+ /* Now that the method, uri and protocol are all processed,
+ * we can safely resume any deferred error reporting
+ */
if (deferred_error != rrl_none) {
if (deferred_error == rrl_badmethod)
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03445)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03445)
"HTTP Request Line; Invalid method token: '%.*s'",
field_name_len(r->method), r->method);
+ else if (deferred_error == rrl_badmethod09)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 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);
else if (deferred_error == rrl_missinguri)
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03446)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03446)
"HTTP Request Line; Missing URI");
+ else if (deferred_error == rrl_baduri)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03454)
+ "HTTP Request Line; URI incorrectly encoded: '%.*s'",
+ field_name_len(r->uri), r->uri);
else if (deferred_error == rrl_badwhitespace)
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03447)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 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");
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03448)
+ "HTTP Request Line; Excess whitespace "
+ "(disallowed by HttpProtocolOptions Strict");
else if (deferred_error == rrl_trailingtext)
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03449)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 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)
+ else if (deferred_error == rrl_reject09)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02401)
+ "HTTP Request Line; Rejected HTTP/0.9 request");
+ else if (deferred_error == rrl_badprotocol)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 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;
+ goto rrl_failed;
}
if (conf->http_methods == AP_HTTP_METHODS_REGISTERED
&& r->method_number == M_INVALID) {
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02423)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 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;
+ /* This can't happen in an HTTP/0.9 request, we verified GET above */
return 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;
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03450)
+ "HTTP Request Line; Unable to parse URI: '%.*s'",
+ field_name_len(r->uri), r->uri);
+ goto rrl_failed;
}
if (strict) {
- if (ap_has_cntrl(r->the_request)) {
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02420)
+ /* No sense re-testing here for what was evaulated above */
+ if (!stricturi && ap_has_cntrl(r->the_request)) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02420)
"HTTP Request Line; URI must not contain control"
" characters");
r->status = HTTP_BAD_REQUEST;
- return 0;
+ goto rrl_failed;
}
if (r->parsed_uri.fragment) {
/* RFC3986 3.5: no fragment */
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02421)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02421)
"HTTP Request Line; URI must not contain a fragment");
r->status = HTTP_BAD_REQUEST;
- return 0;
+ goto rrl_failed;
}
if (r->parsed_uri.user || r->parsed_uri.password) {
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02422)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02422)
"HTTP Request Line; URI must not contain a "
"username/password");
r->status = HTTP_BAD_REQUEST;
- return 0;
+ goto rrl_failed;
}
}
return 1;
+
+rrl_failed:
+ if (r->proto_num == HTTP_VERSION(0, 9)) {
+ /* Send all parsing and protocol error response with 1.x behavior,
+ * and reserve 505 errors for actual HTTP protocols presented.
+ * As called out in RFC7230 3.5, any errors parsing the protocol
+ * from the request line are nearly always misencoded HTTP/1.x
+ * requests. Only a valid 0.9 request with no parsing errors
+ * at all may be treated as a simple request, if allowed.
+ */
+ r->assbackwards = 0;
+ r->connection->keepalive = AP_CONN_CLOSE;
+ r->proto_num = HTTP_VERSION(1, 0);
+ r->protocol = "HTTP/1.0";
+ }
+ return 0;
}
static int table_do_fn_check_lengths(void *r_, const char *key,
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);
- int strictspaces = (conf->http_whitespace == AP_HTTP_WHITESPACE_STRICT);
/*
* Read header lines until we get the empty separator line, a read error,
field = NULL;
rv = ap_rgetline(&field, r->server->limit_req_fieldsize + 2,
- &len, r, 0, bb);
+ &len, r, strict ? AP_GETLINE_CRLF : 0, bb);
if (rv != APR_SUCCESS) {
if (APR_STATUS_IS_TIMEUP(rv)) {
if (last_field == NULL) {
r->status = HTTP_BAD_REQUEST;
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03442)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03442)
"Line folding encountered before first"
" header line");
return;
if (field[1] == '\0') {
r->status = HTTP_BAD_REQUEST;
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03443)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03443)
"Empty folded line encountered");
return;
}
}
memcpy(last_field + last_len, field, len +1); /* +1 for nul */
/* Replace obs-fold w/ SP per RFC 7230 3.2.4 */
- if (strict || strictspaces) {
- last_field[last_len] = ' ';
- }
+ last_field[last_len] = ' ';
last_len += len;
/* We've appended this obs-fold line to last_len, proceed to
{
/* Not Strict ('Unsafe' mode), using the legacy parser */
- if (strictspaces && strpbrk(last_field, "\n\v\f\r")) {
- r->status = HTTP_BAD_REQUEST;
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03451)
- "Request header presented bad whitespace "
- "(disallowed by StrictWhitespace)");
- return;
- }
- else {
- char *ll = last_field;
- while ((ll = strpbrk(ll, "\n\v\f\r")))
- *(ll++) = ' ';
- }
-
if (!(value = strchr(last_field, ':'))) { /* Find ':' or */
r->status = HTTP_BAD_REQUEST; /* abort bad request */
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00564)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00564)
"Request header field is missing ':' "
"separator: %.*s", (int)LOG_NAME_MAX_LEN,
last_field);
*value++ = '\0'; /* NUL-terminate at colon */
- if (strictspaces && strpbrk(last_field, " \t")) {
+ if (strpbrk(last_field, "\t\n\v\f\r ")) {
r->status = HTTP_BAD_REQUEST;
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03452)
- "Request header field name with whitespace "
- "(disallowed by StrictWhitespace)");
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03452)
+ "Request header field name presented"
+ " invalid whitespace");
return;
}
++value; /* Skip to start of value */
}
- /* Strip LWS after field-name: */
- while (tmp_field > last_field
- && (*tmp_field == ' ' || *tmp_field == '\t')) {
- *(tmp_field--) = '\0';
+ if (strpbrk(value, "\n\v\f\r")) {
+ r->status = HTTP_BAD_REQUEST;
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03451)
+ "Request header field value presented"
+ " bad whitespace");
+ return;
}
if (tmp_field == last_field) {
r->status = HTTP_BAD_REQUEST;
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03453)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03453)
"Request header field name was empty");
return;
}
value = (char *)ap_scan_http_token(last_field);
if ((value == last_field) || *value != ':') {
r->status = HTTP_BAD_REQUEST;
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02426)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02426)
"Request header field name is malformed: "
"%.*s", (int)LOG_NAME_MAX_LEN, last_field);
return;
*/
if (*tmp_field != '\0') {
r->status = HTTP_BAD_REQUEST;
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02427)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02427)
"Request header value is malformed: "
"%.*s", (int)LOG_NAME_MAX_LEN, value);
return;
r->server->limit_req_line);
}
else if (r->method == NULL) {
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00566)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00566)
"request failed: malformed request line");
}
access_status = r->status;
ap_get_mime_headers_core(r, tmp_bb);
if (r->status != HTTP_OK) {
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00567)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00567)
"request failed: error reading the headers");
ap_send_error_response(r, 0);
ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
*/
if (!(strcasecmp(tenc, "chunked") == 0 /* fast path */
|| ap_find_last_token(r->pool, tenc, "chunked"))) {
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02539)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02539)
"client sent unknown Transfer-Encoding "
"(%s): %s", tenc, r->uri);
r->status = HTTP_BAD_REQUEST;
apr_table_unset(r->headers_in, "Content-Length");
}
}
- else {
- if (r->header_only) {
- /*
- * Client asked for headers only with HTTP/0.9, which doesn't send
- * headers! Have to dink things just to make sure the error message
- * comes through...
- */
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00568)
- "client sent invalid HTTP/0.9 request: HEAD %s",
- r->uri);
- r->header_only = 0;
- r->status = HTTP_BAD_REQUEST;
- ap_send_error_response(r, 0);
- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
- ap_run_log_transaction(r);
- apr_brigade_destroy(tmp_bb);
- goto traceout;
- }
- }
apr_brigade_destroy(tmp_bb);
* a Host: header, and the server MUST respond with 400 if it doesn't.
*/
access_status = HTTP_BAD_REQUEST;
- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00569)
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00569)
"client sent HTTP/1.1 request without hostname "
"(see RFC2616 section 14.23): %s", r->uri);
}