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
|
## How to build
|
||||||
|
|
||||||
nginx does not support dynamic loading of modules. You need to add
|
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
|
$ cd /path/to/nginx
|
||||||
$ auto/configure --add-module=/path/to/ngx_pagespeed
|
$ auto/configure --add-module=/path/to/ngx_pagespeed
|
||||||
$ make install
|
$ 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
|
## 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
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# 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"
|
# Test whether we have pagespeed and can compile and link against it.
|
||||||
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
|
. "$this_dir/cpp_feature"
|
||||||
|
|
||||||
# TODO link against libpagespeed / libpsol
|
if [ $ngx_found = yes ]; then
|
||||||
# CORE_LIBS="$CORE_LIBS -lpagespeed"
|
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
|
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