summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mod_proxy.c44
1 files changed, 42 insertions, 2 deletions
diff --git a/src/mod_proxy.c b/src/mod_proxy.c
index c3179b36..8821e981 100644
--- a/src/mod_proxy.c
+++ b/src/mod_proxy.c
@@ -45,6 +45,7 @@ typedef struct http_header_remap_opts {
const array *hosts_request;
const array *hosts_response;
int https_remap;
+ int upgrade;
/*(not used in plugin_config, but used in handler_ctx)*/
const buffer *http_host;
const buffer *forwarded_host;
@@ -314,6 +315,17 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
&& !buffer_is_equal_string(ds->value, CONST_STR_LEN("0"));
continue;
}
+ else if (buffer_is_equal_string(da->key, CONST_STR_LEN("upgrade"))) {
+ data_string *ds = (data_string *)da;
+ if (ds->type != TYPE_STRING) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected value for proxy.header; expected \"upgrade\" => \"enable\" or \"disable\"");
+ return HANDLER_ERROR;
+ }
+ s->header.upgrade = !buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))
+ && !buffer_is_equal_string(ds->value, CONST_STR_LEN("0"));
+ continue;
+ }
if (da->type != TYPE_ARRAY || !array_is_kvstring(da->value)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"unexpected value for proxy.header; expected ( \"param\" => ( \"key\" => \"value\" ) ) near key", da->key);
@@ -1173,6 +1185,8 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
buffer *b = buffer_init();
const int remap_headers = (NULL != hctx->remap_hdrs.urlpaths
|| NULL != hctx->remap_hdrs.hosts_request);
+ const int upgrade = hctx->remap_hdrs.upgrade
+ && (NULL != array_get_element(con->request.headers, "Upgrade"));
buffer_string_prepare_copy(b, 8192-1);
/* build header */
@@ -1183,7 +1197,10 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
buffer_append_string_buffer(b, con->request.uri);
if (remap_headers)
http_header_remap_uri(b, buffer_string_length(b) - buffer_string_length(con->request.uri), &hctx->remap_hdrs, 1);
- buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n"));
+ if (!upgrade)
+ buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n"));
+ else
+ buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.1\r\n"));
if (hctx->conf.replace_http_host && !buffer_string_is_empty(hctx->host->key)) {
if (hctx->conf.debug > 1) {
@@ -1287,7 +1304,10 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
http_header_remap_uri(b, buffer_string_length(b) - vlen - 2, &hctx->remap_hdrs, 1);
}
- buffer_append_string_len(b, CONST_STR_LEN("Connection: close\r\n\r\n"));
+ if (!upgrade)
+ buffer_append_string_len(b, CONST_STR_LEN("Connection: close\r\n\r\n"));
+ else
+ buffer_append_string_len(b, CONST_STR_LEN("Connection: close, upgrade\r\n\r\n"));
hctx->wb_reqlen = buffer_string_length(b);
chunkqueue_append_buffer(hctx->wb, b);
@@ -1597,6 +1617,25 @@ static handler_t proxy_response_read(server *srv, handler_ctx *hctx) {
/* response headers just completed */
+ if (con->parsed_response & HTTP_UPGRADE) {
+ if (hctx->remap_hdrs.upgrade && con->http_status == 101) {
+ /* 101 Switching Protocols; transition to transparent proxy */
+ hctx->wb_reqlen = -1;
+ proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
+ http_response_upgrade_read_body_unknown(srv, con);
+ }
+ else {
+ con->parsed_response &= ~HTTP_UPGRADE;
+ #if 0
+ /* preserve prior questionable behavior; likely broken behavior
+ * anyway if backend thinks connection is being upgraded but client
+ * does not receive Connection: upgrade */
+ response_header_overwrite(srv, con, CONST_STR_LEN("Upgrade"),
+ CONST_STR_LEN(""));
+ #endif
+ }
+ }
+
/* rewrite paths, if needed */
if (NULL == hctx->remap_hdrs.urlpaths
@@ -1766,6 +1805,7 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
hctx->remap_hdrs = p->conf.header; /*(copies struct)*/
hctx->remap_hdrs.http_host = con->request.http_host;
+ hctx->remap_hdrs.upgrade &= (con->request.http_version == HTTP_VERSION_1_1);
/* mod_proxy currently sends all backend requests as http.
* https-remap is a flag since it might not be needed if backend
* honors Forwarded or X-Forwarded-Proto headers, e.g. by using