2

I have an instance of lighttpd 1.4.35 listening for https traffic and reverse-proxying it to a back-end server. I.e.,

 .----------. .----------. client ---https--> | lighttpd | ---http--> | back-end | <--https--- | | <--http--- | server | `----------' `----------' 

When I do an HTTP post to a proxied page (over https), the back-end server is returning a Location header with http instead of https.

Location: http://lighttpd_url/some_page.htm 

Is there a way lighttpd can rewrite the URL in the location header? I see in lighttpd 1.5.x, proxy-core has a rewrite-response directive, and I guess this is what it would look like:

 proxy-core.rewrite-response = ( "Location" => ( "^http://xyz/(.*)" => "https://xyz/$1" ), ) 

But how do I rewrite the Location header in lighttpd 1.4.x?

3
  • Unfortunately, I don't think there's any way to do this without the rewrite-response option. Commented Jun 26, 2014 at 20:35
  • @ShaneMadden: Thanks, I think you're correct after looking at the source code. It appears mod_rewrite doesn't get a chance to change the headers in mod_proxy responses. Commented Jun 26, 2014 at 23:58
  • You could try to load mod_magnet before mod_proxy and use magnet.attract-raw-url-to to load a lua script which sets lighty.env["uri.scheme"] = "https", making mod_proxy send a X-Forwarded-Proto: https header, so the backend generates correct location headers. Commented Jun 27, 2014 at 15:02

1 Answer 1

2

As of 1.4.35, mod_proxy doesn't let you modify response headers. But I really needed the simple functionality of changing Location response headers from http to https, so I hacked it into mod_proxy.c.

Here is the patch in case it's useful to anyone else. After applying this patch and then rebuilding and installing from source, you can add proxy.force_https_location = 1 to your config file to enable the feature globally.

--- src/mod_proxy.c-orig 2014-06-26 14:33:50.000000000 -0700 +++ src/mod_proxy.c 2014-06-26 16:08:11.000000000 -0700 @@ -64,6 +64,7 @@ typedef struct { array *extensions; unsigned short debug; + unsigned short force_https_location; proxy_balance_t balance; } plugin_config; @@ -191,6 +192,7 @@ { "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "proxy.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ + { "proxy.force_https_location", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -203,10 +205,12 @@ s = malloc(sizeof(plugin_config)); s->extensions = array_init(); s->debug = 0; + s->force_https_location = 0; cv[0].destination = s->extensions; cv[1].destination = &(s->debug); cv[2].destination = p->balance_buf; + cv[3].destination = &(s->force_https_location); buffer_reset(p->balance_buf); @@ -568,10 +572,13 @@ int key_len; data_string *ds; int copy_header; + int is_location_header; ns[0] = '\0'; ns[1] = '\0'; + is_location_header = 0; + if (-1 == http_response_status) { /* The first line of a Response message is the Status-Line */ @@ -614,6 +621,7 @@ if (0 == strncasecmp(key, "Location", key_len)) { con->parsed_response |= HTTP_LOCATION; } + is_location_header = 1; break; case 10: if (0 == strncasecmp(key, "Connection", key_len)) { @@ -635,7 +643,26 @@ ds = data_response_init(); } buffer_copy_string_len(ds->key, key, key_len); - buffer_copy_string(ds->value, value); + + if (is_location_header && p->conf.force_https_location) { + const unsigned int http_prefix_len = 7; /* strlen("http://") */ + + if (0 == strncasecmp(value, "http://", http_prefix_len)) { + buffer_copy_string(ds->value, "https://"); + buffer_append_string(ds->value, value + http_prefix_len); + + if (p->conf.debug) { + log_error_write(srv, __FILE__, __LINE__, "sb", "forced Location to https: ", ds->value); + } + } + else { + buffer_copy_string(ds->value, value); + } + } + else + { + buffer_copy_string(ds->value, value); + } array_insert_unique(con->response.headers, (data_unset *)ds); } @@ -873,6 +897,7 @@ PATCH(extensions); PATCH(debug); PATCH(balance); + PATCH(force_https_location); /* skip the first, the global context */ for (i = 1; i < srv->config_context->used; i++) { @@ -892,6 +917,8 @@ PATCH(debug); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) { PATCH(balance); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.force_https_location"))) { + PATCH(force_https_location); } } } 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.