Merge pull request #208 from pagespeed/jefftk-respect-x-forwarded-proto

request-headers: support X-Forwarded-Proto
This commit is contained in:
Jeff Kaufman
2013-04-03 07:26:28 -07:00
3 changed files with 86 additions and 0 deletions
+71
View File
@@ -1158,6 +1158,65 @@ bool ps_determine_options(ngx_http_request_t* r,
return true;
}
// Fix URL based on X-Forwarded-Proto.
// http://code.google.com/p/modpagespeed/issues/detail?id=546 For example, if
// Apache gives us the URL "http://www.example.com/" and there is a header:
// "X-Forwarded-Proto: https", then we update this base URL to
// "https://www.example.com/". This only ever changes the protocol of the url.
//
// Returns true if it modified url, false otherwise.
bool ps_apply_x_forwarded_proto(ngx_http_request_t* r, GoogleString* url) {
// First check for an X-Forwarded-Proto header.
const ngx_str_t* x_forwarded_proto_header = NULL;
// Standard nginx idiom for iterating over a list. See ngx_list.h
ngx_uint_t i;
ngx_list_part_t* part = &(r->headers_in.headers.part);
ngx_table_elt_t* header = static_cast<ngx_table_elt_t*>(part->elts);
for (i = 0 ; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = static_cast<ngx_table_elt_t*>(part->elts);
i = 0;
}
if (STR_CASE_EQ_LITERAL(header[i].key, "X-Forwarded-Proto")) {
x_forwarded_proto_header = &header[i].value;
break;
}
}
if (x_forwarded_proto_header == NULL) {
return false; // No X-Forwarded-Proto header found.
}
StringPiece x_forwarded_proto
= str_to_string_piece(*x_forwarded_proto_header);
if (!STR_CASE_EQ_LITERAL(*x_forwarded_proto_header, "http") &&
!STR_CASE_EQ_LITERAL(*x_forwarded_proto_header, "https")) {
LOG(WARNING) << "Unsupported X-Forwarded-Proto: " << x_forwarded_proto
<< " for URL " << url << " protocol not changed.";
return false;
}
StringPiece url_sp(*url);
StringPiece::size_type colon_pos = url_sp.find(":");
if (colon_pos == StringPiece::npos) {
return false; // URL appears to have no protocol; give up.
}
// Replace URL protocol with that specified in X-Forwarded-Proto.
*url = net_instaweb::StrCat(x_forwarded_proto, url_sp.substr(colon_pos));
return true;
}
// Set us up for processing a request.
CreateRequestContext::Response ps_create_request_context(
@@ -1278,6 +1337,16 @@ CreateRequestContext::Response ps_create_request_context(
return CreateRequestContext::kPagespeedDisabled;
}
if (options->respect_x_forwarded_proto()) {
bool modified_url = ps_apply_x_forwarded_proto(r, &url_string);
if (modified_url) {
url.Reset(url_string);
CHECK(url.is_valid()) << "The output of ps_apply_x_forwarded_proto should"
<< " always be a valid url because it only changes"
<< " the scheme between http and https.";
}
}
// TODO(jefftk): port ProxyInterface::InitiatePropertyCacheLookup so that we
// have the propery cache in nginx.
@@ -1311,6 +1380,8 @@ CreateRequestContext::Response ps_create_request_context(
NULL /* original_content_fetch */);
}
// Set up a cleanup handler on the request.
ngx_http_cleanup_t* cleanup = ngx_http_cleanup_add(r, 0);
if (cleanup == NULL) {
+8
View File
@@ -183,4 +183,12 @@ check_from "$JS_HEADERS" fgrep -qi 'Vary: Accept-Encoding'
check_from "$JS_HEADERS" egrep -qi '(Etag: W/"0")|(Etag: W/"0-gzip")'
check_from "$JS_HEADERS" fgrep -qi 'Last-Modified:'
start_test Respect X-Forwarded-Proto when told to
FETCHED=$OUTDIR/x_forwarded_proto
URL=$SECONDARY_HOSTNAME/mod_pagespeed_example/?ModPagespeedFilters=add_base_tag
HEADERS="--header=X-Forwarded-Proto:https --header=Host:xfp.example.com"
check $WGET_DUMP -O $FETCHED $HEADERS $URL
# When enabled, we respect X-Forwarded-Proto and thus list base as https.
check fgrep -q '<base href="https://' $FETCHED
check_failures_and_exit
+7
View File
@@ -25,6 +25,13 @@ http {
server_name loopbackfetch.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
}
server {
listen @@SECONDARY_PORT@@;
server_name xfp.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
pagespeed RespectXForwardedProto on;
}
server {
listen @@PRIMARY_PORT@@;