Compare commits
183 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4103004cee | |||
| 0f3f268b36 | |||
| 30fdd02d0c | |||
| 0572a5bebf | |||
| 4bd5b7c663 | |||
| a9c292d8dc | |||
| 907c57a217 | |||
| a7bef40eac | |||
| af5c568a92 | |||
| 5cc1ffb352 | |||
| d01093ba9b | |||
| a578057e2f | |||
| 5bd43dce9a | |||
| 19ebf69bad | |||
| 4df7460d62 | |||
| c5c443f256 | |||
| b9ca5d865d | |||
| 0cf3f1c6d7 | |||
| 7857bab7fb | |||
| b11ab687c1 | |||
| a81cc997a9 | |||
| 4c9298446c | |||
| 7355f2e207 | |||
| 9da85bb9d5 | |||
| 90ac91fe9e | |||
| da466c1487 | |||
| 2a409777dc | |||
| c3f41512cf | |||
| 0980633dd2 | |||
| c1c83aa69b | |||
| b037cc2b3e | |||
| 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 | |||
| 6af5774ef8 | |||
| 117994993a | |||
| 5487b7350c | |||
| 261b602f83 | |||
| ae3cf7a425 | |||
| b4af0738a5 | |||
| ff049a55c3 | |||
| 0772787ad4 | |||
| 7eedc2ce3c | |||
| 7af665b5dd | |||
| 8136a15352 | |||
| 31024cfc24 | |||
| 703fda7eba | |||
| d4bc40007e | |||
| f2e2ab6056 | |||
| e06a65e7e6 | |||
| 3231949e03 | |||
| f5713996f2 | |||
| cf434f71cc |
+1
-1
@@ -1,4 +1,4 @@
|
||||
test/tmp
|
||||
psol/
|
||||
psol-*.tar.gz
|
||||
|
||||
*.*.*.*.tar.gz
|
||||
|
||||
@@ -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.8.31.2-beta.zip
|
||||
$ unzip v1.8.31.2-beta.zip # or unzip v1.8.31.2-beta
|
||||
$ cd ngx_pagespeed-1.8.31.2-beta/
|
||||
$ wget https://dl.google.com/dl/page-speed/psol/1.8.31.2.tar.gz
|
||||
$ tar -xzvf 1.8.31.2.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.6.tar.gz
|
||||
$ tar -xvzf nginx-1.4.6.tar.gz
|
||||
$ cd nginx-1.4.6/
|
||||
$ ./configure --add-module=$HOME/ngx_pagespeed-1.8.31.2-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.8.31.2-...
|
||||
```
|
||||
|
||||
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.8.31.2.tar.gz"
|
||||
echo " $ tar -xzvf 1.8.31.2.tar.gz # expands to psol/"
|
||||
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.9.32.10.tar.gz"
|
||||
echo " $ tar -xzvf 1.9.32.10.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`
|
||||
@@ -113,6 +99,31 @@ 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 \
|
||||
@@ -128,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;
|
||||
@@ -167,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 \
|
||||
@@ -199,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,9 +13,9 @@
|
||||
# Author: vid@zippykid.com (Vid Luther)
|
||||
# jefftk@google.com (Jeff Kaufman)
|
||||
|
||||
URL="https://modpagespeed.googlecode.com/svn/trunk/src/"
|
||||
URL="https://github.com/pagespeed/mod_pagespeed/raw/master/"
|
||||
URL+="net/instaweb/genfiles/conf/pagespeed_libraries.conf"
|
||||
curl -s "$URL" \
|
||||
curl -L -s -S "$URL" \
|
||||
| grep ModPagespeedLibrary \
|
||||
| while read library size hash url ; do
|
||||
echo " pagespeed Library $size $hash $url;"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -137,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);
|
||||
|
||||
+816
-476
File diff suppressed because it is too large
Load Diff
+19
-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();
|
||||
|
||||
@@ -103,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();
|
||||
@@ -130,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_;
|
||||
@@ -143,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,
|
||||
|
||||
@@ -18,50 +18,40 @@
|
||||
#define NGX_MESSAGE_HANDLER_H_
|
||||
|
||||
extern "C" {
|
||||
#include <ngx_auto_config.h>
|
||||
#if (NGX_THREADS)
|
||||
#include <ngx_thread.h>
|
||||
#endif
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_log.h>
|
||||
}
|
||||
|
||||
#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 +60,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);
|
||||
|
||||
+363
-137
File diff suppressed because it is too large
Load Diff
@@ -71,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*>(
|
||||
@@ -111,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);
|
||||
@@ -208,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);
|
||||
@@ -225,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.
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#define NGX_REWRITE_DRIVER_FACTORY_H_
|
||||
|
||||
extern "C" {
|
||||
#include <ngx_auto_config.h>
|
||||
#if (NGX_THREADS)
|
||||
#include <ngx_thread.h>
|
||||
#endif
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
#include <ngx_config.h>
|
||||
@@ -92,18 +96,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;
|
||||
}
|
||||
@@ -117,16 +109,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);
|
||||
@@ -135,6 +125,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_;
|
||||
|
||||
@@ -143,20 +142,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_;
|
||||
|
||||
@@ -166,6 +161,8 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
||||
|
||||
GoogleString hostname_;
|
||||
int port_;
|
||||
bool process_script_variables_;
|
||||
bool process_script_variables_set_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NgxRewriteDriverFactory);
|
||||
};
|
||||
|
||||
+215
-64
@@ -31,6 +31,7 @@ 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 {
|
||||
@@ -46,9 +47,10 @@ 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",
|
||||
@@ -61,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",
|
||||
@@ -69,12 +72,14 @@ 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"
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -95,6 +100,7 @@ NgxRewriteOptions::NgxRewriteOptions(ThreadSystem* thread_system)
|
||||
void NgxRewriteOptions::Init() {
|
||||
DCHECK(ngx_properties_ != NULL)
|
||||
<< "Call NgxRewriteOptions::Initialize() before construction";
|
||||
clear_inherited_scripts_ = false;
|
||||
InitializeOptions(ngx_properties_);
|
||||
}
|
||||
|
||||
@@ -102,23 +108,27 @@ void NgxRewriteOptions::AddProperties() {
|
||||
// Nginx-specific options.
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::statistics_path_, "nsp", kStatisticsPath,
|
||||
kProcessScope, "Set the statistics path. Ex: /ngx_pagespeed_statistics");
|
||||
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");
|
||||
"Set the global statistics path. Ex: /ngx_pagespeed_global_statistics",
|
||||
false);
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::console_path_, "ncp", kConsolePath, kProcessScope,
|
||||
"Set the console path. Ex: /pagespeed_console");
|
||||
"", &NgxRewriteOptions::console_path_, "ncp", kConsolePath, kServerScope,
|
||||
"Set the console path. Ex: /pagespeed_console", false);
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::messages_path_, "nmp", kMessagesPath,
|
||||
kProcessScope, "Set the messages path. Ex: /ngx_pagespeed_message");
|
||||
kServerScope, "Set the messages path. Ex: /ngx_pagespeed_message",
|
||||
false);
|
||||
add_ngx_option(
|
||||
"", &NgxRewriteOptions::admin_path_, "nap", kAdminPath,
|
||||
kProcessScope, "Set the admin path. Ex: /pagespeed_admin");
|
||||
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");
|
||||
kProcessScope, "Set the global admin path. Ex: /pagespeed_global_admin",
|
||||
false);
|
||||
|
||||
MergeSubclassProperties(ngx_properties_);
|
||||
|
||||
@@ -248,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];
|
||||
@@ -264,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) {
|
||||
@@ -356,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);
|
||||
|
||||
@@ -27,13 +27,81 @@ 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
|
||||
@@ -56,12 +124,23 @@ 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.
|
||||
@@ -86,6 +165,12 @@ class NgxRewriteOptions : public SystemRewriteOptions {
|
||||
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:
|
||||
@@ -129,9 +214,10 @@ class NgxRewriteOptions : public SystemRewriteOptions {
|
||||
const char* id,
|
||||
StringPiece option_name,
|
||||
OptionScope scope,
|
||||
const char* help) {
|
||||
const char* help,
|
||||
bool safe_to_print) {
|
||||
AddProperty(default_value, offset, id, option_name, scope, help,
|
||||
ngx_properties_);
|
||||
safe_to_print, ngx_properties_);
|
||||
}
|
||||
|
||||
Option<GoogleString> statistics_path_;
|
||||
@@ -141,6 +227,9 @@ class NgxRewriteOptions : public SystemRewriteOptions {
|
||||
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);
|
||||
|
||||
@@ -48,7 +48,7 @@ SystemRequestContext* NgxServerContext::NewRequestContext(
|
||||
ngx_http_request_t* r) {
|
||||
// Based on ngx_http_variable_server_port.
|
||||
bool port_set = false;
|
||||
int local_port;
|
||||
int local_port = 0;
|
||||
#if (NGX_HAVE_INET6)
|
||||
if (r->connection->local_sockaddr->sa_family == AF_INET6) {
|
||||
local_port = ntohs(reinterpret_cast<struct sockaddr_in6*>(
|
||||
@@ -77,4 +77,9 @@ SystemRequestContext* NgxServerContext::NewRequestContext(
|
||||
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_));
|
||||
@@ -223,7 +225,7 @@ namespace net_instaweb {
|
||||
AsyncFetch* async_fetch) {
|
||||
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
+324
-134
@@ -71,12 +71,12 @@ function keepalive_test() {
|
||||
if [ -z "$POST_DATA" ]; then
|
||||
curl -m 2 -S -s -v -H "Accept-Encoding: $accept_encoding" \
|
||||
-H "Host: $HOST_NAME" $URL $URL $URL $URL $URL > /dev/null \
|
||||
2>>"$TEST_TMP/$CURL_LOG_FILE"
|
||||
2>>"$TEST_TMP/$CURL_LOG_FILE" || true
|
||||
else
|
||||
curl -X POST --data "$POST_DATA" -m 2 -S -s -v \
|
||||
-H "Accept-Encoding: $accept_encoding" -H "Host: $HOST_NAME"\
|
||||
$URL $URL $URL $URL $URL > /dev/null \
|
||||
2>>"$TEST_TMP/$CURL_LOG_FILE"
|
||||
2>>"$TEST_TMP/$CURL_LOG_FILE" || true
|
||||
fi
|
||||
done
|
||||
done
|
||||
@@ -92,13 +92,16 @@ function keepalive_test() {
|
||||
| grep -v "^\\* Connection.*left intact"\
|
||||
| grep -v "^} \\[data not shown"\
|
||||
| grep -v "^\\* upload completely sent off"\
|
||||
| grep -v "^\\* Found bundle for host"\
|
||||
| grep -v "^\\* connected"\
|
||||
| grep -v "^\\* Found bundle for host"\
|
||||
| grep -v "^\\* Adding handle"\
|
||||
| grep -v "^\\* Curl_addHandleToPipeline"\
|
||||
| grep -v "^\\* - Conn "\
|
||||
| grep -v "^\\* Server "\
|
||||
| grep -v "^\\* Trying.*\\.\\.\\.")
|
||||
| grep -v "^\\* Trying.*\\.\\.\\."\
|
||||
| grep -v "^\\* Hostname was NOT found in DNS cache" \
|
||||
|| true)
|
||||
|
||||
# Nothing should remain after that.
|
||||
check [ -z "$OUT" ]
|
||||
@@ -106,7 +109,8 @@ function keepalive_test() {
|
||||
# Filter the nginx log from our vhost from unimportant messages.
|
||||
OUT=$(cat "$TEST_TMP/$NGX_LOG_FILE"\
|
||||
| grep -v "closed keepalive connection$" \
|
||||
| grep -v ".*Cache Flush.*")
|
||||
| grep -v ".*Cache Flush.*" \
|
||||
|| true)
|
||||
|
||||
# Nothing should remain after that.
|
||||
check [ -z "$OUT" ]
|
||||
@@ -218,24 +222,20 @@ check_rewriting_status() {
|
||||
else
|
||||
check_not zgrep -q "pagespeed.ic" $OUT_CONTENTS_FILE
|
||||
fi
|
||||
# Reset WGET_ARGS.
|
||||
WGET_ARGS=""
|
||||
}
|
||||
|
||||
# Helper method that obtains a gzipped response and verifies that rewriting
|
||||
# has happened. Also takes an extra parameter that identifies extra headers
|
||||
# to be added during wget.
|
||||
check_for_rewriting() {
|
||||
WGET_ARGS="$GZIP_WGET_ARGS $1"
|
||||
check_rewriting_status true
|
||||
WGET_ARGS="$GZIP_WGET_ARGS $1" check_rewriting_status true
|
||||
}
|
||||
|
||||
# Helper method that obtains a gzipped response and verifies that no rewriting
|
||||
# has happened. Also takes an extra parameter that identifies extra headers
|
||||
# to be added during wget.
|
||||
check_for_no_rewriting() {
|
||||
WGET_ARGS="$GZIP_WGET_ARGS $1"
|
||||
check_rewriting_status false
|
||||
WGET_ARGS="$GZIP_WGET_ARGS $1" check_rewriting_status false
|
||||
}
|
||||
|
||||
if $RUN_TESTS; then
|
||||
@@ -250,6 +250,12 @@ else
|
||||
exit 4
|
||||
fi
|
||||
|
||||
# check_stat in system_test_helpers.sh needs to know whether statstistics are
|
||||
# enabled, which is always the case for ngx_pagespeed.
|
||||
statistics_enabled=1
|
||||
CACHE_FLUSH_TEST="on"
|
||||
CACHE_PURGE_METHODS="PURGE GET"
|
||||
|
||||
# run generic system tests
|
||||
SYSTEM_TEST_FILE="$MOD_PAGESPEED_DIR/src/net/instaweb/system/system_test.sh"
|
||||
|
||||
@@ -259,10 +265,12 @@ if [ ! -e "$SYSTEM_TEST_FILE" ] ; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
PSA_JS_LIBRARY_URL_PREFIX="pagespeed_static"
|
||||
PSA_JS_LIBRARY_URL_PREFIX="pagespeed_custom_static"
|
||||
|
||||
# An expected failure can be indicated like: "~In-place resource optimization~"
|
||||
PAGESPEED_EXPECTED_FAILURES="
|
||||
~Override server header in resource flow.~
|
||||
~Override server header in IPRO flow.~
|
||||
"
|
||||
|
||||
# Some tests are flakey under valgrind. For now, add them to the expected failures
|
||||
@@ -404,12 +412,12 @@ check_from "$OUT" egrep -q \
|
||||
'^X-Page-Speed: [0-9]+[.][0-9]+[.][0-9]+[.][0-9]+-[0-9]+'
|
||||
|
||||
start_test pagespeed is defaulting to more than PassThrough
|
||||
fetch_until $TEST_ROOT/bot_test.html 'grep -c \.pagespeed\.' 2
|
||||
fetch_until $TEST_ROOT/bot_test.html 'fgrep -c .pagespeed.' 2
|
||||
|
||||
start_test 404s are served and properly recorded.
|
||||
NUM_404=$(scrape_stat resource_404_count)
|
||||
echo "Initial 404s: $NUM_404"
|
||||
WGET_ERROR=$($WGET -O /dev/null $BAD_RESOURCE_URL 2>&1)
|
||||
WGET_ERROR=$(check_not $WGET -O /dev/null $BAD_RESOURCE_URL 2>&1)
|
||||
check_from "$WGET_ERROR" fgrep -q "404 Not Found"
|
||||
|
||||
# Check that the stat got bumped.
|
||||
@@ -442,16 +450,13 @@ if [ "$HOSTNAME" = "localhost:$PRIMARY_PORT" ] ; then
|
||||
ALT_STAT_URL=$(echo $STATISTICS_URL | sed s#localhost#$NON_LOCAL_IP#)
|
||||
|
||||
echo "wget $ALT_STAT_URL >& $TEMPDIR/alt_stat_url.$$"
|
||||
wget $ALT_STAT_URL >& "$TEMPDIR/alt_stat_url.$$"
|
||||
check [ $? = 8 ]
|
||||
check_error_code 8 wget $ALT_STAT_URL >& "$TEMPDIR/alt_stat_url.$$"
|
||||
rm -f "$TEMPDIR/alt_stat_url.$$"
|
||||
|
||||
ALT_CE_URL="$ALT_STAT_URL.pagespeed.ce.8CfGBvwDhH.css"
|
||||
wget -O - $ALT_CE_URL >& "$TEMPDIR/alt_ce_url.$$"
|
||||
check [ $? = 8 ]
|
||||
|
||||
wget -O - --header="Host: $HOSTNAME" $ALT_CE_URL >& "$TEMPDIR/alt_ce_url.$$"
|
||||
check [ $? = 8 ]
|
||||
check_error_code 8 wget -O - $ALT_CE_URL >& "$TEMPDIR/alt_ce_url.$$"
|
||||
check_error_code 8 wget -O - --header="Host: $HOSTNAME" $ALT_CE_URL \
|
||||
>& "$TEMPDIR/alt_ce_url.$$"
|
||||
rm -f "$TEMPDIR/alt_ce_url.$$"
|
||||
|
||||
# Even though we don't have a cookie, we will conservatively avoid
|
||||
@@ -522,7 +527,59 @@ if [ "$HOSTNAME" = "localhost:$PRIMARY_PORT" ] ; then
|
||||
AUTH=""
|
||||
fi
|
||||
|
||||
WGET_ARGS=""
|
||||
start_test "Custom statistics paths in server block"
|
||||
|
||||
# Served on normal paths by default.
|
||||
URL="inherit-paths.example.com/ngx_pagespeed_statistics"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
|
||||
check_from "$OUT" fgrep -q cache_time_us
|
||||
|
||||
URL="inherit-paths.example.com/ngx_pagespeed_message"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
|
||||
check_from "$OUT" fgrep -q Info
|
||||
|
||||
URL="inherit-paths.example.com/pagespeed_console"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
|
||||
check_from "$OUT" fgrep -q console_div
|
||||
|
||||
URL="inherit-paths.example.com/pagespeed_admin/"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
|
||||
check_from "$OUT" fgrep -q Admin
|
||||
|
||||
# Not served on normal paths when overriden.
|
||||
URL="custom-paths.example.com/ngx_pagespeed_statistics"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET_DUMP $URL)
|
||||
check_not_from "$OUT" fgrep -q cache_time_us
|
||||
|
||||
URL="custom-paths.example.com/ngx_pagespeed_message"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET_DUMP $URL)
|
||||
check_not_from "$OUT" fgrep -q Info
|
||||
|
||||
URL="custom-paths.example.com/pagespeed_console"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET_DUMP $URL)
|
||||
check_not_from "$OUT" fgrep -q console_div
|
||||
|
||||
URL="custom-paths.example.com/pagespeed_admin/"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET_DUMP $URL)
|
||||
check_not_from "$OUT" fgrep -q Admin
|
||||
|
||||
# Served on custom paths when overriden
|
||||
URL="custom-paths.example.com/custom_pagespeed_statistics"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
|
||||
check_from "$OUT" fgrep -q cache_time_us
|
||||
|
||||
URL="custom-paths.example.com/custom_pagespeed_message"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
|
||||
check_from "$OUT" fgrep -q Info
|
||||
|
||||
URL="custom-paths.example.com/custom_pagespeed_console"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
|
||||
check_from "$OUT" fgrep -q console_div
|
||||
|
||||
URL="custom-paths.example.com/custom_pagespeed_admin/"
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
|
||||
check_from "$OUT" fgrep -q Admin
|
||||
|
||||
function gunzip_grep_0ff() {
|
||||
gunzip - | fgrep -q "color:#00f"
|
||||
echo $?
|
||||
@@ -549,21 +606,21 @@ start_test Accept bad query params and headers
|
||||
# The examples page should have this EXPECTED_EXAMPLES_TEXT on it.
|
||||
EXPECTED_EXAMPLES_TEXT="PageSpeed Examples Directory"
|
||||
OUT=$(wget -O - $EXAMPLE_ROOT)
|
||||
check_from "$OUT" grep "$EXPECTED_EXAMPLES_TEXT"
|
||||
check_from "$OUT" fgrep -q "$EXPECTED_EXAMPLES_TEXT"
|
||||
|
||||
# It should still be there with bad query params.
|
||||
OUT=$(wget -O - $EXAMPLE_ROOT?PageSpeedFilters=bogus)
|
||||
check_from "$OUT" grep "$EXPECTED_EXAMPLES_TEXT"
|
||||
check_from "$OUT" fgrep -q "$EXPECTED_EXAMPLES_TEXT"
|
||||
|
||||
# And also with bad request headers.
|
||||
OUT=$(wget -O - --header=PageSpeedFilters:bogus $EXAMPLE_ROOT)
|
||||
check_from "$OUT" grep "$EXPECTED_EXAMPLES_TEXT"
|
||||
check_from "$OUT" fgrep -q "$EXPECTED_EXAMPLES_TEXT"
|
||||
|
||||
# Tests that an origin header with a Vary header other than Vary:Accept-Encoding
|
||||
# loses that header when we are not respecting vary.
|
||||
start_test Vary:User-Agent on resources is held by our cache.
|
||||
URL="$TEST_ROOT/vary/no_respect/index.html"
|
||||
fetch_until -save $URL 'grep -c \.pagespeed\.cf\.' 1
|
||||
fetch_until -save $URL 'fgrep -c .pagespeed.cf.' 1
|
||||
|
||||
# Extract out the rewritten CSS file from the HTML saved by fetch_until
|
||||
# above (see -save and definition of fetch_until). Fetch that CSS
|
||||
@@ -624,14 +681,12 @@ echo "JS_URL=\$\(egrep -o http://.*[.]pagespeed.*[.]js $FETCHED\)=\"$JS_URL\""
|
||||
JS_HEADERS=$($WGET -O /dev/null -q -S --header='Accept-Encoding: gzip' \
|
||||
$JS_URL 2>&1)
|
||||
echo JS_HEADERS=$JS_HEADERS
|
||||
check_from "$JS_HEADERS" egrep -qi 'HTTP/1[.]. 200 OK'
|
||||
check_200_http_response "$JS_HEADERS"
|
||||
check_from "$JS_HEADERS" fgrep -qi 'Content-Encoding: gzip'
|
||||
check_from "$JS_HEADERS" fgrep -qi 'Vary: Accept-Encoding'
|
||||
check_from "$JS_HEADERS" egrep -qi '(Etag: W/"0")|(Etag: W/"0-gzip")'
|
||||
check_from "$JS_HEADERS" fgrep -qi 'Last-Modified:'
|
||||
|
||||
WGET_ARGS="" # Done with test_filter, so clear WGET_ARGS.
|
||||
|
||||
start_test Respect X-Forwarded-Proto when told to
|
||||
FETCHED=$OUTDIR/x_forwarded_proto
|
||||
URL=$SECONDARY_HOSTNAME/mod_pagespeed_example/?PageSpeedFilters=add_base_tag
|
||||
@@ -644,21 +699,20 @@ check fgrep -q '<base href="https://' $FETCHED
|
||||
test_filter remove_comments retains appropriate comments.
|
||||
URL="$SECONDARY_HOSTNAME/mod_pagespeed_example/$FILE"
|
||||
check run_wget_with_args $URL --header=Host:retaincomment.example.com
|
||||
check grep -q retained $FETCHED # RetainComment directive
|
||||
check fgrep -q retained $FETCHED # RetainComment directive
|
||||
|
||||
# Make sure that when in PreserveURLs mode that we don't rewrite URLs. This is
|
||||
# non-exhaustive, the unit tests should cover the rest.
|
||||
# Note: We block with psatest here because this is a negative test. We wouldn't
|
||||
# otherwise know how many wget attempts should be made.
|
||||
start_test PreserveURLs on prevents URL rewriting
|
||||
WGET_ARGS="--header=X-PSA-Blocking-Rewrite:psatest"
|
||||
WGET_ARGS+=" --header=Host:preserveurls.example.com"
|
||||
|
||||
start_test PreserveURLs on prevents URL rewriting
|
||||
FILE=preserveurls/on/preserveurls.html
|
||||
URL=$SECONDARY_HOSTNAME/mod_pagespeed_test/$FILE
|
||||
FETCHED=$OUTDIR/preserveurls.html
|
||||
check run_wget_with_args $URL
|
||||
WGET_ARGS=""
|
||||
check_not fgrep -q .pagespeed. $FETCHED
|
||||
|
||||
# When PreserveURLs is off do a quick check to make sure that normal rewriting
|
||||
@@ -692,10 +746,8 @@ URL="$SECONDARY_HOSTNAME/mod_pagespeed_test/no_transform/BikeCrashIcn.png"
|
||||
wget -O - -S $URL $WGET_ARGS &> $FETCHED
|
||||
# Make sure that the no-transfrom header is still there
|
||||
check grep -q 'Cache-Control:.*no-transform' $FETCHED
|
||||
WGET_ARGS=""
|
||||
|
||||
start_test respect vary user-agent
|
||||
WGET_ARGS=""
|
||||
URL="$SECONDARY_HOSTNAME/mod_pagespeed_test/vary/index.html"
|
||||
URL+="?PageSpeedFilters=inline_css"
|
||||
FETCH_CMD="$WGET_DUMP --header=Host:respectvary.example.com $URL"
|
||||
@@ -724,9 +776,8 @@ start_test rewrite on Cache-control: no-transform
|
||||
URL=$TEST_ROOT/disable_no_transform/index.html?PageSpeedFilters=inline_css
|
||||
fetch_until -save -recursive $URL 'grep -c style' 2
|
||||
|
||||
WGET_ARGS=""
|
||||
start_test ShardDomain directive in location block
|
||||
fetch_until -save $TEST_ROOT/shard/shard.html 'grep -c \.pagespeed\.' 4
|
||||
fetch_until -save $TEST_ROOT/shard/shard.html 'fgrep -c .pagespeed.ce' 4
|
||||
check [ $(grep -ce href=\"http://shard1 $FETCH_FILE) = 2 ];
|
||||
check [ $(grep -ce href=\"http://shard2 $FETCH_FILE) = 2 ];
|
||||
|
||||
@@ -804,7 +855,6 @@ start_test combine_javascript with long URL still works
|
||||
URL=$TEST_ROOT/combine_js_very_many.html?PageSpeedFilters=combine_javascript
|
||||
fetch_until $URL 'grep -c src=' 4
|
||||
|
||||
WGET_ARGS=""
|
||||
start_test UseExperimentalJsMinifier
|
||||
URL="$TEST_ROOT/experimental_js_minifier/index.html"
|
||||
URL+="?PageSpeedFilters=rewrite_javascript"
|
||||
@@ -871,10 +921,9 @@ PageSpeedFilters=inline_javascript,debug"
|
||||
OUTFILE=$OUTDIR/blocking_rewrite.out.html
|
||||
$WGET_DUMP --header 'X-PSA-Blocking-Rewrite: psatest' $URL > $OUTFILE
|
||||
check egrep -q 'script[[:space:]]src=' $OUTFILE
|
||||
EXPECTED_COMMENT_LINE="<!--InlineJs: Cannot create resource: either its \
|
||||
domain is unauthorized and InlineUnauthorizedResources is not enabled, \
|
||||
or it cannot be fetched (check the server logs)-->"
|
||||
check grep -q "$EXPECTED_COMMENT_LINE" $OUTFILE
|
||||
EXPECTED_COMMENT_LINE="<!--The preceding resource was not rewritten \
|
||||
because its domain (www.gstatic.com) is not authorized-->"
|
||||
check [ $(grep -o "$EXPECTED_COMMENT_LINE" $OUTFILE | wc -l) -eq 1 ]
|
||||
|
||||
start_test inline_unauthorized_resources allows inlining
|
||||
HOST_NAME="http://unauthorizedresources.example.com"
|
||||
@@ -898,10 +947,9 @@ PageSpeedFilters=inline_css,debug"
|
||||
OUTFILE=$OUTDIR/blocking_rewrite.out.html
|
||||
$WGET_DUMP --header 'X-PSA-Blocking-Rewrite: psatest' $URL > $OUTFILE
|
||||
check egrep -q 'link[[:space:]]rel=' $OUTFILE
|
||||
EXPECTED_COMMENT_LINE="<!--InlineCss: Cannot create resource: either its \
|
||||
domain is unauthorized and InlineUnauthorizedResources is not enabled, \
|
||||
or it cannot be fetched (check the server logs)-->"
|
||||
check grep -q "$EXPECTED_COMMENT_LINE" $OUTFILE
|
||||
EXPECTED_COMMENT_LINE="<!--The preceding resource was not rewritten \
|
||||
because its domain (www.google.com) is not authorized-->"
|
||||
check [ $(grep -o "$EXPECTED_COMMENT_LINE" $OUTFILE | wc -l) -eq 1 ]
|
||||
|
||||
start_test inline_unauthorized_resources allows inlining
|
||||
HOST_NAME="http://unauthorizedresources.example.com"
|
||||
@@ -999,7 +1047,6 @@ wget -O - --header 'X-PSA-Blocking-Rewrite: psatest' $URL > $TEMPDIR/flush.$$
|
||||
check [ `wget -O - $URL | grep -o 'link rel="subresource"' | wc -l` = 0 ]
|
||||
rm -f $TEMPDIR/flush.$$
|
||||
|
||||
WGET_ARGS=""
|
||||
start_test Respect custom options on resources.
|
||||
IMG_NON_CUSTOM="$EXAMPLE_ROOT/images/xPuzzle.jpg.pagespeed.ic.fakehash.jpg"
|
||||
IMG_CUSTOM="$TEST_ROOT/custom_options/xPuzzle.jpg.pagespeed.ic.fakehash.jpg"
|
||||
@@ -1052,18 +1099,26 @@ WGET_ARGS="--save-headers"
|
||||
# We should be able to fetch the original ...
|
||||
echo http_proxy=$SECONDARY_HOSTNAME $WGET --save-headers -O - $ORIGINAL
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET --save-headers -O - $ORIGINAL 2>&1)
|
||||
check_from "$OUT" fgrep " 200 OK"
|
||||
check_200_http_response "$OUT"
|
||||
# ... AND the rewritten version.
|
||||
echo http_proxy=$SECONDARY_HOSTNAME $WGET --save-headers -O - $FILTERED
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET --save-headers -O - $FILTERED 2>&1)
|
||||
check_from "$OUT" fgrep " 200 OK"
|
||||
check_200_http_response "$OUT"
|
||||
|
||||
start_test MapProxyDomain
|
||||
# depends on MapProxyDomain in pagespeed_test.conf.template
|
||||
URL=$EXAMPLE_ROOT/proxy_external_resource.html
|
||||
LEAF="proxy_external_resource.html?PageSpeedFilters=-inline_images"
|
||||
URL="$EXAMPLE_ROOT/$LEAF"
|
||||
echo Rewrite HTML with reference to a proxyable image.
|
||||
fetch_until -save -recursive $URL?PageSpeedFilters=-inline_images \
|
||||
'grep -c 1.gif.pagespeed' 1
|
||||
fetch_until -save -recursive $URL 'grep -c 1.gif.pagespeed' 1 --save-headers
|
||||
PAGESPEED_GIF=$(grep -o '/*1.gif.pagespeed[^"]*' $WGET_DIR/$LEAF)
|
||||
check_from "$PAGESPEED_GIF" grep "gif$"
|
||||
|
||||
echo "If the next line fails, look in $WGET_DIR/wget_output.txt and you should"
|
||||
echo "see a 404. This represents a failed attempt to download the proxied gif."
|
||||
# TODO(jefftk): debug why this test sometimes fails with the native fetcher.
|
||||
# https://github.com/pagespeed/ngx_pagespeed/issues/774
|
||||
check test -f "$WGET_DIR$PAGESPEED_GIF"
|
||||
|
||||
start_test OptimizeForBandwidth
|
||||
# We use blocking-rewrite tests because we want to make sure we don't
|
||||
@@ -1103,12 +1158,11 @@ test_optimize_for_bandwidth core_filters/rewrite_css.html \
|
||||
#
|
||||
# With the proper hash, we'll get a long cache lifetime.
|
||||
SECONDARY_HOST="http://mpd.example.com/gstatic_images"
|
||||
PROXIED_IMAGE="$SECONDARY_HOST/$(basename $WGET_DIR/*1.gif.pagespeed*)"
|
||||
WGET_ARGS="--save-headers"
|
||||
PROXIED_IMAGE="$SECONDARY_HOST$PAGESPEED_GIF"
|
||||
|
||||
start_test $PROXIED_IMAGE expecting one year cache.
|
||||
http_proxy=$SECONDARY_HOSTNAME fetch_until $PROXIED_IMAGE \
|
||||
"grep -c max-age=31536000" 1
|
||||
"grep -c max-age=31536000" 1 --save-headers
|
||||
|
||||
# With the wrong hash, we'll get a short cache lifetime (and also no output
|
||||
# cache hit.
|
||||
@@ -1116,14 +1170,12 @@ WRONG_HASH="0"
|
||||
PROXIED_IMAGE="$SECONDARY_HOST/1.gif.pagespeed.ce.$WRONG_HASH.jpg"
|
||||
start_test Fetching $PROXIED_IMAGE expecting short private cache.
|
||||
http_proxy=$SECONDARY_HOSTNAME fetch_until $PROXIED_IMAGE \
|
||||
"grep -c max-age=300,private" 1
|
||||
|
||||
WGET_ARGS=""
|
||||
"grep -c max-age=300,private" 1 --save-headers
|
||||
|
||||
start_test ShowCache without URL gets a form, inputs, preloaded UA.
|
||||
ADMIN_CACHE=$PRIMARY_SERVER/pagespeed_admin/cache
|
||||
OUT=$($WGET_DUMP $ADMIN_CACHE)
|
||||
check_from "$OUT" fgrep -q "<form "
|
||||
check_from "$OUT" fgrep -q "<form>"
|
||||
check_from "$OUT" fgrep -q "<input "
|
||||
check_from "$OUT" fgrep -q "Cache-Control: max-age=0, no-cache"
|
||||
# Preloaded user_agent value field leading with "Mozilla" set in
|
||||
@@ -1131,8 +1183,8 @@ check_from "$OUT" fgrep -q "Cache-Control: max-age=0, no-cache"
|
||||
check_from "$OUT" fgrep -q 'name=user_agent value="Mozilla'
|
||||
|
||||
start_test ShowCache with bogus URL gives a 404
|
||||
wget $PRIMARY_SERVER/pagespeed_cache?url=bogus_format >& /dev/null
|
||||
check [ $? = 8 ]
|
||||
check_error_code 8 \
|
||||
wget $PRIMARY_SERVER/pagespeed_cache?url=bogus_format >& /dev/null
|
||||
|
||||
start_test ShowCache with valid, present URL, with unique options.
|
||||
options="PageSpeedImageInlineMaxBytes=6765"
|
||||
@@ -1174,38 +1226,17 @@ check_from "$OUT" grep $'^Cache-Control: max-age=0, no-cache\r$'
|
||||
|
||||
start_test server-side includes
|
||||
fetch_until -save $TEST_ROOT/ssi/ssi.shtml?PageSpeedFilters=combine_css \
|
||||
'grep -c \.pagespeed\.' 1
|
||||
'fgrep -c .pagespeed.' 1
|
||||
check [ $(grep -ce $combine_css_filename $FETCH_FILE) = 1 ];
|
||||
|
||||
start_test Embed image configuration in rewritten image URL.
|
||||
|
||||
# The apache test names these virtual hosts as embed_config_*, which is
|
||||
# unfortunate as underscores are not allowed in domain names. Apache doesn't
|
||||
# care, and nginx doesn't either, except when you're proxying. So you can do:
|
||||
#
|
||||
# GET /embed_config.html HTTP/1.1
|
||||
# Host: embed_config_html.example.com
|
||||
#
|
||||
# and it will work fine, but if you do:
|
||||
#
|
||||
# GET http://embed_config_html.example.com/embed_config.html HTTP/1.1
|
||||
#
|
||||
# then nginx will close the connection before you can even give it a Host
|
||||
# header. I've modified this test code to replace embed_config_ with
|
||||
# embed-config-, but the html file on disk has the underscore versions. Let's
|
||||
# make a new html file that has the hyphen version:
|
||||
cat "$SERVER_ROOT/mod_pagespeed_test/embed_config.html" | \
|
||||
sed s/embed_config_/embed-config-/g > \
|
||||
"$SERVER_ROOT/mod_pagespeed_test/embed-config.html"
|
||||
|
||||
# The embedded configuration is placed between the "pagespeed" and "ic", e.g.
|
||||
# *xPuzzle.jpg.pagespeed.gp+jp+pj+js+rj+rp+rw+ri+cp+md+iq=73.ic.oFXPiLYMka.jpg
|
||||
# We use a regex matching "gp+jp+pj+js+rj+rp+rw+ri+cp+md+iq=73" rather than
|
||||
# spelling it out to avoid test regolds when we add image filter IDs.
|
||||
WGET_ARGS="--save-headers"
|
||||
http_proxy=$SECONDARY_HOSTNAME fetch_until -save -recursive \
|
||||
http://embed-config-html.example.org/embed-config.html \
|
||||
'grep -c \.pagespeed\.' 3
|
||||
http://embed-config-html.example.org/embed_config.html \
|
||||
'fgrep -c .pagespeed.' 3 --save-headers
|
||||
|
||||
# with the default rewriters in vhost embed-config-resources.example.com
|
||||
# the image will be >200k. But by enabling resizing & compression 73
|
||||
@@ -1274,7 +1305,6 @@ function embed_image_config_post_flush() {
|
||||
# places where we flush cache, which requires sleeps since the
|
||||
# cache-flush is poll driven.
|
||||
start_test Embed image/css configuration decoding with clear cache.
|
||||
WGET_ARGS=""
|
||||
echo Looking for $EMBED_CONFIGURATION_IMAGE expecting \
|
||||
$EMBED_CONFIGURATION_IMAGE_LENGTH bytes
|
||||
http_proxy=$SECONDARY_HOSTNAME fetch_until "$EMBED_CONFIGURATION_IMAGE" \
|
||||
@@ -1324,10 +1354,10 @@ check touch "$SECONDARY_CACHE/cache.flush"
|
||||
check touch "$IPRO_CACHE/cache.flush"
|
||||
sleep 1
|
||||
|
||||
CSS_FILE="$SERVER_ROOT/mod_pagespeed_test/update.css"
|
||||
CSS_FILE="$SERVER_ROOT/mod_pagespeed_test/cache_flush/update.css"
|
||||
echo ".class myclass { color: $COLOR0; }" > "$CSS_FILE"
|
||||
|
||||
URL_PATH="mod_pagespeed_test/cache_flush_test.html"
|
||||
URL_PATH="mod_pagespeed_test/cache_flush/cache_flush_test.html"
|
||||
|
||||
URL="$SECONDARY_HOSTNAME/$URL_PATH"
|
||||
CACHE_A="--header=Host:cache_a.example.com"
|
||||
@@ -1465,7 +1495,7 @@ else
|
||||
EXPECTED="Serf status 111"
|
||||
fi
|
||||
for i in {1..100}; do
|
||||
ERRS=$(grep -c "$EXPECTED" $FETCHER_REFUSED_PATH)
|
||||
ERRS=$(grep -c "$EXPECTED" $FETCHER_REFUSED_PATH || true)
|
||||
if [ $ERRS -ge 1 ]; then
|
||||
break;
|
||||
fi;
|
||||
@@ -1475,7 +1505,7 @@ done;
|
||||
echo "."
|
||||
# Kill the log monitor silently.
|
||||
kill $TAIL_PID
|
||||
wait $TAIL_PID 2> /dev/null
|
||||
wait $TAIL_PID 2> /dev/null || true
|
||||
check [ $ERRS -ge 1 ]
|
||||
|
||||
# TODO(jefftk): when we support ListOutstandingUrlsOnError uncomment the below
|
||||
@@ -1494,7 +1524,6 @@ check [ $ERRS -ge 1 ]
|
||||
#
|
||||
# This rewrites the CSS, absolutifying the embedded relative image URL
|
||||
# reference based on the the main server host.
|
||||
WGET_ARGS=""
|
||||
start_test Relative images embedded in a CSS file served from a mapped domain
|
||||
DIR="mod_pagespeed_test/map_css_embedded"
|
||||
URL="http://www.example.com/$DIR/issue494.html"
|
||||
@@ -1551,7 +1580,8 @@ OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET -O /dev/null $ALLOWED 2>&1)
|
||||
check_from "$OUT" fgrep -q "200 OK"
|
||||
# .cf. is forbidden
|
||||
FORBIDDEN=$FORBIDDEN_STYLES_ROOT/A.all_styles.css.pagespeed.cf.UH8L-zY4b4.css
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET -O /dev/null $FORBIDDEN 2>&1)
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET -O /dev/null $FORBIDDEN \
|
||||
2>&1)
|
||||
check_from "$OUT" fgrep -q "404 Not Found"
|
||||
# The image will be optimized but NOT resized to the much smaller size,
|
||||
# so it will be >200k (optimized) rather than <20k (resized).
|
||||
@@ -1629,7 +1659,6 @@ function test_forbid_all_disabled() {
|
||||
$WGET $WGET_ARGS -q -O $OUTFILE $HEADER $URL
|
||||
check egrep -q '<style>.yellow' $OUTFILE
|
||||
rm -f $OUTFILE
|
||||
WGET_ARGS=""
|
||||
}
|
||||
start_test ForbidAllDisabledFilters baseline check.
|
||||
test_forbid_all_disabled "" ""
|
||||
@@ -1797,11 +1826,11 @@ check_not_from "$OUT" grep 'pagespeed_beacon.*exptid'
|
||||
# order they're defined in the config file.
|
||||
start_test Resource urls are rewritten to include experiment indexes.
|
||||
http_proxy=$SECONDARY_HOSTNAME \
|
||||
WGET_ARGS="--header Cookie:PageSpeedExperiment=7" fetch_until $EXP_EXTEND_CACHE \
|
||||
"fgrep -c .pagespeed.a.ic." 1
|
||||
fetch_until $EXP_EXTEND_CACHE \
|
||||
"fgrep -c .pagespeed.a.ic." 1 --header=Cookie:PageSpeedExperiment=7
|
||||
http_proxy=$SECONDARY_HOSTNAME \
|
||||
WGET_ARGS="--header Cookie:PageSpeedExperiment=2" fetch_until $EXP_EXTEND_CACHE \
|
||||
"fgrep -c .pagespeed.b.ic." 1
|
||||
fetch_until $EXP_EXTEND_CACHE \
|
||||
"fgrep -c .pagespeed.b.ic." 1 --header=Cookie:PageSpeedExperiment=2
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP --header='Cookie: PageSpeedExperiment=7' \
|
||||
$EXP_EXTEND_CACHE)
|
||||
check_from "$OUT" fgrep ".pagespeed.a.ic."
|
||||
@@ -1924,6 +1953,51 @@ check [ `grep -c '<style>[.]big{[^}]*}</style>' $FETCH_UNTIL_OUTFILE` = 1 ]
|
||||
check [ `grep -c '<style>[.]blue{[^}]*}[.]bold{[^}]*}</style>' \
|
||||
$FETCH_UNTIL_OUTFILE` = 1 ]
|
||||
|
||||
# Now repeat the critical_css_filter test on a host that processes post data via
|
||||
# temp files to test that ngx_pagespeed specific code path.
|
||||
test_filter prioritize_critical_css Able to read POST data from temp file.
|
||||
URL="http://beacon-post-temp-file.example.com/mod_pagespeed_example/prioritize_critical_css.html"
|
||||
http_proxy=$SECONDARY_HOSTNAME\
|
||||
fetch_until -save $URL 'fgrep -c pagespeed.criticalCssBeaconInit' 1
|
||||
check [ $(fgrep -o ".very_large_class_name_" $FETCH_FILE | wc -l) -eq 36 ]
|
||||
CALL_PAT=".*criticalCssBeaconInit("
|
||||
SKIP_ARG="[^,]*,"
|
||||
CAPTURE_ARG="'\([^']*\)'.*"
|
||||
BEACON_PATH=$(sed -n "s/${CALL_PAT}${CAPTURE_ARG}/\1/p" $FETCH_FILE)
|
||||
ESCAPED_URL=$( \
|
||||
sed -n "s/${CALL_PAT}${SKIP_ARG}${CAPTURE_ARG}/\1/p" $FETCH_FILE)
|
||||
OPTIONS_HASH=$( \
|
||||
sed -n "s/${CALL_PAT}${SKIP_ARG}${SKIP_ARG}${CAPTURE_ARG}/\1/p" $FETCH_FILE)
|
||||
NONCE=$( \
|
||||
sed -n "s/${CALL_PAT}${SKIP_ARG}${SKIP_ARG}${SKIP_ARG}${CAPTURE_ARG}/\1/p" \
|
||||
$FETCH_FILE)
|
||||
BEACON_URL="http://${SECONDARY_HOSTNAME}${BEACON_PATH}?url=${ESCAPED_URL}"
|
||||
BEACON_DATA="oh=${OPTIONS_HASH}&n=${NONCE}&cs=.big,.blue,.bold,.foo"
|
||||
|
||||
OUT=$(wget -q --save-headers -O - --no-http-keep-alive \
|
||||
--post-data "$BEACON_DATA" "$BEACON_URL" \
|
||||
--header "Host:beacon-post-temp-file.example.com")
|
||||
check_from "$OUT" grep '^HTTP/1.1 204'
|
||||
|
||||
# Now make sure we see the correct critical css rules.
|
||||
http_proxy=$SECONDARY_HOSTNAME\
|
||||
fetch_until $URL \
|
||||
'grep -c <style>[.]blue{[^}]*}</style>' 1
|
||||
http_proxy=$SECONDARY_HOSTNAME\
|
||||
fetch_until $URL \
|
||||
'grep -c <style>[.]big{[^}]*}</style>' 1
|
||||
http_proxy=$SECONDARY_HOSTNAME\
|
||||
fetch_until $URL \
|
||||
'grep -c <style>[.]blue{[^}]*}[.]bold{[^}]*}</style>' 1
|
||||
http_proxy=$SECONDARY_HOSTNAME\
|
||||
fetch_until -save $URL \
|
||||
'grep -c <style>[.]foo{[^}]*}</style>' 1
|
||||
# The last one should also have the other 3, too.
|
||||
check [ `grep -c '<style>[.]blue{[^}]*}</style>' $FETCH_UNTIL_OUTFILE` = 1 ]
|
||||
check [ `grep -c '<style>[.]big{[^}]*}</style>' $FETCH_UNTIL_OUTFILE` = 1 ]
|
||||
check [ `grep -c '<style>[.]blue{[^}]*}[.]bold{[^}]*}</style>' \
|
||||
$FETCH_UNTIL_OUTFILE` = 1 ]
|
||||
|
||||
# This test checks that the ClientDomainRewrite directive can turn on.
|
||||
start_test ClientDomainRewrite on directive
|
||||
HOST_NAME="http://client-domain-rewrite.example.com"
|
||||
@@ -1933,7 +2007,6 @@ MATCHES=$(echo "$RESPONSE_OUT" | grep -c pagespeed\.clientDomainRewriterInit)
|
||||
check [ $MATCHES -eq 1 ]
|
||||
|
||||
# Verify rendered image dimensions test.
|
||||
WGET_ARGS=""
|
||||
start_test resize_rendered_image_dimensions with critical images beacon
|
||||
HOST_NAME="http://renderedimagebeacon.example.com"
|
||||
URL="$HOST_NAME/mod_pagespeed_test/image_rewriting/image_resize_using_rendered_dimensions.html"
|
||||
@@ -1997,24 +2070,22 @@ OUT1=$(http_proxy=$SECONDARY_HOSTNAME \
|
||||
$WGET_DUMP --header 'X-PSA-Blocking-Rewrite: psatest' $URL)
|
||||
check_not_from "$OUT1" egrep -q 'pagespeed\.criticalCssBeaconInit'
|
||||
check_from "$OUT1" grep -q "Cache-Control: private, max-age=3000"
|
||||
|
||||
# 2. We get an instrumented page if the correct key is present.
|
||||
OUT2=$(http_proxy=$SECONDARY_HOSTNAME \
|
||||
$WGET_DUMP $WGET_ARGS \
|
||||
--header 'X-PSA-Blocking-Rewrite: psatest'\
|
||||
--header="PS-ShouldBeacon: random_rebeaconing_key" $URL)
|
||||
check_from "$OUT2" grep -q "Cache-Control: max-age=0, no-cache"
|
||||
check_from "$OUT2" egrep -q "pagespeed\.criticalCssBeaconInit"
|
||||
http_proxy=$SECONDARY_HOSTNAME \
|
||||
fetch_until -save $URL 'grep -c criticalCssBeaconInit' 2 \
|
||||
"--header=PS-ShouldBeacon:random_rebeaconing_key --save-headers"
|
||||
check grep -q "Cache-Control: max-age=0, no-cache" $FETCH_UNTIL_OUTFILE
|
||||
|
||||
# 3. We do not get an instrumented page if the wrong key is present.
|
||||
WGET_ARGS="--header=\"PS-ShouldBeacon: wrong_rebeaconing_key\""
|
||||
OUT3=$(http_proxy=$SECONDARY_HOSTNAME \
|
||||
OUT3=$(http_proxy=$SECONDARY_HOSTNAME check_not \
|
||||
$WGET_DUMP $WGET_ARGS $URL)
|
||||
check_not_from "$OUT3" egrep -q "pagespeed\.criticalCssBeaconInit"
|
||||
check_from "$OUT3" grep -q "Cache-Control: private, max-age=3000"
|
||||
|
||||
|
||||
# Verify that we can send a critical image beacon and that lazyload_images
|
||||
# does not try to lazyload the critical images.
|
||||
WGET_ARGS=""
|
||||
start_test lazyload_images,rewrite_images with critical images beacon
|
||||
HOST_NAME="http://imagebeacon.example.com"
|
||||
URL="$HOST_NAME/mod_pagespeed_test/image_rewriting/rewrite_images.html"
|
||||
@@ -2093,15 +2164,12 @@ check_not fgrep -q "interesting_color" $FETCH_FILE
|
||||
# c) selectors that don't depend on flattening should appear in the selector
|
||||
# list.
|
||||
check [ $(fgrep -c "non_flattened_selector" $FETCH_FILE) -eq 1 ]
|
||||
EXPECTED_IMPORT_FAILURE_LINE="<!--Flattening failed: Cannot import "
|
||||
EXPECTED_IMPORT_FAILURE_LINE+="http://www.google.com/css/maia.css: is it on "
|
||||
EXPECTED_IMPORT_FAILURE_LINE+="an unauthorized domain?-->"
|
||||
check grep -q "$EXPECTED_IMPORT_FAILURE_LINE" $FETCH_FILE
|
||||
EXPECTED_COMMENT_LINE="<!--CriticalCssBeacon: Cannot create resource: either "
|
||||
EXPECTED_COMMENT_LINE+="its domain is unauthorized and "
|
||||
EXPECTED_COMMENT_LINE+="InlineUnauthorizedResources is not enabled, or it "
|
||||
EXPECTED_COMMENT_LINE+="cannot be fetched (check the server logs)-->"
|
||||
check grep -q "$EXPECTED_COMMENT_LINE" $FETCH_FILE
|
||||
EXPECTED_IMPORT_FAILURE_LINE="<!--Flattening failed: Cannot import \
|
||||
http://www.google.com/css/maia.css as it is on an unauthorized domain-->"
|
||||
check [ $(grep -o "$EXPECTED_IMPORT_FAILURE_LINE" $FETCH_FILE | wc -l) -eq 1 ]
|
||||
EXPECTED_COMMENT_LINE="<!--The preceding resource was not rewritten \
|
||||
because its domain (www.google.com) is not authorized-->"
|
||||
check [ $(grep -o "$EXPECTED_COMMENT_LINE" $FETCH_FILE | wc -l) -eq 1 ]
|
||||
|
||||
start_test inline_unauthorized_resources allows unauthorized css selectors
|
||||
HOST_NAME="http://unauthorizedresources.example.com"
|
||||
@@ -2150,7 +2218,7 @@ keepalive_test "keepalive-beacon-post.example.com" "/ngx_pagespeed_beacon"\
|
||||
|
||||
start_test keepalive with static resources
|
||||
keepalive_test "keepalive-static.example.com"\
|
||||
"/pagespeed_static/js_defer.0.js" ""
|
||||
"/pagespeed_custom_static/js_defer.0.js" ""
|
||||
|
||||
# Test for MaxCombinedCssBytes. The html used in the test, 'combine_css.html',
|
||||
# has 4 CSS files in the following order.
|
||||
@@ -2177,7 +2245,6 @@ check [ $(grep -c 'styles/big.css\"' $FETCH_UNTIL_OUTFILE) = 1 ]
|
||||
# response-headers from the server. The reponse-headers from Serf never seem to
|
||||
# include the Connection header. So we have to pick a JS file that is not
|
||||
# otherwise used after cache is flushed in this block.
|
||||
WGET_ARGS=""
|
||||
start_test Sane Connection header
|
||||
URL="$TEST_ROOT/normal.js"
|
||||
fetch_until -save $URL 'grep -c W/\"PSA-aj-' 1 --save-headers
|
||||
@@ -2185,7 +2252,7 @@ CONNECTION=$(extract_headers $FETCH_UNTIL_OUTFILE | fgrep "Connection:")
|
||||
check_not_from "$CONNECTION" fgrep -qi "Keep-Alive, Keep-Alive"
|
||||
check_from "$CONNECTION" fgrep -qi "Keep-Alive"
|
||||
|
||||
start_test pagespeed_static defer js served with correct headers.
|
||||
start_test pagespeed_custom_static defer js served with correct headers.
|
||||
# First, determine which hash js_defer is served with. We need a correct hash
|
||||
# to get it served up with an Etag, which is one of the things we want to test.
|
||||
URL="$HOSTNAME/mod_pagespeed_example/defer_javascript.html?PageSpeed=on&PageSpeedFilters=defer_javascript"
|
||||
@@ -2230,11 +2297,8 @@ function test_ipro_for_browser_webp() {
|
||||
IN_ACCEPT="$1"; shift
|
||||
IMAGE_TYPE="$1"; shift
|
||||
OUT_CONTENT_TYPE="$1"; shift
|
||||
OUT_VARY="${1-}"; shift
|
||||
OUT_CC="${1-}"; shift
|
||||
WGET_ARGS="--save-headers \
|
||||
${IN_UA:+--user-agent $IN_UA} \
|
||||
${IN_ACCEPT:+--header=Accept:image/$IN_ACCEPT}"
|
||||
OUT_VARY="${1-}"; shift || true
|
||||
OUT_CC="${1-}"; shift || true
|
||||
# Remaining args are the expected headers (Name:Value), photo, or synthetic.
|
||||
if [ "$IMAGE_TYPE" = "photo" ]; then
|
||||
URL="http://ipro-for-browser.example.com/images/Puzzle.jpg"
|
||||
@@ -2260,6 +2324,9 @@ function test_ipro_for_browser_webp() {
|
||||
TEST_ID+=" Cache-Control:${OUT_CC}."
|
||||
fi
|
||||
start_test $TEST_ID
|
||||
WGET_ARGS="--save-headers \
|
||||
${IN_UA:+--user-agent $IN_UA} \
|
||||
${IN_ACCEPT:+--header=Accept:image/$IN_ACCEPT}"
|
||||
http_proxy=$SECONDARY_HOSTNAME \
|
||||
fetch_until -save $URL 'grep -c W/\"PSA-aj-' 1
|
||||
check_from "$(extract_headers $FETCH_UNTIL_OUTFILE)" \
|
||||
@@ -2340,12 +2407,53 @@ test_decent_browsers "New Opera" \
|
||||
"Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14"
|
||||
|
||||
WGETRC=$OLD_WGETRC
|
||||
WGET_ARGS=""
|
||||
|
||||
JS_URL="$HOSTNAME/pagespeed_static/js_defer.$HASH.js"
|
||||
start_test Request Option Override : Correct values are passed
|
||||
HOST_NAME="http://request-option-override.example.com"
|
||||
OPTS="?ModPagespeed=on"
|
||||
OPTS+="&ModPagespeedFilters=+collapse_whitespace,+remove_comments"
|
||||
OPTS+="&PageSpeedRequestOptionOverride=abc"
|
||||
URL="$HOST_NAME/mod_pagespeed_test/forbidden.html$OPTS"
|
||||
OUT="$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)"
|
||||
echo wget $URL
|
||||
check_not_from "$OUT" grep -q '<!--'
|
||||
|
||||
start_test Request Option Override : Incorrect values are passed
|
||||
HOST_NAME="http://request-option-override.example.com"
|
||||
OPTS="?ModPagespeed=on"
|
||||
OPTS+="&ModPagespeedFilters=+collapse_whitespace,+remove_comments"
|
||||
OPTS+="&PageSpeedRequestOptionOverride=notabc"
|
||||
URL="$HOST_NAME/mod_pagespeed_test/forbidden.html$OPTS"
|
||||
OUT="$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)"
|
||||
echo wget $URL
|
||||
check_from "$OUT" grep -q '<!--'
|
||||
|
||||
start_test Request Option Override : Correct values are passed as headers
|
||||
HOST_NAME="http://request-option-override.example.com"
|
||||
OPTS="--header=ModPagespeed:on"
|
||||
OPTS+=" --header=ModPagespeedFilters:+collapse_whitespace,+remove_comments"
|
||||
OPTS+=" --header=PageSpeedRequestOptionOverride:abc"
|
||||
URL="$HOST_NAME/mod_pagespeed_test/forbidden.html"
|
||||
echo wget $OPTS $URL
|
||||
OUT="$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $OPTS $URL)"
|
||||
check_not_from "$OUT" grep -q '<!--'
|
||||
|
||||
start_test Request Option Override : Incorrect values are passed as headers
|
||||
HOST_NAME="http://request-option-override.example.com"
|
||||
OPTS="--header=ModPagespeed:on"
|
||||
OPTS+=" --header=ModPagespeedFilters:+collapse_whitespace,+remove_comments"
|
||||
OPTS+=" --header=PageSpeedRequestOptionOverride:notabc"
|
||||
URL="$HOST_NAME/mod_pagespeed_test/forbidden.html"
|
||||
echo wget $OPTS $URL
|
||||
OUT="$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $OPTS $URL)"
|
||||
check_from "$OUT" grep -q '<!--'
|
||||
|
||||
start_test JS gzip headers
|
||||
|
||||
JS_URL="$HOSTNAME/pagespeed_custom_static/js_defer.$HASH.js"
|
||||
JS_HEADERS=$($WGET -O /dev/null -q -S --header='Accept-Encoding: gzip' \
|
||||
$JS_URL 2>&1)
|
||||
check_from "$JS_HEADERS" egrep -qi 'HTTP/1[.]. 200 OK'
|
||||
check_200_http_response "$JS_HEADERS"
|
||||
check_from "$JS_HEADERS" fgrep -qi 'Content-Encoding: gzip'
|
||||
check_from "$JS_HEADERS" fgrep -qi 'Vary: Accept-Encoding'
|
||||
# Nginx's gzip module clears etags, which we don't want. Make sure we have it.
|
||||
@@ -2533,15 +2641,19 @@ ETAG=$(extract_headers $FETCH_UNTIL_OUTFILE | awk '/ETag:/ {print $2}')
|
||||
echo $WGET_DUMP --header "If-None-Match: $ETAG" $URL
|
||||
OUTFILE=$OUTDIR/etags
|
||||
# Note: -o gets debug info which is the only place that 304 message is sent.
|
||||
$WGET -o $OUTFILE -O /dev/null --header "If-None-Match: $ETAG" $URL
|
||||
check_not $WGET -o $OUTFILE -O /dev/null --header "If-None-Match: $ETAG" $URL
|
||||
check fgrep -q "awaiting response... 304" $OUTFILE
|
||||
|
||||
start_test PageSpeed resources should have a content length.
|
||||
URL="$EXAMPLE_ROOT/styles/W.rewrite_css_images.css.pagespeed.cf.Hash.css"
|
||||
OUT=$($WGET_DUMP --save-headers $URL)
|
||||
check_from "$OUT" egrep -q $'^Content-Length: ([0-9])*\r$'
|
||||
check_not_from "$OUT" egrep -iq $'^Transfer-Encoding: chunked\r$'
|
||||
check_not_from "$OUT" egrep -iq $'^Connection: close\r$'
|
||||
# Test if the warning messages are colored in message_history page.
|
||||
# We color the messages in message_history page to make it clearer to read.
|
||||
# Red for Error messages. Brown for Warning messages.
|
||||
# Orange for Fatal messages. Black by default.
|
||||
# Won't test Error messages and Fatal messages in this test.
|
||||
start_test Messages are colored in message_history
|
||||
INJECT=$($CURL --silent $HOSTNAME/?PageSpeed=Warning_trigger)
|
||||
OUT=$($WGET -q -O - $HOSTNAME/pagespeed_admin/message_history | \
|
||||
grep Warning_trigger)
|
||||
check_from "$OUT" fgrep -q "color:brown;"
|
||||
|
||||
start_test Downstream cache integration caching headers.
|
||||
URL="http://downstreamcacheresource.example.com/mod_pagespeed_example/images/"
|
||||
@@ -2581,9 +2693,8 @@ check_from "$OUT" grep -q "/mod_pagespeed_example"
|
||||
|
||||
start_test Check keepalive after a 304 responses.
|
||||
# '-m 2' specifies that the whole operation is allowed to take 2 seconds max.
|
||||
curl -vv -m 2 http://$PRIMARY_HOSTNAME/foo.css.pagespeed.ce.0.css \
|
||||
check curl -vv -m 2 http://$PRIMARY_HOSTNAME/foo.css.pagespeed.ce.0.css \
|
||||
-H 'If-Modified-Since: Z' http://$PRIMARY_HOSTNAME/foo
|
||||
check [ $? = "0" ]
|
||||
|
||||
start_test Date response header set
|
||||
OUT=$($WGET_DUMP $EXAMPLE_ROOT/combine_css.html)
|
||||
@@ -2594,12 +2705,91 @@ OUT=$($WGET_DUMP --header=Host:date.example.com \
|
||||
check_from "$OUT" egrep -q '^Date: Fri, 16 Oct 2009 23:05:07 GMT'
|
||||
WGET_ARGS=
|
||||
|
||||
#very basic tests to test gzip nesting configuration
|
||||
start_test Nested gzip gzip off
|
||||
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/"
|
||||
HEADERS="--header=Accept-Encoding:gzip --header=Host:gzip-test1.example.com"
|
||||
OUT=$($WGET_DUMP -O /dev/null -S $HEADERS $URL 2>&1)
|
||||
check_not_from "$OUT" fgrep -qi 'Content-Encoding: gzip'
|
||||
check_not_from "$OUT" fgrep -qi 'Vary: Accept-Encoding'
|
||||
|
||||
start_test Nested gzip gzip on
|
||||
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/styles/big.css"
|
||||
HEADERS="--header=Accept-Encoding:gzip --header=Host:gzip-test1.example.com"
|
||||
OUT=$($WGET_DUMP -O /dev/null -S $HEADERS $URL 2>&1)
|
||||
check_from "$OUT" fgrep -qi 'Content-Encoding: gzip'
|
||||
check_from "$OUT" fgrep -qi 'Vary: Accept-Encoding'
|
||||
|
||||
start_test Nested gzip pagespeed off
|
||||
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/"
|
||||
HEADERS="--header=Accept-Encoding:gzip --header=Host:gzip-test2.example.com"
|
||||
OUT=$($WGET_DUMP -O /dev/null -S $HEADERS $URL 2>&1)
|
||||
check_not_from "$OUT" fgrep -qi 'Content-Encoding: gzip'
|
||||
check_not_from "$OUT" fgrep -qi 'Vary: Accept-Encoding'
|
||||
|
||||
start_test Nested gzip pagespeed on
|
||||
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/styles/big.css"
|
||||
HEADERS="--header=Accept-Encoding:gzip --header=Host:gzip-test2.example.com"
|
||||
OUT=$($WGET_DUMP -O /dev/null -S $HEADERS $URL 2>&1)
|
||||
check_from "$OUT" fgrep -qi 'Content-Encoding: gzip'
|
||||
check_from "$OUT" fgrep -qi 'Vary: Accept-Encoding'
|
||||
|
||||
start_test Test that POST requests are rewritten.
|
||||
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/rewrite_images.html"
|
||||
HEADERS="--header=Host:proxy-post.example.com --post-data=abcdefgh"
|
||||
OUT=$($WGET_DUMP -S $HEADERS $URL 2>&1)
|
||||
check_from "$OUT" fgrep -qi 'addInstrumentationInit'
|
||||
|
||||
if [ "$NATIVE_FETCHER" != "on" ]; then
|
||||
start_test Test that we can rewrite an HTTPS resource.
|
||||
fetch_until $TEST_ROOT/https_fetch/https_fetch.html \
|
||||
'grep -c /https_gstatic_dot_com/1.gif.pagespeed.ce' 1
|
||||
fi
|
||||
|
||||
start_test Base config has purging disabled. Check error message syntax.
|
||||
OUT=$($WGET_DUMP "$HOSTNAME/pagespeed_admin/cache?purge=*")
|
||||
check_from "$OUT" fgrep -q "pagespeed EnableCachePurge on;"
|
||||
|
||||
start_test Default server header in html flow.
|
||||
URL=http://headers.example.com/mod_pagespeed_example/
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP -O /dev/null -S $URL 2>&1)
|
||||
# '|| true' in the line below supresses the exit code from grep when there is no
|
||||
# match in its input (1).
|
||||
MATCHES=$(echo "$OUT" | grep -c "Server: nginx/") || true
|
||||
check [ $MATCHES -eq 1 ]
|
||||
|
||||
start_test Default server header in resource flow.
|
||||
URL=http://headers.example.com/mod_pagespeed_example/
|
||||
URL+=combine_javascript2.js+combine_javascript1.js.pagespeed.jc.0.js
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP -O /dev/null -S $URL 2>&1)
|
||||
MATCHES=$(echo "$OUT" | grep -c "Server: nginx/") || true
|
||||
check [ $MATCHES -eq 1 ]
|
||||
|
||||
start_test Default server header in IPRO flow.
|
||||
URL=http://headers.example.com//mod_pagespeed_example/combine_javascript2.js
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP -O /dev/null -S $URL 2>&1)
|
||||
MATCHES=$(echo "$OUT" | grep -c "Server: nginx/") || true
|
||||
check [ $MATCHES -eq 1 ]
|
||||
|
||||
start_test Override server header in html flow.
|
||||
URL=http://headers.example.com/mod_pagespeed_test/whitespace.html
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP -O /dev/null -S $URL 2>&1)
|
||||
MATCHES=$(echo "$OUT" | grep -c "Server: override") || true
|
||||
check [ $MATCHES -eq 1 ]
|
||||
|
||||
start_test Override server header in resource flow.
|
||||
URL=http://headers.example.com/mod_pagespeed_test/
|
||||
URL+=A.proxy_pass.css.pagespeed.cf.0.css
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP -O /dev/null -S $URL 2>&1)
|
||||
MATCHES=$(echo "$OUT" | grep -c "Server: override") || true
|
||||
check [ $MATCHES -eq 1 ]
|
||||
|
||||
start_test Override server header in IPRO flow.
|
||||
URL=http://headers.example.com/mod_pagespeed_test/proxy_pass.css
|
||||
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP -O /dev/null -S $URL 2>&1)
|
||||
MATCHES=$(echo "$OUT" | grep -c "Server: override") || true
|
||||
check [ $MATCHES -eq 1 ]
|
||||
|
||||
if $USE_VALGRIND; then
|
||||
# It is possible that there are still ProxyFetches outstanding
|
||||
# at this point in time. Give them a few extra seconds to allow
|
||||
|
||||
@@ -27,6 +27,7 @@ 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;
|
||||
@@ -34,6 +35,14 @@ http {
|
||||
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
|
||||
@@ -73,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@@";
|
||||
|
||||
@@ -92,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@@";
|
||||
|
||||
@@ -150,9 +161,9 @@ http {
|
||||
set $bypass_cache "1";
|
||||
}
|
||||
|
||||
# For testing purposes, we never generate values that will result in a beacon
|
||||
# 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,
|
||||
# This is for testing purposes, note that in a production environment,
|
||||
# you want 'set_random $rand 0 100;' unconditionally!
|
||||
set $rand 5;
|
||||
|
||||
@@ -174,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;
|
||||
}
|
||||
@@ -212,6 +224,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name if-in-server.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
@@ -232,6 +245,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name if-in-location.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
@@ -251,6 +265,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name mpd.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
@@ -261,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;
|
||||
@@ -275,6 +291,7 @@ http {
|
||||
}
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name experiment.noga.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -288,6 +305,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name preserveurls.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -317,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@@";
|
||||
|
||||
@@ -329,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@@";
|
||||
|
||||
@@ -344,6 +364,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name downstreamcacheresource.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
pagespeed RewriteLevel PassThrough;
|
||||
@@ -353,6 +374,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name renderedimagebeacon.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -370,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@@";
|
||||
|
||||
@@ -401,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";
|
||||
@@ -419,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@@";
|
||||
|
||||
@@ -434,6 +459,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name unauthorizedresources.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -444,6 +470,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name client-domain-rewrite.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -459,6 +486,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name url-attribute.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -492,6 +520,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name domain-hyperlinks-on.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -506,6 +535,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name domain-hyperlinks-off.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -520,6 +550,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name retaincomment.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -529,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@@";
|
||||
|
||||
@@ -538,6 +570,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name xfp.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -546,6 +579,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name xheader.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -559,6 +593,7 @@ http {
|
||||
# Note that we test with two distinct caches.
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name embed-config-html.example.org;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -578,6 +613,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name embed-config-resources.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -598,6 +634,7 @@ 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;
|
||||
@@ -609,6 +646,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name respectvary.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -618,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@@";
|
||||
|
||||
@@ -638,6 +690,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name cache_c.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
|
||||
@@ -651,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@@";
|
||||
|
||||
@@ -664,6 +718,7 @@ http {
|
||||
# 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@@";
|
||||
|
||||
@@ -677,6 +732,7 @@ http {
|
||||
# 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@@";
|
||||
|
||||
@@ -688,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@@";
|
||||
|
||||
@@ -701,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@@";
|
||||
|
||||
@@ -713,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@@";
|
||||
|
||||
@@ -724,6 +813,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name blocking.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
@@ -733,6 +823,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name keepalive-html.example.com;
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@";
|
||||
pagespeed RewriteLevel CoreFilters;
|
||||
@@ -741,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;
|
||||
@@ -748,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;
|
||||
@@ -755,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;
|
||||
@@ -762,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;
|
||||
@@ -769,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;
|
||||
@@ -778,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;
|
||||
@@ -787,6 +884,7 @@ http {
|
||||
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name ipro.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
|
||||
@@ -810,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";
|
||||
|
||||
@@ -824,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";
|
||||
|
||||
@@ -838,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";
|
||||
|
||||
@@ -848,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";
|
||||
|
||||
@@ -857,14 +959,120 @@ 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 @@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;
|
||||
}
|
||||
|
||||
# Test that pagespeed is disabled when sendfile headers are present.
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name uses-sendfile.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
pagespeed EnableFilters inline_javascript,rewrite_javascript;
|
||||
add_header 'X-Sendfile' 'blablabla';
|
||||
}
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name doesnt-sendfile.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
pagespeed EnableFilters inline_javascript,rewrite_javascript;
|
||||
}
|
||||
server {
|
||||
listen @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name uses-xaccelredirect.example.com;
|
||||
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
|
||||
pagespeed EnableFilters inline_javascript,rewrite_javascript;
|
||||
add_header 'X-Accel-Redirect' 'blablabla';
|
||||
}
|
||||
|
||||
# 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";
|
||||
|
||||
@@ -880,18 +1088,120 @@ http {
|
||||
|
||||
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 {
|
||||
listen @@PRIMARY_PORT@@;
|
||||
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 @@SECONDARY_PORT@@;
|
||||
listen [::]:@@SECONDARY_PORT@@;
|
||||
server_name headers.example.com;
|
||||
root "@@SERVER_ROOT@@";
|
||||
pagespeed FileCachePath "@@FILE_CACHE@@_purge";
|
||||
pagespeed RewriteLevel CoreFilters;
|
||||
|
||||
pagespeed InPlaceRewriteDeadlineMs -1;
|
||||
pagespeed LoadFromFile "http://headers.example.com/"
|
||||
"@@SERVER_ROOT@@/";
|
||||
location /mod_pagespeed_test/ {
|
||||
more_set_headers "Server: overriden";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -932,7 +1242,6 @@ http {
|
||||
#pagespeed MemcachedThreads 1;
|
||||
|
||||
pagespeed on;
|
||||
pagespeed MessageBufferSize 200000;
|
||||
|
||||
#pagespeed CacheFlushPollIntervalSec 1;
|
||||
|
||||
@@ -953,11 +1262,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;
|
||||
}
|
||||
|
||||
@@ -1130,8 +1441,11 @@ http {
|
||||
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;
|
||||
@@ -1145,8 +1459,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;
|
||||
|
||||
@@ -1169,27 +1483,6 @@ http {
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
# set up gzip
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
# 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