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:
Jeff Kaufman
2012-10-01 14:42:25 -04:00
parent 64a66cfb07
commit cff21ace3a
5 changed files with 370 additions and 58 deletions
+26 -2
View File
@@ -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.
+26 -5
View File
@@ -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
View File
@@ -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*
-51
View File
@@ -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
};
+196
View File
@@ -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
};