Compare commits
218 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da466c1487 | |||
| 2a409777dc | |||
| c3f41512cf | |||
| 0980633dd2 | |||
| c1c83aa69b | |||
| 4885d44f69 | |||
| 7b84f92adf | |||
| a403e62074 | |||
| b5dc1083f4 | |||
| ab9929e5a5 | |||
| 9832a049fe | |||
| 14822570c4 | |||
| ccd800a0b1 | |||
| e2e21474ce | |||
| 7680a159a7 | |||
| 7aa5bc4a99 | |||
| 462acc9eee | |||
| 4678a62be8 | |||
| 525e331c0c | |||
| dc40c902ec | |||
| 6a8a1c5bf7 | |||
| 5bcd9e277e | |||
| 554577bbf2 | |||
| 458a2f5236 | |||
| 71e89efc64 | |||
| 5a23347e64 | |||
| 7ce289346a | |||
| 6b4a9dc487 | |||
| a3f2e4766c | |||
| ab0a5e4b65 | |||
| a458a65d4e | |||
| d00911b00f | |||
| ed80427ae6 | |||
| f556ca4926 | |||
| cad618dff7 | |||
| a906411367 | |||
| e6c5bc1b2e | |||
| d6d3b90ea3 | |||
| d7afd2acbc | |||
| 05f6993801 | |||
| fe63bbf53f | |||
| c7aa72d9c5 | |||
| 8f6bb0c9e3 | |||
| 84f2a1884e | |||
| da83f73f19 | |||
| 2bfc05b4c6 | |||
| ea9e209687 | |||
| c073a3120b | |||
| 5e3b2f23a5 | |||
| f41ecf4010 | |||
| 34a62db9cf | |||
| b0efa9f982 | |||
| fb00ac373b | |||
| 9550629768 | |||
| 26a5deb341 | |||
| 7bcd5aadde | |||
| bbdfb5b429 | |||
| 594ba13606 | |||
| 9d0b896737 | |||
| 89f6465288 | |||
| eb11cfe0cf | |||
| 7a0e45d025 | |||
| 3cf731ee24 | |||
| 1a4ffcf335 | |||
| 72c7e584f7 | |||
| 1f02f368e1 | |||
| 0c1cbbdf64 | |||
| 75a4481750 | |||
| 08f69913dc | |||
| f2d6bcf3ac | |||
| 2c89815084 | |||
| e55b062c17 | |||
| 62ef051844 | |||
| 36b07ca209 | |||
| b1e188bdb6 | |||
| 1280cd0dfa | |||
| a06551a97d | |||
| 679618f998 | |||
| fb9b355715 | |||
| f71ac7dd0c | |||
| 19f479a6b6 | |||
| 7431946d23 | |||
| 0d760dbf31 | |||
| e9d7b2ad01 | |||
| 0d89df0e80 | |||
| 218d74f206 | |||
| bcefd56941 | |||
| 676344bc8a | |||
| 7293f649d1 | |||
| 10f5093bf6 | |||
| 357eb92683 | |||
| 4d940fb84e | |||
| a6c6d13392 | |||
| 9007e582ad | |||
| 1ca04d514c | |||
| 8e08b2b7e0 | |||
| ad1a1594d6 | |||
| d5e37d2d2e | |||
| 4bceb402a6 | |||
| 80a50fe9d8 | |||
| 28192a509e | |||
| 9331815350 | |||
| 727d339dfd | |||
| b3e5297dc3 | |||
| 639a01015c | |||
| 29a43196e8 | |||
| 0b20c91217 | |||
| d654062516 | |||
| b6991fd107 | |||
| bf042f8af9 | |||
| 22950666e0 | |||
| a6a2da765b | |||
| 70038bc64a | |||
| 815fa29985 | |||
| c82bb2c7a4 | |||
| e9eaa23356 | |||
| 96f185d472 | |||
| 168df6ae68 | |||
| c9a106b4b0 | |||
| 00080ff728 | |||
| a7969a6382 | |||
| 243d4e1931 | |||
| b6098ce302 | |||
| 8246c03fda | |||
| 36d285a354 | |||
| 149d1c7a5c | |||
| 9e9bf76164 | |||
| 09bc3b0aba | |||
| 502abb2f10 | |||
| 08bdfb8c65 | |||
| 8a8f62fefa | |||
| 94ab5c33f8 | |||
| 0e766e4096 | |||
| 99ac026f00 | |||
| 90e4c40d86 | |||
| a7fdc86744 | |||
| aed13fc578 | |||
| cd753a22a7 | |||
| 0de4e20be1 | |||
| 6af5774ef8 | |||
| 117994993a | |||
| 5487b7350c | |||
| 261b602f83 | |||
| ae3cf7a425 | |||
| b4af0738a5 | |||
| ff049a55c3 | |||
| 0772787ad4 | |||
| 7eedc2ce3c | |||
| 7af665b5dd | |||
| 8136a15352 | |||
| 31024cfc24 | |||
| 703fda7eba | |||
| d4bc40007e | |||
| f2e2ab6056 | |||
| e06a65e7e6 | |||
| 3231949e03 | |||
| f5713996f2 | |||
| 185632583b | |||
| c5dbfa16cd | |||
| 33b2e82ec6 | |||
| b87ffce5ba | |||
| 7d5fc11afd | |||
| 7cba7ba4f4 | |||
| cf434f71cc | |||
| ba8c149a88 | |||
| f5bac604a1 | |||
| f18faa3ae1 | |||
| 070ae2aad2 | |||
| 674c70e32c | |||
| b4ef143a88 | |||
| ffdc3c8fd6 | |||
| af10fc3ddb | |||
| e9a099f9c5 | |||
| e4a2933c58 | |||
| 2601232457 | |||
| a3e1810a6a | |||
| 72f3c79fec | |||
| 323e820fde | |||
| a9a7bf56ac | |||
| 2358f957cb | |||
| 7d72a7c89a | |||
| 8830724580 | |||
| c2d07a8d5a | |||
| c3bff67637 | |||
| 5a1a29ee8b | |||
| 61025c5e4f | |||
| d3e7900704 | |||
| 85e19c962b | |||
| 20fd7d18dd | |||
| 4667aa1fc3 | |||
| 6ced8c0f65 | |||
| bfaf4268cf | |||
| 78cf39f9b3 | |||
| 215071a383 | |||
| 630f7d848b | |||
| d90245af69 | |||
| f25569690a | |||
| 707d671826 | |||
| f8b87ea436 | |||
| 86d840f76e | |||
| 0110d33fa7 | |||
| 497594ba7f | |||
| 336352df38 | |||
| 0edd405eb8 | |||
| d004c4d916 | |||
| c754cf1be0 | |||
| 091ef6399b | |||
| 9e4d26da5e | |||
| 9699caeab5 | |||
| c371d516a8 | |||
| bf6c6c0e9b | |||
| e8dd9fd3c3 | |||
| 64eaa2a659 | |||
| 6db4d02a91 | |||
| 1354cee4ed | |||
| 6ccb815df3 | |||
| 72ddb34a1c | |||
| ae2d4bac7f |
@@ -19,94 +19,15 @@ optimizations, see our <a href="http://ngxpagespeed.com">demonstration site</a>.
|
||||
|
||||
## How to build
|
||||
|
||||
Because nginx does not support dynamic loading of modules, you need to compile
|
||||
nginx from source to add ngx_pagespeed. Alternatively, if you're using Tengine you can [install ngx_pagespeed without
|
||||
recompiling Tengine](https://github.com/pagespeed/ngx_pagespeed/wiki/Using-ngx_pagespeed-with-Tengine).
|
||||
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
# These are for RedHat, CentOS, and Fedora.
|
||||
$ sudo yum install gcc-c++ pcre-dev pcre-devel zlib-devel make
|
||||
|
||||
# These are for Debian. Ubuntu will be similar.
|
||||
$ sudo apt-get install build-essential zlib1g-dev libpcre3 libpcre3-dev
|
||||
```
|
||||
|
||||
2. Download ngx_pagespeed:
|
||||
|
||||
```bash
|
||||
$ cd ~
|
||||
$ wget https://github.com/pagespeed/ngx_pagespeed/archive/v1.7.30.3-beta.zip
|
||||
$ unzip v1.7.30.3-beta.zip # or unzip v1.7.30.3-beta
|
||||
$ cd ngx_pagespeed-1.7.30.3-beta/
|
||||
$ wget https://dl.google.com/dl/page-speed/psol/1.7.30.3.tar.gz
|
||||
$ tar -xzvf 1.7.30.3.tar.gz # expands to psol/
|
||||
```
|
||||
|
||||
3. Download and build nginx:
|
||||
|
||||
```bash
|
||||
$ cd ~
|
||||
$ # check http://nginx.org/en/download.html for the latest version
|
||||
$ wget http://nginx.org/download/nginx-1.4.4.tar.gz
|
||||
$ tar -xvzf nginx-1.4.4.tar.gz
|
||||
$ cd nginx-1.4.4/
|
||||
$ ./configure --add-module=$HOME/ngx_pagespeed-1.7.30.3-beta
|
||||
$ make
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
If this doesn't work see the [build
|
||||
troubleshooting](https://github.com/pagespeed/ngx_pagespeed/wiki/Build-Troubleshooting) page.
|
||||
|
||||
This will use a binary PageSpeed Optimization Library, but it's also possible to
|
||||
[build PSOL from
|
||||
source](https://github.com/pagespeed/ngx_pagespeed/wiki/Building-PSOL-From-Source).
|
||||
|
||||
Note: ngx_pagespeed currently doesn't support Windows or MacOS because the
|
||||
underlying PSOL library doesn't.
|
||||
Follow the steps on <a
|
||||
href="https://developers.google.com/speed/pagespeed/module/build_ngx_pagespeed_from_source">build
|
||||
ngx_pagespeed from source</a>.
|
||||
|
||||
## How to use
|
||||
|
||||
In your `nginx.conf`, add to the main or server block:
|
||||
|
||||
```nginx
|
||||
pagespeed on;
|
||||
pagespeed FileCachePath /var/ngx_pagespeed_cache; # Use tmpfs for best results.
|
||||
```
|
||||
|
||||
In every server block where pagespeed is enabled add:
|
||||
|
||||
```apache
|
||||
# Ensure requests for pagespeed optimized resources go to the pagespeed
|
||||
# handler and no extraneous headers get set.
|
||||
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; }
|
||||
location ~ "^/ngx_pagespeed_static/" { }
|
||||
location ~ "^/ngx_pagespeed_beacon$" { }
|
||||
location /ngx_pagespeed_statistics { allow 127.0.0.1; deny all; }
|
||||
location /ngx_pagespeed_global_statistics { allow 127.0.0.1; deny all; }
|
||||
location /ngx_pagespeed_message { allow 127.0.0.1; deny all; }
|
||||
location /pagespeed_console { allow 127.0.0.1; deny all; }
|
||||
```
|
||||
|
||||
To confirm that the module is loaded, fetch a page and check that you see the
|
||||
`X-Page-Speed` header:
|
||||
|
||||
```bash
|
||||
$ curl -I 'http://localhost:8050/some_page/' | grep X-Page-Speed
|
||||
X-Page-Speed: 1.7.30.3-...
|
||||
```
|
||||
|
||||
Looking at the source of a few pages you should see various changes, such as
|
||||
urls being replaced with new ones like `yellow.css.pagespeed.ce.lzJ8VcVi1l.css`.
|
||||
|
||||
For complete documentation, see [Using
|
||||
PageSpeed](https://developers.google.com/speed/pagespeed/module/using).
|
||||
|
||||
There are extensive system tests which cover most of ngx_pagespeed's
|
||||
functionality. Consider [testing your
|
||||
installation](https://github.com/pagespeed/ngx_pagespeed/wiki/Testing).
|
||||
Follow the steps on <a
|
||||
href="https://developers.google.com/speed/pagespeed/module/configuration">PageSpeed
|
||||
configuration</a>.
|
||||
|
||||
For feedback, questions, and to follow
|
||||
the progress of the project:
|
||||
@@ -115,20 +36,3 @@ the progress of the project:
|
||||
list](https://groups.google.com/forum/#!forum/ngx-pagespeed-discuss)
|
||||
- [ngx-pagespeed-announce mailing
|
||||
list](https://groups.google.com/forum/#!forum/ngx-pagespeed-announce)
|
||||
|
||||
Note: The
|
||||
[canonicalize_javascript_libraries](https://developers.google.com/speed/pagespeed/module/filter-canonicalize-js)
|
||||
depends on `pagespeed_libraries.conf` which is distributed in Apache's format.
|
||||
To convert it to the Nginx format, run:
|
||||
|
||||
```bash
|
||||
$ scripts/pagespeed_libraries_generator.sh > ~/pagespeed_libraries.conf
|
||||
$ sudo mv ~/pagespeed_libraries.conf /etc/nginx/
|
||||
```
|
||||
|
||||
And then include it in your Nginx configuration by reference:
|
||||
|
||||
```nginx
|
||||
include pagespeed_libraries.conf;
|
||||
pagespeed EnableFilters canonicalize_javascript_libraries;
|
||||
```
|
||||
|
||||
@@ -27,8 +27,8 @@ if [ "$mod_pagespeed_dir" = "unset" ] ; then
|
||||
echo " You need to separately download the pagespeed library:"
|
||||
echo ""
|
||||
echo " $ cd /path/to/ngx_pagespeed"
|
||||
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.7.30.2.tar.gz"
|
||||
echo " $ tar -xzvf 1.7.30.2.tar.gz # expands to psol/"
|
||||
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.9.32.3.tar.gz"
|
||||
echo " $ tar -xzvf 1.9.32.3.tar.gz # expands to psol/"
|
||||
echo ""
|
||||
echo " Or see the installation instructions:"
|
||||
echo " https://github.com/pagespeed/ngx_pagespeed#how-to-build"
|
||||
@@ -39,20 +39,6 @@ else
|
||||
build_from_source=true
|
||||
fi
|
||||
|
||||
echo "mod_pagespeed_dir=$mod_pagespeed_dir"
|
||||
echo "build_from_source=$build_from_source"
|
||||
|
||||
ngx_feature="psol"
|
||||
ngx_feature_name=""
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="
|
||||
#include \"net/instaweb/htmlparse/public/html_parse.h\"
|
||||
#include \"net/instaweb/htmlparse/public/html_writer_filter.h\"
|
||||
#include \"net/instaweb/util/public/string.h\"
|
||||
#include \"net/instaweb/util/public/string_writer.h\"
|
||||
#include \"net/instaweb/util/public/null_message_handler.h\"
|
||||
"
|
||||
|
||||
os_name='unknown_os'
|
||||
arch_name='unknown_arch'
|
||||
uname_os=`uname`
|
||||
@@ -109,6 +95,35 @@ case "$NGX_GCC_VER" in
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$WNO_ERROR" = "YES" ]; then
|
||||
CFLAGS="$CFLAGS -Wno-error"
|
||||
fi
|
||||
|
||||
psol_binary="${PSOL_BINARY:-unset}"
|
||||
if [ "$psol_binary" = "unset" ] ; then
|
||||
if $build_from_source ; then
|
||||
psol_binary="\
|
||||
$mod_pagespeed_dir/net/instaweb/automatic/pagespeed_automatic.a"
|
||||
else
|
||||
psol_library_dir="$ngx_addon_dir/psol/lib/$buildtype/$os_name/$arch_name"
|
||||
psol_binary="$psol_library_dir/pagespeed_automatic.a"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "mod_pagespeed_dir=$mod_pagespeed_dir"
|
||||
echo "build_from_source=$build_from_source"
|
||||
|
||||
ngx_feature="psol"
|
||||
ngx_feature_name=""
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="
|
||||
#include \"pagespeed/kernel/base/string.h\"
|
||||
#include \"pagespeed/kernel/base/string_writer.h\"
|
||||
#include \"pagespeed/kernel/base/null_message_handler.h\"
|
||||
#include \"pagespeed/kernel/html/html_parse.h\"
|
||||
#include \"pagespeed/kernel/html/html_writer_filter.h\"
|
||||
"
|
||||
|
||||
pagespeed_include="\
|
||||
$mod_pagespeed_dir \
|
||||
$mod_pagespeed_dir/third_party/chromium/src \
|
||||
@@ -124,15 +139,7 @@ pagespeed_include="\
|
||||
$mod_pagespeed_dir/third_party/aprutil/gen/arch/$os_name/$arch_name/include"
|
||||
ngx_feature_path="$pagespeed_include"
|
||||
|
||||
if $build_from_source ; then
|
||||
psol_library_binaries="\
|
||||
$mod_pagespeed_dir/net/instaweb/automatic/pagespeed_automatic.a"
|
||||
else
|
||||
psol_library_dir="$ngx_addon_dir/psol/lib/$buildtype/$os_name/$arch_name"
|
||||
psol_library_binaries="$psol_library_dir/pagespeed_automatic.a"
|
||||
fi
|
||||
|
||||
pagespeed_libs="-lstdc++ $psol_library_binaries -lrt -pthread -lm"
|
||||
pagespeed_libs="-lstdc++ $psol_binary -lrt -pthread -lm"
|
||||
ngx_feature_libs="$pagespeed_libs"
|
||||
ngx_feature_test="
|
||||
GoogleString output_buffer;
|
||||
@@ -163,18 +170,21 @@ if [ $ngx_found = yes ]; then
|
||||
$ps_src/ngx_base_fetch.h \
|
||||
$ps_src/ngx_caching_headers.h \
|
||||
$ps_src/ngx_fetch.h \
|
||||
$ps_src/ngx_gzip_setter.h \
|
||||
$ps_src/ngx_list_iterator.h \
|
||||
$ps_src/ngx_message_handler.h \
|
||||
$ps_src/ngx_pagespeed.h \
|
||||
$ps_src/ngx_rewrite_driver_factory.h \
|
||||
$ps_src/ngx_rewrite_options.h \
|
||||
$ps_src/ngx_server_context.h \
|
||||
$ps_src/ngx_url_async_fetcher.h"
|
||||
$ps_src/ngx_url_async_fetcher.h \
|
||||
$psol_binary"
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
|
||||
$ps_src/log_message_handler.cc \
|
||||
$ps_src/ngx_base_fetch.cc \
|
||||
$ps_src/ngx_caching_headers.cc \
|
||||
$ps_src/ngx_fetch.cc \
|
||||
$ps_src/ngx_gzip_setter.cc \
|
||||
$ps_src/ngx_list_iterator.cc \
|
||||
$ps_src/ngx_message_handler.cc \
|
||||
$ps_src/ngx_pagespeed.cc \
|
||||
@@ -195,7 +205,7 @@ if [ $ngx_found = yes ]; then
|
||||
else
|
||||
cat << END
|
||||
$0: error: module ngx_pagespeed requires the pagespeed optimization library.
|
||||
Look in obj/autoconf.err for more details.
|
||||
Look in objs/autoconf.err for more details.
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
+13
-8
@@ -39,7 +39,7 @@ NgxBaseFetch::NgxBaseFetch(ngx_http_request_t* r, int pipe_fd,
|
||||
last_buf_sent_(false),
|
||||
pipe_fd_(pipe_fd),
|
||||
references_(2),
|
||||
handle_error_(true),
|
||||
ipro_lookup_(false),
|
||||
preserve_caching_headers_(preserve_caching_headers) {
|
||||
if (pthread_mutex_init(&mutex_, NULL)) CHECK(0);
|
||||
}
|
||||
@@ -106,11 +106,10 @@ ngx_int_t NgxBaseFetch::CollectAccumulatedWrites(ngx_chain_t** link_ptr) {
|
||||
ngx_int_t NgxBaseFetch::CollectHeaders(ngx_http_headers_out_t* headers_out) {
|
||||
const ResponseHeaders* pagespeed_headers = response_headers();
|
||||
|
||||
// TODO(chaizhenhua): Add and check.
|
||||
// if (content_length_known()) {
|
||||
// headers_out->content_length = NULL;
|
||||
// headers_out->content_length_n = content_length();
|
||||
// }
|
||||
if (content_length_known()) {
|
||||
headers_out->content_length = NULL;
|
||||
headers_out->content_length_n = content_length();
|
||||
}
|
||||
|
||||
return copy_response_headers_to_ngx(request_, *pagespeed_headers,
|
||||
preserve_caching_headers_);
|
||||
@@ -138,14 +137,20 @@ void NgxBaseFetch::HandleHeadersComplete() {
|
||||
int status_code = response_headers()->status_code();
|
||||
bool status_ok = (status_code != 0) && (status_code < 400);
|
||||
|
||||
if (status_ok || handle_error_) {
|
||||
if (!ipro_lookup_ || status_ok) {
|
||||
// If this is a 404 response we need to count it in the stats.
|
||||
if (response_headers()->status_code() == HttpStatus::kNotFound) {
|
||||
server_context_->rewrite_stats()->resource_404_count()->Add(1);
|
||||
}
|
||||
}
|
||||
|
||||
RequestCollection(); // Headers available.
|
||||
// For the IPRO lookup, suppress notification of the nginx side here.
|
||||
// If we send both this event and the one from done, nasty stuff will happen
|
||||
// if we loose the race with with the nginx side destructing this base fetch
|
||||
// instance (and thereby clearing the byte and its pending extraneous event.
|
||||
if (!ipro_lookup_) {
|
||||
RequestCollection(); // Headers available.
|
||||
}
|
||||
}
|
||||
|
||||
bool NgxBaseFetch::HandleFlush(MessageHandler* handler) {
|
||||
|
||||
@@ -79,7 +79,7 @@ class NgxBaseFetch : public AsyncFetch {
|
||||
|
||||
// Called by nginx when it's done with us.
|
||||
void Release();
|
||||
void set_handle_error(bool x) { handle_error_ = x; }
|
||||
void set_ipro_lookup(bool x) { ipro_lookup_ = x; }
|
||||
|
||||
private:
|
||||
virtual bool HandleWrite(const StringPiece& sp, MessageHandler* handler);
|
||||
@@ -117,7 +117,7 @@ class NgxBaseFetch : public AsyncFetch {
|
||||
// decremented once when Done() is called and once when Release() is called.
|
||||
int references_;
|
||||
pthread_mutex_t mutex_;
|
||||
bool handle_error_;
|
||||
bool ipro_lookup_;
|
||||
PreserveCachingHeaders preserve_caching_headers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NgxBaseFetch);
|
||||
|
||||
+808
-466
File diff suppressed because it is too large
Load Diff
+25
-10
@@ -16,6 +16,15 @@
|
||||
|
||||
// Author: x.dinic@gmail.com (Junmin Xiong)
|
||||
//
|
||||
// PageSpeed needs some way to talk to the internet and request resources. For
|
||||
// example, if it's optimizing www.example.com/index.html and it sees html with
|
||||
// <img src="//images.example.com/cat.jpg"> and images.example.com is authorized
|
||||
// for rewriting in the config, then it needs to fetch cat.jpg from
|
||||
// images.example.com and optimize it. In apache (always) and nginx (by
|
||||
// default) we use a fetcher called "serf". This works fine, but it does run
|
||||
// its own event loop. To be more efficient, this is a "native" fetcher that
|
||||
// uses nginx's event loop.
|
||||
//
|
||||
// The fetch is started by the main thread. It will fetch the remote resource
|
||||
// from the specific url asynchronously.
|
||||
|
||||
@@ -42,12 +51,13 @@ namespace net_instaweb {
|
||||
typedef bool (*response_handler_pt)(ngx_connection_t* c);
|
||||
|
||||
class NgxUrlAsyncFetcher;
|
||||
class NgxConnection;
|
||||
|
||||
class NgxFetch : public PoolElement<NgxFetch> {
|
||||
public:
|
||||
NgxFetch(const GoogleString& url,
|
||||
AsyncFetch* async_fetch,
|
||||
MessageHandler* message_handler,
|
||||
ngx_msec_t timeout_ms,
|
||||
ngx_log_t* log);
|
||||
~NgxFetch();
|
||||
|
||||
@@ -83,6 +93,12 @@ class NgxFetch : public PoolElement<NgxFetch> {
|
||||
void set_timeout_event(ngx_event_t* x) {
|
||||
timeout_event_ = x;
|
||||
}
|
||||
void release_resolver() {
|
||||
if (resolver_ctx_ != NULL && resolver_ctx_ != NGX_NO_RESOLVER) {
|
||||
ngx_resolve_name_done(resolver_ctx_);
|
||||
resolver_ctx_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
response_handler_pt response_handler;
|
||||
@@ -97,19 +113,19 @@ class NgxFetch : public PoolElement<NgxFetch> {
|
||||
response_handler = handler;
|
||||
}
|
||||
// Only the Static functions could be used in callbacks.
|
||||
static void NgxFetchResolveDone(ngx_resolver_ctx_t* ctx);
|
||||
static void ResolveDoneHandler(ngx_resolver_ctx_t* ctx);
|
||||
// Write the request.
|
||||
static void NgxFetchWrite(ngx_event_t* wev);
|
||||
static void ConnectionWriteHandler(ngx_event_t* wev);
|
||||
// Wait for the response.
|
||||
static void NgxFetchRead(ngx_event_t* rev);
|
||||
static void ConnectionReadHandler(ngx_event_t* rev);
|
||||
// Read and parse the first status line.
|
||||
static bool NgxFetchHandleStatusLine(ngx_connection_t* c);
|
||||
static bool HandleStatusLine(ngx_connection_t* c);
|
||||
// Read and parse the HTTP headers.
|
||||
static bool NgxFetchHandleHeader(ngx_connection_t* c);
|
||||
static bool HandleHeader(ngx_connection_t* c);
|
||||
// Read the response body.
|
||||
static bool NgxFetchHandleBody(ngx_connection_t* c);
|
||||
static bool HandleBody(ngx_connection_t* c);
|
||||
// Cancel the fetch when it's timeout.
|
||||
static void NgxFetchTimeout(ngx_event_t* tev);
|
||||
static void TimeoutHandler(ngx_event_t* tev);
|
||||
|
||||
// Add the pagespeed User-Agent.
|
||||
void FixUserAgent();
|
||||
@@ -124,7 +140,6 @@ class NgxFetch : public PoolElement<NgxFetch> {
|
||||
int64 bytes_received_;
|
||||
int64 fetch_start_ms_;
|
||||
int64 fetch_end_ms_;
|
||||
int64 timeout_ms_;
|
||||
bool done_;
|
||||
int64 content_length_;
|
||||
bool content_length_known_;
|
||||
@@ -137,7 +152,7 @@ class NgxFetch : public PoolElement<NgxFetch> {
|
||||
ngx_http_request_t* r_;
|
||||
ngx_http_status_t* status_;
|
||||
ngx_event_t* timeout_event_;
|
||||
ngx_connection_t* connection_;
|
||||
NgxConnection* connection_;
|
||||
ngx_resolver_ctx_t* resolver_ctx_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NgxFetch);
|
||||
|
||||
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* Copyright 2014 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: kspoelstra@we-amp.com (Kees Spoelstra)
|
||||
|
||||
#include "ngx_gzip_setter.h"
|
||||
|
||||
#include <ngx_conf_file.h>
|
||||
|
||||
namespace net_instaweb {
|
||||
|
||||
NgxGZipSetter g_gzip_setter;
|
||||
|
||||
extern "C" {
|
||||
// These functions replace the setters for:
|
||||
// gzip
|
||||
// gzip_types
|
||||
// gzip_http_version
|
||||
// gzip_vary
|
||||
//
|
||||
// If these functions are called it means there is an explicit gzip
|
||||
// configuration. The gzip configuration set by pagespeed is then rolled
|
||||
// back and pagespeed will stop enabling gzip automatically.
|
||||
char* ngx_gzip_redirect_conf_set_flag_slot(
|
||||
ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
|
||||
if (g_gzip_setter.enabled()) {
|
||||
g_gzip_setter.RollBackAndDisable(cf);
|
||||
}
|
||||
char* ret = ngx_conf_set_flag_slot(cf, cmd, conf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* ngx_gzip_redirect_http_types_slot(
|
||||
ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
|
||||
if (g_gzip_setter.enabled()) {
|
||||
g_gzip_setter.RollBackAndDisable(cf);
|
||||
}
|
||||
char* ret = ngx_http_types_slot(cf, cmd, conf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* ngx_gzip_redirect_conf_set_enum_slot(
|
||||
ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
|
||||
if (g_gzip_setter.enabled()) {
|
||||
g_gzip_setter.RollBackAndDisable(cf);
|
||||
}
|
||||
char* ret = ngx_conf_set_enum_slot(cf, cmd, conf);
|
||||
return ret;
|
||||
}
|
||||
char* ngx_gzip_redirect_conf_set_bitmask_slot(
|
||||
ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
|
||||
if (g_gzip_setter.enabled()) {
|
||||
g_gzip_setter.RollBackAndDisable(cf);
|
||||
}
|
||||
char* ret = ngx_conf_set_bitmask_slot(cf, cmd, conf);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
NgxGZipSetter::NgxGZipSetter() : enabled_(false), initialized_(false) { }
|
||||
NgxGZipSetter::~NgxGZipSetter() { }
|
||||
|
||||
// Helper functions to determine signature.
|
||||
bool HasLocalConfig(ngx_command_t* command) {
|
||||
return (!(command->type & (NGX_DIRECT_CONF|NGX_MAIN_CONF)) &&
|
||||
command->conf == NGX_HTTP_LOC_CONF_OFFSET);
|
||||
}
|
||||
bool IsNgxFlagCommand(ngx_command_t* command) {
|
||||
return (command->set == ngx_conf_set_flag_slot &&
|
||||
HasLocalConfig(command));
|
||||
}
|
||||
bool IsNgxHttpTypesCommand(ngx_command_t* command) {
|
||||
return (command->set == ngx_http_types_slot &&
|
||||
HasLocalConfig(command));
|
||||
}
|
||||
bool IsNgxEnumCommand(ngx_command_t* command) {
|
||||
return (command->set == ngx_conf_set_enum_slot &&
|
||||
HasLocalConfig(command));
|
||||
}
|
||||
bool IsNgxBitmaskCommand(ngx_command_t* command) {
|
||||
return (command->set == ngx_conf_set_bitmask_slot &&
|
||||
HasLocalConfig(command));
|
||||
}
|
||||
|
||||
// Initialize the NgxGZipSetter.
|
||||
// Find the gzip, gzip_vary, gzip_http_version and gzip_types commands in the
|
||||
// gzip module. Enable if the signature of the zip command matches with what we
|
||||
// trust. Also sets up redirects for the configurations. These redirect handle
|
||||
// a rollback if expicit configuration is found.
|
||||
// If commands are not found the method will inform the user by logging.
|
||||
void NgxGZipSetter::Init(ngx_conf_t* cf) {
|
||||
#if (NGX_HTTP_GZIP)
|
||||
bool gzip_signature_mismatch = false;
|
||||
bool other_signature_mismatch = false;
|
||||
// If we initialized already we don't have to scan again.
|
||||
if (initialized_) {
|
||||
// Config might have changed, so re-enable if we have gzip.
|
||||
if (gzip_command_.command_ != NULL) {
|
||||
enabled_ = true;
|
||||
} else {
|
||||
enabled_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (int m = 0; ngx_modules[m] != NULL; m++) {
|
||||
if (ngx_modules[m]->commands != NULL) {
|
||||
for (int c = 0; ngx_modules[m]->commands[c].name.len; c++) {
|
||||
ngx_command_t* current_command =& ngx_modules[m]->commands[c];
|
||||
|
||||
// We look for the gzip command, and the exact signature we trust
|
||||
// this means configured as an config location offset
|
||||
// and a ngx_flag_t setter.
|
||||
// Also see:
|
||||
// ngx_conf_handler in ngx_conf_file.c
|
||||
// ngx_http_gzip_filter_commands in ngx_http_gzip_filter.c
|
||||
if (gzip_command_.command_ == NULL &&
|
||||
STR_EQ_LITERAL(current_command->name, "gzip")) {
|
||||
if (IsNgxFlagCommand(current_command)) {
|
||||
current_command->set = ngx_gzip_redirect_conf_set_flag_slot;
|
||||
gzip_command_.command_ = current_command;
|
||||
gzip_command_.module_ = ngx_modules[m];
|
||||
enabled_ = true;
|
||||
} else {
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0,
|
||||
"pagespeed: cannot set gzip, signature mismatch");
|
||||
gzip_signature_mismatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gzip_http_version_command_.command_ &&
|
||||
STR_EQ_LITERAL(current_command->name, "gzip_http_version")) {
|
||||
if (IsNgxEnumCommand(current_command)) {
|
||||
current_command->set = ngx_gzip_redirect_conf_set_enum_slot;
|
||||
gzip_http_version_command_.command_ = current_command;
|
||||
gzip_http_version_command_.module_ = ngx_modules[m];
|
||||
} else {
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0,
|
||||
"pagespeed: cannot set gzip_http_version, signature mismatch");
|
||||
other_signature_mismatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gzip_proxied_command_.command_ &&
|
||||
STR_EQ_LITERAL(current_command->name, "gzip_proxied")) {
|
||||
if (IsNgxBitmaskCommand(current_command)) {
|
||||
current_command->set = ngx_gzip_redirect_conf_set_bitmask_slot;
|
||||
gzip_proxied_command_.command_ = current_command;
|
||||
gzip_proxied_command_.module_ = ngx_modules[m];
|
||||
} else {
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0,
|
||||
"pagespeed: cannot set gzip_proxied, signature mismatch");
|
||||
other_signature_mismatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gzip_http_types_command_.command_ &&
|
||||
STR_EQ_LITERAL(current_command->name, "gzip_types")) {
|
||||
if (IsNgxHttpTypesCommand(current_command)) {
|
||||
current_command->set = ngx_gzip_redirect_http_types_slot;
|
||||
gzip_http_types_command_.command_ = current_command;
|
||||
gzip_http_types_command_.module_ = ngx_modules[m];
|
||||
} else {
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0,
|
||||
"pagespeed: cannot set gzip_types, signature mismatch");
|
||||
other_signature_mismatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gzip_vary_command_.command_ &&
|
||||
STR_EQ_LITERAL(current_command->name, "gzip_vary")) {
|
||||
if (IsNgxFlagCommand(current_command)) {
|
||||
current_command->set = ngx_gzip_redirect_conf_set_flag_slot;
|
||||
gzip_vary_command_.command_ = current_command;
|
||||
gzip_vary_command_.module_ = ngx_modules[m];
|
||||
} else {
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0,
|
||||
"pagespeed: cannot set gzip_vary, signature mismatch");
|
||||
other_signature_mismatch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
initialized_ = true;
|
||||
if (gzip_signature_mismatch) {
|
||||
return; // Already logged error.
|
||||
} else if (!enabled_) {
|
||||
// Looked through all the available commands and didn't find the "gzip" one.
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0, "pagespeed: cannot set gzip, command not found");
|
||||
return;
|
||||
} else if (other_signature_mismatch) {
|
||||
return; // Already logged error.
|
||||
} else if (!gzip_vary_command_.command_) {
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0, "pagespeed: missing gzip_vary");
|
||||
return;
|
||||
} else if (!gzip_http_types_command_.command_) {
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0, "pagespeed: missing gzip_types");
|
||||
return;
|
||||
} else if (!gzip_http_version_command_.command_) {
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0, "pagespeed: missing gzip_http_version");
|
||||
return;
|
||||
} else if (!gzip_proxied_command_.command_) {
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0, "pagespeed: missing gzip_proxied");
|
||||
return;
|
||||
} else {
|
||||
return; // Success.
|
||||
}
|
||||
#else
|
||||
ngx_conf_log_error(
|
||||
NGX_LOG_WARN, cf, 0, "pagespeed: gzip not compiled into nginx");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
void* ngx_command_ctx::GetConfPtr(ngx_conf_t* cf) {
|
||||
return GetModuleConfPtr(cf) + command_->offset;
|
||||
}
|
||||
|
||||
char* ngx_command_ctx::GetModuleConfPtr(ngx_conf_t* cf) {
|
||||
return reinterpret_cast<char*>(
|
||||
ngx_http_conf_get_module_loc_conf(cf, (*(module_))));
|
||||
}
|
||||
|
||||
void NgxGZipSetter::SetNgxConfFlag(ngx_conf_t* cf,
|
||||
ngx_command_ctx* command_ctx,
|
||||
ngx_flag_t value) {
|
||||
ngx_flag_t* flag = reinterpret_cast<ngx_flag_t*>(command_ctx->GetConfPtr(cf));
|
||||
*flag = value;
|
||||
// Save the flag position for possible rollback.
|
||||
ngx_flags_set_.push_back(flag);
|
||||
}
|
||||
|
||||
void NgxGZipSetter::SetNgxConfEnum(ngx_conf_t* cf,
|
||||
ngx_command_ctx* command_ctx,
|
||||
ngx_uint_t value) {
|
||||
ngx_uint_t* enum_to_set =
|
||||
reinterpret_cast<ngx_uint_t*>(command_ctx->GetConfPtr(cf));
|
||||
*enum_to_set = value;
|
||||
ngx_uint_set_.push_back(enum_to_set);
|
||||
}
|
||||
|
||||
void NgxGZipSetter::SetNgxConfBitmask(ngx_conf_t* cf,
|
||||
ngx_command_ctx* command_ctx,
|
||||
ngx_uint_t value) {
|
||||
ngx_uint_t* enum_to_set =
|
||||
reinterpret_cast<ngx_uint_t*>(command_ctx->GetConfPtr(cf));
|
||||
*enum_to_set = value;
|
||||
ngx_uint_set_.push_back(enum_to_set);
|
||||
}
|
||||
|
||||
// These are the content types we want to compress.
|
||||
ngx_str_t gzip_http_types[] = {
|
||||
ngx_string("application/ecmascript"),
|
||||
ngx_string("application/javascript"),
|
||||
ngx_string("application/json"),
|
||||
ngx_string("application/pdf"),
|
||||
ngx_string("application/postscript"),
|
||||
ngx_string("application/x-javascript"),
|
||||
ngx_string("image/svg+xml"),
|
||||
ngx_string("text/css"),
|
||||
ngx_string("text/csv"),
|
||||
// ngx_string("text/html"), // This is the default implied value.
|
||||
ngx_string("text/javascript"),
|
||||
ngx_string("text/plain"),
|
||||
ngx_string("text/xml"),
|
||||
ngx_null_string // Indicates end of array.
|
||||
};
|
||||
|
||||
gzs_enable_result NgxGZipSetter::SetGZipForLocation(ngx_conf_t* cf,
|
||||
bool value) {
|
||||
if (!enabled_) {
|
||||
return kEnableGZipNotEnabled;
|
||||
}
|
||||
if (gzip_command_.command_) {
|
||||
SetNgxConfFlag(cf, &gzip_command_, value);
|
||||
}
|
||||
return kEnableGZipOk;
|
||||
}
|
||||
|
||||
void NgxGZipSetter::EnableGZipForLocation(ngx_conf_t* cf) {
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// When we get called twice for the same location{}, we ignore the second call
|
||||
// to prevent adding duplicate gzip http types and so on.
|
||||
ngx_flag_t* flag =
|
||||
reinterpret_cast<ngx_flag_t*>(gzip_command_.GetConfPtr(cf));
|
||||
if (*flag == 1) {
|
||||
return;
|
||||
}
|
||||
SetGZipForLocation(cf, true);
|
||||
if (gzip_vary_command_.command_) {
|
||||
SetNgxConfFlag(cf, &gzip_vary_command_, 1);
|
||||
}
|
||||
if (gzip_http_version_command_.command_) {
|
||||
SetNgxConfEnum(cf, &gzip_http_version_command_, NGX_HTTP_VERSION_10);
|
||||
}
|
||||
if (gzip_proxied_command_.command_) {
|
||||
SetNgxConfBitmask(
|
||||
cf, &gzip_http_version_command_, NGX_HTTP_GZIP_PROXIED_ANY);
|
||||
}
|
||||
|
||||
// This is actually the most prone to future API changes, because gzip_types
|
||||
// is not a simple type like ngx_flag_t. The signature check should be enough
|
||||
// to prevent problems.
|
||||
AddGZipHTTPTypes(cf);
|
||||
return;
|
||||
}
|
||||
|
||||
void NgxGZipSetter::AddGZipHTTPTypes(ngx_conf_t* cf) {
|
||||
if (gzip_http_types_command_.command_) {
|
||||
// Following should not happen, but if it does return gracefully.
|
||||
if (cf->args->nalloc < 2) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"pagespeed: unexpected small cf->args in gzip_types");
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_command_t* command = gzip_http_types_command_.command_;
|
||||
char* gzip_conf = reinterpret_cast<char* >(
|
||||
gzip_http_types_command_.GetModuleConfPtr(cf));
|
||||
|
||||
// Backup the old settings.
|
||||
ngx_str_t old_elt0 = reinterpret_cast<ngx_str_t*>(cf->args->elts)[0];
|
||||
ngx_str_t old_elt1 = reinterpret_cast<ngx_str_t*>(cf->args->elts)[1];
|
||||
ngx_uint_t old_nelts = cf->args->nelts;
|
||||
|
||||
// Setup first arg.
|
||||
ngx_str_t gzip_types_string = ngx_string("gzip_types");
|
||||
reinterpret_cast<ngx_str_t*>(cf->args->elts)[0] = gzip_types_string;
|
||||
cf->args->nelts = 2;
|
||||
|
||||
ngx_str_t* http_types = gzip_http_types;
|
||||
while (http_types->data) {
|
||||
ngx_str_t d;
|
||||
// We allocate the http type on the configuration pool and actually
|
||||
// leak this if we rollback. This does not seem to be a big problem,
|
||||
// because nginx also allocates tokens in ngx_conf_file.c and does not
|
||||
// free them. This way they can be used safely by configurations.
|
||||
// We must use a copy of gzip_http_types array here because nginx will
|
||||
// manipulate the values.
|
||||
// TODO(kspoelstra): better would be to allocate once on init and not
|
||||
// every time we enable gzip. This needs further investigation, sharing
|
||||
// tokens might be problematic.
|
||||
// For now I think it is not a large problem. This might add up in case
|
||||
// of a large multi server/location config with a lot of "pagespeed on"
|
||||
// directives.
|
||||
// Estimates are 300-400KB for 1000 times "pagespeed on".
|
||||
d.data = reinterpret_cast<u_char*>(
|
||||
ngx_pnalloc(cf->pool, http_types->len + 1));
|
||||
snprintf(reinterpret_cast<char*>(d.data), http_types->len + 1, "%s",
|
||||
reinterpret_cast<const char*>(http_types->data));
|
||||
d.len = http_types->len;
|
||||
reinterpret_cast<ngx_str_t*>(cf->args->elts)[1] = d;
|
||||
// Call the original setter.
|
||||
ngx_http_types_slot(cf, command, gzip_conf);
|
||||
http_types++;
|
||||
}
|
||||
|
||||
// Restore args.
|
||||
cf->args->nelts = old_nelts;
|
||||
reinterpret_cast<ngx_str_t*>(cf->args->elts)[1] = old_elt1;
|
||||
reinterpret_cast<ngx_str_t*>(cf->args->elts)[0] = old_elt0;
|
||||
|
||||
// Backup configuration location for rollback.
|
||||
ngx_httptypes_set_.push_back(gzip_conf + command->offset);
|
||||
}
|
||||
}
|
||||
|
||||
void NgxGZipSetter::RollBackAndDisable(ngx_conf_t* cf) {
|
||||
ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0,
|
||||
"pagespeed: rollback gzip, explicit configuration");
|
||||
for (std::vector<ngx_flag_t*>::iterator i = ngx_flags_set_.begin();
|
||||
i != ngx_flags_set_.end(); ++i) {
|
||||
*(*i)=NGX_CONF_UNSET;
|
||||
}
|
||||
for (std::vector<ngx_uint_t*>::iterator i = ngx_uint_set_.begin();
|
||||
i != ngx_uint_set_.end(); ++i) {
|
||||
*(*i)=NGX_CONF_UNSET_UINT;
|
||||
}
|
||||
for (std::vector<void*>::iterator i = ngx_httptypes_set_.begin();
|
||||
i != ngx_httptypes_set_.end(); ++i) {
|
||||
ngx_array_t** type_array = reinterpret_cast<ngx_array_t**>(*i);
|
||||
ngx_array_destroy(*type_array);
|
||||
*type_array = NULL;
|
||||
}
|
||||
enabled_ = 0;
|
||||
}
|
||||
|
||||
} // namespace net_instaweb
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2014 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: kspoelstra@we-amp.com (Kees Spoelstra)
|
||||
|
||||
/*
|
||||
* NgxGZipSetter sets up gzip for pagespeed
|
||||
* with the following configuration:
|
||||
* gzip on;
|
||||
* gzip_vary on;
|
||||
* gzip_types application/ecmascript;
|
||||
* gzip_types application/javascript;
|
||||
* gzip_types application/json;
|
||||
* gzip_types application/pdf;
|
||||
* gzip_types application/postscript;
|
||||
* gzip_types application/x-javascript;
|
||||
* gzip_types image/svg+xml;
|
||||
* gzip_types text/css;
|
||||
* gzip_types text/csv;
|
||||
* gzip_types text/javascript;
|
||||
* gzip_types text/plain;
|
||||
* gzip_types text/xml;
|
||||
* gzip_http_version 1.0;
|
||||
*
|
||||
* If there is an explicit gzip configuration in the nginx.conf
|
||||
* pagespeed will rollback the set configuration and let the
|
||||
* user decide what the configuration will be.
|
||||
*
|
||||
* It manipulates the configuration by manipulating ngx_flag_t
|
||||
* and ngx_uint_t settings directly and using the nginx setter for
|
||||
* gzip_http_types.
|
||||
* This is probably a safe way to do it. If this mechanism
|
||||
* changes all non nginx module setup & configuration will
|
||||
* fail.
|
||||
*/
|
||||
|
||||
#ifndef NGX_GZIP_SETTER_H_
|
||||
#define NGX_GZIP_SETTER_H_
|
||||
|
||||
extern "C" {
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
}
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ngx_pagespeed.h"
|
||||
|
||||
#include "net/instaweb/util/public/basictypes.h"
|
||||
|
||||
namespace net_instaweb {
|
||||
|
||||
// We need this class because configuration for gzip is in different modules, so
|
||||
// just saving the command will not work.
|
||||
class ngx_command_ctx {
|
||||
public:
|
||||
ngx_command_ctx() : command_(NULL), module_(NULL) { }
|
||||
void* GetConfPtr(ngx_conf_t* cf);
|
||||
char* GetModuleConfPtr(ngx_conf_t* cf);
|
||||
ngx_command_t* command_;
|
||||
ngx_module_t* module_;
|
||||
};
|
||||
|
||||
enum gzs_enable_result {
|
||||
kEnableGZipOk,
|
||||
kEnableGZipPartial,
|
||||
kEnableGZipNotEnabled
|
||||
};
|
||||
|
||||
class NgxGZipSetter {
|
||||
std::vector<ngx_flag_t*> ngx_flags_set_;
|
||||
std::vector<ngx_uint_t*> ngx_uint_set_;
|
||||
std::vector<void*> ngx_httptypes_set_;
|
||||
ngx_command_ctx gzip_command_;
|
||||
ngx_command_ctx gzip_http_types_command_;
|
||||
ngx_command_ctx gzip_proxied_command_;
|
||||
ngx_command_ctx gzip_vary_command_;
|
||||
ngx_command_ctx gzip_http_version_command_;
|
||||
bool enabled_;
|
||||
bool initialized_;
|
||||
|
||||
public:
|
||||
NgxGZipSetter();
|
||||
~NgxGZipSetter();
|
||||
void Init(ngx_conf_t* cf);
|
||||
|
||||
void SetNgxConfFlag(ngx_conf_t* cf,
|
||||
ngx_command_ctx* command_ctx,
|
||||
ngx_flag_t value);
|
||||
void SetNgxConfEnum(ngx_conf_t* cf,
|
||||
ngx_command_ctx* command_ctx,
|
||||
ngx_uint_t value);
|
||||
void SetNgxConfBitmask(ngx_conf_t* cf,
|
||||
ngx_command_ctx* command_ctx,
|
||||
ngx_uint_t value);
|
||||
void EnableGZipForLocation(ngx_conf_t* cf);
|
||||
gzs_enable_result SetGZipForLocation(ngx_conf_t* cf, bool value);
|
||||
void AddGZipHTTPTypes(ngx_conf_t* cf);
|
||||
void RollBackAndDisable(ngx_conf_t* cf);
|
||||
|
||||
bool enabled() { return enabled_; }
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(NgxGZipSetter);
|
||||
};
|
||||
|
||||
extern NgxGZipSetter g_gzip_setter;
|
||||
|
||||
} // namespace net_instaweb
|
||||
|
||||
#endif // NGX_GZIP_SETTER_H_
|
||||
@@ -56,11 +56,9 @@ extern "C" {
|
||||
|
||||
namespace net_instaweb {
|
||||
|
||||
NgxMessageHandler::NgxMessageHandler(AbstractMutex* mutex)
|
||||
: mutex_(mutex),
|
||||
buffer_(NULL),
|
||||
NgxMessageHandler::NgxMessageHandler(Timer* timer, AbstractMutex* mutex)
|
||||
: SystemMessageHandler(timer, mutex),
|
||||
log_(NULL) {
|
||||
SetPidString(static_cast<int64>(getpid()));
|
||||
}
|
||||
|
||||
// Installs a signal handler for common crash signals, that tries to print
|
||||
@@ -73,14 +71,6 @@ void NgxMessageHandler::InstallCrashHandler(ngx_log_t* log) {
|
||||
signal(SIGSEGV, signal_handler);
|
||||
}
|
||||
|
||||
bool NgxMessageHandler::Dump(Writer* writer) {
|
||||
// Can't dump before SharedCircularBuffer is set up.
|
||||
if (buffer_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
return buffer_->Dump(writer, &handler_);
|
||||
}
|
||||
|
||||
ngx_uint_t NgxMessageHandler::GetNgxLogLevel(MessageType type) {
|
||||
switch (type) {
|
||||
case kInfo:
|
||||
@@ -98,11 +88,6 @@ ngx_uint_t NgxMessageHandler::GetNgxLogLevel(MessageType type) {
|
||||
return NGX_LOG_ALERT;
|
||||
}
|
||||
|
||||
void NgxMessageHandler::set_buffer(SharedCircularBuffer* buff) {
|
||||
ScopedMutex lock(mutex_.get());
|
||||
buffer_ = buff;
|
||||
}
|
||||
|
||||
void NgxMessageHandler::MessageVImpl(MessageType type, const char* msg,
|
||||
va_list args) {
|
||||
ngx_uint_t log_level = GetNgxLogLevel(type);
|
||||
@@ -113,25 +98,8 @@ void NgxMessageHandler::MessageVImpl(MessageType type, const char* msg,
|
||||
} else {
|
||||
GoogleMessageHandler::MessageVImpl(type, msg, args);
|
||||
}
|
||||
|
||||
// Prepare a log message for the SharedCircularBuffer only.
|
||||
// Prepend time and severity to message.
|
||||
// Format is [time] [severity] [pid] message.
|
||||
GoogleString message;
|
||||
GoogleString time;
|
||||
PosixTimer timer;
|
||||
if (!ConvertTimeToString(timer.NowMs(), &time)) {
|
||||
time = "?";
|
||||
}
|
||||
StrAppend(&message, "[", time, "] ",
|
||||
"[", MessageTypeToString(type), "] ");
|
||||
StrAppend(&message, pid_string_, " ", formatted_message, "\n");
|
||||
{
|
||||
ScopedMutex lock(mutex_.get());
|
||||
if (buffer_ != NULL) {
|
||||
buffer_->Write(message);
|
||||
}
|
||||
}
|
||||
AddMessageToBuffer(type, formatted_message);
|
||||
}
|
||||
|
||||
void NgxMessageHandler::FileMessageVImpl(MessageType type, const char* file,
|
||||
|
||||
@@ -24,44 +24,30 @@ extern "C" {
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
#include "net/instaweb/system/public/system_message_handler.h"
|
||||
#include "net/instaweb/util/public/basictypes.h"
|
||||
#include "net/instaweb/util/public/google_message_handler.h"
|
||||
#include "net/instaweb/util/public/message_handler.h"
|
||||
#include "net/instaweb/util/public/scoped_ptr.h"
|
||||
#include "net/instaweb/util/public/string.h"
|
||||
#include "net/instaweb/util/public/string_util.h"
|
||||
|
||||
namespace net_instaweb {
|
||||
|
||||
class AbstractMutex;
|
||||
class SharedCircularBuffer;
|
||||
class Timer;
|
||||
class Writer;
|
||||
|
||||
// Implementation of a message handler that uses ngx_log_error()
|
||||
// logging to emit messages, with a fallback to GoogleMessageHandler
|
||||
class NgxMessageHandler : public GoogleMessageHandler {
|
||||
class NgxMessageHandler : public SystemMessageHandler {
|
||||
public:
|
||||
explicit NgxMessageHandler(AbstractMutex* mutex);
|
||||
explicit NgxMessageHandler(Timer* timer, AbstractMutex* mutex);
|
||||
|
||||
// Installs a signal handler for common crash signals that tries to print
|
||||
// out a backtrace.
|
||||
static void InstallCrashHandler(ngx_log_t* log);
|
||||
|
||||
// When NgxRewriteDriver instantiates the NgxMessageHandlers, the
|
||||
// SharedCircularBuffer and ngx_log_t are not available yet. These
|
||||
// will later be set in RootInit/Childinit
|
||||
// Messages logged before that will be passed on to handler_;
|
||||
void set_buffer(SharedCircularBuffer* buff);
|
||||
void set_log(ngx_log_t* log) { log_ = log; }
|
||||
ngx_log_t* log() { return log_; }
|
||||
|
||||
void SetPidString(const int64 pid) {
|
||||
pid_string_ = StrCat("[", Integer64ToString(pid), "]");
|
||||
}
|
||||
// Dump contents of SharedCircularBuffer.
|
||||
bool Dump(Writer* writer);
|
||||
|
||||
protected:
|
||||
virtual void MessageVImpl(MessageType type, const char* msg, va_list args);
|
||||
|
||||
@@ -70,13 +56,6 @@ class NgxMessageHandler : public GoogleMessageHandler {
|
||||
|
||||
private:
|
||||
ngx_uint_t GetNgxLogLevel(MessageType type);
|
||||
|
||||
scoped_ptr<AbstractMutex> mutex_;
|
||||
GoogleString pid_string_;
|
||||
// handler_ is used as a fallback when we can not use ngx_log_errort
|
||||
// It's also used when calling Dump on the internal SharedCircularBuffer
|
||||
GoogleMessageHandler handler_;
|
||||
SharedCircularBuffer* buffer_;
|
||||
ngx_log_t* log_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NgxMessageHandler);
|
||||
|
||||
+587
-251
File diff suppressed because it is too large
Load Diff
@@ -103,6 +103,10 @@ typedef struct {
|
||||
RewriteDriver* driver;
|
||||
InPlaceResourceRecorder* recorder;
|
||||
ResponseHeaders* ipro_response_headers;
|
||||
|
||||
// We need to remember the URL here as well since we may modify what NGX
|
||||
// gets by stripping our special query params and honoring X-Forwarded-Proto.
|
||||
GoogleString url_string;
|
||||
} ps_request_ctx_t;
|
||||
|
||||
|
||||
@@ -117,6 +121,8 @@ ngx_int_t copy_response_headers_to_ngx(
|
||||
const ResponseHeaders& pagespeed_headers,
|
||||
PreserveCachingHeaders preserve_caching_headers);
|
||||
|
||||
StringPiece ps_determine_host(ngx_http_request_t* r);
|
||||
|
||||
} // namespace net_instaweb
|
||||
|
||||
#endif // NGX_PAGESPEED_H_
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "net/instaweb/rewriter/public/rewrite_driver.h"
|
||||
#include "net/instaweb/rewriter/public/rewrite_driver_factory.h"
|
||||
#include "net/instaweb/rewriter/public/server_context.h"
|
||||
#include "net/instaweb/rewriter/public/static_asset_manager.h"
|
||||
#include "net/instaweb/system/public/in_place_resource_recorder.h"
|
||||
#include "net/instaweb/system/public/serf_url_async_fetcher.h"
|
||||
#include "net/instaweb/system/public/system_caches.h"
|
||||
@@ -63,9 +62,6 @@ class UrlAsyncFetcher;
|
||||
class UrlFetcher;
|
||||
class Writer;
|
||||
|
||||
const char NgxRewriteDriverFactory::kStaticAssetPrefix[] =
|
||||
"/ngx_pagespeed_static/";
|
||||
|
||||
class SharedCircularBuffer;
|
||||
|
||||
NgxRewriteDriverFactory::NgxRewriteDriverFactory(
|
||||
@@ -75,17 +71,20 @@ NgxRewriteDriverFactory::NgxRewriteDriverFactory(
|
||||
NULL /* default shared memory runtime */, hostname, port),
|
||||
main_conf_(NULL),
|
||||
threads_started_(false),
|
||||
use_per_vhost_statistics_(false),
|
||||
ngx_message_handler_(new NgxMessageHandler(thread_system()->NewMutex())),
|
||||
ngx_message_handler_(
|
||||
new NgxMessageHandler(timer(), thread_system()->NewMutex())),
|
||||
ngx_html_parse_message_handler_(
|
||||
new NgxMessageHandler(thread_system()->NewMutex())),
|
||||
install_crash_handler_(false),
|
||||
new NgxMessageHandler(timer(), thread_system()->NewMutex())),
|
||||
log_(NULL),
|
||||
resolver_timeout_(NGX_CONF_UNSET_MSEC),
|
||||
use_native_fetcher_(false),
|
||||
// 100 Aligns to nginx's server-side default.
|
||||
native_fetcher_max_keepalive_requests_(100),
|
||||
ngx_shared_circular_buffer_(NULL),
|
||||
hostname_(hostname.as_string()),
|
||||
port_(port) {
|
||||
port_(port),
|
||||
process_script_variables_(false),
|
||||
process_script_variables_set_(false) {
|
||||
InitializeDefaultOptions();
|
||||
default_options()->set_beacon_url("/ngx_pagespeed_beacon");
|
||||
SystemRewriteOptions* system_options = dynamic_cast<SystemRewriteOptions*>(
|
||||
@@ -115,6 +114,7 @@ UrlAsyncFetcher* NgxRewriteDriverFactory::AllocateFetcher(
|
||||
resolver_timeout_,
|
||||
config->blocking_fetch_timeout_ms(),
|
||||
resolver_,
|
||||
native_fetcher_max_keepalive_requests_,
|
||||
thread_system(),
|
||||
message_handler());
|
||||
ngx_url_async_fetchers_.push_back(fetcher);
|
||||
@@ -151,11 +151,6 @@ RewriteOptions* NgxRewriteDriverFactory::NewRewriteOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
void NgxRewriteDriverFactory::InitStaticAssetManager(
|
||||
StaticAssetManager* static_asset_manager) {
|
||||
static_asset_manager->set_library_url_prefix(kStaticAssetPrefix);
|
||||
}
|
||||
|
||||
bool NgxRewriteDriverFactory::InitNgxUrlAsyncFetchers() {
|
||||
log_ = ngx_cycle->log;
|
||||
for (size_t i = 0; i < ngx_url_async_fetchers_.size(); ++i) {
|
||||
@@ -217,7 +212,7 @@ void NgxRewriteDriverFactory::StartThreads() {
|
||||
|
||||
void NgxRewriteDriverFactory::LoggingInit(ngx_log_t* log) {
|
||||
net_instaweb::log_message_handler::Install(log);
|
||||
if (install_crash_handler_) {
|
||||
if (install_crash_handler()) {
|
||||
NgxMessageHandler::InstallCrashHandler(log);
|
||||
}
|
||||
ngx_message_handler_->set_log(log);
|
||||
@@ -234,7 +229,7 @@ void NgxRewriteDriverFactory::SetCircularBuffer(
|
||||
void NgxRewriteDriverFactory::SetServerContextMessageHandler(
|
||||
ServerContext* server_context, ngx_log_t* log) {
|
||||
NgxMessageHandler* handler = new NgxMessageHandler(
|
||||
thread_system()->NewMutex());
|
||||
timer(), thread_system()->NewMutex());
|
||||
handler->set_log(log);
|
||||
// The ngx_shared_circular_buffer_ will be NULL if MessageBufferSize hasn't
|
||||
// been raised from its default of 0.
|
||||
|
||||
@@ -45,14 +45,11 @@ class NgxUrlAsyncFetcher;
|
||||
class SharedCircularBuffer;
|
||||
class SharedMemRefererStatistics;
|
||||
class SlowWorker;
|
||||
class StaticAssetManager;
|
||||
class Statistics;
|
||||
class SystemThreadSystem;
|
||||
|
||||
class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
||||
public:
|
||||
static const char kStaticAssetPrefix[];
|
||||
|
||||
// We take ownership of the thread system.
|
||||
explicit NgxRewriteDriverFactory(
|
||||
const ProcessContext& process_context,
|
||||
@@ -68,9 +65,6 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
||||
// Create a new RewriteOptions. In this implementation it will be an
|
||||
// NgxRewriteOptions.
|
||||
virtual RewriteOptions* NewRewriteOptions();
|
||||
// Initializes the StaticAssetManager.
|
||||
virtual void InitStaticAssetManager(
|
||||
StaticAssetManager* static_asset_manager);
|
||||
virtual ServerContext* NewDecodingServerContext();
|
||||
bool InitNgxUrlAsyncFetchers();
|
||||
// Check resolver configured or not.
|
||||
@@ -98,18 +92,6 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
||||
|
||||
void set_main_conf(NgxRewriteOptions* main_conf) { main_conf_ = main_conf; }
|
||||
|
||||
bool use_per_vhost_statistics() const {
|
||||
return use_per_vhost_statistics_;
|
||||
}
|
||||
void set_use_per_vhost_statistics(bool x) {
|
||||
use_per_vhost_statistics_ = x;
|
||||
}
|
||||
bool install_crash_handler() const {
|
||||
return install_crash_handler_;
|
||||
}
|
||||
void set_install_crash_handler(bool x) {
|
||||
install_crash_handler_ = x;
|
||||
}
|
||||
void set_resolver(ngx_resolver_t* resolver) {
|
||||
resolver_ = resolver;
|
||||
}
|
||||
@@ -123,16 +105,14 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
||||
void set_use_native_fetcher(bool x) {
|
||||
use_native_fetcher_ = x;
|
||||
}
|
||||
void set_rate_limit_background_fetches(bool x) {
|
||||
rate_limit_background_fetches_ = x;
|
||||
int native_fetcher_max_keepalive_requests() {
|
||||
return native_fetcher_max_keepalive_requests_;
|
||||
}
|
||||
|
||||
// We use a beacon handler to collect data for critical images,
|
||||
// css, etc., so filters should be configured accordingly.
|
||||
//
|
||||
// TODO(jefftk): move to SystemRewriteDriverFactory
|
||||
virtual bool UseBeaconResultsInFilters() const {
|
||||
return true;
|
||||
void set_native_fetcher_max_keepalive_requests(int x) {
|
||||
native_fetcher_max_keepalive_requests_ = x;
|
||||
}
|
||||
bool process_script_variables() {
|
||||
return process_script_variables_;
|
||||
}
|
||||
|
||||
void LoggingInit(ngx_log_t* log);
|
||||
@@ -141,6 +121,15 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
||||
|
||||
virtual void SetCircularBuffer(SharedCircularBuffer* buffer);
|
||||
|
||||
bool SetProcessScriptVariables(bool process_script_variables) {
|
||||
if (!process_script_variables_set_) {
|
||||
process_script_variables_ = process_script_variables;
|
||||
process_script_variables_set_ = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
Timer* timer_;
|
||||
|
||||
@@ -149,20 +138,16 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
||||
NgxRewriteOptions* main_conf_;
|
||||
|
||||
bool threads_started_;
|
||||
// If true, we'll have a separate statistics object for each vhost
|
||||
// (along with a global aggregate), rather than just a single object
|
||||
// aggregating all of them.
|
||||
bool use_per_vhost_statistics_;
|
||||
NgxMessageHandler* ngx_message_handler_;
|
||||
NgxMessageHandler* ngx_html_parse_message_handler_;
|
||||
bool install_crash_handler_;
|
||||
|
||||
std::vector<NgxUrlAsyncFetcher*> ngx_url_async_fetchers_;
|
||||
ngx_log_t* log_;
|
||||
ngx_msec_t resolver_timeout_;
|
||||
ngx_resolver_t* resolver_;
|
||||
bool use_native_fetcher_;
|
||||
bool rate_limit_background_fetches_;
|
||||
int native_fetcher_max_keepalive_requests_;
|
||||
|
||||
typedef std::set<NgxMessageHandler*> NgxMessageHandlerSet;
|
||||
NgxMessageHandlerSet server_context_message_handlers_;
|
||||
|
||||
@@ -172,6 +157,8 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
||||
|
||||
GoogleString hostname_;
|
||||
int port_;
|
||||
bool process_script_variables_;
|
||||
bool process_script_variables_set_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NgxRewriteDriverFactory);
|
||||
};
|
||||
|
||||
+235
-65
@@ -31,17 +31,26 @@ extern "C" {
|
||||
#include "net/instaweb/rewriter/public/file_load_policy.h"
|
||||
#include "net/instaweb/rewriter/public/rewrite_options.h"
|
||||
#include "net/instaweb/system/public/system_caches.h"
|
||||
#include "net/instaweb/util/public/message_handler.h"
|
||||
#include "net/instaweb/util/public/timer.h"
|
||||
|
||||
namespace net_instaweb {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kStatisticsPath[] = "StatisticsPath";
|
||||
const char kGlobalStatisticsPath[] = "GlobalStatisticsPath";
|
||||
const char kConsolePath[] = "ConsolePath";
|
||||
const char kMessagesPath[] = "MessagesPath";
|
||||
const char kAdminPath[] = "AdminPath";
|
||||
const char kGlobalAdminPath[] = "GlobalAdminPath";
|
||||
|
||||
// These options are copied from mod_instaweb.cc, where APACHE_CONFIG_OPTIONX
|
||||
// indicates that they can not be set at the directory/location level. They set
|
||||
// options in the RewriteDriverFactory, so they do not appear in RewriteOptions.
|
||||
// They are not alphabetized on purpose, but rather left in the same order as in
|
||||
// mod_instaweb.cc in case we end up needing to compare.
|
||||
// options in the RewriteDriverFactory, so they're entirely global and do not
|
||||
// appear in RewriteOptions. They are not alphabetized on purpose, but rather
|
||||
// left in the same order as in mod_instaweb.cc in case we end up needing to
|
||||
// compare.
|
||||
// TODO(oschaaf): this duplication is a short term solution.
|
||||
const char* const server_only_options[] = {
|
||||
"FetcherTimeoutMs",
|
||||
@@ -54,6 +63,7 @@ const char* const server_only_options[] = {
|
||||
"MessageBufferSize",
|
||||
"NumRewriteThreads",
|
||||
"NumExpensiveRewriteThreads",
|
||||
"StaticAssetPrefix",
|
||||
"TrackOriginalContentLength",
|
||||
"UsePerVHostStatistics", // TODO(anupama): What to do about "No longer used"
|
||||
"BlockingRewriteRefererUrls",
|
||||
@@ -62,16 +72,16 @@ const char* const server_only_options[] = {
|
||||
"LoadFromFileMatch",
|
||||
"LoadFromFileRule",
|
||||
"LoadFromFileRuleMatch",
|
||||
"UseNativeFetcher"
|
||||
"UseNativeFetcher",
|
||||
"NativeFetcherMaxKeepaliveRequests"
|
||||
};
|
||||
|
||||
// Options that can only be used in the main (http) option scope.
|
||||
const char* const main_only_options[] = {
|
||||
"UseNativeFetcher"
|
||||
"UseNativeFetcher",
|
||||
"NativeFetcherMaxKeepaliveRequests"
|
||||
};
|
||||
|
||||
const char kNgxPagespeedStatisticsHandlerPath[] = "/ngx_pagespeed_statistics";
|
||||
|
||||
} // namespace
|
||||
|
||||
RewriteOptions::Properties* NgxRewriteOptions::ngx_properties_ = NULL;
|
||||
@@ -90,16 +100,35 @@ NgxRewriteOptions::NgxRewriteOptions(ThreadSystem* thread_system)
|
||||
void NgxRewriteOptions::Init() {
|
||||
DCHECK(ngx_properties_ != NULL)
|
||||
<< "Call NgxRewriteOptions::Initialize() before construction";
|
||||
clear_inherited_scripts_ = false;
|
||||
InitializeOptions(ngx_properties_);
|
||||
|
||||
// Nginx-specific default.
|
||||
// TODO(sligocki): Get rid of this line and let both Apache and Nginx use
|
||||
// /pagespeed_statistics as the handler.
|
||||
statistics_handler_path_.set_default(kNgxPagespeedStatisticsHandlerPath);
|
||||
}
|
||||
|
||||
void NgxRewriteOptions::AddProperties() {
|
||||
// Nothing ngx-specific for now.
|
||||
// Nginx-specific options.
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::statistics_path_, "nsp", kStatisticsPath,
|
||||
kServerScope, "Set the statistics path. Ex: /ngx_pagespeed_statistics",
|
||||
false);
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::global_statistics_path_, "ngsp",
|
||||
kGlobalStatisticsPath, kProcessScope,
|
||||
"Set the global statistics path. Ex: /ngx_pagespeed_global_statistics",
|
||||
false);
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::console_path_, "ncp", kConsolePath, kServerScope,
|
||||
"Set the console path. Ex: /pagespeed_console", false);
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::messages_path_, "nmp", kMessagesPath,
|
||||
kServerScope, "Set the messages path. Ex: /ngx_pagespeed_message",
|
||||
false);
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::admin_path_, "nap", kAdminPath,
|
||||
kServerScope, "Set the admin path. Ex: /pagespeed_admin", false);
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::global_admin_path_, "ngap", kGlobalAdminPath,
|
||||
kProcessScope, "Set the global admin path. Ex: /pagespeed_global_admin",
|
||||
false);
|
||||
|
||||
MergeSubclassProperties(ngx_properties_);
|
||||
|
||||
@@ -229,7 +258,7 @@ const char* ps_error_string_for_option(
|
||||
const char* NgxRewriteOptions::ParseAndSetOptions(
|
||||
StringPiece* args, int n_args, ngx_pool_t* pool, MessageHandler* handler,
|
||||
NgxRewriteDriverFactory* driver_factory,
|
||||
RewriteOptions::OptionScope scope) {
|
||||
RewriteOptions::OptionScope scope, ngx_conf_t* cf, bool compile_scripts) {
|
||||
CHECK_GE(n_args, 1);
|
||||
|
||||
StringPiece directive = args[0];
|
||||
@@ -245,77 +274,139 @@ const char* NgxRewriteOptions::ParseAndSetOptions(
|
||||
pool, directive, "cannot be set at this scope.");
|
||||
}
|
||||
|
||||
ScriptLine* script_line;
|
||||
script_line = NULL;
|
||||
// Only allow script variable support for LoadFromFile for now.
|
||||
// Note that LoadFromFile should not be scriptable on wildcard hosts,
|
||||
// as browsers might be able to manipulate its natural use-case: $http_host.
|
||||
if (!StringCaseStartsWith(directive, "LoadFromFile")) {
|
||||
compile_scripts = false;
|
||||
}
|
||||
|
||||
if (n_args == 1 && StringCaseEqual(directive, "ClearInheritedScripts")) {
|
||||
clear_inherited_scripts_ = true;
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
if (compile_scripts) {
|
||||
CHECK(cf != NULL);
|
||||
int i;
|
||||
// Skip the first arg which is always 'pagespeed'
|
||||
for (i = 1; i < n_args; i++) {
|
||||
ngx_str_t script_source;
|
||||
|
||||
script_source.len = args[i].as_string().length();
|
||||
std::string tmp = args[i].as_string();
|
||||
script_source.data = reinterpret_cast<u_char*>(
|
||||
const_cast<char*>(tmp.c_str()));
|
||||
|
||||
if (ngx_http_script_variables_count(&script_source) > 0) {
|
||||
ngx_http_script_compile_t* sc =
|
||||
reinterpret_cast<ngx_http_script_compile_t*>(
|
||||
ngx_pcalloc(cf->pool, sizeof(ngx_http_script_compile_t)));
|
||||
sc->cf = cf;
|
||||
sc->source = &script_source;
|
||||
sc->lengths = reinterpret_cast<ngx_array_t**>(
|
||||
ngx_pcalloc(cf->pool, sizeof(ngx_array_t*)));
|
||||
sc->values = reinterpret_cast<ngx_array_t**>(
|
||||
ngx_pcalloc(cf->pool, sizeof(ngx_array_t*)));
|
||||
sc->variables = 1;
|
||||
sc->complete_lengths = 1;
|
||||
sc->complete_values = 1;
|
||||
if (ngx_http_script_compile(sc) != NGX_OK) {
|
||||
return ps_error_string_for_option(
|
||||
pool, directive, "Failed to compile script variables");
|
||||
} else {
|
||||
if (script_line == NULL) {
|
||||
script_line = new ScriptLine(args, n_args, scope);
|
||||
}
|
||||
script_line->AddScriptAndArgIndex(sc, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (script_line != NULL) {
|
||||
script_lines_.push_back(RefCountedPtr<ScriptLine>(script_line));
|
||||
// We have found script variables in the current configuration line, and
|
||||
// prepared the associated rewriteoptions for that.
|
||||
// We will defer parsing, validation and processing of this line to
|
||||
// request time. That means we are done handling this configuration line.
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
}
|
||||
|
||||
GoogleString msg;
|
||||
OptionSettingResult result;
|
||||
if (n_args == 1) {
|
||||
result = ParseAndSetOptions0(directive, &msg, handler);
|
||||
} else if (n_args == 2) {
|
||||
StringPiece arg = args[1];
|
||||
// TODO(morlovich): Remove these special hacks, and handle these via
|
||||
// ParseAndSetOptionFromEnum1.
|
||||
if (IsDirective(directive, "UsePerVHostStatistics")) {
|
||||
if (IsDirective(directive, "UseNativeFetcher")) {
|
||||
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
|
||||
arg, driver_factory,
|
||||
&NgxRewriteDriverFactory::set_use_per_vhost_statistics);
|
||||
} else if (IsDirective(directive, "InstallCrashHandler")) {
|
||||
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
|
||||
arg, driver_factory,
|
||||
&NgxRewriteDriverFactory::set_install_crash_handler);
|
||||
} else if (IsDirective(directive, "MessageBufferSize")) {
|
||||
int message_buffer_size;
|
||||
bool ok = StringToInt(arg.as_string(), &message_buffer_size);
|
||||
if (ok && message_buffer_size >= 0) {
|
||||
driver_factory->set_message_buffer_size(message_buffer_size);
|
||||
&NgxRewriteDriverFactory::set_use_native_fetcher);
|
||||
} else if (IsDirective(directive, "NativeFetcherMaxKeepaliveRequests")) {
|
||||
int max_keepalive_requests;
|
||||
if (StringToInt(arg, &max_keepalive_requests) &&
|
||||
max_keepalive_requests > 0) {
|
||||
driver_factory->set_native_fetcher_max_keepalive_requests(
|
||||
max_keepalive_requests);
|
||||
result = RewriteOptions::kOptionOk;
|
||||
} else {
|
||||
result = RewriteOptions::kOptionValueInvalid;
|
||||
}
|
||||
} else if (IsDirective(directive, "UseNativeFetcher")) {
|
||||
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
|
||||
arg, driver_factory,
|
||||
&NgxRewriteDriverFactory::set_use_native_fetcher);
|
||||
} else if (IsDirective(directive, "RateLimitBackgroundFetches")) {
|
||||
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
|
||||
arg, driver_factory,
|
||||
&NgxRewriteDriverFactory::set_rate_limit_background_fetches);
|
||||
} else if (IsDirective(directive, "ForceCaching")) {
|
||||
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
|
||||
arg, driver_factory,
|
||||
&SystemRewriteDriverFactory::set_force_caching);
|
||||
} else if (IsDirective(directive, "ListOutstandingUrlsOnError")) {
|
||||
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
|
||||
arg, driver_factory,
|
||||
&SystemRewriteDriverFactory::list_outstanding_urls_on_error);
|
||||
} else if (IsDirective(directive, "TrackOriginalContentLength")) {
|
||||
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
|
||||
arg, driver_factory,
|
||||
&SystemRewriteDriverFactory::set_track_original_content_length);
|
||||
} else {
|
||||
result = ParseAndSetOptionFromName1(directive, args[1], &msg, handler);
|
||||
}
|
||||
} else if (n_args == 3) {
|
||||
// Short-term special handling, until this moves to common code.
|
||||
// TODO(morlovich): Clean this up.
|
||||
if (StringCaseEqual(directive, "CreateSharedMemoryMetadataCache")) {
|
||||
int64 kb = 0;
|
||||
if (!StringToInt64(args[2], &kb) || kb < 0) {
|
||||
result = RewriteOptions::kOptionValueInvalid;
|
||||
msg = "size_kb must be a positive 64-bit integer";
|
||||
} else if (StringCaseEqual("ProcessScriptVariables", args[0])) {
|
||||
if (scope == RewriteOptions::kProcessScopeStrict) {
|
||||
if (StringCaseEqual(arg, "on")) {
|
||||
if (driver_factory->SetProcessScriptVariables(true)) {
|
||||
result = RewriteOptions::kOptionOk;
|
||||
} else {
|
||||
return const_cast<char*>(
|
||||
"pagespeed ProcessScriptVariables: can only be set once");
|
||||
}
|
||||
} else if (StringCaseEqual(arg, "off")) {
|
||||
if (driver_factory->SetProcessScriptVariables(false)) {
|
||||
result = RewriteOptions::kOptionOk;
|
||||
} else {
|
||||
return const_cast<char*>(
|
||||
"pagespeed ProcessScriptVariables: can only be set once");
|
||||
}
|
||||
} else {
|
||||
return const_cast<char*>(
|
||||
"pagespeed ProcessScriptVariables: invalid value");
|
||||
}
|
||||
} else {
|
||||
bool ok = driver_factory->caches()->CreateShmMetadataCache(
|
||||
args[1].as_string(), kb, &msg);
|
||||
result = ok ? kOptionOk : kOptionValueInvalid;
|
||||
return const_cast<char*>(
|
||||
"ProcessScriptVariables is only allowed at the top level");
|
||||
}
|
||||
} else {
|
||||
result = ParseAndSetOptionFromName2(directive, args[1], args[2],
|
||||
&msg, handler);
|
||||
result = ParseAndSetOptionFromName1(directive, arg, &msg, handler);
|
||||
if (result == RewriteOptions::kOptionNameUnknown) {
|
||||
result = driver_factory->ParseAndSetOption1(
|
||||
directive,
|
||||
arg,
|
||||
scope >= RewriteOptions::kProcessScope,
|
||||
&msg,
|
||||
handler);
|
||||
}
|
||||
}
|
||||
} else if (n_args == 3) {
|
||||
result = ParseAndSetOptionFromName2(directive, args[1], args[2],
|
||||
&msg, handler);
|
||||
if (result == RewriteOptions::kOptionNameUnknown) {
|
||||
result = driver_factory->ParseAndSetOption2(
|
||||
directive,
|
||||
args[1],
|
||||
args[2],
|
||||
scope >= RewriteOptions::kProcessScope,
|
||||
&msg,
|
||||
handler);
|
||||
}
|
||||
} else if (n_args == 4) {
|
||||
result = ParseAndSetOptionFromName3(
|
||||
directive, args[1], args[2], args[3], &msg, handler);
|
||||
} else {
|
||||
return ps_error_string_for_option(
|
||||
pool, directive, "not recognized or too many arguments");
|
||||
result = RewriteOptions::kOptionNameUnknown;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
@@ -337,13 +428,92 @@ const char* NgxRewriteOptions::ParseAndSetOptions(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Execute all entries in the script_lines vector, and hand the result off to
|
||||
// ParseAndSetOptions to obtain the final option values.
|
||||
bool NgxRewriteOptions::ExecuteScriptVariables(
|
||||
ngx_http_request_t* r, MessageHandler* handler,
|
||||
NgxRewriteDriverFactory* driver_factory) {
|
||||
bool script_error = false;
|
||||
|
||||
if (script_lines_.size() > 0) {
|
||||
std::vector<RefCountedPtr<ScriptLine> >::iterator it;
|
||||
for (it = script_lines_.begin() ; it != script_lines_.end(); ++it) {
|
||||
ScriptLine* script_line = it->get();
|
||||
StringPiece args[NGX_PAGESPEED_MAX_ARGS];
|
||||
std::vector<ScriptArgIndex*>::iterator cs_it;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < script_line->n_args(); i++) {
|
||||
args[i] = script_line->args()[i];
|
||||
}
|
||||
|
||||
for (cs_it = script_line->data().begin();
|
||||
cs_it != script_line->data().end(); cs_it++) {
|
||||
ngx_http_script_compile_t* script;
|
||||
ngx_array_t* values;
|
||||
ngx_array_t* lengths;
|
||||
ngx_str_t value;
|
||||
|
||||
script = (*cs_it)->script();
|
||||
lengths = *script->lengths;
|
||||
values = *script->values;
|
||||
|
||||
if (ngx_http_script_run(r, &value, lengths->elts, 0, values->elts)
|
||||
== NULL) {
|
||||
handler->Message(kError, "ngx_http_script_run error");
|
||||
script_error = true;
|
||||
break;
|
||||
} else {
|
||||
args[(*cs_it)->index()] = str_to_string_piece(value);
|
||||
}
|
||||
}
|
||||
|
||||
const char* status = ParseAndSetOptions(args, script_line->n_args(),
|
||||
r->pool, handler, driver_factory, script_line->scope(), NULL /*cf*/,
|
||||
false /*compile scripts*/);
|
||||
|
||||
if (status != NULL) {
|
||||
script_error = true;
|
||||
handler->Message(kWarning,
|
||||
"Error setting option value from script: '%s'", status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (script_error) {
|
||||
handler->Message(kWarning,
|
||||
"Script error(s) in configuration, disabling optimization");
|
||||
set_enabled(RewriteOptions::kEnabledOff);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NgxRewriteOptions::CopyScriptLinesTo(
|
||||
NgxRewriteOptions* destination) const {
|
||||
destination->script_lines_ = script_lines_;
|
||||
}
|
||||
|
||||
void NgxRewriteOptions::AppendScriptLinesTo(
|
||||
NgxRewriteOptions* destination) const {
|
||||
destination->script_lines_.insert(destination->script_lines_.end(),
|
||||
script_lines_.begin(), script_lines_.end());
|
||||
}
|
||||
|
||||
NgxRewriteOptions* NgxRewriteOptions::Clone() const {
|
||||
NgxRewriteOptions* options = new NgxRewriteOptions(
|
||||
StrCat("cloned from ", description()), thread_system());
|
||||
this->CopyScriptLinesTo(options);
|
||||
options->Merge(*this);
|
||||
return options;
|
||||
}
|
||||
|
||||
void NgxRewriteOptions::Merge(const RewriteOptions& src) {
|
||||
SystemRewriteOptions::Merge(src);
|
||||
}
|
||||
|
||||
const NgxRewriteOptions* NgxRewriteOptions::DynamicCast(
|
||||
const RewriteOptions* instance) {
|
||||
return dynamic_cast<const NgxRewriteOptions*>(instance);
|
||||
|
||||
+122
-4
@@ -27,20 +27,89 @@ extern "C" {
|
||||
#include <ngx_http.h>
|
||||
}
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "net/instaweb/util/public/message_handler.h"
|
||||
#include "net/instaweb/util/public/ref_counted_ptr.h"
|
||||
#include "net/instaweb/util/public/stl_util.h" // for STLDeleteElements
|
||||
#include "net/instaweb/rewriter/public/rewrite_options.h"
|
||||
#include "net/instaweb/system/public/system_rewrite_options.h"
|
||||
|
||||
#define NGX_PAGESPEED_MAX_ARGS 10
|
||||
|
||||
namespace net_instaweb {
|
||||
|
||||
class NgxRewriteDriverFactory;
|
||||
|
||||
class ScriptArgIndex {
|
||||
public:
|
||||
explicit ScriptArgIndex(ngx_http_script_compile_t* script, int index)
|
||||
: script_(script), index_(index) {
|
||||
CHECK(script != NULL);
|
||||
CHECK(index > 0 && index < NGX_PAGESPEED_MAX_ARGS);
|
||||
}
|
||||
|
||||
virtual ~ScriptArgIndex() {}
|
||||
|
||||
ngx_http_script_compile_t* script() { return script_; }
|
||||
int index() { return index_; }
|
||||
|
||||
private:
|
||||
// Not owned.
|
||||
ngx_http_script_compile_t* script_;
|
||||
int index_;
|
||||
};
|
||||
|
||||
// Refcounted, because the ScriptArgIndexes inside data_ can be shared between
|
||||
// different rewriteoptions.
|
||||
class ScriptLine : public RefCounted<ScriptLine> {
|
||||
public:
|
||||
explicit ScriptLine(StringPiece* args, int n_args,
|
||||
RewriteOptions::OptionScope scope)
|
||||
: n_args_(n_args),
|
||||
scope_(scope) {
|
||||
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
args_[i] = args[i];
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~ScriptLine() {
|
||||
STLDeleteElements(&data_);
|
||||
data_.clear();
|
||||
}
|
||||
|
||||
void AddScriptAndArgIndex(ngx_http_script_compile_t* script,
|
||||
int script_index) {
|
||||
CHECK(script != NULL);
|
||||
CHECK(script_index < NGX_PAGESPEED_MAX_ARGS);
|
||||
data_.push_back(new ScriptArgIndex(script, script_index));
|
||||
}
|
||||
|
||||
int n_args() { return n_args_;}
|
||||
StringPiece* args() { return args_;}
|
||||
RewriteOptions::OptionScope scope() { return scope_; }
|
||||
std::vector<ScriptArgIndex*>& data() {
|
||||
return data_;
|
||||
}
|
||||
|
||||
private:
|
||||
StringPiece args_[NGX_PAGESPEED_MAX_ARGS];
|
||||
int n_args_;
|
||||
RewriteOptions::OptionScope scope_;
|
||||
std::vector<ScriptArgIndex*> data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScriptLine);
|
||||
};
|
||||
|
||||
class NgxRewriteOptions : public SystemRewriteOptions {
|
||||
public:
|
||||
// See rewrite_options::Initialize and ::Terminate
|
||||
static void Initialize();
|
||||
static void Terminate();
|
||||
|
||||
NgxRewriteOptions(const StringPiece& description, ThreadSystem* thread_system);
|
||||
NgxRewriteOptions(const StringPiece& description,
|
||||
ThreadSystem* thread_system);
|
||||
explicit NgxRewriteOptions(ThreadSystem* thread_system);
|
||||
virtual ~NgxRewriteOptions() { }
|
||||
|
||||
@@ -55,18 +124,53 @@ class NgxRewriteOptions : public SystemRewriteOptions {
|
||||
// on failure.
|
||||
//
|
||||
// pool is a memory pool for allocating error strings.
|
||||
// cf is only required when compile_scripts is true
|
||||
// when compile_scripts is true, the rewrite_options will be prepared
|
||||
// for replacing any script $variables encountered in args. when false,
|
||||
// script variables will be substituted using the prepared rewrite options.
|
||||
const char* ParseAndSetOptions(
|
||||
StringPiece* args, int n_args, ngx_pool_t* pool, MessageHandler* handler,
|
||||
NgxRewriteDriverFactory* driver_factory, OptionScope scope);
|
||||
NgxRewriteDriverFactory* driver_factory, OptionScope scope,
|
||||
ngx_conf_t* cf, bool compile_scripts);
|
||||
bool ExecuteScriptVariables(
|
||||
ngx_http_request_t* r, MessageHandler* handler,
|
||||
NgxRewriteDriverFactory* driver_factory);
|
||||
void CopyScriptLinesTo(NgxRewriteOptions* destination) const;
|
||||
void AppendScriptLinesTo(NgxRewriteOptions* destination) const;
|
||||
|
||||
// Make an identical copy of these options and return it.
|
||||
virtual NgxRewriteOptions* Clone() const;
|
||||
virtual void Merge(const RewriteOptions& src);
|
||||
|
||||
// Returns a suitably down cast version of 'instance' if it is an instance
|
||||
// of this class, NULL if not.
|
||||
static const NgxRewriteOptions* DynamicCast(const RewriteOptions* instance);
|
||||
static NgxRewriteOptions* DynamicCast(RewriteOptions* instance);
|
||||
|
||||
const GoogleString& statistics_path() const {
|
||||
return statistics_path_.value();
|
||||
}
|
||||
const GoogleString& global_statistics_path() const {
|
||||
return global_statistics_path_.value();
|
||||
}
|
||||
const GoogleString& console_path() const {
|
||||
return console_path_.value();
|
||||
}
|
||||
const GoogleString& messages_path() const {
|
||||
return messages_path_.value();
|
||||
}
|
||||
const GoogleString& admin_path() const {
|
||||
return admin_path_.value();
|
||||
}
|
||||
const GoogleString& global_admin_path() const {
|
||||
return global_admin_path_.value();
|
||||
}
|
||||
const std::vector<RefCountedPtr<ScriptLine> >& script_lines() const {
|
||||
return script_lines_;
|
||||
}
|
||||
const bool& clear_inherited_scripts() const {
|
||||
return clear_inherited_scripts_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper methods for ParseAndSetOptions(). Each can:
|
||||
@@ -108,10 +212,24 @@ class NgxRewriteOptions : public SystemRewriteOptions {
|
||||
static void add_ngx_option(typename OptionClass::ValueType default_value,
|
||||
OptionClass NgxRewriteOptions::*offset,
|
||||
const char* id,
|
||||
StringPiece option_name) {
|
||||
AddProperty(default_value, offset, id, option_name, ngx_properties_);
|
||||
StringPiece option_name,
|
||||
OptionScope scope,
|
||||
const char* help,
|
||||
bool safe_to_print) {
|
||||
AddProperty(default_value, offset, id, option_name, scope, help,
|
||||
safe_to_print, ngx_properties_);
|
||||
}
|
||||
|
||||
Option<GoogleString> statistics_path_;
|
||||
Option<GoogleString> global_statistics_path_;
|
||||
Option<GoogleString> console_path_;
|
||||
Option<GoogleString> messages_path_;
|
||||
Option<GoogleString> admin_path_;
|
||||
Option<GoogleString> global_admin_path_;
|
||||
|
||||
bool clear_inherited_scripts_;
|
||||
std::vector<RefCountedPtr<ScriptLine> > script_lines_;
|
||||
|
||||
// Helper for ParseAndSetOptions. Returns whether the two directives equal,
|
||||
// ignoring case.
|
||||
bool IsDirective(StringPiece config_directive, StringPiece compare_directive);
|
||||
|
||||
@@ -72,8 +72,14 @@ SystemRequestContext* NgxServerContext::NewRequestContext(
|
||||
|
||||
return new SystemRequestContext(thread_system()->NewMutex(),
|
||||
timer(),
|
||||
ps_determine_host(r),
|
||||
local_port,
|
||||
str_to_string_piece(local_ip));
|
||||
}
|
||||
|
||||
GoogleString NgxServerContext::FormatOption(StringPiece option_name,
|
||||
StringPiece args) {
|
||||
return StrCat("pagespeed ", option_name, " ", args, ";");
|
||||
}
|
||||
|
||||
} // namespace net_instaweb
|
||||
|
||||
@@ -55,6 +55,8 @@ class NgxServerContext : public SystemServerContext {
|
||||
return dynamic_cast<NgxMessageHandler*>(message_handler());
|
||||
}
|
||||
|
||||
virtual GoogleString FormatOption(StringPiece option_name, StringPiece args);
|
||||
|
||||
private:
|
||||
NgxRewriteDriverFactory* ngx_factory_;
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace net_instaweb {
|
||||
ngx_msec_t resolver_timeout,
|
||||
ngx_msec_t fetch_timeout,
|
||||
ngx_resolver_t* resolver,
|
||||
int max_keepalive_requests,
|
||||
ThreadSystem* thread_system,
|
||||
MessageHandler* handler)
|
||||
: fetchers_count_(0),
|
||||
@@ -63,7 +64,8 @@ namespace net_instaweb {
|
||||
byte_count_(0),
|
||||
thread_system_(thread_system),
|
||||
message_handler_(handler),
|
||||
mutex_(NULL) {
|
||||
mutex_(NULL),
|
||||
max_keepalive_requests_(max_keepalive_requests) {
|
||||
resolver_timeout_ = resolver_timeout;
|
||||
fetch_timeout_ = fetch_timeout;
|
||||
ngx_memzero(&proxy_, sizeof(proxy_));
|
||||
@@ -221,9 +223,9 @@ namespace net_instaweb {
|
||||
void NgxUrlAsyncFetcher::Fetch(const GoogleString& url,
|
||||
MessageHandler* message_handler,
|
||||
AsyncFetch* async_fetch) {
|
||||
async_fetch = EnableInflation(async_fetch, NULL);
|
||||
async_fetch = EnableInflation(async_fetch);
|
||||
NgxFetch* fetch = new NgxFetch(url, async_fetch,
|
||||
message_handler, fetch_timeout_, log_);
|
||||
message_handler, log_);
|
||||
ScopedMutex lock(mutex_);
|
||||
pending_fetches_.Add(fetch);
|
||||
SendCmd('F');
|
||||
@@ -249,7 +251,7 @@ namespace net_instaweb {
|
||||
|
||||
// This is the read event which is called in the main thread.
|
||||
// It will do the real work. Add the work event and start the fetch.
|
||||
void NgxUrlAsyncFetcher::CommandHandler(ngx_event_t *cmdev) {
|
||||
void NgxUrlAsyncFetcher::CommandHandler(ngx_event_t* cmdev) {
|
||||
char command;
|
||||
int rc;
|
||||
ngx_connection_t* c = static_cast<ngx_connection_t*>(cmdev->data);
|
||||
|
||||
@@ -53,12 +53,13 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
|
||||
NgxUrlAsyncFetcher(
|
||||
const char* proxy, ngx_log_t* log, ngx_msec_t resolver_timeout,
|
||||
ngx_msec_t fetch_timeout, ngx_resolver_t* resolver,
|
||||
ThreadSystem* thread_system, MessageHandler* handler);
|
||||
int max_keepalive_requests, ThreadSystem* thread_system,
|
||||
MessageHandler* handler);
|
||||
|
||||
~NgxUrlAsyncFetcher();
|
||||
|
||||
// It should be called in the module init_process callback function. Do some
|
||||
// intializations which can't be done in the master process
|
||||
// initializations which can't be done in the master process
|
||||
bool Init();
|
||||
|
||||
// shutdown all the fetches.
|
||||
@@ -139,6 +140,7 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
|
||||
ngx_connection_t* command_connection_; // the command pipe
|
||||
int pipe_fd_; // the write pipe end
|
||||
ngx_resolver_t* resolver_;
|
||||
int max_keepalive_requests_;
|
||||
ngx_msec_t resolver_timeout_;
|
||||
ngx_msec_t fetch_timeout_;
|
||||
|
||||
|
||||
Executable → Regular
+564
-217
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,22 @@ http {
|
||||
proxy_cache_path "@@PROXY_CACHE@@" levels=1:2 keys_zone=htmlcache:60m inactive=90m max_size=50m;
|
||||
proxy_temp_path "@@TMP_PROXY_CACHE@@";
|
||||
|
||||
pagespeed ProcessScriptVariables on;
|
||||
pagespeed StatisticsPath /ngx_pagespeed_statistics;
|
||||
pagespeed GlobalStatisticsPath /ngx_pagespeed_global_statistics;
|
||||
pagespeed ConsolePath /pagespeed_console;
|
||||
pagespeed MessagesPath /ngx_pagespeed_message;
|
||||
pagespeed AdminPath /pagespeed_admin;
|
||||
pagespeed GlobalAdminPath /pagespeed_global_admin;
|
||||
|
||||
pagespeed StaticAssetPrefix /pagespeed_custom_static/;
|
||||
|
||||
pagespeed MessageBufferSize 200000;
|
||||
# Increase the default fetcher timeout to resolve sporadic flakeyness when
|
||||
# the native fetcher uses 8.8.8.8 to resolve.
|
||||
pagespeed FetcherTimeoutMs 10000;
|
||||
pagespeed NativeFetcherMaxKeepaliveRequests 50;
|
||||
|
||||
root "@@SERVER_ROOT@@";
|
||||
|
||||
# Block 5a: Decide on Cache-Control header value to use for outgoing
|
||||
@@ -42,7 +58,6 @@ http {
|
||||
pagespeed UsePerVHostStatistics on;
|
||||
pagespeed InPlaceResourceOptimization on;
|
||||
pagespeed CreateSharedMemoryMetadataCache "@@SHM_CACHE@@" 8192;
|
||||
pagespeed PreserveUrlRelativity on;
|
||||
pagespeed BlockingRewriteKey psatest;
|
||||
|
||||
# CriticalImagesBeaconEnabled is now on by default, but we disable in testing.
|
||||
@@ -67,6 +82,7 @@ http {
|
||||
# test ModPagespeedMaxCacheableContentLength, i.e.,
|
||||
# max_cacheable_response_content_length.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name max-cacheable-content-length.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -86,6 +102,7 @@ http {
|
||||
# running on the PRIMARY_PORT when the response is not available in
|
||||
# the cache. It also services purge requests from the upstream server.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name proxy_cache.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -144,7 +161,15 @@ http {
|
||||
set $bypass_cache "1";
|
||||
}
|
||||
|
||||
set_random $rand 0 100;
|
||||
# For testing purposes, we never generate values that will result in a beacon
|
||||
# unless a test request it via "X-Allow-Beacon: yes" in its request header.
|
||||
# This is for testing purposes, note that in a production environment,
|
||||
# you want 'set_random $rand 0 100;' unconditionally!
|
||||
set $rand 5;
|
||||
|
||||
if ($http_x_allow_beacon ~ "yes") {
|
||||
set_random $rand 0 100;
|
||||
}
|
||||
set $should_beacon_header_val "";
|
||||
if ($rand ~* "^[0-4]$") {
|
||||
set $should_beacon_header_val "random_rebeaconing_key";
|
||||
@@ -160,6 +185,7 @@ http {
|
||||
# Block 4: Location block for purge requests.
|
||||
location ~ /purge(/.*) {
|
||||
allow 127.0.0.1;
|
||||
allow ::1;
|
||||
deny all;
|
||||
proxy_cache_purge htmlcache $ps_capability_list$1$is_args$args;
|
||||
}
|
||||
@@ -198,6 +224,48 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name if-in-server.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
set $inline_javascript "No";
|
||||
|
||||
if ($http_x_custom_header_inline_js) {
|
||||
# TODO(jefftk): Turn on NGX_HTTP_SIF_CONF and figure out how to get
|
||||
# pagespeed directives inside of a server location block to be respected,
|
||||
# then uncomment the following line and duplicate the if-in-location test
|
||||
# for if-in-server.
|
||||
#pagespeed EnableFilters inline_javascript;
|
||||
set $inline_javascript "Yes";
|
||||
}
|
||||
|
||||
add_header "X-Inline-Javascript" $inline_javascript;
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name if-in-location.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
|
||||
location / {
|
||||
set $inline_javascript "No";
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
|
||||
if ($http_x_custom_header_inline_js) {
|
||||
pagespeed EnableFilters inline_javascript;
|
||||
set $inline_javascript "Yes";
|
||||
}
|
||||
|
||||
add_header "X-Inline-Javascript" $inline_javascript;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name mpd.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
@@ -208,6 +276,7 @@ http {
|
||||
# These two vhosts are for testing the experiment framework (Furious).
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name experiment.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
pagespeed InPlaceResourceOptimization off;
|
||||
@@ -218,9 +287,11 @@ http {
|
||||
pagespeed ExperimentSpec
|
||||
"id=7;enable=recompress_images;disable=convert_jpeg_to_progressive;percent=50";
|
||||
pagespeed ExperimentSpec "id=2;enable=recompress_images;percent=50";
|
||||
pagespeed ExperimentSpec "id=3;default;percent=0";
|
||||
}
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name experiment.noga.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -229,10 +300,12 @@ http {
|
||||
pagespeed ExperimentSpec
|
||||
"id=7;enable=recompress_images;disable=convert_jpeg_to_progressive;percent=50";
|
||||
pagespeed ExperimentSpec "id=2;enable=recompress_images;percent=50";
|
||||
pagespeed ExperimentSpec "id=3;default;percent=0";
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name preserveurls.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -262,6 +335,7 @@ http {
|
||||
# Setup a vhost with the critical image beacon and lazyload filter enabled
|
||||
# to make sure that critical images are not lazyloaded.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name imagebeacon.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -274,6 +348,7 @@ http {
|
||||
# Setup a vhost with the critical image beacon enabled to make sure that
|
||||
# downstream caches and rebeaconing interact correctly.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name downstreamcacherebeacon.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -289,6 +364,17 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name downstreamcacheresource.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
pagespeed EnableFilters rewrite_images;
|
||||
pagespeed DownstreamCachePurgeLocationPrefix "http://localhost:@@SECONDARY_PORT@@/purge";
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name renderedimagebeacon.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -306,6 +392,7 @@ http {
|
||||
# inheretence in Nginx we need to have location blocks inside a server block.
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name optimizeforbandwidth.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -337,6 +424,7 @@ http {
|
||||
# to go back to this VirtualHost so we rely on the new third optional
|
||||
# argument to MapOriginDomain.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name customhostheader.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@_test";
|
||||
root "@@SERVER_ROOT@@/mod_pagespeed_test";
|
||||
@@ -355,6 +443,7 @@ http {
|
||||
# Sets up a virtual host where we can specify forbidden filters without
|
||||
# affecting any other hosts.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name forbidden.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -370,6 +459,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name unauthorizedresources.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -380,6 +470,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name client-domain-rewrite.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -395,6 +486,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name url-attribute.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -415,6 +507,9 @@ http {
|
||||
pagespeed UrlValuedAttribute img alt-src Image;
|
||||
pagespeed UrlValuedAttribute video alt-a Image;
|
||||
pagespeed UrlValuedAttribute video alt-b Image;
|
||||
|
||||
# Also test that we can redefine spec-defined attributes.
|
||||
pagespeed UrlValuedAttribute blockquote cite Image;
|
||||
}
|
||||
|
||||
server {
|
||||
@@ -425,6 +520,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name domain-hyperlinks-on.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -439,6 +535,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name domain-hyperlinks-off.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -453,6 +550,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name retaincomment.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -462,6 +560,7 @@ http {
|
||||
server {
|
||||
# Test host for shared memory cache.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name shmcache.example.com;
|
||||
pagespeed FileCachePath "@@SHM_CACHE@@";
|
||||
|
||||
@@ -471,6 +570,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name xfp.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -479,6 +579,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name xheader.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -492,7 +593,8 @@ http {
|
||||
# Note that we test with two distinct caches.
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
server_name embed-config-html.example.com;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name embed-config-html.example.org;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
root "@@SERVER_ROOT@@/mod_pagespeed_test";
|
||||
@@ -502,12 +604,16 @@ http {
|
||||
pagespeed DisableFilters inline_css,extend_cache,inline_javascript;
|
||||
pagespeed Domain embed-config-resources.example.com;
|
||||
|
||||
# Share a cache keyspace with embed-config-resources.example.com.
|
||||
pagespeed CacheFragment "embed-config";
|
||||
|
||||
pagespeed LoadFromFile "http://embed-config-resources.example.com/"
|
||||
"@@SERVER_ROOT@@/mod_pagespeed_example/";
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name embed-config-resources.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -517,7 +623,10 @@ http {
|
||||
|
||||
# Note that we do not set the jpeg quality here, but take
|
||||
# it from image URL query parameters that we synthesize in
|
||||
# from embed-config-html.example.com.
|
||||
# from embed-config-html.example.org.
|
||||
|
||||
# Share a cache keyspace with embed-config-html.example.org.
|
||||
pagespeed CacheFragment "embed-config";
|
||||
|
||||
pagespeed LoadFromFile "http://embed-config-resources.example.com/"
|
||||
"@@SERVER_ROOT@@/mod_pagespeed_example/";
|
||||
@@ -525,17 +634,19 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name ipro-for-browser.example.com;
|
||||
root "@@SERVER_ROOT@@/mod_pagespeed_example";
|
||||
pagespeed EnableFilters rewrite_images,rewrite_css;
|
||||
pagespeed EnableFilters convert_to_webp_lossless;
|
||||
pagespeed EnableFilters in_place_optimize_for_browser;
|
||||
pagespeed InPlaceResourceOptimization on;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@_ipro_for_browser";
|
||||
pagespeed FileCachePath "@@IPRO_CACHE@@";
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name respectvary.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -545,16 +656,30 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name cache_a.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
pagespeed CacheFlushPollIntervalSec 1;
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
pagespeed EnableFilters inline_css;
|
||||
|
||||
# Make a non-empty subdirectory config to make sure that
|
||||
# cache.flush updates get transmitted to nested configurations.
|
||||
#
|
||||
# TODO(jmarantz): This test currently fails on ngx_pagespeed, meaning we
|
||||
# don't handle cache flushing correctly here. Uncomment the config below to
|
||||
# expose the error.
|
||||
#location /mod_pagespeed_test/cache_flush/ {
|
||||
# pagespeed RewriteLevel PassThrough;
|
||||
# pagespeed EnableFilters inline_css;
|
||||
# pagespeed DisableFilters add_instrumentation;
|
||||
#}
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name cache_b.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
@@ -565,6 +690,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name cache_c.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -578,6 +704,7 @@ http {
|
||||
server {
|
||||
# Sets up a logical home-page server on www.example.com
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name www.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -585,11 +712,13 @@ http {
|
||||
pagespeed MapRewriteDomain cdn.example.com origin.example.com;
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
pagespeed EnableFilters rewrite_css,rewrite_images;
|
||||
pagespeed CacheFragment "example";
|
||||
}
|
||||
server {
|
||||
# Sets up a logical origin for CDNs to fetch content from, on
|
||||
# origin.example.com.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name origin.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -597,11 +726,13 @@ http {
|
||||
pagespeed MapRewriteDomain cdn.example.com origin.example.com;
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
pagespeed EnableFilters rewrite_css,rewrite_images;
|
||||
pagespeed CacheFragment "example";
|
||||
}
|
||||
server {
|
||||
# Sets up a logical cdn, which is where we tell browsers to fetch resources
|
||||
# from.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name cdn.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -613,6 +744,18 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name lff-ipro.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
pagespeed LoadFromFile
|
||||
"http://lff-ipro.example.com/mod_pagespeed_example/lff_ipro"
|
||||
"@@SERVER_ROOT@@/mod_pagespeed_example/lff_ipro";
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name tryfiles.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -626,6 +769,7 @@ http {
|
||||
server {
|
||||
# Proxy modpagespeed.com for testing Issue 582.
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name modpagespeed.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -638,6 +782,26 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name custom-paths.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
pagespeed StatisticsPath /custom_pagespeed_statistics;
|
||||
pagespeed ConsolePath /custom_pagespeed_console;
|
||||
pagespeed MessagesPath /custom_pagespeed_message;
|
||||
pagespeed AdminPath /custom_pagespeed_admin;
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name inherit-paths.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name notransform.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -649,6 +813,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name blocking.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
@@ -658,6 +823,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name keepalive-html.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
pagespeed RewriteLevel CoreFilters;
|
||||
@@ -666,6 +832,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name keepalive-resource.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
error_log "@@TEST_TMP@@/keepalive-resource.example.com.error.log" warn;
|
||||
@@ -673,6 +840,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name keepalive-beacon-get.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
error_log "@@TEST_TMP@@/keepalive-beacon-get.example.com.error.log" warn;
|
||||
@@ -680,6 +848,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name keepalive-beacon-post.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
error_log "@@TEST_TMP@@/keepalive-beacon-post.example.com.error.log" warn;
|
||||
@@ -687,6 +856,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name keepalive-static.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
error_log "@@TEST_TMP@@/keepalive-static.example.com.error.log" warn;
|
||||
@@ -694,6 +864,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name response-header-filters.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
@@ -703,6 +874,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name response-header-disable.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
pagespeed EnableFilters add_instrumentation;
|
||||
@@ -712,6 +884,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name ipro.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
@@ -735,6 +908,7 @@ http {
|
||||
# 1. L2_d=LRU, L2_m=LRU
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name lrud-lrum.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@_lrud_lrum";
|
||||
|
||||
@@ -749,6 +923,7 @@ http {
|
||||
"@@SECONDARY_CACHE@@_lrud_shmm" 8192;
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name lrud-shmm.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@_lrud_shmm";
|
||||
|
||||
@@ -763,6 +938,7 @@ http {
|
||||
"@@SECONDARY_CACHE@@_noned_shmm" 8192;
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name noned-shmm.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@_noned_shmm";
|
||||
|
||||
@@ -773,6 +949,7 @@ http {
|
||||
# 4. L2_d=none, L2_m=none
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name noned-nonem.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@_noned_nonem";
|
||||
|
||||
@@ -782,20 +959,220 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name date.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
add_header "Date" "Date: Fri, 16 Oct 2009 23:05:07 GMT";
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@PRIMARY_PORT@@;
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name options-by-cookies-enabled.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@_optionsbycookieson";
|
||||
pagespeed AllowOptionsToBeSetByCookies true;
|
||||
pagespeed StickyQueryParameters sticky_secret;
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
pagespeed EnableFilters collapse_whitespace;
|
||||
pagespeed DisableFilters remove_comments,add_instrumentation;
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name options-by-cookies-disabled.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@_optionsbycookiesoff";
|
||||
pagespeed AllowOptionsToBeSetByCookies false;
|
||||
pagespeed DisableFilters add_instrumentation;
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name redirect.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@_redirected";
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
pagespeed EnableFilters add_instrumentation,collapse_whitespace;
|
||||
location /redirect {
|
||||
rewrite ^/redirect/(.*) http://$server_name/$1 permanent;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name request-option-override.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
pagespeed RequestOptionOverride abc;
|
||||
pagespeed RewriteLevel Passthrough;
|
||||
pagespeed EnableFilters collapse_whitespace;
|
||||
pagespeed DisableFilters remove_comments,add_instrumentation;
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name signed-urls.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
pagespeed UrlSigningKey helloworld;
|
||||
pagespeed RewriteLevel Passthrough;
|
||||
pagespeed EnableFilters collapse_whitespace,rewrite_images;
|
||||
pagespeed DisableFilters remove_comments,add_instrumentation;
|
||||
}
|
||||
|
||||
# For testing signed URLs, ignoring signature validity.
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name signed-urls-transition.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
pagespeed UrlSigningKey helloworld;
|
||||
pagespeed AcceptInvalidSignatures true;
|
||||
pagespeed RewriteLevel Passthrough;
|
||||
pagespeed EnableFilters collapse_whitespace,rewrite_images;
|
||||
pagespeed DisableFilters remove_comments,add_instrumentation;
|
||||
}
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name unsigned-urls-transition.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
# This server will not sign URLs, but AcceptInvalidSignature is on.
|
||||
pagespeed AcceptInvalidSignatures true;
|
||||
pagespeed RewriteLevel Passthrough;
|
||||
pagespeed EnableFilters collapse_whitespace,rewrite_images;
|
||||
pagespeed DisableFilters remove_comments,add_instrumentation;
|
||||
}
|
||||
|
||||
# Proxy + IPRO a gzip'd file for testing Issue 896.
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name ipro-proxy.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@_ipro_proxy";
|
||||
|
||||
pagespeed on;
|
||||
pagespeed InPlaceResourceOptimization on;
|
||||
pagespeed EnableFilters rewrite_domains;
|
||||
|
||||
location / {
|
||||
proxy_pass
|
||||
"http://localhost:@@PRIMARY_PORT@@/mod_pagespeed_test/ipro/mod_deflate/";
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name compressed-css.example.com;
|
||||
pagespeed on;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
pagespeed InPlaceResourceOptimization on;
|
||||
}
|
||||
|
||||
# nested gzip config: pagespeed gzip on/off
|
||||
server {
|
||||
pagespeed on;
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name gzip-test1.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
location /mod_pagespeed_example/ {
|
||||
pagespeed gzip off;
|
||||
}
|
||||
location /mod_pagespeed_example/styles/ {
|
||||
pagespeed gzip on;
|
||||
}
|
||||
}
|
||||
|
||||
# nested gzip config: pagespeed on/off
|
||||
server {
|
||||
pagespeed on;
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name gzip-test2.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
location /mod_pagespeed_example/ {
|
||||
pagespeed off;
|
||||
}
|
||||
location /mod_pagespeed_example/styles/ {
|
||||
pagespeed on;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
pagespeed on;
|
||||
pagespeed EnableFilters add_instrumentation;
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name proxy-post.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
location / {
|
||||
# Transform the POST to a GET request for the origin,
|
||||
# as nginx's static handler doesn't allow POST requests.
|
||||
proxy_method GET;
|
||||
proxy_pass http://127.0.0.1:@@SECONDARY_PORT@@/;
|
||||
proxy_set_header "Host" "proxy-post-origin.example.com";
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
pagespeed off;
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name proxy-post-origin.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
root "@@SERVER_ROOT@@";
|
||||
}
|
||||
|
||||
server {
|
||||
# Write all post data to temp files
|
||||
client_body_in_file_only clean;
|
||||
pagespeed CriticalImagesBeaconEnabled true;
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name beacon-post-temp-file.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name purge.example.com;
|
||||
|
||||
# Test purging individual URLs without flushing the entire metadata cache.
|
||||
pagespeed EnableCachePurge on;
|
||||
|
||||
pagespeed PurgeMethod PURGE;
|
||||
root "@@SERVER_ROOT@@";
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@_purge";
|
||||
pagespeed DisableFilters add_instrumentation;
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
pagespeed EnableFilters rewrite_css;
|
||||
}
|
||||
|
||||
server {
|
||||
listen @@PRIMARY_PORT@@;
|
||||
listen [::]:@@PRIMARY_PORT@@;
|
||||
server_name localhost;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
location ~ ^/pagespeed_admin {
|
||||
allow 127.0.0.1;
|
||||
allow ::1;
|
||||
deny all;
|
||||
}
|
||||
|
||||
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" {
|
||||
add_header "" "";
|
||||
}
|
||||
|
||||
# Backend for ipro-proxy.example.com
|
||||
location /mod_pagespeed_test/ipro/mod_deflate/ {
|
||||
pagespeed off;
|
||||
}
|
||||
|
||||
location /mod_pagespeed_test/cachable_rewritten_html/ {
|
||||
# This location has the html files that will be configured to be stored
|
||||
# in the proxy_cache layer.
|
||||
@@ -824,7 +1201,6 @@ http {
|
||||
#pagespeed MemcachedThreads 1;
|
||||
|
||||
pagespeed on;
|
||||
pagespeed MessageBufferSize 200000;
|
||||
|
||||
#pagespeed CacheFlushPollIntervalSec 1;
|
||||
|
||||
@@ -845,11 +1221,13 @@ http {
|
||||
|
||||
location /ngx_pagespeed_statistics {
|
||||
allow 127.0.0.1;
|
||||
allow ::1;
|
||||
deny all;
|
||||
}
|
||||
|
||||
location /ngx_pagespeed_message {
|
||||
allow 127.0.0.1;
|
||||
allow ::1;
|
||||
deny all;
|
||||
}
|
||||
|
||||
@@ -955,7 +1333,16 @@ http {
|
||||
|
||||
location /mod_pagespeed_test/ipro/instant/wait/ {
|
||||
pagespeed InPlaceWaitForOptimized on;
|
||||
# TODO: Valgrind runs pass only if the below line is uncommented.
|
||||
|
||||
# TODO(jefftk): When running with valgrind we need to raise the rewrite
|
||||
# deadline or else we get "Deadline exceeded for rewrite of resource".
|
||||
# I had thought InPlaceWaitForOptimized was supposed to disable the
|
||||
# rewrite deadline, but it seems not to.
|
||||
#
|
||||
# InPlaceWaitForOptimized is definitely doing something, though: when I
|
||||
# remove the InPlaceRewriteDeadlineMs line below and run without valgrind,
|
||||
# purple.css is optimized via ipro on the first request but if I set
|
||||
# InPlaceWaitForOptimized to off then it is not.
|
||||
pagespeed InPlaceRewriteDeadlineMs 1000;
|
||||
}
|
||||
|
||||
@@ -963,6 +1350,13 @@ http {
|
||||
pagespeed InPlaceRewriteDeadlineMs -1;
|
||||
}
|
||||
|
||||
# Test to make sure that user-authenticated resources do not get cached and
|
||||
# optimized.
|
||||
location /mod_pagespeed_test/auth/ {
|
||||
auth_basic "Restricted";
|
||||
auth_basic_user_file "@@SERVER_ROOT@@mod_pagespeed_test/auth/passwd.conf";
|
||||
}
|
||||
|
||||
location /mod_pagespeed_test/ipro/cookie/ {
|
||||
# Add Vary:Cookie. This should prevent us from optimizing the
|
||||
# vary_cookie.css even though PagespeedRespectVary is off.
|
||||
@@ -998,8 +1392,19 @@ http {
|
||||
pagespeed UseExperimentalJsMinifier on;
|
||||
}
|
||||
|
||||
pagespeed FetchHttps enable;
|
||||
location /mod_pagespeed_test/https_fetch/ {
|
||||
pagespeed DisableFilters inline_images;
|
||||
pagespeed MapProxyDomain
|
||||
http://localhost:@@PRIMARY_PORT@@/https_gstatic_dot_com
|
||||
https://www.gstatic.com/psa/static;
|
||||
}
|
||||
|
||||
# $host implicitly tests script variable support. I'd love to test it more
|
||||
# directly, but so far this is the best I've come up with and duplicating
|
||||
# the test doesn't seem to make sense.
|
||||
pagespeed LoadFromFile
|
||||
"http://localhost:@@PRIMARY_PORT@@/mod_pagespeed_test/ipro/instant/"
|
||||
"http://$host:@@PRIMARY_PORT@@/mod_pagespeed_test/ipro/instant/"
|
||||
"@@SERVER_ROOT@@/mod_pagespeed_test/ipro/instant/";
|
||||
|
||||
pagespeed EnableFilters remove_comments;
|
||||
@@ -1013,8 +1418,8 @@ http {
|
||||
"@@SERVER_ROOT@@/mod_pagespeed_test/load_from_file/file_\1/";
|
||||
pagespeed LoadFromFileRule Disallow
|
||||
"@@SERVER_ROOT@@/mod_pagespeed_test/load_from_file/file_dir/httponly/";
|
||||
pagespeed LoadFromFileRuleMatch Disallow \.ssp.css$;
|
||||
pagespeed LoadFromFileRuleMatch Allow exception\.ssp\.css$;
|
||||
pagespeed LoadFromFileRuleMatch Disallow \.ssp.css$ps_dollar;
|
||||
pagespeed LoadFromFileRuleMatch Allow exception\.ssp\.css$ps_dollar;
|
||||
|
||||
#charset koi8-r;
|
||||
|
||||
@@ -1037,26 +1442,6 @@ http {
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
# set up gzip
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
# Turn on gzip for all content types that should benefit from it.
|
||||
gzip_types application/ecmascript;
|
||||
gzip_types application/javascript;
|
||||
gzip_types application/json;
|
||||
gzip_types application/pdf;
|
||||
gzip_types application/postscript;
|
||||
gzip_types application/x-javascript;
|
||||
gzip_types image/svg+xml;
|
||||
gzip_types text/css;
|
||||
gzip_types text/csv;
|
||||
# "gzip_types text/html" is assumed.
|
||||
gzip_types text/javascript;
|
||||
gzip_types text/plain;
|
||||
gzip_types text/xml;
|
||||
|
||||
gzip_http_version 1.0;
|
||||
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
|
||||
@@ -73,6 +73,9 @@ function run_test_checking_failure() {
|
||||
3)
|
||||
return # Only expected failures.
|
||||
;;
|
||||
4)
|
||||
return # Return passing error code when running manually.
|
||||
;;
|
||||
*)
|
||||
exit 1 # Real failure.
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user