Gents,
rfc2817, Upgrading to TLS Within HTTP/1.1, says that a (mandatory)
connection upgrade looks is requested as:
OPTIONS * HTTP/1.1
Host: example.bank.com
Upgrade: TLS/1.0
Connection: Upgrade
"SSLEngine optional" is needed for the upgrade to succeed.
This happens to collide with the "OPTIONS *" from the internal dummy
connection (which used to be a "GET / HTTP/1.0" in early 2.2 versions).
There is probably only one single system/device on the planet that does
that - Apple's IOS when printing with the "secure" button tapped.
If this is fixed there may be more browsers/libraries using it.
Thanks,
Roman.
Suggested patch, requesting to include (attached):
diff -rpNU 10 ../httpd-2.4.6-o/modules/http/http_core.c
./modules/http/http_core.c
--- ../httpd-2.4.6-o/modules/http/http_core.c 2011-11-22 00:07:16.000000000
+0100
+++ ./modules/http/http_core.c 2013-09-11 16:30:27.000000000 +0200
@@ -245,20 +245,34 @@ static int http_create_request(request_r
NULL, r, r->connection);
}
return OK;
}
static int http_send_options(request_rec *r)
{
if ((r->method_number == M_OPTIONS) && r->uri && (r->uri[0] == '*') &&
(r->uri[1] == '\0')) {
+ if(apr_table_get(r->headers_in, "Upgrade") != NULL) {
+ /*
+ a connection upgrade to TLS with rfc2817
+ looks like:
+ OPTIONS * HTTP/1.1
+ Host: example.bank.com
+ Upgrade: TLS/1.0
+ Connection: Upgrade
+ ...
+ Check if the Upgrade header line is present
+ and don't return DONE if so.
+ */
+ return DECLINED;
+ }
return DONE; /* Send HTTP pong, without Allow header */
}
return DECLINED;
}
static int http_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t
*ptemp, server_rec *s)
{
apr_uint64_t val;
if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm) != APR_SUCCESS) {
async_mpm = 0;diff -rNU 30 ../httpd-2.2.25-o/modules/http/http_core.c ./modules/http/http_core.c
--- ../httpd-2.2.25-o/modules/http/http_core.c 2007-11-15 23:08:30.000000000 +0100
+++ ./modules/http/http_core.c 2013-09-11 16:25:54.000000000 +0200
@@ -205,60 +205,74 @@
csd = ap_get_module_config(c->conn_config, &core_module);
}
apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 1);
apr_socket_timeout_set(csd, c->base_server->keep_alive_timeout);
/* Go straight to select() to wait for the next request */
}
return OK;
}
static int http_create_request(request_rec *r)
{
if (!r->main && !r->prev) {
ap_add_output_filter_handle(ap_byterange_filter_handle,
NULL, r, r->connection);
ap_add_output_filter_handle(ap_content_length_filter_handle,
NULL, r, r->connection);
ap_add_output_filter_handle(ap_http_header_filter_handle,
NULL, r, r->connection);
ap_add_output_filter_handle(ap_http_outerror_filter_handle,
NULL, r, r->connection);
}
return OK;
}
static int http_send_options(request_rec *r)
{
if ((r->method_number == M_OPTIONS) && r->uri && (r->uri[0] == '*') &&
(r->uri[1] == '\0')) {
+ if(apr_table_get(r->headers_in, "Upgrade") != NULL) {
+ /*
+ a connection upgrade to TLS with rfc2817
+ looks like:
+ OPTIONS * HTTP/1.1
+ Host: example.bank.com
+ Upgrade: TLS/1.0
+ Connection: Upgrade
+ ...
+ Check if the Upgrade header line is present
+ and don't return DONE if so.
+ */
+ return DECLINED;
+ }
return DONE; /* Send HTTP pong, without Allow header */
}
return DECLINED;
}
static void register_hooks(apr_pool_t *p)
{
/**
* If we ae using an MPM That Supports Async Connections,
* use a different processing function
*/
int async_mpm = 0;
if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm) == APR_SUCCESS
&& async_mpm == 1) {
ap_hook_process_connection(ap_process_http_async_connection, NULL,
NULL, APR_HOOK_REALLY_LAST);
}
else {
ap_hook_process_connection(ap_process_http_connection, NULL, NULL,
APR_HOOK_REALLY_LAST);
}
ap_hook_map_to_storage(ap_send_http_trace,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_map_to_storage(http_send_options,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_http_scheme(http_scheme,NULL,NULL,APR_HOOK_REALLY_LAST);
ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST);
ap_hook_create_request(http_create_request, NULL, NULL, APR_HOOK_REALLY_LAST);
ap_http_input_filter_handle =
ap_register_input_filter("HTTP_IN", ap_http_filter,
NULL, AP_FTYPE_PROTOCOL);
diff -rNU 30 ../httpd-2.4.6-o/modules/http/http_core.c ./modules/http/http_core.c
--- ../httpd-2.4.6-o/modules/http/http_core.c 2011-11-22 00:07:16.000000000 +0100
+++ ./modules/http/http_core.c 2013-09-11 16:30:27.000000000 +0200
@@ -225,60 +225,74 @@
static int ap_process_http_connection(conn_rec *c)
{
if (async_mpm && !c->clogging_input_filters) {
return ap_process_http_async_connection(c);
}
else {
return ap_process_http_sync_connection(c);
}
}
static int http_create_request(request_rec *r)
{
if (!r->main && !r->prev) {
ap_add_output_filter_handle(ap_byterange_filter_handle,
NULL, r, r->connection);
ap_add_output_filter_handle(ap_content_length_filter_handle,
NULL, r, r->connection);
ap_add_output_filter_handle(ap_http_header_filter_handle,
NULL, r, r->connection);
ap_add_output_filter_handle(ap_http_outerror_filter_handle,
NULL, r, r->connection);
}
return OK;
}
static int http_send_options(request_rec *r)
{
if ((r->method_number == M_OPTIONS) && r->uri && (r->uri[0] == '*') &&
(r->uri[1] == '\0')) {
+ if(apr_table_get(r->headers_in, "Upgrade") != NULL) {
+ /*
+ a connection upgrade to TLS with rfc2817
+ looks like:
+ OPTIONS * HTTP/1.1
+ Host: example.bank.com
+ Upgrade: TLS/1.0
+ Connection: Upgrade
+ ...
+ Check if the Upgrade header line is present
+ and don't return DONE if so.
+ */
+ return DECLINED;
+ }
return DONE; /* Send HTTP pong, without Allow header */
}
return DECLINED;
}
static int http_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
apr_uint64_t val;
if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm) != APR_SUCCESS) {
async_mpm = 0;
}
ap_random_insecure_bytes(&val, sizeof(val));
ap_multipart_boundary = apr_psprintf(p, "%0" APR_UINT64_T_HEX_FMT, val);
return OK;
}
static void register_hooks(apr_pool_t *p)
{
ap_hook_post_config(http_post_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_process_connection(ap_process_http_connection, NULL, NULL,
APR_HOOK_REALLY_LAST);
ap_hook_map_to_storage(ap_send_http_trace,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_map_to_storage(http_send_options,NULL,NULL,APR_HOOK_MIDDLE);
ap_hook_http_scheme(http_scheme,NULL,NULL,APR_HOOK_REALLY_LAST);
ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST);
ap_hook_create_request(http_create_request, NULL, NULL, APR_HOOK_REALLY_LAST);
ap_http_input_filter_handle =
ap_register_input_filter("HTTP_IN", ap_http_filter,
NULL, AP_FTYPE_PROTOCOL);