merge pull request #22 Support Custom Options

off by default, either of these commands below would fetch the example file with the filter on:

     curl 'http://localhost:8050/mod_pagespeed_example/add_instrumentation.html?ModPagespeedFilters=add_instrumentation'
     curl --header 'ModPagespeedFilters:add_instrumentation' 'http://localhost:8050/mod_pagespeed_example/add_instrumentation.html'

Compared to just

     curl http://localhost:8050/mod_pagespeed_example/add_instrumentation.html

the difference is that there's a chunk of complicated javascript at the end
added by the filter.
This commit is contained in:
Jeff Kaufman
2012-11-07 11:14:33 -05:00
parent 850b9b291f
commit 4fda597427
3 changed files with 60 additions and 16 deletions
+26 -13
View File
@@ -27,19 +27,39 @@ namespace net_instaweb {
NgxBaseFetch::NgxBaseFetch(ngx_http_request_t* r, int pipe_fd) NgxBaseFetch::NgxBaseFetch(ngx_http_request_t* r, int pipe_fd)
: request_(r), done_called_(false), last_buf_sent_(false), : request_(r), done_called_(false), last_buf_sent_(false),
pipe_fd_(pipe_fd) { pipe_fd_(pipe_fd) {
PopulateRequestHeaders();
} }
NgxBaseFetch::~NgxBaseFetch() { } NgxBaseFetch::~NgxBaseFetch() { }
void NgxBaseFetch::PopulateHeaders() { void NgxBaseFetch::PopulateRequestHeaders() {
CopyHeadersFromTable<RequestHeaders>(&request_->headers_in.headers,
request_headers());
}
void NgxBaseFetch::PopulateResponseHeaders() {
CopyHeadersFromTable<ResponseHeaders>(&request_->headers_out.headers,
response_headers());
// Manually copy over the content type because it's not included in
// request_->headers_out.headers.
response_headers()->Add(
HttpAttributes::kContentType,
ngx_http_pagespeed_str_to_string_piece(
&request_->headers_out.content_type));
}
template<class HeadersT>
void NgxBaseFetch::CopyHeadersFromTable(ngx_list_t* headers_from,
HeadersT* headers_to) {
// http_version is the version number of protocol; 1.1 = 1001. See // http_version is the version number of protocol; 1.1 = 1001. See
// NGX_HTTP_VERSION_* in ngx_http_request.h // NGX_HTTP_VERSION_* in ngx_http_request.h
response_headers()->set_major_version(request_->http_version / 1000); headers_to->set_major_version(request_->http_version / 1000);
response_headers()->set_minor_version(request_->http_version % 1000); headers_to->set_minor_version(request_->http_version % 1000);
// Standard nginx idiom for iterating over a list. See ngx_list.h // Standard nginx idiom for iterating over a list. See ngx_list.h
ngx_uint_t i; ngx_uint_t i;
ngx_list_part_t* part = &request_->headers_out.headers.part; ngx_list_part_t* part = &headers_from->part;
ngx_table_elt_t* header = static_cast<ngx_table_elt_t*>(part->elts); ngx_table_elt_t* header = static_cast<ngx_table_elt_t*>(part->elts);
for (i = 0 ; /* void */; i++) { for (i = 0 ; /* void */; i++) {
@@ -57,15 +77,8 @@ void NgxBaseFetch::PopulateHeaders() {
StringPiece value = ngx_http_pagespeed_str_to_string_piece( StringPiece value = ngx_http_pagespeed_str_to_string_piece(
&header[i].value); &header[i].value);
response_headers()->Add(key, value); headers_to->Add(key, value);
} }
// For some reason content_type is not included in
// request_->headers_out.headers, which means I don't fully understand how
// headers_out works, but manually copying over content type works.
StringPiece content_type = ngx_http_pagespeed_str_to_string_piece(
&request_->headers_out.content_type);
response_headers()->Add(HttpAttributes::kContentType, content_type);
} }
bool NgxBaseFetch::HandleWrite(const StringPiece& sp, bool NgxBaseFetch::HandleWrite(const StringPiece& sp,
+10 -1
View File
@@ -37,6 +37,7 @@ extern "C" {
} }
#include "net/instaweb/http/public/async_fetch.h" #include "net/instaweb/http/public/async_fetch.h"
#include "net/instaweb/http/public/headers.h"
#include "net/instaweb/util/public/string.h" #include "net/instaweb/util/public/string.h"
namespace net_instaweb { namespace net_instaweb {
@@ -46,8 +47,11 @@ class NgxBaseFetch : public AsyncFetch {
NgxBaseFetch(ngx_http_request_t* r, int pipe_fd); NgxBaseFetch(ngx_http_request_t* r, int pipe_fd);
virtual ~NgxBaseFetch(); virtual ~NgxBaseFetch();
// Copies the request headers out of request_->headers_in->headers.
void PopulateRequestHeaders();
// Copies the response headers out of request_->headers_out->headers. // Copies the response headers out of request_->headers_out->headers.
void PopulateHeaders(); void PopulateResponseHeaders();
// Puts a chain in link_ptr if we have any output data buffered. Returns // Puts a chain in link_ptr if we have any output data buffered. Returns
// NGX_OK on success, NGX_ERROR on errors. If there's no data to send, sends // NGX_OK on success, NGX_ERROR on errors. If there's no data to send, sends
@@ -71,6 +75,11 @@ class NgxBaseFetch : public AsyncFetch {
virtual void HandleHeadersComplete(); virtual void HandleHeadersComplete();
virtual void HandleDone(bool success); virtual void HandleDone(bool success);
// Helper method for PopulateRequestHeaders and PopulateResponseHeaders.
template<class HeadersT>
void CopyHeadersFromTable(ngx_list_t* headers_from, HeadersT* headers_to);
// Indicate to nginx that we would like it to call // Indicate to nginx that we would like it to call
// CollectAccumulatedWrites(). // CollectAccumulatedWrites().
void RequestCollection(); void RequestCollection();
+24 -2
View File
@@ -590,13 +590,34 @@ ngx_http_pagespeed_create_request_context(ngx_http_request_t* r,
// on the proxy fetch below. // on the proxy fetch below.
ctx->base_fetch = new net_instaweb::NgxBaseFetch(r, file_descriptors[1]); ctx->base_fetch = new net_instaweb::NgxBaseFetch(r, file_descriptors[1]);
// Stripping ModPagespeed query params before the property cache lookup to
// make cache key consistent for both lookup and storing in cache.
//
// Sets option from request headers and url.
net_instaweb::ServerContext::OptionsBoolPair query_options_success =
ctx->cfg->server_context->GetQueryOptions(
&url, ctx->base_fetch->request_headers(), NULL);
bool get_query_options_success = query_options_success.second;
if (!get_query_options_success) {
// Failed to parse query params or request headers.
// TODO(jefftk): send a helpful error message to the visitor.
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"ngx_http_pagespeed_create_request_context: "
"parsing headers or query params failed.");
ngx_http_pagespeed_release_request_context(ctx);
return NGX_ERROR;
}
// Will be NULL if there aren't custom options..
net_instaweb::RewriteOptions* custom_options = query_options_success.first;
// This code is based off of ProxyInterface::ProxyRequestCallback and // This code is based off of ProxyInterface::ProxyRequestCallback and
// ProxyFetchFactory::StartNewProxyFetch // ProxyFetchFactory::StartNewProxyFetch
// If the global options say we're running furious (the experiment framework) // If the global options say we're running furious (the experiment framework)
// then clone them into custom_options so we can manipulate custom options // then clone them into custom_options so we can manipulate custom options
// without affecting the global options. // without affecting the global options.
net_instaweb::RewriteOptions* custom_options = NULL;
net_instaweb::RewriteOptions* global_options = net_instaweb::RewriteOptions* global_options =
ctx->cfg->server_context->global_options(); ctx->cfg->server_context->global_options();
if (global_options->running_furious()) { if (global_options->running_furious()) {
@@ -724,7 +745,8 @@ ngx_http_pagespeed_body_filter(ngx_http_request_t* r, ngx_chain_t* in) {
// Call this here and not in the header filter because we want to see the // Call this here and not in the header filter because we want to see the
// headers after any other filters are finished modifying them. At this // headers after any other filters are finished modifying them. At this
// point they are final. // point they are final.
ctx->base_fetch->PopulateHeaders(); // TODO(jefftk): is this thread safe? // TODO(jefftk): is this thread safe?
ctx->base_fetch->PopulateResponseHeaders();
} }
if (in != NULL) { if (in != NULL) {