Merged in changes from jefftk-experimental to:
- link in psol - manipulate the buffer chain to add a 'processed by us' comment - use chunked encoding to we don't have to update the headers when we change the length of the request - use c++ for the module
This commit is contained in:
@@ -6,12 +6,36 @@ This is the [nginx](http://nginx.org/) port of
|
||||
## How to build
|
||||
|
||||
nginx does not support dynamic loading of modules. You need to add
|
||||
ngx_pagespeed as a build time dependency.
|
||||
ngx_pagespeed as a build time dependency, and to do that you have to first build
|
||||
the pagespeed optimization library.
|
||||
|
||||
First build mod_pagespeed, following these instructions:
|
||||
http://code.google.com/p/modpagespeed/wiki/HowToBuild
|
||||
|
||||
Then move the mod_pagespeed directory to a parallel directory to your
|
||||
ngx_pagespeed checkout:
|
||||
|
||||
$ cd /path/to/ngx_pagespeed
|
||||
$ mv /where/you/built/mod_pagespeed /path/to/mod_pagespeed
|
||||
|
||||
Now build nginx:
|
||||
|
||||
$ cd /path/to/nginx
|
||||
$ auto/configure --add-module=/path/to/ngx_pagespeed
|
||||
$ make install
|
||||
|
||||
While ngx_pagespeed doesn't need to be anywhere specific in relation to nginx,
|
||||
the mod_pagespeed directory and the ngx_pagespeed directory must have the same
|
||||
parent.
|
||||
|
||||
## How to use
|
||||
|
||||
TODO
|
||||
To your nginx.conf add to the main block or to a server or location block:
|
||||
|
||||
pagespeed on;
|
||||
|
||||
Then fetch a page and note that it adds a comment:
|
||||
|
||||
<!-- Processed through ngx_pagespeed using PSOL version 0.10.0.0 -->
|
||||
|
||||
That's all it does so far.
|
||||
@@ -12,12 +12,33 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ngx_addon_name=ngx_pagespeed
|
||||
this_dir="$(dirname ${BASH_SOURCE[0]})"
|
||||
mod_pagespeed_dir="$this_dir/../mod_pagespeed/src/out/Release"
|
||||
ngx_feature="psol"
|
||||
ngx_feature_name=""
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include \"net/instaweb/public/version.h\""
|
||||
pagespeed_include="$mod_pagespeed_dir/obj/gen"
|
||||
ngx_feature_path="$pagespeed_include"
|
||||
pagespeed_lib_dir="$mod_pagespeed_dir/obj.target/net/instaweb/"
|
||||
pagespeed_libs="-linstaweb_automatic -L $pagespeed_lib_dir -lstdc++"
|
||||
ngx_feature_libs="$pagespeed_libs"
|
||||
ngx_feature_test="char c = MOD_PAGESPEED_VERSION_STRING[0]"
|
||||
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_pagespeed.c"
|
||||
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
|
||||
# Test whether we have pagespeed and can compile and link against it.
|
||||
. "$this_dir/cpp_feature"
|
||||
|
||||
# TODO link against libpagespeed / libpsol
|
||||
# CORE_LIBS="$CORE_LIBS -lpagespeed"
|
||||
if [ $ngx_found = yes ]; then
|
||||
ngx_addon_name=ngx_pagespeed
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_pagespeed.cc"
|
||||
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
|
||||
CORE_LIBS="$CORE_LIBS $pagespeed_libs"
|
||||
CORE_INCS="$CORE_INCS $pagespeed_include"
|
||||
else
|
||||
cat << END
|
||||
$0: error: module ngx_pagespeed requires the pagespeed optimization library
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
have=NGX_PAGESPEED . auto/have
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
# Copyright (C) Igor Sysoev
|
||||
# Copyright (C) Nginx, Inc.
|
||||
# 2012-10-01 Modified from auto/feature by jefftk to support c++ test files.
|
||||
|
||||
echo $ngx_n "checking for $ngx_feature ...$ngx_c"
|
||||
|
||||
cat << END >> $NGX_AUTOCONF_ERR
|
||||
|
||||
----------------------------------------
|
||||
checking for $ngx_feature
|
||||
|
||||
END
|
||||
|
||||
ngx_found=no
|
||||
|
||||
if test -n "$ngx_feature_name"; then
|
||||
ngx_have_feature=`echo $ngx_feature_name \
|
||||
| tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ`
|
||||
fi
|
||||
|
||||
if test -n "$ngx_feature_path"; then
|
||||
for ngx_temp in $ngx_feature_path; do
|
||||
ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp"
|
||||
done
|
||||
fi
|
||||
|
||||
cat << END > $NGX_AUTOTEST.cc
|
||||
|
||||
#include <sys/types.h>
|
||||
$NGX_INCLUDE_UNISTD_H
|
||||
$ngx_feature_incs
|
||||
|
||||
int main() {
|
||||
$ngx_feature_test;
|
||||
return 0;
|
||||
}
|
||||
|
||||
END
|
||||
|
||||
|
||||
ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS $ngx_feature_inc_path \
|
||||
-o $NGX_AUTOTEST $NGX_AUTOTEST.cc $NGX_TEST_LD_OPT $ngx_feature_libs"
|
||||
|
||||
ngx_feature_inc_path=
|
||||
|
||||
eval "/bin/sh -c \"$ngx_test\" >> $NGX_AUTOCONF_ERR 2>&1"
|
||||
|
||||
|
||||
if [ -x $NGX_AUTOTEST ]; then
|
||||
|
||||
case "$ngx_feature_run" in
|
||||
|
||||
yes)
|
||||
# /bin/sh is used to intercept "Killed" or "Abort trap" messages
|
||||
if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
|
||||
echo " found"
|
||||
ngx_found=yes
|
||||
|
||||
if test -n "$ngx_feature_name"; then
|
||||
have=$ngx_have_feature . auto/have
|
||||
fi
|
||||
|
||||
else
|
||||
echo " found but is not working"
|
||||
fi
|
||||
;;
|
||||
|
||||
value)
|
||||
# /bin/sh is used to intercept "Killed" or "Abort trap" messages
|
||||
if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
|
||||
echo " found"
|
||||
ngx_found=yes
|
||||
|
||||
cat << END >> $NGX_AUTO_CONFIG_H
|
||||
|
||||
#ifndef $ngx_feature_name
|
||||
#define $ngx_feature_name `$NGX_AUTOTEST`
|
||||
#endif
|
||||
|
||||
END
|
||||
else
|
||||
echo " found but is not working"
|
||||
fi
|
||||
;;
|
||||
|
||||
bug)
|
||||
# /bin/sh is used to intercept "Killed" or "Abort trap" messages
|
||||
if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then
|
||||
echo " not found"
|
||||
|
||||
else
|
||||
echo " found"
|
||||
ngx_found=yes
|
||||
|
||||
if test -n "$ngx_feature_name"; then
|
||||
have=$ngx_have_feature . auto/have
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo " found"
|
||||
ngx_found=yes
|
||||
|
||||
if test -n "$ngx_feature_name"; then
|
||||
have=$ngx_have_feature . auto/have
|
||||
fi
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
else
|
||||
echo " not found"
|
||||
|
||||
echo "----------" >> $NGX_AUTOCONF_ERR
|
||||
cat $NGX_AUTOTEST.cc >> $NGX_AUTOCONF_ERR
|
||||
echo "----------" >> $NGX_AUTOCONF_ERR
|
||||
echo $ngx_test >> $NGX_AUTOCONF_ERR
|
||||
echo "----------" >> $NGX_AUTOCONF_ERR
|
||||
fi
|
||||
|
||||
rm $NGX_AUTOTEST*
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
ngx_module_t ngx_pagespeed;
|
||||
|
||||
static ngx_http_module_t ctx = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ngx_command_t cmds[] = {
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
ngx_module_t ngx_pagespeed = {
|
||||
NGX_MODULE_V1,
|
||||
&ctx,
|
||||
cmds,
|
||||
NGX_HTTP_MODULE,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Usage:
|
||||
* server {
|
||||
* pagespeed on|off;
|
||||
* }
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
}
|
||||
|
||||
#include "net/instaweb/public/version.h"
|
||||
|
||||
extern ngx_module_t ngx_pagespeed;
|
||||
|
||||
typedef struct {
|
||||
ngx_flag_t active;
|
||||
} ngx_http_pagespeed_loc_conf_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_conf_set_flag_slot,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_pagespeed_loc_conf_t, active),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
static void*
|
||||
ngx_http_pagespeed_create_loc_conf(ngx_conf_t* cf)
|
||||
{
|
||||
ngx_http_pagespeed_loc_conf_t* conf;
|
||||
|
||||
conf = static_cast<ngx_http_pagespeed_loc_conf_t*>(
|
||||
ngx_pcalloc(cf->pool, sizeof(ngx_http_pagespeed_loc_conf_t)));
|
||||
if (conf == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
conf->active = NGX_CONF_UNSET;
|
||||
return conf;
|
||||
}
|
||||
|
||||
static char*
|
||||
ngx_http_pagespeed_merge_loc_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_conf_merge_value(conf->active, prev->active, 0); // Default off.
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
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 adding 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_body_filter(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;
|
||||
for ( chain_link = in; chain_link != NULL; chain_link = chain_link->next ) {
|
||||
if (chain_link->buf->last_buf) {
|
||||
chain_contains_last_buffer = 1;
|
||||
if (chain_link->next != NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0,
|
||||
"Chain link thinks its last but has a child.");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
break; // Chain link now is the last link in the chain.
|
||||
}
|
||||
}
|
||||
|
||||
if (!chain_contains_last_buffer) {
|
||||
// None of the buffers had last_buf set, meaning we have an incomplete chain
|
||||
// and are still waiting to get the final buffer. Let other body filters
|
||||
// act on the buffers we have so far and wait until we're called again with
|
||||
// the last buffer.
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
// Prepare a new buffer to put the note into.
|
||||
ngx_buf_t* b = static_cast<ngx_buf_t*>(ngx_calloc_buf(r->pool));
|
||||
if (b == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
// Write to the new buffer.
|
||||
const char note[] = "<!-- Processed through ngx_pagespeed using PSOL version "
|
||||
MOD_PAGESPEED_VERSION_STRING " -->\n";
|
||||
int note_len = strlen(note);
|
||||
b->start = b->pos = static_cast<u_char*>(ngx_pnalloc(r->pool, note_len));
|
||||
strncpy((char*)b->pos, note, note_len);
|
||||
b->end = b->last = b->pos + note_len;
|
||||
b->temporary = 1;
|
||||
|
||||
// Link the new buffer into the buffer chain.
|
||||
ngx_chain_t* added_link = static_cast<ngx_chain_t*>(
|
||||
ngx_alloc_chain_link(r->pool));
|
||||
if (added_link == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
added_link->buf = b;
|
||||
|
||||
// Add our new link to the buffer chain.
|
||||
added_link->next = NULL;
|
||||
chain_link->next = added_link;
|
||||
|
||||
// Mark our new link as the end of the chain.
|
||||
chain_link->buf->last_buf = 0;
|
||||
added_link->buf->last_buf = 1;
|
||||
chain_link->buf->last_in_chain = 0;
|
||||
added_link->buf->last_in_chain = 1;
|
||||
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
if (pagespeed_config->active) {
|
||||
ngx_http_next_header_filter = ngx_http_top_header_filter;
|
||||
ngx_http_top_header_filter = ngx_http_pagespeed_header_filter;
|
||||
|
||||
ngx_http_next_body_filter = ngx_http_top_body_filter;
|
||||
ngx_http_top_body_filter = ngx_http_pagespeed_body_filter;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
ngx_module_t ngx_pagespeed = {
|
||||
NGX_MODULE_V1,
|
||||
&ngx_http_pagespeed_module_ctx,
|
||||
ngx_http_pagespeed_commands,
|
||||
NGX_HTTP_MODULE,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NGX_MODULE_V1_PADDING
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user