diff --git a/NEWS b/NEWS index e8ad0757..2485abbd 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,7 @@ NEWS * [core] recognize more http methods to forward to backends (fixes #2346) * [ssl] use DH only if openssl supports it (fixes #2479) * [network] use constants available at compile time for maximum number of chunks for writev instead of calling sysconf (fixes #2470) + * [ssl] Fix $HTTP["scheme"] conditional, could be "http" for ssl connections if the ssl $SERVER["socket"] conditional was nested (fixes #2501) - 1.4.32 - 2012-11-21 * Code cleanup with clang/sparse (fixes #2437, thx kibi) diff --git a/src/base.h b/src/base.h index 9c75cc96..90b2847d 100644 --- a/src/base.h +++ b/src/base.h @@ -289,7 +289,7 @@ typedef struct { unsigned short use_ipv6, set_v6only; /* set_v6only is only a temporary option */ unsigned short defer_accept; - unsigned short is_ssl; + unsigned short ssl_enabled; /* only interesting for setting up listening sockets. don't use at runtime */ unsigned short allow_http11; unsigned short etag_use_inode; unsigned short etag_use_mtime; @@ -432,7 +432,7 @@ typedef struct { int error_handler_saved_status; int in_error_handler; - void *srv_socket; /* reference to the server-socket (typecast to server_socket) */ + struct server_socket *srv_socket; /* reference to the server-socket */ #ifdef USE_OPENSSL SSL *ssl; @@ -525,7 +525,7 @@ typedef struct { unsigned short reject_expect_100_with_417; } server_config; -typedef struct { +typedef struct server_socket { sock_addr addr; int fd; int fde_ndx; @@ -545,7 +545,6 @@ typedef struct { #ifdef USE_OPENSSL SSL_CTX *ssl_ctx; #endif - unsigned short is_proxy_ssl; } server_socket; typedef struct { diff --git a/src/buffer.c b/src/buffer.c index d986fdaa..eea7041d 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -538,6 +538,12 @@ int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) { return buffer_is_equal(a, &b); } +/* buffer_is_equal_caseless_string(b, CONST_STR_LEN("value")) */ +int buffer_is_equal_caseless_string(buffer *a, const char *s, size_t b_len) { + if (a->used != b_len + 1) return 0; + + return (0 == strcasecmp(a->ptr, s)); +} int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) { size_t const len = (a_len < b_len) ? a_len : b_len; diff --git a/src/buffer.h b/src/buffer.h index bda04241..c381652c 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -82,6 +82,7 @@ int buffer_is_empty(buffer *b); int buffer_is_equal(buffer *a, buffer *b); int buffer_is_equal_right_len(buffer *a, buffer *b, size_t len); int buffer_is_equal_string(buffer *a, const char *s, size_t b_len); +int buffer_is_equal_caseless_string(buffer *a, const char *s, size_t b_len); int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len); typedef enum { diff --git a/src/configfile.c b/src/configfile.c index bb71b956..15cc6e44 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -177,7 +177,7 @@ static int config_insert(server *srv) { s->max_read_idle = 60; s->max_write_idle = 360; s->use_xattr = 0; - s->is_ssl = 0; + s->ssl_enabled = 0; s->ssl_honor_cipher_order = 1; s->ssl_use_sslv2 = 0; s->ssl_use_sslv3 = 1; @@ -231,7 +231,7 @@ static int config_insert(server *srv) { cv[27].destination = &(s->use_xattr); cv[28].destination = s->mimetypes; cv[29].destination = s->ssl_pemfile; - cv[30].destination = &(s->is_ssl); + cv[30].destination = &(s->ssl_enabled); cv[31].destination = &(s->log_file_not_found); cv[32].destination = &(s->log_request_handling); @@ -332,7 +332,7 @@ int config_setup_connection(server *srv, connection *con) { PATCH(range_requests); PATCH(force_lowercase_filenames); - PATCH(is_ssl); + PATCH(ssl_enabled); PATCH(ssl_pemfile); #ifdef USE_OPENSSL @@ -418,7 +418,7 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) { } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.cipher-list"))) { PATCH(ssl_cipher_list); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) { - PATCH(is_ssl); + PATCH(ssl_enabled); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.dh-file"))) { PATCH(ssl_dh_file); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ec-curve"))) { @@ -1306,7 +1306,7 @@ int config_set_defaults(server *srv) { } if (srv->srvconf.port == 0) { - srv->srvconf.port = s->is_ssl ? 443 : 80; + srv->srvconf.port = s->ssl_enabled ? 443 : 80; } if (srv->srvconf.event_handler->used == 0) { @@ -1344,7 +1344,7 @@ int config_set_defaults(server *srv) { } } - if (s->is_ssl) { + if (s->ssl_enabled) { if (buffer_is_empty(s->ssl_pemfile)) { /* PEM file is require */ diff --git a/src/connections.c b/src/connections.c index b653e882..9bb40f0a 100644 --- a/src/connections.c +++ b/src/connections.c @@ -200,7 +200,7 @@ static int connection_handle_read_ssl(server *srv, connection *con) { int r, ssl_err, len, count = 0, read_offset, toread; buffer *b = NULL; - if (!con->conf.is_ssl) return -1; + if (!con->srv_socket->is_ssl) return -1; ERR_clear_error(); do { @@ -334,7 +334,7 @@ static int connection_handle_read(server *srv, connection *con) { buffer *b; int toread, read_offset; - if (con->conf.is_ssl) { + if (con->srv_socket->is_ssl) { return connection_handle_read_ssl(srv, con); } @@ -1174,7 +1174,7 @@ static handler_t connection_handle_fdevent(server *srv, void *context, int reven joblist_append(srv, con); - if (con->conf.is_ssl) { + if (con->srv_socket->is_ssl) { /* ssl may read and write for both reads and writes */ if (revents & (FDEVENT_IN | FDEVENT_OUT)) { con->is_readable = 1; @@ -1345,7 +1345,6 @@ connection *connection_accept(server *srv, server_socket *srv_socket) { con->renegotiations = 0; SSL_set_app_data(con->ssl, con); SSL_set_accept_state(con->ssl); - con->conf.is_ssl=1; if (1 != (SSL_set_fd(con->ssl, cnt))) { log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", @@ -1390,12 +1389,6 @@ int connection_state_machine(server *srv, connection *con) { connection_set_state(srv, con, CON_STATE_READ); - /* patch con->conf.is_ssl if the connection is a ssl-socket already */ - -#ifdef USE_OPENSSL - con->conf.is_ssl = srv_sock->is_ssl; -#endif - break; case CON_STATE_REQUEST_END: /* transient */ if (srv->srvconf.log_state_handling) { diff --git a/src/http-header-glue.c b/src/http-header-glue.c index 4a74c0ee..fe2f4fb3 100644 --- a/src/http-header-glue.c +++ b/src/http-header-glue.c @@ -123,11 +123,8 @@ int http_response_redirect_to_directory(server *srv, connection *con) { o = buffer_init(); - if (con->conf.is_ssl) { - buffer_copy_string_len(o, CONST_STR_LEN("https://")); - } else { - buffer_copy_string_len(o, CONST_STR_LEN("http://")); - } + buffer_copy_string_buffer(o, con->uri.scheme); + buffer_append_string_len(o, CONST_STR_LEN("://")); if (con->uri.authority->used) { buffer_append_string_buffer(o, con->uri.authority); } else { @@ -193,10 +190,15 @@ int http_response_redirect_to_directory(server *srv, connection *con) { return -1; } - if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || - (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) { - buffer_append_string_len(o, CONST_STR_LEN(":")); - buffer_append_long(o, srv->srvconf.port); + { + unsigned short default_port = 80; + if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) { + default_port = 443; + } + if (default_port != srv->srvconf.port) { + buffer_append_string_len(o, CONST_STR_LEN(":")); + buffer_append_long(o, srv->srvconf.port); + } } } buffer_append_string_buffer(o, con->uri.path); diff --git a/src/mod_cgi.c b/src/mod_cgi.c index 5e65f4b0..4a0d6416 100644 --- a/src/mod_cgi.c +++ b/src/mod_cgi.c @@ -923,11 +923,9 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * CONST_BUF_LEN(con->authed_user)); } -#ifdef USE_OPENSSL - if (srv_sock->is_ssl) { - cgi_env_add(&env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")); - } -#endif + if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) { + cgi_env_add(&env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")); + } /* request.content_length < SSIZE_MAX, see request.c */ LI_ltostr(buf, con->request.content_length); diff --git a/src/mod_extforward.c b/src/mod_extforward.c index 358443c0..dd52f310 100644 --- a/src/mod_extforward.c +++ b/src/mod_extforward.c @@ -423,17 +423,18 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) { if (real_remote_addr != NULL) { /* parsed */ sock_addr sock; - server_socket *srv_sock = con->srv_socket; data_string *forwarded_proto = (data_string *)array_get_element(con->request.headers, "X-Forwarded-Proto"); - if (forwarded_proto && !strcmp(forwarded_proto->value->ptr, "https")) { - srv_sock->is_proxy_ssl = 1; - } else { - srv_sock->is_proxy_ssl = 0; + if (NULL != forwarded_proto) { + if (buffer_is_equal_caseless_string(forwarded_proto->value, CONST_STR_LEN("https"))) { + buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https")); + } else if (buffer_is_equal_caseless_string(forwarded_proto->value, CONST_STR_LEN("http"))) { + buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http")); + } } if (con->conf.log_request_handling) { - log_error_write(srv, __FILE__, __LINE__, "ss", "using address:", real_remote_addr); + log_error_write(srv, __FILE__, __LINE__, "ss", "using address:", real_remote_addr); } #ifdef HAVE_IPV6 ipstr_to_sockaddr(srv, real_remote_addr, &sock); diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c index f0e87b6f..452dfb9f 100644 --- a/src/mod_fastcgi.c +++ b/src/mod_fastcgi.c @@ -2032,7 +2032,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { s = get_http_version_name(con->request.http_version); FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con) - if (srv_sock->is_ssl || srv_sock->is_proxy_ssl) { + if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) { FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")),con) } diff --git a/src/mod_proxy.c b/src/mod_proxy.c index 09d4fc1f..57156ba3 100644 --- a/src/mod_proxy.c +++ b/src/mod_proxy.c @@ -463,7 +463,7 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) { !buffer_is_empty(con->request.http_host)) { proxy_set_header(con, "X-Host", con->request.http_host->ptr); } - proxy_set_header(con, "X-Forwarded-Proto", con->conf.is_ssl ? "https" : "http"); + proxy_set_header(con, "X-Forwarded-Proto", con->uri.scheme->ptr); /* request header */ for (i = 0; i < con->request.headers->used; i++) { diff --git a/src/mod_scgi.c b/src/mod_scgi.c index 6ae07824..5bfec5c9 100644 --- a/src/mod_scgi.c +++ b/src/mod_scgi.c @@ -1614,7 +1614,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)); #ifdef USE_OPENSSL - if (srv_sock->is_ssl) { + if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) { scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")); } #endif diff --git a/src/network.c b/src/network.c index fb710d89..8b0e8b44 100644 --- a/src/network.c +++ b/src/network.c @@ -391,7 +391,7 @@ static int network_server_init(server *srv, buffer *host_token, specific_config goto error_free_socket; } - if (s->is_ssl) { + if (s->ssl_enabled) { #ifdef USE_OPENSSL if (NULL == (srv_socket->ssl_ctx = s->ssl_ctx)) { log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set"); @@ -425,7 +425,7 @@ static int network_server_init(server *srv, buffer *host_token, specific_config #endif } - srv_socket->is_ssl = s->is_ssl; + srv_socket->is_ssl = s->ssl_enabled; if (srv->srv_sockets.size == 0) { srv->srv_sockets.size = 4; diff --git a/src/response.c b/src/response.c index fd1ab195..efb09373 100644 --- a/src/response.c +++ b/src/response.c @@ -264,7 +264,8 @@ handler_t http_response_prepare(server *srv, connection *con) { * */ - if (con->conf.is_ssl) { + /* initial scheme value. can be overwritten for example by mod_extforward later */ + if (con->srv_socket->is_ssl) { buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https")); } else { buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http")); @@ -351,7 +352,7 @@ handler_t http_response_prepare(server *srv, connection *con) { } #ifdef USE_OPENSSL - if (con->conf.is_ssl && con->conf.ssl_verifyclient) { + if (con->srv_socket->is_ssl && con->conf.ssl_verifyclient) { https_add_ssl_entries(con); } #endif