Support Blocking Rewrite Flow
Run all responses through PSOL's rewriter in a blocking manner. While eventually we need to be using the asynchronous rewriting interface, this is a simple proof of concept. In test/expected/test.html you can see the effect of running this code on test/www/test/html
This commit is contained in:
@@ -60,11 +60,23 @@ parent.
|
||||
|
||||
## How to use
|
||||
|
||||
To your nginx.conf add to the main block or to a server or location block:
|
||||
In your nginx.conf, add to the main or server block:
|
||||
|
||||
pagespeed on;
|
||||
pagespeed_cache /path/to/cache/dir;
|
||||
|
||||
To confirm that the module is working, fetch a page and check that you see the
|
||||
To confirm that the module is loaded, fetch a page and check that you see the
|
||||
following comment in the source:
|
||||
|
||||
<!-- Processed through ngx_pagespeed using PSOL version 0.10.0.0 -->
|
||||
|
||||
### Testing
|
||||
|
||||
There is an example html file in:
|
||||
|
||||
test/www/test.html
|
||||
|
||||
If you fetch it through nginx with ngx_pagespeed enabled you should see it
|
||||
rewritten to look like the html in:
|
||||
|
||||
test/expected/test.html
|
||||
|
||||
@@ -25,6 +25,7 @@ ngx_feature_incs="
|
||||
"
|
||||
pagespeed_include="$mod_pagespeed_dir
|
||||
$mod_pagespeed_dir/third_party/chromium/src/
|
||||
$mod_pagespeed_dir/third_party/protobuf/src/
|
||||
$mod_pagespeed_dir/out/Release/obj/gen/"
|
||||
ngx_feature_path="$pagespeed_include"
|
||||
pagespeed_automatic_dir="$mod_pagespeed_dir/net/instaweb/automatic"
|
||||
@@ -52,8 +53,10 @@ ngx_feature_test="
|
||||
. "$ngx_addon_dir/cpp_feature"
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
ps_src="$ngx_addon_dir/src"
|
||||
ngx_addon_name=ngx_pagespeed
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_pagespeed.cc"
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ps_src/ngx_pagespeed.cc"
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ps_src/ngx_rewrite_driver_factory.cc"
|
||||
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
|
||||
CORE_LIBS="$CORE_LIBS $pagespeed_libs"
|
||||
CORE_INCS="$CORE_INCS $pagespeed_include"
|
||||
|
||||
+240
-100
@@ -27,8 +27,10 @@ extern "C" {
|
||||
#include <ngx_http.h>
|
||||
}
|
||||
|
||||
#include "net/instaweb/htmlparse/public/html_parse.h"
|
||||
#include "net/instaweb/htmlparse/public/html_writer_filter.h"
|
||||
#include "ngx_rewrite_driver_factory.h"
|
||||
|
||||
#include "net/instaweb/rewriter/public/process_context.h"
|
||||
#include "net/instaweb/rewriter/public/rewrite_driver.h"
|
||||
#include "net/instaweb/public/version.h"
|
||||
#include "net/instaweb/util/public/string.h"
|
||||
#include "net/instaweb/util/public/string_writer.h"
|
||||
@@ -36,44 +38,73 @@ extern "C" {
|
||||
|
||||
extern ngx_module_t ngx_pagespeed;
|
||||
|
||||
// Hacks for debugging.
|
||||
#define DBG(r, args...) \
|
||||
ngx_log_error(NGX_LOG_ALERT, (r)->connection->log, 0, args)
|
||||
#define CDBG(cf, args...) \
|
||||
ngx_conf_log_error(NGX_LOG_ALERT, cf, 0, args)
|
||||
|
||||
typedef struct {
|
||||
ngx_flag_t active;
|
||||
} ngx_http_pagespeed_loc_conf_t;
|
||||
ngx_str_t cache_dir;
|
||||
net_instaweb::NgxRewriteDriverFactory* driver_factory;
|
||||
net_instaweb::ServerContext* server_context;
|
||||
} ngx_http_pagespeed_srv_conf_t;
|
||||
|
||||
typedef struct {
|
||||
net_instaweb::RewriteDriver* driver;
|
||||
scoped_ptr<GoogleString> output;
|
||||
scoped_ptr<net_instaweb::StringWriter> writer;
|
||||
} ngx_http_pagespeed_request_ctx_t;
|
||||
|
||||
static ngx_command_t ngx_http_pagespeed_commands[] = {
|
||||
{ ngx_string("pagespeed"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_flag_slot,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_pagespeed_loc_conf_t, active),
|
||||
NGX_HTTP_SRV_CONF_OFFSET,
|
||||
offsetof(ngx_http_pagespeed_srv_conf_t, active),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("pagespeed_cache"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_str_slot,
|
||||
NGX_HTTP_SRV_CONF_OFFSET,
|
||||
offsetof(ngx_http_pagespeed_srv_conf_t, cache_dir),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
static void*
|
||||
ngx_http_pagespeed_create_loc_conf(ngx_conf_t* cf)
|
||||
ngx_http_pagespeed_create_srv_conf(ngx_conf_t* cf)
|
||||
{
|
||||
ngx_http_pagespeed_loc_conf_t* conf;
|
||||
ngx_http_pagespeed_srv_conf_t* conf;
|
||||
|
||||
conf = static_cast<ngx_http_pagespeed_loc_conf_t*>(
|
||||
ngx_pcalloc(cf->pool, sizeof(ngx_http_pagespeed_loc_conf_t)));
|
||||
conf = static_cast<ngx_http_pagespeed_srv_conf_t*>(
|
||||
ngx_pcalloc(cf->pool, sizeof(ngx_http_pagespeed_srv_conf_t)));
|
||||
if (conf == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
conf->active = NGX_CONF_UNSET;
|
||||
|
||||
// set by ngx_pcalloc():
|
||||
// conf->cache_dir = { 0, NULL };
|
||||
// conf->driver_factory = NULL;
|
||||
// conf->server_context = NULL;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
static char*
|
||||
ngx_http_pagespeed_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child)
|
||||
ngx_http_pagespeed_merge_srv_conf(ngx_conf_t* cf, void* parent, void* child)
|
||||
{
|
||||
ngx_http_pagespeed_loc_conf_t* prev =
|
||||
static_cast<ngx_http_pagespeed_loc_conf_t*>(parent);
|
||||
ngx_http_pagespeed_loc_conf_t* conf =
|
||||
static_cast<ngx_http_pagespeed_loc_conf_t*>(child);
|
||||
ngx_http_pagespeed_srv_conf_t* prev =
|
||||
static_cast<ngx_http_pagespeed_srv_conf_t*>(parent);
|
||||
ngx_http_pagespeed_srv_conf_t* conf =
|
||||
static_cast<ngx_http_pagespeed_srv_conf_t*>(child);
|
||||
|
||||
ngx_conf_merge_value(conf->active, prev->active, 0); // Default off.
|
||||
ngx_conf_merge_str_value(conf->cache_dir, prev->cache_dir, "");
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
@@ -81,20 +112,10 @@ ngx_http_pagespeed_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child)
|
||||
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
|
||||
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
|
||||
|
||||
static
|
||||
ngx_int_t ngx_http_pagespeed_header_filter(ngx_http_request_t* r)
|
||||
{
|
||||
// We're modifying content below, so switch to 'Transfer-Encoding: chunked'
|
||||
// and calculate on the fly.
|
||||
ngx_http_clear_content_length(r);
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
// Add a buffer to the end of the buffer chain indicating that we were processed
|
||||
// through ngx_pagespeed.
|
||||
static
|
||||
ngx_int_t ngx_http_pagespeed_note_processed(ngx_http_request_t* r,
|
||||
ngx_chain_t* in) {
|
||||
static ngx_int_t
|
||||
ngx_http_pagespeed_note_processed(ngx_http_request_t* r, ngx_chain_t* in) {
|
||||
// Find the end of the buffer chain.
|
||||
ngx_chain_t* chain_link;
|
||||
int chain_contains_last_buffer = 0;
|
||||
@@ -154,59 +175,143 @@ ngx_int_t ngx_http_pagespeed_note_processed(ngx_http_request_t* r,
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
// Replace each buffer with a new one that's been through HtmlParse.
|
||||
static
|
||||
ngx_int_t ngx_http_pagespeed_parse_and_replace_buffer(ngx_http_request_t* r,
|
||||
ngx_chain_t* in) {
|
||||
GoogleString output_buffer;
|
||||
net_instaweb::StringWriter write_to_string(&output_buffer);
|
||||
static void
|
||||
ngx_http_pagespeed_release_request_context(
|
||||
ngx_http_request_t* r, ngx_http_pagespeed_request_ctx_t* ctx) {
|
||||
|
||||
// release request context
|
||||
ngx_http_set_ctx(r, NULL, ngx_pagespeed);
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
|
||||
// Get the context for this request. ngx_http_pagespeed_create_request_context
|
||||
// should already have been called to create it.
|
||||
static ngx_http_pagespeed_request_ctx_t*
|
||||
ngx_http_pagespeed_get_request_context(ngx_http_request_t* r) {
|
||||
return static_cast<ngx_http_pagespeed_request_ctx_t*>(
|
||||
ngx_http_get_module_ctx(r, ngx_pagespeed));
|
||||
}
|
||||
|
||||
// Initialize the ngx_http_pagespeed_srv_conf_t by allocating and configuring
|
||||
// the long-lived objects it contains.
|
||||
// TODO(jefftk): This shouldn't be done on the first request but instead
|
||||
// when we're done processing the configuration.
|
||||
static void
|
||||
ngx_http_pagespeed_initialize_server_context(
|
||||
ngx_http_pagespeed_srv_conf_t* cfg) {
|
||||
net_instaweb::NgxRewriteDriverFactory::Initialize();
|
||||
// TODO(jefftk): We should call NgxRewriteDriverFactory::Terminate() when
|
||||
// we're done with it.
|
||||
|
||||
cfg->driver_factory = new net_instaweb::NgxRewriteDriverFactory();
|
||||
cfg->driver_factory->set_filename_prefix(StringPiece(
|
||||
reinterpret_cast<char*>(cfg->cache_dir.data), cfg->cache_dir.len));
|
||||
cfg->server_context = cfg->driver_factory->CreateServerContext();
|
||||
|
||||
// In real use, with filters coming from the user, this would be some other
|
||||
// kind of message handler that actually sent errors back to the user.
|
||||
net_instaweb::NullMessageHandler handler;
|
||||
|
||||
net_instaweb::HtmlParse html_parse(&handler);
|
||||
net_instaweb::HtmlWriterFilter html_writer_filter(&html_parse);
|
||||
// Turn on some filters so we can see if this is working. These filters are
|
||||
// specifically chosen as ones that don't make requests for subresources or do
|
||||
// work that needs to complete asynchronously. They should be fast enough to
|
||||
// run in the line of the request.
|
||||
net_instaweb::RewriteOptions* global_options =
|
||||
cfg->server_context->global_options();
|
||||
global_options->SetRewriteLevel(net_instaweb::RewriteOptions::kPassThrough);
|
||||
global_options->EnableFiltersByCommaSeparatedList(
|
||||
"collapse_whitespace,remove_comments,remove_quotes", &handler);
|
||||
}
|
||||
|
||||
html_writer_filter.set_writer(&write_to_string);
|
||||
html_parse.AddFilter(&html_writer_filter);
|
||||
|
||||
u_char* file_contents = NULL;
|
||||
StringPiece buffer_contents;
|
||||
// Set us up for processing a request. When the request finishes, call
|
||||
// ngx_http_pagespeed_release_request_context.
|
||||
static ngx_int_t
|
||||
ngx_http_pagespeed_create_request_context(ngx_http_request_t* r) {
|
||||
ngx_http_pagespeed_srv_conf_t* cfg =
|
||||
static_cast<ngx_http_pagespeed_srv_conf_t*>(
|
||||
ngx_http_get_module_srv_conf(r, ngx_pagespeed));
|
||||
|
||||
if (cfg->driver_factory == NULL) {
|
||||
// This is the first request handled by this server block.
|
||||
ngx_http_pagespeed_initialize_server_context(cfg);
|
||||
}
|
||||
|
||||
// Pull the server context out of the per-server config.
|
||||
net_instaweb::ServerContext* server_context =
|
||||
static_cast<ngx_http_pagespeed_srv_conf_t*>(
|
||||
ngx_http_get_module_srv_conf(r, ngx_pagespeed))->server_context;
|
||||
|
||||
if (server_context == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0,
|
||||
"ServerContext should have been initialized.");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
// TODO(jefftk): figure out how to get the real url out of r.
|
||||
StringPiece url("http://localhost");
|
||||
|
||||
ngx_http_pagespeed_request_ctx_t* ctx =
|
||||
new ngx_http_pagespeed_request_ctx_t();
|
||||
|
||||
ctx->driver = server_context->NewRewriteDriver();
|
||||
|
||||
// TODO(jefftk): replace this with a writer that generates proper nginx
|
||||
// buffers and puts them in the chain. Or avoids the double
|
||||
// copy some other way.
|
||||
ctx->output.reset(new GoogleString());
|
||||
ctx->writer.reset(new net_instaweb::StringWriter(ctx->output.get()));
|
||||
ctx->driver->SetWriter(ctx->writer.get());
|
||||
|
||||
// For testing we always want to perform any optimizations we can, so we
|
||||
// wait until everything is done rather than using a deadline, the way we
|
||||
// want to eventually.
|
||||
ctx->driver->set_fully_rewrite_on_flush(true);
|
||||
|
||||
ngx_http_set_ctx(r, ctx, ngx_pagespeed);
|
||||
bool ok = ctx->driver->StartParse(url);
|
||||
if (!ok) {
|
||||
ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0,
|
||||
"Failed to StartParse on url %*s",
|
||||
url.size(), url.data());
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
// Replace each buffer chain with a new one that's been optimized.
|
||||
static ngx_int_t
|
||||
ngx_http_pagespeed_optimize_and_replace_buffer(ngx_http_request_t* r,
|
||||
ngx_chain_t* in) {
|
||||
ngx_http_pagespeed_request_ctx_t* ctx =
|
||||
ngx_http_pagespeed_get_request_context(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_chain_t* cur;
|
||||
for (cur = in; cur != NULL; cur = cur->next) {
|
||||
html_parse.StartParse("http://example.com");
|
||||
int last_buf = 0;
|
||||
int last_in_chain = 0;
|
||||
for (cur = in; cur != NULL;) {
|
||||
last_buf = cur->buf->last_buf;
|
||||
last_in_chain = cur->buf->last_in_chain;
|
||||
|
||||
if (cur->buf->file != NULL) {
|
||||
ssize_t file_size = cur->buf->file_last - cur->buf->file_pos;
|
||||
// TODO(jefftk): if file_size is big enough can we still read it all at
|
||||
// once?
|
||||
file_contents = static_cast<u_char*>(ngx_pnalloc(r->pool, file_size));
|
||||
if (file_contents == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0,
|
||||
"failed to allocate %d bytes", file_size);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
ssize_t n = ngx_read_file(cur->buf->file, file_contents, file_size,
|
||||
cur->buf->file_pos);
|
||||
if (n != file_size) {
|
||||
ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0,
|
||||
"Failed to read file; got %d bytes expected %d bytes",
|
||||
n, file_size);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
buffer_contents = StringPiece(reinterpret_cast<char*>(file_contents),
|
||||
file_size);
|
||||
} else {
|
||||
buffer_contents = StringPiece(reinterpret_cast<char*>(cur->buf->pos),
|
||||
cur->buf->last - cur->buf->pos);
|
||||
}
|
||||
html_parse.ParseText(buffer_contents);
|
||||
if (file_contents != NULL) {
|
||||
// TODO(jefftk): this pfree call fails with NGX_DECLINED, but I think
|
||||
// that's just NGINX only bothering to free large allocs.
|
||||
ngx_pfree(r->pool, file_contents);
|
||||
file_contents = NULL;
|
||||
}
|
||||
ctx->driver->ParseText(StringPiece(reinterpret_cast<char*>(cur->buf->pos),
|
||||
cur->buf->last - cur->buf->pos));
|
||||
|
||||
html_parse.FinishParse();
|
||||
// We're done with buffers as we pass them to the rewrite driver, so free
|
||||
// them and their chain links as we go. Don't free the first buffer (in)
|
||||
// which we need below.
|
||||
ngx_chain_t* next_link = cur->next;
|
||||
if (cur != in) {
|
||||
ngx_pfree(r->pool, cur->buf);
|
||||
ngx_pfree(r->pool, cur);
|
||||
}
|
||||
cur = next_link;
|
||||
}
|
||||
in->next = NULL; // We freed all the later buffers.
|
||||
|
||||
// Prepare the new buffer.
|
||||
ngx_buf_t* b = static_cast<ngx_buf_t*>(ngx_calloc_buf(r->pool));
|
||||
@@ -216,33 +321,48 @@ ngx_int_t ngx_http_pagespeed_parse_and_replace_buffer(ngx_http_request_t* r,
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
b->temporary = 1;
|
||||
b->last_buf = last_buf;
|
||||
b->last_in_chain = last_in_chain;
|
||||
in->next = NULL;
|
||||
|
||||
// replace the first link's buffer with our new one.
|
||||
ngx_pfree(r->pool, in->buf);
|
||||
in->buf = b;
|
||||
|
||||
if (last_buf) {
|
||||
ctx->driver->FinishParse();
|
||||
} else {
|
||||
ctx->driver->Flush();
|
||||
}
|
||||
|
||||
// TODO(jefftk): need to store how much went out on previous flushes and only
|
||||
// copy here the new stuff. Keep the count in the request context.
|
||||
b->pos = b->start = static_cast<u_char*>(
|
||||
ngx_pnalloc(r->pool, output_buffer.length()));
|
||||
ngx_pnalloc(r->pool, ctx->output->length()));
|
||||
if (b->pos == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0,
|
||||
"failed to allocate %d bytes", output_buffer.length());
|
||||
"failed to allocate %d bytes", ctx->output->length());
|
||||
return NGX_ERROR;
|
||||
}
|
||||
output_buffer.copy(reinterpret_cast<char*>(b->pos), output_buffer.length());
|
||||
b->last = b->end = b->pos + output_buffer.length();
|
||||
b->temporary = 1;
|
||||
b->last_buf = cur->buf->last_buf;
|
||||
b->last_in_chain = cur->buf->last_in_chain;
|
||||
ctx->output->copy(reinterpret_cast<char*>(b->pos), ctx->output->length());
|
||||
b->last = b->end = b->pos + ctx->output->length();
|
||||
|
||||
ngx_pfree(r->pool, cur->buf);
|
||||
cur->buf = b;
|
||||
|
||||
output_buffer.clear();
|
||||
if (last_buf) {
|
||||
ngx_http_pagespeed_release_request_context(r, ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
static
|
||||
ngx_int_t ngx_http_pagespeed_body_filter(ngx_http_request_t* r, ngx_chain_t* in)
|
||||
static ngx_int_t
|
||||
ngx_http_pagespeed_body_filter(ngx_http_request_t* r, ngx_chain_t* in)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
rc = ngx_http_pagespeed_parse_and_replace_buffer(r, in);
|
||||
rc = ngx_http_pagespeed_optimize_and_replace_buffer(r, in);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
@@ -255,12 +375,29 @@ ngx_int_t ngx_http_pagespeed_body_filter(ngx_http_request_t* r, ngx_chain_t* in)
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_pagespeed_header_filter(ngx_http_request_t* r)
|
||||
{
|
||||
// We're modifying content below, so switch to 'Transfer-Encoding: chunked'
|
||||
// and calculate on the fly.
|
||||
ngx_http_clear_content_length(r);
|
||||
|
||||
r->filter_need_in_memory = 1;
|
||||
|
||||
int rc = ngx_http_pagespeed_create_request_context(r);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_pagespeed_init(ngx_conf_t* cf)
|
||||
{
|
||||
ngx_http_pagespeed_loc_conf_t* pagespeed_config;
|
||||
pagespeed_config = static_cast<ngx_http_pagespeed_loc_conf_t*>(
|
||||
ngx_http_conf_get_module_loc_conf(cf, ngx_pagespeed));
|
||||
ngx_http_pagespeed_srv_conf_t* pagespeed_config;
|
||||
pagespeed_config = static_cast<ngx_http_pagespeed_srv_conf_t*>(
|
||||
ngx_http_conf_get_module_srv_conf(cf, ngx_pagespeed));
|
||||
|
||||
if (pagespeed_config->active) {
|
||||
ngx_http_next_header_filter = ngx_http_top_header_filter;
|
||||
@@ -273,20 +410,23 @@ ngx_http_pagespeed_init(ngx_conf_t* cf)
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
static ngx_http_module_t ngx_http_pagespeed_module_ctx = {
|
||||
NULL,
|
||||
ngx_http_pagespeed_init, // Post configuration.
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
ngx_http_pagespeed_create_loc_conf,
|
||||
ngx_http_pagespeed_merge_loc_conf
|
||||
static ngx_http_module_t ngx_http_pagespeed_module = {
|
||||
NULL, // preconfiguration
|
||||
ngx_http_pagespeed_init, // postconfiguration
|
||||
|
||||
NULL, // create main configuration
|
||||
NULL, // init main configuration
|
||||
|
||||
ngx_http_pagespeed_create_srv_conf, // create server configuration
|
||||
ngx_http_pagespeed_merge_srv_conf, // merge server configuration
|
||||
|
||||
NULL, // create location configuration
|
||||
NULL // merge location configuration
|
||||
};
|
||||
|
||||
ngx_module_t ngx_pagespeed = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_http_pagespeed_module_ctx,
|
||||
&ngx_http_pagespeed_module,
|
||||
ngx_http_pagespeed_commands,
|
||||
NGX_HTTP_MODULE,
|
||||
NULL,
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Author: jefftk@google.com (Jeff Kaufman)
|
||||
|
||||
#include "ngx_rewrite_driver_factory.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "net/instaweb/http/public/content_type.h"
|
||||
#include "net/instaweb/http/public/fake_url_async_fetcher.h"
|
||||
#include "net/instaweb/http/public/http_cache.h"
|
||||
#include "net/instaweb/http/public/wget_url_fetcher.h"
|
||||
#include "net/instaweb/rewriter/public/server_context.h"
|
||||
#include "net/instaweb/rewriter/public/rewrite_driver.h"
|
||||
#include "net/instaweb/rewriter/public/rewrite_driver_factory.h"
|
||||
#include "net/instaweb/rewriter/public/rewrite_gflags.h"
|
||||
#include "net/instaweb/util/public/google_message_handler.h"
|
||||
#include "net/instaweb/util/public/google_timer.h"
|
||||
#include "net/instaweb/util/public/lru_cache.h"
|
||||
#include "net/instaweb/util/public/md5_hasher.h"
|
||||
#include "net/instaweb/util/public/stdio_file_system.h"
|
||||
#include "net/instaweb/util/public/simple_stats.h"
|
||||
#include "net/instaweb/util/public/string.h"
|
||||
#include "net/instaweb/util/public/string_util.h"
|
||||
#include "net/instaweb/util/public/thread_system.h"
|
||||
#include "net/instaweb/util/public/threadsafe_cache.h"
|
||||
|
||||
namespace net_instaweb {
|
||||
|
||||
class CacheInterface;
|
||||
class FileSystem;
|
||||
class Hasher;
|
||||
class MessageHandler;
|
||||
class Statistics;
|
||||
class Timer;
|
||||
class UrlAsyncFetcher;
|
||||
class UrlFetcher;
|
||||
class Writer;
|
||||
|
||||
NgxRewriteDriverFactory::NgxRewriteDriverFactory() {
|
||||
RewriteDriverFactory::InitStats(&simple_stats_);
|
||||
SetStatistics(&simple_stats_);
|
||||
}
|
||||
|
||||
NgxRewriteDriverFactory::~NgxRewriteDriverFactory() {
|
||||
}
|
||||
|
||||
Hasher* NgxRewriteDriverFactory::NewHasher() {
|
||||
return new MD5Hasher;
|
||||
}
|
||||
|
||||
UrlFetcher* NgxRewriteDriverFactory::DefaultUrlFetcher() {
|
||||
return new WgetUrlFetcher;
|
||||
}
|
||||
|
||||
UrlAsyncFetcher* NgxRewriteDriverFactory::DefaultAsyncUrlFetcher() {
|
||||
return new FakeUrlAsyncFetcher(ComputeUrlFetcher());
|
||||
}
|
||||
|
||||
MessageHandler* NgxRewriteDriverFactory::DefaultHtmlParseMessageHandler() {
|
||||
return new GoogleMessageHandler;
|
||||
}
|
||||
|
||||
MessageHandler* NgxRewriteDriverFactory::DefaultMessageHandler() {
|
||||
return DefaultHtmlParseMessageHandler();
|
||||
}
|
||||
|
||||
FileSystem* NgxRewriteDriverFactory::DefaultFileSystem() {
|
||||
return new StdioFileSystem;
|
||||
}
|
||||
|
||||
Timer* NgxRewriteDriverFactory::DefaultTimer() {
|
||||
return new GoogleTimer;
|
||||
}
|
||||
|
||||
void NgxRewriteDriverFactory::SetupCaches(ServerContext* resource_manager) {
|
||||
LRUCache* lru_cache = new LRUCache(gflags_.lru_cache_size_bytes());
|
||||
CacheInterface* cache = new ThreadsafeCache(
|
||||
lru_cache, thread_system()->NewMutex());
|
||||
HTTPCache* http_cache = new HTTPCache(cache, timer(), hasher(), statistics());
|
||||
resource_manager->set_http_cache(http_cache);
|
||||
resource_manager->set_metadata_cache(cache);
|
||||
resource_manager->MakePropertyCaches(cache);
|
||||
}
|
||||
|
||||
Statistics* NgxRewriteDriverFactory::statistics() {
|
||||
return &simple_stats_;
|
||||
}
|
||||
|
||||
} // namespace net_instaweb
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Author: jefftk@google.com (Jeff Kaufman)
|
||||
|
||||
#ifndef NGX_REWRITE_DRIVER_FACTORY_H_
|
||||
#define NGX_REWRITE_DRIVER_FACTORY_H_
|
||||
|
||||
#include "net/instaweb/rewriter/public/rewrite_driver_factory.h"
|
||||
#include "net/instaweb/rewriter/public/rewrite_gflags.h"
|
||||
#include "net/instaweb/util/public/simple_stats.h"
|
||||
|
||||
namespace net_instaweb {
|
||||
|
||||
class NgxRewriteDriverFactory : public RewriteDriverFactory {
|
||||
public:
|
||||
NgxRewriteDriverFactory();
|
||||
virtual ~NgxRewriteDriverFactory();
|
||||
virtual Hasher* NewHasher();
|
||||
virtual UrlFetcher* DefaultUrlFetcher();
|
||||
virtual UrlAsyncFetcher* DefaultAsyncUrlFetcher();
|
||||
virtual MessageHandler* DefaultHtmlParseMessageHandler();
|
||||
virtual MessageHandler* DefaultMessageHandler();
|
||||
virtual FileSystem* DefaultFileSystem();
|
||||
virtual Timer* DefaultTimer();
|
||||
virtual void SetupCaches(ServerContext* resource_manager);
|
||||
virtual Statistics* statistics();
|
||||
|
||||
private:
|
||||
SimpleStats simple_stats_;
|
||||
const RewriteGflags gflags_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NgxRewriteDriverFactory);
|
||||
};
|
||||
|
||||
} // namespace net_instaweb
|
||||
|
||||
#endif // NGX_REWRITE_DRIVER_FACTORY_H_
|
||||
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel=stylesheet href=style.css>
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Example Html Page</h1>
|
||||
<script src=script.js></script>
|
||||
<script> alert("an alert"); </script>
|
||||
<p>
|
||||
This is an example.
|
||||
<b>bold text</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
<!-- Processed through ngx_pagespeed using PSOL version 0.10.0.0 -->
|
||||
@@ -0,0 +1,23 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Example Html Page</h1>
|
||||
<script src="script.js"></script>
|
||||
<script> alert("an alert"); </script>
|
||||
<p>
|
||||
This is an example.
|
||||
|
||||
|
||||
<!-- a comment -->
|
||||
|
||||
<!-- another comment -->
|
||||
|
||||
<b>bold text</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user