Compare commits
282 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 0de4e20be1 | |||
| 6af5774ef8 | |||
| 117994993a | |||
| 5487b7350c | |||
| 261b602f83 | |||
| ae3cf7a425 | |||
| b4af0738a5 | |||
| ff049a55c3 | |||
| 0772787ad4 | |||
| 7eedc2ce3c | |||
| 7af665b5dd | |||
| 8136a15352 | |||
| 31024cfc24 | |||
| 703fda7eba | |||
| d4bc40007e | |||
| f2e2ab6056 | |||
| e06a65e7e6 | |||
| 3231949e03 | |||
| f5713996f2 | |||
| 185632583b | |||
| c5dbfa16cd | |||
| 33b2e82ec6 | |||
| b87ffce5ba | |||
| 7d5fc11afd | |||
| 7cba7ba4f4 | |||
| cf434f71cc | |||
| ba8c149a88 | |||
| f5bac604a1 | |||
| f18faa3ae1 | |||
| 070ae2aad2 | |||
| 674c70e32c | |||
| b4ef143a88 | |||
| ffdc3c8fd6 | |||
| af10fc3ddb | |||
| e9a099f9c5 | |||
| e4a2933c58 | |||
| 2601232457 | |||
| a3e1810a6a | |||
| 72f3c79fec | |||
| 323e820fde | |||
| a9a7bf56ac | |||
| 2358f957cb | |||
| 7d72a7c89a | |||
| 8830724580 | |||
| c2d07a8d5a | |||
| c3bff67637 | |||
| 5a1a29ee8b | |||
| 61025c5e4f | |||
| d3e7900704 | |||
| 85e19c962b | |||
| 20fd7d18dd | |||
| 4667aa1fc3 | |||
| 6ced8c0f65 | |||
| bfaf4268cf | |||
| 78cf39f9b3 | |||
| 215071a383 | |||
| 630f7d848b | |||
| d90245af69 | |||
| f25569690a | |||
| 707d671826 | |||
| f8b87ea436 | |||
| 86d840f76e | |||
| 0110d33fa7 | |||
| 497594ba7f | |||
| 336352df38 | |||
| 0edd405eb8 | |||
| d004c4d916 | |||
| c754cf1be0 | |||
| 091ef6399b | |||
| 9e4d26da5e | |||
| 027d481817 | |||
| 67106e920e | |||
| 9699caeab5 | |||
| c371d516a8 | |||
| 207eb2d131 | |||
| d9e2142f31 | |||
| bf6c6c0e9b | |||
| e8dd9fd3c3 | |||
| 33d006625e | |||
| 2dcaa95278 | |||
| f5252b569a | |||
| 64eaa2a659 | |||
| 4783144e7d | |||
| 83205c9c31 | |||
| 625e762961 | |||
| c20affe323 | |||
| 7a9e6de802 | |||
| 96cf9a22f7 | |||
| ab83a70a35 | |||
| 6db4d02a91 | |||
| 1354cee4ed | |||
| 658b2cf7a9 | |||
| 092bbf2862 | |||
| 6ccb815df3 | |||
| f04c533df0 | |||
| 8468e4849a | |||
| df5736609d | |||
| 7fbb2c61ee | |||
| af772c2fe8 | |||
| a4bd9b9c13 | |||
| f87d0f7ae2 | |||
| 501742cb56 | |||
| a669be99b1 | |||
| 328d3afc9b | |||
| 2681c24ee0 | |||
| f86f47fda4 | |||
| 179c81afa3 | |||
| 8d7eb20c89 | |||
| 1fe6c54b94 | |||
| 1667879202 | |||
| 0076e45677 | |||
| 1f3560ea21 | |||
| 54352bff72 | |||
| 329985659c | |||
| db870f7023 | |||
| ed14455412 | |||
| be4d263d10 | |||
| 0bafd6b7e0 | |||
| 9bbe912bd7 | |||
| b78eb8a939 | |||
| e082a01912 | |||
| fa5815e1e8 | |||
| f12af2f03b | |||
| e22fae46bc | |||
| 53a599fbd4 |
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
test/tmp
|
test/tmp
|
||||||
psol/
|
psol/
|
||||||
psol-*.tar.gz
|
psol-*.tar.gz
|
||||||
|
*.*.*.*.tar.gz
|
||||||
|
|||||||
@@ -19,93 +19,15 @@ optimizations, see our <a href="http://ngxpagespeed.com">demonstration site</a>.
|
|||||||
|
|
||||||
## How to build
|
## How to build
|
||||||
|
|
||||||
Because nginx does not support dynamic loading of modules, you need to compile
|
Follow the steps on <a
|
||||||
nginx from source to add ngx_pagespeed. Alternatively, if you're using Tengine you can [install ngx_pagespeed without
|
href="https://developers.google.com/speed/pagespeed/module/build_ngx_pagespeed_from_source">build
|
||||||
recompiling Tengine](https://github.com/pagespeed/ngx_pagespeed/wiki/Using-ngx_pagespeed-with-Tengine).
|
ngx_pagespeed from source</a>.
|
||||||
|
|
||||||
1. Install dependencies:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# These are for RedHat, CentOS, and Fedora.
|
|
||||||
$ sudo yum install gcc-c++ pcre-dev pcre-devel zlib-devel make
|
|
||||||
|
|
||||||
# These are for Debian. Ubuntu will be similar.
|
|
||||||
$ sudo apt-get install build-essential zlib1g-dev libpcre3 libpcre3-dev
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Download ngx_pagespeed:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ cd ~
|
|
||||||
$ wget https://github.com/pagespeed/ngx_pagespeed/archive/v1.7.30.2-beta.zip
|
|
||||||
$ unzip v1.7.30.2-beta.zip # or unzip v1.7.30.2-beta
|
|
||||||
$ cd ngx_pagespeed-1.7.30.2-beta/
|
|
||||||
$ wget https://dl.google.com/dl/page-speed/psol/1.7.30.2.tar.gz
|
|
||||||
$ tar -xzvf 1.7.30.2.tar.gz # expands to psol/
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Download and build nginx:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ # check http://nginx.org/en/download.html for the latest version
|
|
||||||
$ wget http://nginx.org/download/nginx-1.4.4.tar.gz
|
|
||||||
$ tar -xvzf nginx-1.4.4.tar.gz
|
|
||||||
$ cd nginx-1.4.4/
|
|
||||||
$ ./configure --add-module=$HOME/ngx_pagespeed-1.7.30.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.
|
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
In your `nginx.conf`, add to the main or server block:
|
Follow the steps on <a
|
||||||
|
href="https://developers.google.com/speed/pagespeed/module/configuration">PageSpeed
|
||||||
```nginx
|
configuration</a>.
|
||||||
pagespeed on;
|
|
||||||
pagespeed FileCachePath /var/ngx_pagespeed_cache;
|
|
||||||
```
|
|
||||||
|
|
||||||
In every server block where pagespeed is enabled add:
|
|
||||||
|
|
||||||
```apache
|
|
||||||
# Ensure requests for pagespeed optimized resources go to the pagespeed
|
|
||||||
# handler and no extraneous headers get set.
|
|
||||||
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; }
|
|
||||||
location ~ "^/ngx_pagespeed_static/" { }
|
|
||||||
location ~ "^/ngx_pagespeed_beacon$" { }
|
|
||||||
location /ngx_pagespeed_statistics { allow 127.0.0.1; deny all; }
|
|
||||||
location /ngx_pagespeed_global_statistics { allow 127.0.0.1; deny all; }
|
|
||||||
location /ngx_pagespeed_message { allow 127.0.0.1; deny all; }
|
|
||||||
location /pagespeed_console { allow 127.0.0.1; deny all; }
|
|
||||||
```
|
|
||||||
|
|
||||||
To confirm that the module is loaded, fetch a page and check that you see the
|
|
||||||
`X-Page-Speed` header:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ curl -I 'http://localhost:8050/some_page/' | grep X-Page-Speed
|
|
||||||
X-Page-Speed: 1.7.30.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).
|
|
||||||
|
|
||||||
For feedback, questions, and to follow
|
For feedback, questions, and to follow
|
||||||
the progress of the project:
|
the progress of the project:
|
||||||
@@ -114,20 +36,3 @@ the progress of the project:
|
|||||||
list](https://groups.google.com/forum/#!forum/ngx-pagespeed-discuss)
|
list](https://groups.google.com/forum/#!forum/ngx-pagespeed-discuss)
|
||||||
- [ngx-pagespeed-announce mailing
|
- [ngx-pagespeed-announce mailing
|
||||||
list](https://groups.google.com/forum/#!forum/ngx-pagespeed-announce)
|
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 " You need to separately download the pagespeed library:"
|
||||||
echo ""
|
echo ""
|
||||||
echo " $ cd /path/to/ngx_pagespeed"
|
echo " $ cd /path/to/ngx_pagespeed"
|
||||||
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.7.30.2.tar.gz"
|
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.9.32.4.tar.gz"
|
||||||
echo " $ tar -xzvf 1.7.30.2.tar.gz # expands to psol/"
|
echo " $ tar -xzvf 1.9.32.4.tar.gz # expands to psol/"
|
||||||
echo ""
|
echo ""
|
||||||
echo " Or see the installation instructions:"
|
echo " Or see the installation instructions:"
|
||||||
echo " https://github.com/pagespeed/ngx_pagespeed#how-to-build"
|
echo " https://github.com/pagespeed/ngx_pagespeed#how-to-build"
|
||||||
@@ -39,20 +39,6 @@ else
|
|||||||
build_from_source=true
|
build_from_source=true
|
||||||
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 \"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'
|
os_name='unknown_os'
|
||||||
arch_name='unknown_arch'
|
arch_name='unknown_arch'
|
||||||
uname_os=`uname`
|
uname_os=`uname`
|
||||||
@@ -89,9 +75,7 @@ if [ "$uname_arch" = "i686" ]; then
|
|||||||
FLAG_MARCH='-march=i686'
|
FLAG_MARCH='-march=i686'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Building with HTTPS fetching enabled pulls in a version of OpenSSL that causes
|
CFLAGS="$CFLAGS $FLAG_MARCH"
|
||||||
# linker errors, so disable it here.
|
|
||||||
CFLAGS="$CFLAGS -DSERF_HTTPS_FETCHING=0 $FLAG_MARCH"
|
|
||||||
|
|
||||||
case "$NGX_GCC_VER" in
|
case "$NGX_GCC_VER" in
|
||||||
4.8*)
|
4.8*)
|
||||||
@@ -111,6 +95,35 @@ case "$NGX_GCC_VER" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
if [ "$WNO_ERROR" = "YES" ]; then
|
||||||
|
CFLAGS="$CFLAGS -Wno-error"
|
||||||
|
fi
|
||||||
|
|
||||||
|
psol_binary="${PSOL_BINARY:-unset}"
|
||||||
|
if [ "$psol_binary" = "unset" ] ; then
|
||||||
|
if $build_from_source ; then
|
||||||
|
psol_binary="\
|
||||||
|
$mod_pagespeed_dir/net/instaweb/automatic/pagespeed_automatic.a"
|
||||||
|
else
|
||||||
|
psol_library_dir="$ngx_addon_dir/psol/lib/$buildtype/$os_name/$arch_name"
|
||||||
|
psol_binary="$psol_library_dir/pagespeed_automatic.a"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "mod_pagespeed_dir=$mod_pagespeed_dir"
|
||||||
|
echo "build_from_source=$build_from_source"
|
||||||
|
|
||||||
|
ngx_feature="psol"
|
||||||
|
ngx_feature_name=""
|
||||||
|
ngx_feature_run=no
|
||||||
|
ngx_feature_incs="
|
||||||
|
#include \"pagespeed/kernel/base/string.h\"
|
||||||
|
#include \"pagespeed/kernel/base/string_writer.h\"
|
||||||
|
#include \"pagespeed/kernel/base/null_message_handler.h\"
|
||||||
|
#include \"pagespeed/kernel/html/html_parse.h\"
|
||||||
|
#include \"pagespeed/kernel/html/html_writer_filter.h\"
|
||||||
|
"
|
||||||
|
|
||||||
pagespeed_include="\
|
pagespeed_include="\
|
||||||
$mod_pagespeed_dir \
|
$mod_pagespeed_dir \
|
||||||
$mod_pagespeed_dir/third_party/chromium/src \
|
$mod_pagespeed_dir/third_party/chromium/src \
|
||||||
@@ -126,22 +139,7 @@ pagespeed_include="\
|
|||||||
$mod_pagespeed_dir/third_party/aprutil/gen/arch/$os_name/$arch_name/include"
|
$mod_pagespeed_dir/third_party/aprutil/gen/arch/$os_name/$arch_name/include"
|
||||||
ngx_feature_path="$pagespeed_include"
|
ngx_feature_path="$pagespeed_include"
|
||||||
|
|
||||||
if $build_from_source ; then
|
pagespeed_libs="-lstdc++ $psol_binary -lrt -pthread -lm"
|
||||||
psol_library_binaries="\
|
|
||||||
$mod_pagespeed_dir/net/instaweb/automatic/pagespeed_automatic.a \
|
|
||||||
$mod_pagespeed_dir/out/$buildtype/obj.target/third_party/serf/libserf.a \
|
|
||||||
$mod_pagespeed_dir/out/$buildtype/obj.target/third_party/aprutil/libaprutil.a \
|
|
||||||
$mod_pagespeed_dir/out/$buildtype/obj.target/third_party/apr/libapr.a"
|
|
||||||
else
|
|
||||||
psol_library_dir="$ngx_addon_dir/psol/lib/$buildtype/$os_name/$arch_name"
|
|
||||||
psol_library_binaries="\
|
|
||||||
$psol_library_dir/pagespeed_automatic.a \
|
|
||||||
$psol_library_dir/libserf.a \
|
|
||||||
$psol_library_dir/libaprutil.a \
|
|
||||||
$psol_library_dir/libapr.a"
|
|
||||||
fi
|
|
||||||
|
|
||||||
pagespeed_libs="-lstdc++ $psol_library_binaries -lrt -pthread -lm"
|
|
||||||
ngx_feature_libs="$pagespeed_libs"
|
ngx_feature_libs="$pagespeed_libs"
|
||||||
ngx_feature_test="
|
ngx_feature_test="
|
||||||
GoogleString output_buffer;
|
GoogleString output_buffer;
|
||||||
@@ -172,31 +170,28 @@ if [ $ngx_found = yes ]; then
|
|||||||
$ps_src/ngx_base_fetch.h \
|
$ps_src/ngx_base_fetch.h \
|
||||||
$ps_src/ngx_caching_headers.h \
|
$ps_src/ngx_caching_headers.h \
|
||||||
$ps_src/ngx_fetch.h \
|
$ps_src/ngx_fetch.h \
|
||||||
|
$ps_src/ngx_gzip_setter.h \
|
||||||
$ps_src/ngx_list_iterator.h \
|
$ps_src/ngx_list_iterator.h \
|
||||||
$ps_src/ngx_message_handler.h \
|
$ps_src/ngx_message_handler.h \
|
||||||
$ps_src/ngx_pagespeed.h \
|
$ps_src/ngx_pagespeed.h \
|
||||||
$ps_src/ngx_rewrite_driver_factory.h \
|
$ps_src/ngx_rewrite_driver_factory.h \
|
||||||
$ps_src/ngx_rewrite_options.h \
|
$ps_src/ngx_rewrite_options.h \
|
||||||
$ps_src/ngx_server_context.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 \
|
NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
|
||||||
$ps_src/log_message_handler.cc \
|
$ps_src/log_message_handler.cc \
|
||||||
$ps_src/ngx_base_fetch.cc \
|
$ps_src/ngx_base_fetch.cc \
|
||||||
$ps_src/ngx_caching_headers.cc \
|
$ps_src/ngx_caching_headers.cc \
|
||||||
$ps_src/ngx_fetch.cc \
|
$ps_src/ngx_fetch.cc \
|
||||||
|
$ps_src/ngx_gzip_setter.cc \
|
||||||
$ps_src/ngx_list_iterator.cc \
|
$ps_src/ngx_list_iterator.cc \
|
||||||
$ps_src/ngx_message_handler.cc \
|
$ps_src/ngx_message_handler.cc \
|
||||||
$ps_src/ngx_pagespeed.cc \
|
$ps_src/ngx_pagespeed.cc \
|
||||||
$ps_src/ngx_rewrite_driver_factory.cc \
|
$ps_src/ngx_rewrite_driver_factory.cc \
|
||||||
$ps_src/ngx_rewrite_options.cc \
|
$ps_src/ngx_rewrite_options.cc \
|
||||||
$ps_src/ngx_server_context.cc \
|
$ps_src/ngx_server_context.cc \
|
||||||
$ps_src/ngx_url_async_fetcher.cc \
|
$ps_src/ngx_url_async_fetcher.cc"
|
||||||
$mod_pagespeed_dir/out/$buildtype/obj/gen/data2c_out/instaweb/net/instaweb/apache/install/mod_pagespeed_example/mod_pagespeed_console_out.cc \
|
|
||||||
$mod_pagespeed_dir/out/$buildtype/obj/gen/data2c_out/instaweb/net/instaweb/apache/install/mod_pagespeed_example/mod_pagespeed_console_css_out.cc \
|
|
||||||
$mod_pagespeed_dir/out/$buildtype/obj/gen/data2c_out/instaweb/net/instaweb/apache/install/mod_pagespeed_example/mod_pagespeed_console_html_out.cc \
|
|
||||||
$mod_pagespeed_dir/net/instaweb/system/add_headers_fetcher.cc \
|
|
||||||
$mod_pagespeed_dir/net/instaweb/system/loopback_route_fetcher.cc \
|
|
||||||
$mod_pagespeed_dir/net/instaweb/system/serf_url_async_fetcher.cc"
|
|
||||||
|
|
||||||
# Make pagespeed run immediately before gzip.
|
# Make pagespeed run immediately before gzip.
|
||||||
HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES |\
|
HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES |\
|
||||||
@@ -206,9 +201,11 @@ if [ $ngx_found = yes ]; then
|
|||||||
sed "s/$HTTP_GZIP_FILTER_MODULE/ngx_pagespeed_etag_filter $HTTP_GZIP_FILTER_MODULE/")
|
sed "s/$HTTP_GZIP_FILTER_MODULE/ngx_pagespeed_etag_filter $HTTP_GZIP_FILTER_MODULE/")
|
||||||
CORE_LIBS="$CORE_LIBS $pagespeed_libs"
|
CORE_LIBS="$CORE_LIBS $pagespeed_libs"
|
||||||
CORE_INCS="$CORE_INCS $pagespeed_include"
|
CORE_INCS="$CORE_INCS $pagespeed_include"
|
||||||
|
echo "List of modules (in reverse order of applicability): "$HTTP_FILTER_MODULES
|
||||||
else
|
else
|
||||||
cat << END
|
cat << END
|
||||||
$0: error: module ngx_pagespeed requires the pagespeed optimization library
|
$0: error: module ngx_pagespeed requires the pagespeed optimization library.
|
||||||
|
Look in objs/autoconf.err for more details.
|
||||||
END
|
END
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
# Author: vid@zippykid.com (Vid Luther)
|
# Author: vid@zippykid.com (Vid Luther)
|
||||||
# jefftk@google.com (Jeff Kaufman)
|
# 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"
|
URL+="net/instaweb/genfiles/conf/pagespeed_libraries.conf"
|
||||||
curl -s "$URL" \
|
curl -L -s -S "$URL" \
|
||||||
| grep ModPagespeedLibrary \
|
| grep ModPagespeedLibrary \
|
||||||
| while read library size hash url ; do
|
| while read library size hash url ; do
|
||||||
echo " pagespeed Library $size $hash $url;"
|
echo " pagespeed Library $size $hash $url;"
|
||||||
|
|||||||
+13
-8
@@ -39,7 +39,7 @@ NgxBaseFetch::NgxBaseFetch(ngx_http_request_t* r, int pipe_fd,
|
|||||||
last_buf_sent_(false),
|
last_buf_sent_(false),
|
||||||
pipe_fd_(pipe_fd),
|
pipe_fd_(pipe_fd),
|
||||||
references_(2),
|
references_(2),
|
||||||
handle_error_(true),
|
ipro_lookup_(false),
|
||||||
preserve_caching_headers_(preserve_caching_headers) {
|
preserve_caching_headers_(preserve_caching_headers) {
|
||||||
if (pthread_mutex_init(&mutex_, NULL)) CHECK(0);
|
if (pthread_mutex_init(&mutex_, NULL)) CHECK(0);
|
||||||
}
|
}
|
||||||
@@ -106,11 +106,10 @@ ngx_int_t NgxBaseFetch::CollectAccumulatedWrites(ngx_chain_t** link_ptr) {
|
|||||||
ngx_int_t NgxBaseFetch::CollectHeaders(ngx_http_headers_out_t* headers_out) {
|
ngx_int_t NgxBaseFetch::CollectHeaders(ngx_http_headers_out_t* headers_out) {
|
||||||
const ResponseHeaders* pagespeed_headers = response_headers();
|
const ResponseHeaders* pagespeed_headers = response_headers();
|
||||||
|
|
||||||
// TODO(chaizhenhua): Add and check.
|
if (content_length_known()) {
|
||||||
// if (content_length_known()) {
|
headers_out->content_length = NULL;
|
||||||
// headers_out->content_length = NULL;
|
headers_out->content_length_n = content_length();
|
||||||
// headers_out->content_length_n = content_length();
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
return copy_response_headers_to_ngx(request_, *pagespeed_headers,
|
return copy_response_headers_to_ngx(request_, *pagespeed_headers,
|
||||||
preserve_caching_headers_);
|
preserve_caching_headers_);
|
||||||
@@ -138,14 +137,20 @@ void NgxBaseFetch::HandleHeadersComplete() {
|
|||||||
int status_code = response_headers()->status_code();
|
int status_code = response_headers()->status_code();
|
||||||
bool status_ok = (status_code != 0) && (status_code < 400);
|
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 this is a 404 response we need to count it in the stats.
|
||||||
if (response_headers()->status_code() == HttpStatus::kNotFound) {
|
if (response_headers()->status_code() == HttpStatus::kNotFound) {
|
||||||
server_context_->rewrite_stats()->resource_404_count()->Add(1);
|
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) {
|
bool NgxBaseFetch::HandleFlush(MessageHandler* handler) {
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class NgxBaseFetch : public AsyncFetch {
|
|||||||
|
|
||||||
// Called by nginx when it's done with us.
|
// Called by nginx when it's done with us.
|
||||||
void Release();
|
void Release();
|
||||||
void set_handle_error(bool x) { handle_error_ = x; }
|
void set_ipro_lookup(bool x) { ipro_lookup_ = x; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool HandleWrite(const StringPiece& sp, MessageHandler* handler);
|
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.
|
// decremented once when Done() is called and once when Release() is called.
|
||||||
int references_;
|
int references_;
|
||||||
pthread_mutex_t mutex_;
|
pthread_mutex_t mutex_;
|
||||||
bool handle_error_;
|
bool ipro_lookup_;
|
||||||
PreserveCachingHeaders preserve_caching_headers_;
|
PreserveCachingHeaders preserve_caching_headers_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(NgxBaseFetch);
|
DISALLOW_COPY_AND_ASSIGN(NgxBaseFetch);
|
||||||
|
|||||||
+805
-450
File diff suppressed because it is too large
Load Diff
+27
-11
@@ -16,6 +16,15 @@
|
|||||||
|
|
||||||
// Author: x.dinic@gmail.com (Junmin Xiong)
|
// 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
|
// The fetch is started by the main thread. It will fetch the remote resource
|
||||||
// from the specific url asynchronously.
|
// from the specific url asynchronously.
|
||||||
|
|
||||||
@@ -42,12 +51,13 @@ namespace net_instaweb {
|
|||||||
typedef bool (*response_handler_pt)(ngx_connection_t* c);
|
typedef bool (*response_handler_pt)(ngx_connection_t* c);
|
||||||
|
|
||||||
class NgxUrlAsyncFetcher;
|
class NgxUrlAsyncFetcher;
|
||||||
|
class NgxConnection;
|
||||||
|
|
||||||
class NgxFetch : public PoolElement<NgxFetch> {
|
class NgxFetch : public PoolElement<NgxFetch> {
|
||||||
public:
|
public:
|
||||||
NgxFetch(const GoogleString& url,
|
NgxFetch(const GoogleString& url,
|
||||||
AsyncFetch* async_fetch,
|
AsyncFetch* async_fetch,
|
||||||
MessageHandler* message_handler,
|
MessageHandler* message_handler,
|
||||||
ngx_msec_t timeout_ms,
|
|
||||||
ngx_log_t* log);
|
ngx_log_t* log);
|
||||||
~NgxFetch();
|
~NgxFetch();
|
||||||
|
|
||||||
@@ -83,6 +93,12 @@ class NgxFetch : public PoolElement<NgxFetch> {
|
|||||||
void set_timeout_event(ngx_event_t* x) {
|
void set_timeout_event(ngx_event_t* x) {
|
||||||
timeout_event_ = x;
|
timeout_event_ = x;
|
||||||
}
|
}
|
||||||
|
void release_resolver() {
|
||||||
|
if (resolver_ctx_ != NULL && resolver_ctx_ != NGX_NO_RESOLVER) {
|
||||||
|
ngx_resolve_name_done(resolver_ctx_);
|
||||||
|
resolver_ctx_ = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
response_handler_pt response_handler;
|
response_handler_pt response_handler;
|
||||||
@@ -97,19 +113,19 @@ class NgxFetch : public PoolElement<NgxFetch> {
|
|||||||
response_handler = handler;
|
response_handler = handler;
|
||||||
}
|
}
|
||||||
// Only the Static functions could be used in callbacks.
|
// 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.
|
// Write the request.
|
||||||
static void NgxFetchWrite(ngx_event_t* wev);
|
static void ConnectionWriteHandler(ngx_event_t* wev);
|
||||||
// Wait for the response.
|
// 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.
|
// 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.
|
// Read and parse the HTTP headers.
|
||||||
static bool NgxFetchHandleHeader(ngx_connection_t* c);
|
static bool HandleHeader(ngx_connection_t* c);
|
||||||
// Read the response body.
|
// 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.
|
// 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.
|
// Add the pagespeed User-Agent.
|
||||||
void FixUserAgent();
|
void FixUserAgent();
|
||||||
@@ -121,12 +137,12 @@ class NgxFetch : public PoolElement<NgxFetch> {
|
|||||||
AsyncFetch* async_fetch_;
|
AsyncFetch* async_fetch_;
|
||||||
ResponseHeadersParser parser_;
|
ResponseHeadersParser parser_;
|
||||||
MessageHandler* message_handler_;
|
MessageHandler* message_handler_;
|
||||||
size_t bytes_received_;
|
int64 bytes_received_;
|
||||||
int64 fetch_start_ms_;
|
int64 fetch_start_ms_;
|
||||||
int64 fetch_end_ms_;
|
int64 fetch_end_ms_;
|
||||||
int64 timeout_ms_;
|
|
||||||
bool done_;
|
bool done_;
|
||||||
int64 content_length_;
|
int64 content_length_;
|
||||||
|
bool content_length_known_;
|
||||||
|
|
||||||
struct sockaddr_in sin_;
|
struct sockaddr_in sin_;
|
||||||
ngx_log_t* log_;
|
ngx_log_t* log_;
|
||||||
@@ -136,7 +152,7 @@ class NgxFetch : public PoolElement<NgxFetch> {
|
|||||||
ngx_http_request_t* r_;
|
ngx_http_request_t* r_;
|
||||||
ngx_http_status_t* status_;
|
ngx_http_status_t* status_;
|
||||||
ngx_event_t* timeout_event_;
|
ngx_event_t* timeout_event_;
|
||||||
ngx_connection_t* connection_;
|
NgxConnection* connection_;
|
||||||
ngx_resolver_ctx_t* resolver_ctx_;
|
ngx_resolver_ctx_t* resolver_ctx_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(NgxFetch);
|
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_
|
||||||
@@ -18,13 +18,13 @@
|
|||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include "apr_time.h"
|
|
||||||
|
|
||||||
#include "net/instaweb/util/public/abstract_mutex.h"
|
#include "net/instaweb/util/public/abstract_mutex.h"
|
||||||
#include "net/instaweb/util/public/debug.h"
|
#include "net/instaweb/util/public/debug.h"
|
||||||
#include "net/instaweb/util/public/shared_circular_buffer.h"
|
#include "net/instaweb/util/public/shared_circular_buffer.h"
|
||||||
#include "net/instaweb/util/public/string_util.h"
|
#include "net/instaweb/util/public/string_util.h"
|
||||||
#include "net/instaweb/public/version.h"
|
#include "net/instaweb/public/version.h"
|
||||||
|
#include "pagespeed/kernel/base/posix_timer.h"
|
||||||
|
#include "pagespeed/kernel/base/time_util.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -56,11 +56,9 @@ extern "C" {
|
|||||||
|
|
||||||
namespace net_instaweb {
|
namespace net_instaweb {
|
||||||
|
|
||||||
NgxMessageHandler::NgxMessageHandler(AbstractMutex* mutex)
|
NgxMessageHandler::NgxMessageHandler(Timer* timer, AbstractMutex* mutex)
|
||||||
: mutex_(mutex),
|
: SystemMessageHandler(timer, mutex),
|
||||||
buffer_(NULL),
|
|
||||||
log_(NULL) {
|
log_(NULL) {
|
||||||
SetPidString(static_cast<int64>(getpid()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Installs a signal handler for common crash signals, that tries to print
|
// 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);
|
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) {
|
ngx_uint_t NgxMessageHandler::GetNgxLogLevel(MessageType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case kInfo:
|
case kInfo:
|
||||||
@@ -98,11 +88,6 @@ ngx_uint_t NgxMessageHandler::GetNgxLogLevel(MessageType type) {
|
|||||||
return NGX_LOG_ALERT;
|
return NGX_LOG_ALERT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NgxMessageHandler::set_buffer(SharedCircularBuffer* buff) {
|
|
||||||
ScopedMutex lock(mutex_.get());
|
|
||||||
buffer_ = buff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NgxMessageHandler::MessageVImpl(MessageType type, const char* msg,
|
void NgxMessageHandler::MessageVImpl(MessageType type, const char* msg,
|
||||||
va_list args) {
|
va_list args) {
|
||||||
ngx_uint_t log_level = GetNgxLogLevel(type);
|
ngx_uint_t log_level = GetNgxLogLevel(type);
|
||||||
@@ -113,26 +98,8 @@ void NgxMessageHandler::MessageVImpl(MessageType type, const char* msg,
|
|||||||
} else {
|
} else {
|
||||||
GoogleMessageHandler::MessageVImpl(type, msg, args);
|
GoogleMessageHandler::MessageVImpl(type, msg, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare a log message for the SharedCircularBuffer only.
|
// Prepare a log message for the SharedCircularBuffer only.
|
||||||
// Prepend time and severity to message.
|
AddMessageToBuffer(type, formatted_message);
|
||||||
// Format is [time] [severity] [pid] message.
|
|
||||||
GoogleString message;
|
|
||||||
char time_buffer[APR_CTIME_LEN + 1];
|
|
||||||
const char* time = time_buffer;
|
|
||||||
apr_status_t status = apr_ctime(time_buffer, apr_time_now());
|
|
||||||
if (status != APR_SUCCESS) {
|
|
||||||
time = "?";
|
|
||||||
}
|
|
||||||
StrAppend(&message, "[", time, "] ",
|
|
||||||
"[", MessageTypeToString(type), "] ");
|
|
||||||
StrAppend(&message, pid_string_, " ", formatted_message, "\n");
|
|
||||||
{
|
|
||||||
ScopedMutex lock(mutex_.get());
|
|
||||||
if (buffer_ != NULL) {
|
|
||||||
buffer_->Write(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NgxMessageHandler::FileMessageVImpl(MessageType type, const char* file,
|
void NgxMessageHandler::FileMessageVImpl(MessageType type, const char* file,
|
||||||
@@ -149,14 +116,4 @@ void NgxMessageHandler::FileMessageVImpl(MessageType type, const char* file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(sligocki): It'd be nice not to do so much string copying.
|
|
||||||
GoogleString NgxMessageHandler::Format(const char* msg, va_list args) {
|
|
||||||
GoogleString buffer;
|
|
||||||
|
|
||||||
// Ignore the name of this routine: it formats with vsnprintf.
|
|
||||||
// See base/stringprintf.cc.
|
|
||||||
StringAppendV(&buffer, msg, args);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace net_instaweb
|
} // namespace net_instaweb
|
||||||
|
|||||||
@@ -18,50 +18,40 @@
|
|||||||
#define NGX_MESSAGE_HANDLER_H_
|
#define NGX_MESSAGE_HANDLER_H_
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#include <ngx_auto_config.h>
|
||||||
|
#if (NGX_THREADS)
|
||||||
|
#include <ngx_thread.h>
|
||||||
|
#endif
|
||||||
#include <ngx_core.h>
|
#include <ngx_core.h>
|
||||||
#include <ngx_log.h>
|
#include <ngx_log.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
|
||||||
|
#include "net/instaweb/system/public/system_message_handler.h"
|
||||||
#include "net/instaweb/util/public/basictypes.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/message_handler.h"
|
||||||
#include "net/instaweb/util/public/scoped_ptr.h"
|
|
||||||
#include "net/instaweb/util/public/string.h"
|
#include "net/instaweb/util/public/string.h"
|
||||||
#include "net/instaweb/util/public/string_util.h"
|
#include "net/instaweb/util/public/string_util.h"
|
||||||
|
|
||||||
namespace net_instaweb {
|
namespace net_instaweb {
|
||||||
|
|
||||||
class AbstractMutex;
|
class AbstractMutex;
|
||||||
class SharedCircularBuffer;
|
|
||||||
class Timer;
|
class Timer;
|
||||||
class Writer;
|
|
||||||
|
|
||||||
// Implementation of a message handler that uses ngx_log_error()
|
// Implementation of a message handler that uses ngx_log_error()
|
||||||
// logging to emit messages, with a fallback to GoogleMessageHandler
|
// logging to emit messages, with a fallback to GoogleMessageHandler
|
||||||
class NgxMessageHandler : public GoogleMessageHandler {
|
class NgxMessageHandler : public SystemMessageHandler {
|
||||||
public:
|
public:
|
||||||
explicit NgxMessageHandler(AbstractMutex* mutex);
|
explicit NgxMessageHandler(Timer* timer, AbstractMutex* mutex);
|
||||||
|
|
||||||
// Installs a signal handler for common crash signals that tries to print
|
// Installs a signal handler for common crash signals that tries to print
|
||||||
// out a backtrace.
|
// out a backtrace.
|
||||||
static void InstallCrashHandler(ngx_log_t* log);
|
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; }
|
void set_log(ngx_log_t* log) { log_ = log; }
|
||||||
ngx_log_t* log() { return 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:
|
protected:
|
||||||
virtual void MessageVImpl(MessageType type, const char* msg, va_list args);
|
virtual void MessageVImpl(MessageType type, const char* msg, va_list args);
|
||||||
|
|
||||||
@@ -70,14 +60,6 @@ class NgxMessageHandler : public GoogleMessageHandler {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ngx_uint_t GetNgxLogLevel(MessageType type);
|
ngx_uint_t GetNgxLogLevel(MessageType type);
|
||||||
GoogleString Format(const char* msg, va_list args);
|
|
||||||
|
|
||||||
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_;
|
ngx_log_t* log_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(NgxMessageHandler);
|
DISALLOW_COPY_AND_ASSIGN(NgxMessageHandler);
|
||||||
|
|||||||
+670
-371
File diff suppressed because it is too large
Load Diff
@@ -103,6 +103,10 @@ typedef struct {
|
|||||||
RewriteDriver* driver;
|
RewriteDriver* driver;
|
||||||
InPlaceResourceRecorder* recorder;
|
InPlaceResourceRecorder* recorder;
|
||||||
ResponseHeaders* ipro_response_headers;
|
ResponseHeaders* ipro_response_headers;
|
||||||
|
|
||||||
|
// We need to remember the URL here as well since we may modify what NGX
|
||||||
|
// gets by stripping our special query params and honoring X-Forwarded-Proto.
|
||||||
|
GoogleString url_string;
|
||||||
} ps_request_ctx_t;
|
} ps_request_ctx_t;
|
||||||
|
|
||||||
|
|
||||||
@@ -117,6 +121,8 @@ ngx_int_t copy_response_headers_to_ngx(
|
|||||||
const ResponseHeaders& pagespeed_headers,
|
const ResponseHeaders& pagespeed_headers,
|
||||||
PreserveCachingHeaders preserve_caching_headers);
|
PreserveCachingHeaders preserve_caching_headers);
|
||||||
|
|
||||||
|
StringPiece ps_determine_host(ngx_http_request_t* r);
|
||||||
|
|
||||||
} // namespace net_instaweb
|
} // namespace net_instaweb
|
||||||
|
|
||||||
#endif // NGX_PAGESPEED_H_
|
#endif // NGX_PAGESPEED_H_
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
#include "net/instaweb/rewriter/public/rewrite_driver.h"
|
#include "net/instaweb/rewriter/public/rewrite_driver.h"
|
||||||
#include "net/instaweb/rewriter/public/rewrite_driver_factory.h"
|
#include "net/instaweb/rewriter/public/rewrite_driver_factory.h"
|
||||||
#include "net/instaweb/rewriter/public/server_context.h"
|
#include "net/instaweb/rewriter/public/server_context.h"
|
||||||
#include "net/instaweb/rewriter/public/static_asset_manager.h"
|
|
||||||
#include "net/instaweb/system/public/in_place_resource_recorder.h"
|
#include "net/instaweb/system/public/in_place_resource_recorder.h"
|
||||||
#include "net/instaweb/system/public/serf_url_async_fetcher.h"
|
#include "net/instaweb/system/public/serf_url_async_fetcher.h"
|
||||||
#include "net/instaweb/system/public/system_caches.h"
|
#include "net/instaweb/system/public/system_caches.h"
|
||||||
@@ -63,26 +62,29 @@ class UrlAsyncFetcher;
|
|||||||
class UrlFetcher;
|
class UrlFetcher;
|
||||||
class Writer;
|
class Writer;
|
||||||
|
|
||||||
const char NgxRewriteDriverFactory::kStaticAssetPrefix[] =
|
|
||||||
"/ngx_pagespeed_static/";
|
|
||||||
|
|
||||||
class SharedCircularBuffer;
|
class SharedCircularBuffer;
|
||||||
|
|
||||||
NgxRewriteDriverFactory::NgxRewriteDriverFactory(
|
NgxRewriteDriverFactory::NgxRewriteDriverFactory(
|
||||||
|
const ProcessContext& process_context,
|
||||||
SystemThreadSystem* system_thread_system, StringPiece hostname, int port)
|
SystemThreadSystem* system_thread_system, StringPiece hostname, int port)
|
||||||
: SystemRewriteDriverFactory(system_thread_system,
|
: SystemRewriteDriverFactory(process_context, system_thread_system,
|
||||||
NULL /* default shared memory runtime */, hostname, port),
|
NULL /* default shared memory runtime */, hostname, port),
|
||||||
main_conf_(NULL),
|
main_conf_(NULL),
|
||||||
threads_started_(false),
|
threads_started_(false),
|
||||||
use_per_vhost_statistics_(false),
|
ngx_message_handler_(
|
||||||
ngx_message_handler_(new NgxMessageHandler(thread_system()->NewMutex())),
|
new NgxMessageHandler(timer(), thread_system()->NewMutex())),
|
||||||
ngx_html_parse_message_handler_(
|
ngx_html_parse_message_handler_(
|
||||||
new NgxMessageHandler(thread_system()->NewMutex())),
|
new NgxMessageHandler(timer(), thread_system()->NewMutex())),
|
||||||
install_crash_handler_(false),
|
|
||||||
log_(NULL),
|
log_(NULL),
|
||||||
resolver_timeout_(NGX_CONF_UNSET_MSEC),
|
resolver_timeout_(NGX_CONF_UNSET_MSEC),
|
||||||
use_native_fetcher_(false),
|
use_native_fetcher_(false),
|
||||||
ngx_shared_circular_buffer_(NULL) {
|
// 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),
|
||||||
|
process_script_variables_(false),
|
||||||
|
process_script_variables_set_(false) {
|
||||||
InitializeDefaultOptions();
|
InitializeDefaultOptions();
|
||||||
default_options()->set_beacon_url("/ngx_pagespeed_beacon");
|
default_options()->set_beacon_url("/ngx_pagespeed_beacon");
|
||||||
SystemRewriteOptions* system_options = dynamic_cast<SystemRewriteOptions*>(
|
SystemRewriteOptions* system_options = dynamic_cast<SystemRewriteOptions*>(
|
||||||
@@ -112,6 +114,7 @@ UrlAsyncFetcher* NgxRewriteDriverFactory::AllocateFetcher(
|
|||||||
resolver_timeout_,
|
resolver_timeout_,
|
||||||
config->blocking_fetch_timeout_ms(),
|
config->blocking_fetch_timeout_ms(),
|
||||||
resolver_,
|
resolver_,
|
||||||
|
native_fetcher_max_keepalive_requests_,
|
||||||
thread_system(),
|
thread_system(),
|
||||||
message_handler());
|
message_handler());
|
||||||
ngx_url_async_fetchers_.push_back(fetcher);
|
ngx_url_async_fetchers_.push_back(fetcher);
|
||||||
@@ -148,11 +151,6 @@ RewriteOptions* NgxRewriteDriverFactory::NewRewriteOptions() {
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NgxRewriteDriverFactory::InitStaticAssetManager(
|
|
||||||
StaticAssetManager* static_asset_manager) {
|
|
||||||
static_asset_manager->set_library_url_prefix(kStaticAssetPrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NgxRewriteDriverFactory::InitNgxUrlAsyncFetchers() {
|
bool NgxRewriteDriverFactory::InitNgxUrlAsyncFetchers() {
|
||||||
log_ = ngx_cycle->log;
|
log_ = ngx_cycle->log;
|
||||||
for (size_t i = 0; i < ngx_url_async_fetchers_.size(); ++i) {
|
for (size_t i = 0; i < ngx_url_async_fetchers_.size(); ++i) {
|
||||||
@@ -177,6 +175,12 @@ NgxServerContext* NgxRewriteDriverFactory::MakeNgxServerContext(
|
|||||||
return server_context;
|
return server_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServerContext* NgxRewriteDriverFactory::NewDecodingServerContext() {
|
||||||
|
ServerContext* sc = new NgxServerContext(this, hostname_, port_);
|
||||||
|
InitStubDecodingServerContext(sc);
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
|
||||||
ServerContext* NgxRewriteDriverFactory::NewServerContext() {
|
ServerContext* NgxRewriteDriverFactory::NewServerContext() {
|
||||||
LOG(DFATAL) << "MakeNgxServerContext should be used instead";
|
LOG(DFATAL) << "MakeNgxServerContext should be used instead";
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -208,7 +212,7 @@ void NgxRewriteDriverFactory::StartThreads() {
|
|||||||
|
|
||||||
void NgxRewriteDriverFactory::LoggingInit(ngx_log_t* log) {
|
void NgxRewriteDriverFactory::LoggingInit(ngx_log_t* log) {
|
||||||
net_instaweb::log_message_handler::Install(log);
|
net_instaweb::log_message_handler::Install(log);
|
||||||
if (install_crash_handler_) {
|
if (install_crash_handler()) {
|
||||||
NgxMessageHandler::InstallCrashHandler(log);
|
NgxMessageHandler::InstallCrashHandler(log);
|
||||||
}
|
}
|
||||||
ngx_message_handler_->set_log(log);
|
ngx_message_handler_->set_log(log);
|
||||||
@@ -218,12 +222,14 @@ void NgxRewriteDriverFactory::LoggingInit(ngx_log_t* log) {
|
|||||||
void NgxRewriteDriverFactory::SetCircularBuffer(
|
void NgxRewriteDriverFactory::SetCircularBuffer(
|
||||||
SharedCircularBuffer* buffer) {
|
SharedCircularBuffer* buffer) {
|
||||||
ngx_shared_circular_buffer_ = buffer;
|
ngx_shared_circular_buffer_ = buffer;
|
||||||
|
ngx_message_handler_->set_buffer(buffer);
|
||||||
|
ngx_html_parse_message_handler_->set_buffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NgxRewriteDriverFactory::SetServerContextMessageHandler(
|
void NgxRewriteDriverFactory::SetServerContextMessageHandler(
|
||||||
ServerContext* server_context, ngx_log_t* log) {
|
ServerContext* server_context, ngx_log_t* log) {
|
||||||
NgxMessageHandler* handler = new NgxMessageHandler(
|
NgxMessageHandler* handler = new NgxMessageHandler(
|
||||||
thread_system()->NewMutex());
|
timer(), thread_system()->NewMutex());
|
||||||
handler->set_log(log);
|
handler->set_log(log);
|
||||||
// The ngx_shared_circular_buffer_ will be NULL if MessageBufferSize hasn't
|
// The ngx_shared_circular_buffer_ will be NULL if MessageBufferSize hasn't
|
||||||
// been raised from its default of 0.
|
// been raised from its default of 0.
|
||||||
|
|||||||
@@ -20,6 +20,10 @@
|
|||||||
#define NGX_REWRITE_DRIVER_FACTORY_H_
|
#define NGX_REWRITE_DRIVER_FACTORY_H_
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#include <ngx_auto_config.h>
|
||||||
|
#if (NGX_THREADS)
|
||||||
|
#include <ngx_thread.h>
|
||||||
|
#endif
|
||||||
#include <ngx_core.h>
|
#include <ngx_core.h>
|
||||||
#include <ngx_http.h>
|
#include <ngx_http.h>
|
||||||
#include <ngx_config.h>
|
#include <ngx_config.h>
|
||||||
@@ -28,7 +32,6 @@ extern "C" {
|
|||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "apr_pools.h"
|
|
||||||
#include "net/instaweb/system/public/system_rewrite_driver_factory.h"
|
#include "net/instaweb/system/public/system_rewrite_driver_factory.h"
|
||||||
#include "net/instaweb/util/public/md5_hasher.h"
|
#include "net/instaweb/util/public/md5_hasher.h"
|
||||||
#include "net/instaweb/util/public/scoped_ptr.h"
|
#include "net/instaweb/util/public/scoped_ptr.h"
|
||||||
@@ -46,16 +49,14 @@ class NgxUrlAsyncFetcher;
|
|||||||
class SharedCircularBuffer;
|
class SharedCircularBuffer;
|
||||||
class SharedMemRefererStatistics;
|
class SharedMemRefererStatistics;
|
||||||
class SlowWorker;
|
class SlowWorker;
|
||||||
class StaticAssetManager;
|
|
||||||
class Statistics;
|
class Statistics;
|
||||||
class SystemThreadSystem;
|
class SystemThreadSystem;
|
||||||
|
|
||||||
class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
||||||
public:
|
public:
|
||||||
static const char kStaticAssetPrefix[];
|
|
||||||
|
|
||||||
// We take ownership of the thread system.
|
// We take ownership of the thread system.
|
||||||
explicit NgxRewriteDriverFactory(
|
explicit NgxRewriteDriverFactory(
|
||||||
|
const ProcessContext& process_context,
|
||||||
SystemThreadSystem* system_thread_system, StringPiece hostname, int port);
|
SystemThreadSystem* system_thread_system, StringPiece hostname, int port);
|
||||||
virtual ~NgxRewriteDriverFactory();
|
virtual ~NgxRewriteDriverFactory();
|
||||||
virtual Hasher* NewHasher();
|
virtual Hasher* NewHasher();
|
||||||
@@ -68,9 +69,7 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
|||||||
// Create a new RewriteOptions. In this implementation it will be an
|
// Create a new RewriteOptions. In this implementation it will be an
|
||||||
// NgxRewriteOptions.
|
// NgxRewriteOptions.
|
||||||
virtual RewriteOptions* NewRewriteOptions();
|
virtual RewriteOptions* NewRewriteOptions();
|
||||||
// Initializes the StaticAssetManager.
|
virtual ServerContext* NewDecodingServerContext();
|
||||||
virtual void InitStaticAssetManager(
|
|
||||||
StaticAssetManager* static_asset_manager);
|
|
||||||
bool InitNgxUrlAsyncFetchers();
|
bool InitNgxUrlAsyncFetchers();
|
||||||
// Check resolver configured or not.
|
// Check resolver configured or not.
|
||||||
bool CheckResolver();
|
bool CheckResolver();
|
||||||
@@ -80,7 +79,7 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
|||||||
// platform-independent statistics.
|
// platform-independent statistics.
|
||||||
static void InitStats(Statistics* statistics);
|
static void InitStats(Statistics* statistics);
|
||||||
NgxServerContext* MakeNgxServerContext(StringPiece hostname, int port);
|
NgxServerContext* MakeNgxServerContext(StringPiece hostname, int port);
|
||||||
ServerContext* NewServerContext();
|
virtual ServerContext* NewServerContext();
|
||||||
|
|
||||||
// Starts pagespeed threads if they've not been started already. Must be
|
// Starts pagespeed threads if they've not been started already. Must be
|
||||||
// called after the caller has finished any forking it intends to do.
|
// called after the caller has finished any forking it intends to do.
|
||||||
@@ -97,18 +96,6 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
|||||||
|
|
||||||
void set_main_conf(NgxRewriteOptions* main_conf) { main_conf_ = main_conf; }
|
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) {
|
void set_resolver(ngx_resolver_t* resolver) {
|
||||||
resolver_ = resolver;
|
resolver_ = resolver;
|
||||||
}
|
}
|
||||||
@@ -122,16 +109,14 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
|||||||
void set_use_native_fetcher(bool x) {
|
void set_use_native_fetcher(bool x) {
|
||||||
use_native_fetcher_ = x;
|
use_native_fetcher_ = x;
|
||||||
}
|
}
|
||||||
void set_rate_limit_background_fetches(bool x) {
|
int native_fetcher_max_keepalive_requests() {
|
||||||
rate_limit_background_fetches_ = x;
|
return native_fetcher_max_keepalive_requests_;
|
||||||
}
|
}
|
||||||
|
void set_native_fetcher_max_keepalive_requests(int x) {
|
||||||
// We use a beacon handler to collect data for critical images,
|
native_fetcher_max_keepalive_requests_ = x;
|
||||||
// css, etc., so filters should be configured accordingly.
|
}
|
||||||
//
|
bool process_script_variables() {
|
||||||
// TODO(jefftk): move to SystemRewriteDriverFactory
|
return process_script_variables_;
|
||||||
virtual bool UseBeaconResultsInFilters() const {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoggingInit(ngx_log_t* log);
|
void LoggingInit(ngx_log_t* log);
|
||||||
@@ -140,6 +125,15 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
|||||||
|
|
||||||
virtual void SetCircularBuffer(SharedCircularBuffer* buffer);
|
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:
|
private:
|
||||||
Timer* timer_;
|
Timer* timer_;
|
||||||
|
|
||||||
@@ -148,20 +142,16 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
|||||||
NgxRewriteOptions* main_conf_;
|
NgxRewriteOptions* main_conf_;
|
||||||
|
|
||||||
bool threads_started_;
|
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_message_handler_;
|
||||||
NgxMessageHandler* ngx_html_parse_message_handler_;
|
NgxMessageHandler* ngx_html_parse_message_handler_;
|
||||||
bool install_crash_handler_;
|
|
||||||
|
|
||||||
std::vector<NgxUrlAsyncFetcher*> ngx_url_async_fetchers_;
|
std::vector<NgxUrlAsyncFetcher*> ngx_url_async_fetchers_;
|
||||||
ngx_log_t* log_;
|
ngx_log_t* log_;
|
||||||
ngx_msec_t resolver_timeout_;
|
ngx_msec_t resolver_timeout_;
|
||||||
ngx_resolver_t* resolver_;
|
ngx_resolver_t* resolver_;
|
||||||
bool use_native_fetcher_;
|
bool use_native_fetcher_;
|
||||||
bool rate_limit_background_fetches_;
|
int native_fetcher_max_keepalive_requests_;
|
||||||
|
|
||||||
typedef std::set<NgxMessageHandler*> NgxMessageHandlerSet;
|
typedef std::set<NgxMessageHandler*> NgxMessageHandlerSet;
|
||||||
NgxMessageHandlerSet server_context_message_handlers_;
|
NgxMessageHandlerSet server_context_message_handlers_;
|
||||||
|
|
||||||
@@ -169,6 +159,11 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
|
|||||||
// TODO(jefftk): merge the nginx and apache ways of doing this.
|
// TODO(jefftk): merge the nginx and apache ways of doing this.
|
||||||
SharedCircularBuffer* ngx_shared_circular_buffer_;
|
SharedCircularBuffer* ngx_shared_circular_buffer_;
|
||||||
|
|
||||||
|
GoogleString hostname_;
|
||||||
|
int port_;
|
||||||
|
bool process_script_variables_;
|
||||||
|
bool process_script_variables_set_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(NgxRewriteDriverFactory);
|
DISALLOW_COPY_AND_ASSIGN(NgxRewriteDriverFactory);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+320
-66
@@ -31,13 +31,56 @@ extern "C" {
|
|||||||
#include "net/instaweb/rewriter/public/file_load_policy.h"
|
#include "net/instaweb/rewriter/public/file_load_policy.h"
|
||||||
#include "net/instaweb/rewriter/public/rewrite_options.h"
|
#include "net/instaweb/rewriter/public/rewrite_options.h"
|
||||||
#include "net/instaweb/system/public/system_caches.h"
|
#include "net/instaweb/system/public/system_caches.h"
|
||||||
|
#include "net/instaweb/util/public/message_handler.h"
|
||||||
#include "net/instaweb/util/public/timer.h"
|
#include "net/instaweb/util/public/timer.h"
|
||||||
|
|
||||||
namespace net_instaweb {
|
namespace net_instaweb {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char kNgxPagespeedStatisticsHandlerPath[] = "/ngx_pagespeed_statistics";
|
const char kStatisticsPath[] = "StatisticsPath";
|
||||||
|
const char kGlobalStatisticsPath[] = "GlobalStatisticsPath";
|
||||||
|
const char kConsolePath[] = "ConsolePath";
|
||||||
|
const char kMessagesPath[] = "MessagesPath";
|
||||||
|
const char kAdminPath[] = "AdminPath";
|
||||||
|
const char kGlobalAdminPath[] = "GlobalAdminPath";
|
||||||
|
|
||||||
|
// These options are copied from mod_instaweb.cc, where APACHE_CONFIG_OPTIONX
|
||||||
|
// indicates that they can not be set at the directory/location level. They set
|
||||||
|
// options in the RewriteDriverFactory, so they'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",
|
||||||
|
"FetchProxy",
|
||||||
|
"ForceCaching",
|
||||||
|
"GeneratedFilePrefix",
|
||||||
|
"ImgMaxRewritesAtOnce",
|
||||||
|
"InheritVHostConfig",
|
||||||
|
"InstallCrashHandler",
|
||||||
|
"MessageBufferSize",
|
||||||
|
"NumRewriteThreads",
|
||||||
|
"NumExpensiveRewriteThreads",
|
||||||
|
"StaticAssetPrefix",
|
||||||
|
"TrackOriginalContentLength",
|
||||||
|
"UsePerVHostStatistics", // TODO(anupama): What to do about "No longer used"
|
||||||
|
"BlockingRewriteRefererUrls",
|
||||||
|
"CreateSharedMemoryMetadataCache",
|
||||||
|
"LoadFromFile",
|
||||||
|
"LoadFromFileMatch",
|
||||||
|
"LoadFromFileRule",
|
||||||
|
"LoadFromFileRuleMatch",
|
||||||
|
"UseNativeFetcher",
|
||||||
|
"NativeFetcherMaxKeepaliveRequests"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Options that can only be used in the main (http) option scope.
|
||||||
|
const char* const main_only_options[] = {
|
||||||
|
"UseNativeFetcher",
|
||||||
|
"NativeFetcherMaxKeepaliveRequests"
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -57,16 +100,35 @@ NgxRewriteOptions::NgxRewriteOptions(ThreadSystem* thread_system)
|
|||||||
void NgxRewriteOptions::Init() {
|
void NgxRewriteOptions::Init() {
|
||||||
DCHECK(ngx_properties_ != NULL)
|
DCHECK(ngx_properties_ != NULL)
|
||||||
<< "Call NgxRewriteOptions::Initialize() before construction";
|
<< "Call NgxRewriteOptions::Initialize() before construction";
|
||||||
|
clear_inherited_scripts_ = false;
|
||||||
InitializeOptions(ngx_properties_);
|
InitializeOptions(ngx_properties_);
|
||||||
|
|
||||||
// Nginx-specific default.
|
|
||||||
// TODO(sligocki): Get rid of this line and let both Apache and Nginx use
|
|
||||||
// /pagespeed_statistics as the handler.
|
|
||||||
statistics_handler_path_.set_default(kNgxPagespeedStatisticsHandlerPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NgxRewriteOptions::AddProperties() {
|
void NgxRewriteOptions::AddProperties() {
|
||||||
// Nothing ngx-specific for now.
|
// Nginx-specific options.
|
||||||
|
add_ngx_option(
|
||||||
|
"", &NgxRewriteOptions::statistics_path_, "nsp", kStatisticsPath,
|
||||||
|
kServerScope, "Set the statistics path. Ex: /ngx_pagespeed_statistics",
|
||||||
|
false);
|
||||||
|
add_ngx_option(
|
||||||
|
"", &NgxRewriteOptions::global_statistics_path_, "ngsp",
|
||||||
|
kGlobalStatisticsPath, kProcessScope,
|
||||||
|
"Set the global statistics path. Ex: /ngx_pagespeed_global_statistics",
|
||||||
|
false);
|
||||||
|
add_ngx_option(
|
||||||
|
"", &NgxRewriteOptions::console_path_, "ncp", kConsolePath, kServerScope,
|
||||||
|
"Set the console path. Ex: /pagespeed_console", false);
|
||||||
|
add_ngx_option(
|
||||||
|
"", &NgxRewriteOptions::messages_path_, "nmp", kMessagesPath,
|
||||||
|
kServerScope, "Set the messages path. Ex: /ngx_pagespeed_message",
|
||||||
|
false);
|
||||||
|
add_ngx_option(
|
||||||
|
"", &NgxRewriteOptions::admin_path_, "nap", kAdminPath,
|
||||||
|
kServerScope, "Set the admin path. Ex: /pagespeed_admin", false);
|
||||||
|
add_ngx_option(
|
||||||
|
"", &NgxRewriteOptions::global_admin_path_, "ngap", kGlobalAdminPath,
|
||||||
|
kProcessScope, "Set the global admin path. Ex: /pagespeed_global_admin",
|
||||||
|
false);
|
||||||
|
|
||||||
MergeSubclassProperties(ngx_properties_);
|
MergeSubclassProperties(ngx_properties_);
|
||||||
|
|
||||||
@@ -94,6 +156,39 @@ bool NgxRewriteOptions::IsDirective(StringPiece config_directive,
|
|||||||
return StringCaseEqual(config_directive, compare_directive);
|
return StringCaseEqual(config_directive, compare_directive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RewriteOptions::OptionScope NgxRewriteOptions::GetOptionScope(
|
||||||
|
StringPiece option_name) {
|
||||||
|
ngx_uint_t i;
|
||||||
|
ngx_uint_t size = sizeof(main_only_options) / sizeof(char*);
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (StringCaseEqual(main_only_options[i], option_name)) {
|
||||||
|
return kProcessScopeStrict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(server_only_options) / sizeof(char*);
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (StringCaseEqual(server_only_options[i], option_name)) {
|
||||||
|
return kServerScope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This could be made more efficient if RewriteOptions provided a map allowing
|
||||||
|
// access of options by their name. It's not too much of a worry at present
|
||||||
|
// since this is just during initialization.
|
||||||
|
for (OptionBaseVector::const_iterator it = all_options().begin();
|
||||||
|
it != all_options().end(); ++it) {
|
||||||
|
RewriteOptions::OptionBase* option = *it;
|
||||||
|
if (option->option_name() == option_name) {
|
||||||
|
// We treat kProcessScope as kProcessScopeStrict, failing to start if an
|
||||||
|
// option is out of place.
|
||||||
|
return option->scope() == kProcessScope ? kProcessScopeStrict
|
||||||
|
: option->scope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kDirectoryScope;
|
||||||
|
}
|
||||||
|
|
||||||
RewriteOptions::OptionSettingResult NgxRewriteOptions::ParseAndSetOptions0(
|
RewriteOptions::OptionSettingResult NgxRewriteOptions::ParseAndSetOptions0(
|
||||||
StringPiece directive, GoogleString* msg, MessageHandler* handler) {
|
StringPiece directive, GoogleString* msg, MessageHandler* handler) {
|
||||||
if (IsDirective(directive, "on")) {
|
if (IsDirective(directive, "on")) {
|
||||||
@@ -144,10 +239,26 @@ RewriteOptions::OptionSettingResult ParseAndSetOptionHelper(
|
|||||||
return RewriteOptions::kOptionOk;
|
return RewriteOptions::kOptionOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char* ps_error_string_for_option(
|
||||||
|
ngx_pool_t* pool, StringPiece directive, StringPiece warning) {
|
||||||
|
GoogleString msg =
|
||||||
|
StrCat("\"", directive, "\" ", warning);
|
||||||
|
char* s = string_piece_to_pool_string(pool, msg);
|
||||||
|
if (s == NULL) {
|
||||||
|
return "failed to allocate memory";
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// Very similar to apache/mod_instaweb::ParseDirective.
|
// Very similar to apache/mod_instaweb::ParseDirective.
|
||||||
const char* NgxRewriteOptions::ParseAndSetOptions(
|
const char* NgxRewriteOptions::ParseAndSetOptions(
|
||||||
StringPiece* args, int n_args, ngx_pool_t* pool, MessageHandler* handler,
|
StringPiece* args, int n_args, ngx_pool_t* pool, MessageHandler* handler,
|
||||||
NgxRewriteDriverFactory* driver_factory) {
|
NgxRewriteDriverFactory* driver_factory,
|
||||||
|
RewriteOptions::OptionScope scope, ngx_conf_t* cf, bool compile_scripts) {
|
||||||
CHECK_GE(n_args, 1);
|
CHECK_GE(n_args, 1);
|
||||||
|
|
||||||
StringPiece directive = args[0];
|
StringPiece directive = args[0];
|
||||||
@@ -158,94 +269,158 @@ const char* NgxRewriteOptions::ParseAndSetOptions(
|
|||||||
directive.remove_prefix(mod_pagespeed.size());
|
directive.remove_prefix(mod_pagespeed.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GetOptionScope(directive) > scope) {
|
||||||
|
return ps_error_string_for_option(
|
||||||
|
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;
|
GoogleString msg;
|
||||||
OptionSettingResult result;
|
OptionSettingResult result;
|
||||||
if (n_args == 1) {
|
if (n_args == 1) {
|
||||||
result = ParseAndSetOptions0(directive, &msg, handler);
|
result = ParseAndSetOptions0(directive, &msg, handler);
|
||||||
} else if (n_args == 2) {
|
} else if (n_args == 2) {
|
||||||
StringPiece arg = args[1];
|
StringPiece arg = args[1];
|
||||||
// TODO(morlovich): Remove these special hacks, and handle these via
|
if (IsDirective(directive, "UseNativeFetcher")) {
|
||||||
// ParseAndSetOptionFromEnum1.
|
|
||||||
if (IsDirective(directive, "UsePerVHostStatistics")) {
|
|
||||||
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
|
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
|
||||||
arg, driver_factory,
|
arg, driver_factory,
|
||||||
&NgxRewriteDriverFactory::set_use_per_vhost_statistics);
|
&NgxRewriteDriverFactory::set_use_native_fetcher);
|
||||||
} else if (IsDirective(directive, "InstallCrashHandler")) {
|
} else if (IsDirective(directive, "NativeFetcherMaxKeepaliveRequests")) {
|
||||||
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
|
int max_keepalive_requests;
|
||||||
arg, driver_factory,
|
if (StringToInt(arg, &max_keepalive_requests) &&
|
||||||
&NgxRewriteDriverFactory::set_install_crash_handler);
|
max_keepalive_requests > 0) {
|
||||||
} else if (IsDirective(directive, "MessageBufferSize")) {
|
driver_factory->set_native_fetcher_max_keepalive_requests(
|
||||||
int message_buffer_size;
|
max_keepalive_requests);
|
||||||
bool ok = StringToInt(arg.as_string(), &message_buffer_size);
|
|
||||||
if (ok && message_buffer_size >= 0) {
|
|
||||||
driver_factory->set_message_buffer_size(message_buffer_size);
|
|
||||||
result = RewriteOptions::kOptionOk;
|
result = RewriteOptions::kOptionOk;
|
||||||
} else {
|
} else {
|
||||||
result = RewriteOptions::kOptionValueInvalid;
|
result = RewriteOptions::kOptionValueInvalid;
|
||||||
}
|
}
|
||||||
} else if (IsDirective(directive, "UseNativeFetcher")) {
|
} else if (StringCaseEqual("ProcessScriptVariables", args[0])) {
|
||||||
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
|
if (scope == RewriteOptions::kProcessScopeStrict) {
|
||||||
arg, driver_factory,
|
if (StringCaseEqual(arg, "on")) {
|
||||||
&NgxRewriteDriverFactory::set_use_native_fetcher);
|
if (driver_factory->SetProcessScriptVariables(true)) {
|
||||||
} else if (IsDirective(directive, "RateLimitBackgroundFetches")) {
|
result = RewriteOptions::kOptionOk;
|
||||||
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
|
} else {
|
||||||
arg, driver_factory,
|
return const_cast<char*>(
|
||||||
&NgxRewriteDriverFactory::set_rate_limit_background_fetches);
|
"pagespeed ProcessScriptVariables: can only be set once");
|
||||||
} else if (IsDirective(directive, "ForceCaching")) {
|
}
|
||||||
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
|
} else if (StringCaseEqual(arg, "off")) {
|
||||||
arg, driver_factory,
|
if (driver_factory->SetProcessScriptVariables(false)) {
|
||||||
&SystemRewriteDriverFactory::set_force_caching);
|
result = RewriteOptions::kOptionOk;
|
||||||
} else if (IsDirective(directive, "ListOutstandingUrlsOnError")) {
|
} else {
|
||||||
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
|
return const_cast<char*>(
|
||||||
arg, driver_factory,
|
"pagespeed ProcessScriptVariables: can only be set once");
|
||||||
&SystemRewriteDriverFactory::list_outstanding_urls_on_error);
|
}
|
||||||
} else if (IsDirective(directive, "TrackOriginalContentLength")) {
|
} else {
|
||||||
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
|
return const_cast<char*>(
|
||||||
arg, driver_factory,
|
"pagespeed ProcessScriptVariables: invalid value");
|
||||||
&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 {
|
} else {
|
||||||
bool ok = driver_factory->caches()->CreateShmMetadataCache(
|
return const_cast<char*>(
|
||||||
args[1].as_string(), kb, &msg);
|
"ProcessScriptVariables is only allowed at the top level");
|
||||||
result = ok ? kOptionOk : kOptionValueInvalid;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = ParseAndSetOptionFromName2(directive, args[1], args[2],
|
result = ParseAndSetOptionFromName1(directive, arg, &msg, handler);
|
||||||
&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) {
|
} else if (n_args == 4) {
|
||||||
result = ParseAndSetOptionFromName3(
|
result = ParseAndSetOptionFromName3(
|
||||||
directive, args[1], args[2], args[3], &msg, handler);
|
directive, args[1], args[2], args[3], &msg, handler);
|
||||||
} else {
|
} else {
|
||||||
return "unknown option";
|
result = RewriteOptions::kOptionNameUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case RewriteOptions::kOptionOk:
|
case RewriteOptions::kOptionOk:
|
||||||
return NGX_CONF_OK;
|
return NGX_CONF_OK;
|
||||||
case RewriteOptions::kOptionNameUnknown:
|
case RewriteOptions::kOptionNameUnknown:
|
||||||
return "unknown option";
|
return ps_error_string_for_option(
|
||||||
|
pool, directive, "not recognized or too many arguments");
|
||||||
case RewriteOptions::kOptionValueInvalid: {
|
case RewriteOptions::kOptionValueInvalid: {
|
||||||
GoogleString full_directive = "\"";
|
GoogleString full_directive;
|
||||||
for (int i = 0 ; i < n_args ; i++) {
|
for (int i = 0 ; i < n_args ; i++) {
|
||||||
StrAppend(&full_directive, i == 0 ? "" : " ", args[i]);
|
StrAppend(&full_directive, i == 0 ? "" : " ", args[i]);
|
||||||
}
|
}
|
||||||
StrAppend(&full_directive, "\": ", msg);
|
return ps_error_string_for_option(pool, full_directive, msg);
|
||||||
char* s = string_piece_to_pool_string(pool, full_directive);
|
|
||||||
if (s == NULL) {
|
|
||||||
return "failed to allocate memory";
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,13 +428,92 @@ const char* NgxRewriteOptions::ParseAndSetOptions(
|
|||||||
return NULL;
|
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* NgxRewriteOptions::Clone() const {
|
||||||
NgxRewriteOptions* options = new NgxRewriteOptions(
|
NgxRewriteOptions* options = new NgxRewriteOptions(
|
||||||
StrCat("cloned from ", description()), thread_system());
|
StrCat("cloned from ", description()), thread_system());
|
||||||
|
this->CopyScriptLinesTo(options);
|
||||||
options->Merge(*this);
|
options->Merge(*this);
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NgxRewriteOptions::Merge(const RewriteOptions& src) {
|
||||||
|
SystemRewriteOptions::Merge(src);
|
||||||
|
}
|
||||||
|
|
||||||
const NgxRewriteOptions* NgxRewriteOptions::DynamicCast(
|
const NgxRewriteOptions* NgxRewriteOptions::DynamicCast(
|
||||||
const RewriteOptions* instance) {
|
const RewriteOptions* instance) {
|
||||||
return dynamic_cast<const NgxRewriteOptions*>(instance);
|
return dynamic_cast<const NgxRewriteOptions*>(instance);
|
||||||
|
|||||||
+124
-3
@@ -27,20 +27,89 @@ extern "C" {
|
|||||||
#include <ngx_http.h>
|
#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/rewriter/public/rewrite_options.h"
|
||||||
#include "net/instaweb/system/public/system_rewrite_options.h"
|
#include "net/instaweb/system/public/system_rewrite_options.h"
|
||||||
|
|
||||||
|
#define NGX_PAGESPEED_MAX_ARGS 10
|
||||||
|
|
||||||
namespace net_instaweb {
|
namespace net_instaweb {
|
||||||
|
|
||||||
class NgxRewriteDriverFactory;
|
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 {
|
class NgxRewriteOptions : public SystemRewriteOptions {
|
||||||
public:
|
public:
|
||||||
// See rewrite_options::Initialize and ::Terminate
|
// See rewrite_options::Initialize and ::Terminate
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
static void Terminate();
|
static void Terminate();
|
||||||
|
|
||||||
NgxRewriteOptions(const StringPiece& description, ThreadSystem* thread_system);
|
NgxRewriteOptions(const StringPiece& description,
|
||||||
|
ThreadSystem* thread_system);
|
||||||
explicit NgxRewriteOptions(ThreadSystem* thread_system);
|
explicit NgxRewriteOptions(ThreadSystem* thread_system);
|
||||||
virtual ~NgxRewriteOptions() { }
|
virtual ~NgxRewriteOptions() { }
|
||||||
|
|
||||||
@@ -55,18 +124,53 @@ class NgxRewriteOptions : public SystemRewriteOptions {
|
|||||||
// on failure.
|
// on failure.
|
||||||
//
|
//
|
||||||
// pool is a memory pool for allocating error strings.
|
// 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(
|
const char* ParseAndSetOptions(
|
||||||
StringPiece* args, int n_args, ngx_pool_t* pool, MessageHandler* handler,
|
StringPiece* args, int n_args, ngx_pool_t* pool, MessageHandler* handler,
|
||||||
|
NgxRewriteDriverFactory* driver_factory, OptionScope scope,
|
||||||
|
ngx_conf_t* cf, bool compile_scripts);
|
||||||
|
bool ExecuteScriptVariables(
|
||||||
|
ngx_http_request_t* r, MessageHandler* handler,
|
||||||
NgxRewriteDriverFactory* driver_factory);
|
NgxRewriteDriverFactory* driver_factory);
|
||||||
|
void CopyScriptLinesTo(NgxRewriteOptions* destination) const;
|
||||||
|
void AppendScriptLinesTo(NgxRewriteOptions* destination) const;
|
||||||
|
|
||||||
// Make an identical copy of these options and return it.
|
// Make an identical copy of these options and return it.
|
||||||
virtual NgxRewriteOptions* Clone() const;
|
virtual NgxRewriteOptions* Clone() const;
|
||||||
|
virtual void Merge(const RewriteOptions& src);
|
||||||
|
|
||||||
// Returns a suitably down cast version of 'instance' if it is an instance
|
// Returns a suitably down cast version of 'instance' if it is an instance
|
||||||
// of this class, NULL if not.
|
// of this class, NULL if not.
|
||||||
static const NgxRewriteOptions* DynamicCast(const RewriteOptions* instance);
|
static const NgxRewriteOptions* DynamicCast(const RewriteOptions* instance);
|
||||||
static NgxRewriteOptions* DynamicCast(RewriteOptions* instance);
|
static NgxRewriteOptions* DynamicCast(RewriteOptions* instance);
|
||||||
|
|
||||||
|
const GoogleString& statistics_path() const {
|
||||||
|
return statistics_path_.value();
|
||||||
|
}
|
||||||
|
const GoogleString& global_statistics_path() const {
|
||||||
|
return global_statistics_path_.value();
|
||||||
|
}
|
||||||
|
const GoogleString& console_path() const {
|
||||||
|
return console_path_.value();
|
||||||
|
}
|
||||||
|
const GoogleString& messages_path() const {
|
||||||
|
return messages_path_.value();
|
||||||
|
}
|
||||||
|
const GoogleString& admin_path() const {
|
||||||
|
return admin_path_.value();
|
||||||
|
}
|
||||||
|
const GoogleString& global_admin_path() const {
|
||||||
|
return global_admin_path_.value();
|
||||||
|
}
|
||||||
|
const std::vector<RefCountedPtr<ScriptLine> >& script_lines() const {
|
||||||
|
return script_lines_;
|
||||||
|
}
|
||||||
|
const bool& clear_inherited_scripts() const {
|
||||||
|
return clear_inherited_scripts_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Helper methods for ParseAndSetOptions(). Each can:
|
// Helper methods for ParseAndSetOptions(). Each can:
|
||||||
@@ -108,14 +212,31 @@ class NgxRewriteOptions : public SystemRewriteOptions {
|
|||||||
static void add_ngx_option(typename OptionClass::ValueType default_value,
|
static void add_ngx_option(typename OptionClass::ValueType default_value,
|
||||||
OptionClass NgxRewriteOptions::*offset,
|
OptionClass NgxRewriteOptions::*offset,
|
||||||
const char* id,
|
const char* id,
|
||||||
StringPiece option_name) {
|
StringPiece option_name,
|
||||||
AddProperty(default_value, offset, id, option_name, ngx_properties_);
|
OptionScope scope,
|
||||||
|
const char* help,
|
||||||
|
bool safe_to_print) {
|
||||||
|
AddProperty(default_value, offset, id, option_name, scope, help,
|
||||||
|
safe_to_print, ngx_properties_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Option<GoogleString> statistics_path_;
|
||||||
|
Option<GoogleString> global_statistics_path_;
|
||||||
|
Option<GoogleString> console_path_;
|
||||||
|
Option<GoogleString> messages_path_;
|
||||||
|
Option<GoogleString> admin_path_;
|
||||||
|
Option<GoogleString> global_admin_path_;
|
||||||
|
|
||||||
|
bool clear_inherited_scripts_;
|
||||||
|
std::vector<RefCountedPtr<ScriptLine> > script_lines_;
|
||||||
|
|
||||||
// Helper for ParseAndSetOptions. Returns whether the two directives equal,
|
// Helper for ParseAndSetOptions. Returns whether the two directives equal,
|
||||||
// ignoring case.
|
// ignoring case.
|
||||||
bool IsDirective(StringPiece config_directive, StringPiece compare_directive);
|
bool IsDirective(StringPiece config_directive, StringPiece compare_directive);
|
||||||
|
|
||||||
|
// Returns a given option's scope.
|
||||||
|
RewriteOptions::OptionScope GetOptionScope(StringPiece option_name);
|
||||||
|
|
||||||
// TODO(jefftk): support fetch proxy in server and location blocks.
|
// TODO(jefftk): support fetch proxy in server and location blocks.
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(NgxRewriteOptions);
|
DISALLOW_COPY_AND_ASSIGN(NgxRewriteOptions);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ SystemRequestContext* NgxServerContext::NewRequestContext(
|
|||||||
ngx_http_request_t* r) {
|
ngx_http_request_t* r) {
|
||||||
// Based on ngx_http_variable_server_port.
|
// Based on ngx_http_variable_server_port.
|
||||||
bool port_set = false;
|
bool port_set = false;
|
||||||
int local_port;
|
int local_port = 0;
|
||||||
#if (NGX_HAVE_INET6)
|
#if (NGX_HAVE_INET6)
|
||||||
if (r->connection->local_sockaddr->sa_family == AF_INET6) {
|
if (r->connection->local_sockaddr->sa_family == AF_INET6) {
|
||||||
local_port = ntohs(reinterpret_cast<struct sockaddr_in6*>(
|
local_port = ntohs(reinterpret_cast<struct sockaddr_in6*>(
|
||||||
@@ -72,8 +72,14 @@ SystemRequestContext* NgxServerContext::NewRequestContext(
|
|||||||
|
|
||||||
return new SystemRequestContext(thread_system()->NewMutex(),
|
return new SystemRequestContext(thread_system()->NewMutex(),
|
||||||
timer(),
|
timer(),
|
||||||
|
ps_determine_host(r),
|
||||||
local_port,
|
local_port,
|
||||||
str_to_string_piece(local_ip));
|
str_to_string_piece(local_ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GoogleString NgxServerContext::FormatOption(StringPiece option_name,
|
||||||
|
StringPiece args) {
|
||||||
|
return StrCat("pagespeed ", option_name, " ", args, ";");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace net_instaweb
|
} // namespace net_instaweb
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ class NgxServerContext : public SystemServerContext {
|
|||||||
return dynamic_cast<NgxMessageHandler*>(message_handler());
|
return dynamic_cast<NgxMessageHandler*>(message_handler());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual GoogleString FormatOption(StringPiece option_name, StringPiece args);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NgxRewriteDriverFactory* ngx_factory_;
|
NgxRewriteDriverFactory* ngx_factory_;
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ namespace net_instaweb {
|
|||||||
ngx_msec_t resolver_timeout,
|
ngx_msec_t resolver_timeout,
|
||||||
ngx_msec_t fetch_timeout,
|
ngx_msec_t fetch_timeout,
|
||||||
ngx_resolver_t* resolver,
|
ngx_resolver_t* resolver,
|
||||||
|
int max_keepalive_requests,
|
||||||
ThreadSystem* thread_system,
|
ThreadSystem* thread_system,
|
||||||
MessageHandler* handler)
|
MessageHandler* handler)
|
||||||
: fetchers_count_(0),
|
: fetchers_count_(0),
|
||||||
@@ -63,13 +64,14 @@ namespace net_instaweb {
|
|||||||
byte_count_(0),
|
byte_count_(0),
|
||||||
thread_system_(thread_system),
|
thread_system_(thread_system),
|
||||||
message_handler_(handler),
|
message_handler_(handler),
|
||||||
mutex_(NULL) {
|
mutex_(NULL),
|
||||||
|
max_keepalive_requests_(max_keepalive_requests) {
|
||||||
resolver_timeout_ = resolver_timeout;
|
resolver_timeout_ = resolver_timeout;
|
||||||
fetch_timeout_ = fetch_timeout;
|
fetch_timeout_ = fetch_timeout;
|
||||||
ngx_memzero(&url_, sizeof(url_));
|
ngx_memzero(&proxy_, sizeof(proxy_));
|
||||||
if (proxy != NULL && *proxy != '\0') {
|
if (proxy != NULL && *proxy != '\0') {
|
||||||
url_.url.data = reinterpret_cast<u_char*>(const_cast<char*>(proxy));
|
proxy_.url.data = reinterpret_cast<u_char*>(const_cast<char*>(proxy));
|
||||||
url_.url.len = ngx_strlen(proxy);
|
proxy_.url.len = ngx_strlen(proxy);
|
||||||
}
|
}
|
||||||
mutex_ = thread_system_->NewMutex();
|
mutex_ = thread_system_->NewMutex();
|
||||||
log_ = log;
|
log_ = log;
|
||||||
@@ -106,6 +108,36 @@ namespace net_instaweb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool NgxUrlAsyncFetcher::ParseUrl(ngx_url_t* url, ngx_pool_t* pool) {
|
||||||
|
size_t scheme_offset;
|
||||||
|
u_short port;
|
||||||
|
if (ngx_strncasecmp(url->url.data, reinterpret_cast<u_char*>(
|
||||||
|
const_cast<char*>("http://")), 7) == 0) {
|
||||||
|
scheme_offset = 7;
|
||||||
|
port = 80;
|
||||||
|
} else if (ngx_strncasecmp(url->url.data, reinterpret_cast<u_char*>(
|
||||||
|
const_cast<char*>("https://")), 8) == 0) {
|
||||||
|
scheme_offset = 8;
|
||||||
|
port = 443;
|
||||||
|
} else {
|
||||||
|
scheme_offset = 0;
|
||||||
|
port = 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
url->url.data += scheme_offset;
|
||||||
|
url->url.len -= scheme_offset;
|
||||||
|
url->default_port = port;
|
||||||
|
// See: http://lxr.evanmiller.org/http/source/core/ngx_inet.c#L875
|
||||||
|
url->no_resolve = 0;
|
||||||
|
url->uri_part = 1;
|
||||||
|
|
||||||
|
if (ngx_parse_url(pool, url) == NGX_OK) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// If there are still active requests, cancel them.
|
// If there are still active requests, cancel them.
|
||||||
void NgxUrlAsyncFetcher::CancelActiveFetches() {
|
void NgxUrlAsyncFetcher::CancelActiveFetches() {
|
||||||
// TODO(oschaaf): this seems tricky, this may end up calling
|
// TODO(oschaaf): this seems tricky, this may end up calling
|
||||||
@@ -167,15 +199,15 @@ namespace net_instaweb {
|
|||||||
command_connection_->read->handler = CommandHandler;
|
command_connection_->read->handler = CommandHandler;
|
||||||
ngx_add_event(command_connection_->read, NGX_READ_EVENT, 0);
|
ngx_add_event(command_connection_->read, NGX_READ_EVENT, 0);
|
||||||
|
|
||||||
if (url_.url.len == 0) {
|
if (proxy_.url.len == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(oschaaf): shouldn't we do this earlier? Do we need to clean
|
// TODO(oschaaf): shouldn't we do this earlier? Do we need to clean
|
||||||
// up when parsing the url failed?
|
// up when parsing the url failed?
|
||||||
if (ngx_parse_url(pool_, &url_) != NGX_OK) {
|
if (!ParseUrl(&proxy_, pool_)) {
|
||||||
ngx_log_error(NGX_LOG_ERR, log_, 0,
|
ngx_log_error(NGX_LOG_ERR, log_, 0,
|
||||||
"NgxUrlAsyncFetcher::Init parse proxy[%V] failed", &url_.url);
|
"NgxUrlAsyncFetcher::Init parse proxy[%V] failed", &proxy_.url);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -191,9 +223,9 @@ namespace net_instaweb {
|
|||||||
void NgxUrlAsyncFetcher::Fetch(const GoogleString& url,
|
void NgxUrlAsyncFetcher::Fetch(const GoogleString& url,
|
||||||
MessageHandler* message_handler,
|
MessageHandler* message_handler,
|
||||||
AsyncFetch* async_fetch) {
|
AsyncFetch* async_fetch) {
|
||||||
async_fetch = EnableInflation(async_fetch, NULL);
|
async_fetch = EnableInflation(async_fetch);
|
||||||
NgxFetch* fetch = new NgxFetch(url, async_fetch,
|
NgxFetch* fetch = new NgxFetch(url, async_fetch,
|
||||||
message_handler, fetch_timeout_, log_);
|
message_handler, log_);
|
||||||
ScopedMutex lock(mutex_);
|
ScopedMutex lock(mutex_);
|
||||||
pending_fetches_.Add(fetch);
|
pending_fetches_.Add(fetch);
|
||||||
SendCmd('F');
|
SendCmd('F');
|
||||||
@@ -219,7 +251,7 @@ namespace net_instaweb {
|
|||||||
|
|
||||||
// This is the read event which is called in the main thread.
|
// 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.
|
// 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;
|
char command;
|
||||||
int rc;
|
int rc;
|
||||||
ngx_connection_t* c = static_cast<ngx_connection_t*>(cmdev->data);
|
ngx_connection_t* c = static_cast<ngx_connection_t*>(cmdev->data);
|
||||||
|
|||||||
@@ -53,12 +53,13 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
|
|||||||
NgxUrlAsyncFetcher(
|
NgxUrlAsyncFetcher(
|
||||||
const char* proxy, ngx_log_t* log, ngx_msec_t resolver_timeout,
|
const char* proxy, ngx_log_t* log, ngx_msec_t resolver_timeout,
|
||||||
ngx_msec_t fetch_timeout, ngx_resolver_t* resolver,
|
ngx_msec_t fetch_timeout, ngx_resolver_t* resolver,
|
||||||
ThreadSystem* thread_system, MessageHandler* handler);
|
int max_keepalive_requests, ThreadSystem* thread_system,
|
||||||
|
MessageHandler* handler);
|
||||||
|
|
||||||
~NgxUrlAsyncFetcher();
|
~NgxUrlAsyncFetcher();
|
||||||
|
|
||||||
// It should be called in the module init_process callback function. Do some
|
// 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();
|
bool Init();
|
||||||
|
|
||||||
// shutdown all the fetches.
|
// shutdown all the fetches.
|
||||||
@@ -115,13 +116,14 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static void TimeoutHandler(ngx_event_t* tev);
|
static void TimeoutHandler(ngx_event_t* tev);
|
||||||
|
static bool ParseUrl(ngx_url_t* url, ngx_pool_t* pool);
|
||||||
friend class NgxFetch;
|
friend class NgxFetch;
|
||||||
|
|
||||||
NgxFetchPool active_fetches_;
|
NgxFetchPool active_fetches_;
|
||||||
// Add the pending task to this list
|
// Add the pending task to this list
|
||||||
NgxFetchPool pending_fetches_;
|
NgxFetchPool pending_fetches_;
|
||||||
NgxFetchPool completed_fetches_;
|
NgxFetchPool completed_fetches_;
|
||||||
ngx_url_t url_;
|
ngx_url_t proxy_;
|
||||||
|
|
||||||
int fetchers_count_;
|
int fetchers_count_;
|
||||||
bool shutdown_;
|
bool shutdown_;
|
||||||
@@ -138,6 +140,7 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
|
|||||||
ngx_connection_t* command_connection_; // the command pipe
|
ngx_connection_t* command_connection_; // the command pipe
|
||||||
int pipe_fd_; // the write pipe end
|
int pipe_fd_; // the write pipe end
|
||||||
ngx_resolver_t* resolver_;
|
ngx_resolver_t* resolver_;
|
||||||
|
int max_keepalive_requests_;
|
||||||
ngx_msec_t resolver_timeout_;
|
ngx_msec_t resolver_timeout_;
|
||||||
ngx_msec_t fetch_timeout_;
|
ngx_msec_t fetch_timeout_;
|
||||||
|
|
||||||
|
|||||||
Executable → Regular
+1115
-381
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -73,6 +73,9 @@ function run_test_checking_failure() {
|
|||||||
3)
|
3)
|
||||||
return # Only expected failures.
|
return # Only expected failures.
|
||||||
;;
|
;;
|
||||||
|
4)
|
||||||
|
return # Return passing error code when running manually.
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
exit 1 # Real failure.
|
exit 1 # Real failure.
|
||||||
esac
|
esac
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
# Copyright 2013 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: oschaaf@we-amp.com (Otto van der Schaaf)
|
||||||
|
|
||||||
|
|
||||||
|
# The first few suppressions can be found in other modules
|
||||||
|
# and easily found when searched for, and seem false positives.
|
||||||
|
{
|
||||||
|
<nginx false positive>
|
||||||
|
Memcheck:Param
|
||||||
|
socketcall.sendmsg(msg.msg_iov[i])
|
||||||
|
fun:__sendmsg_nocancel
|
||||||
|
fun:ngx_write_channel
|
||||||
|
fun:ngx_signal_worker_processes
|
||||||
|
fun:ngx_master_process_cycle
|
||||||
|
fun:main
|
||||||
|
}
|
||||||
|
{
|
||||||
|
<nginx false positive>
|
||||||
|
Memcheck:Param
|
||||||
|
socketcall.sendmsg(msg.msg_iov[i])
|
||||||
|
fun:__sendmsg_nocancel
|
||||||
|
fun:ngx_write_channel
|
||||||
|
fun:ngx_master_process_cycle
|
||||||
|
fun:main
|
||||||
|
}
|
||||||
|
{
|
||||||
|
<nginx false positive>
|
||||||
|
Memcheck:Param
|
||||||
|
socketcall.sendmsg(msg.msg_iov[i])
|
||||||
|
fun:__sendmsg_nocancel
|
||||||
|
fun:ngx_write_channel
|
||||||
|
fun:ngx_pass_open_channel
|
||||||
|
fun:ngx_start_cache_manager_processes
|
||||||
|
fun:ngx_master_process_cycle
|
||||||
|
fun:main
|
||||||
|
}
|
||||||
|
{
|
||||||
|
<nginx false positive>
|
||||||
|
Memcheck:Param
|
||||||
|
socketcall.sendmsg(msg.msg_iov[i])
|
||||||
|
fun:__sendmsg_nocancel
|
||||||
|
fun:ngx_write_channel
|
||||||
|
fun:ngx_pass_open_channel
|
||||||
|
fun:ngx_start_cache_manager_processes
|
||||||
|
fun:ngx_master_process_cycle
|
||||||
|
fun:main
|
||||||
|
}
|
||||||
|
{
|
||||||
|
<nginx false positive>
|
||||||
|
Memcheck:Leak
|
||||||
|
fun:malloc
|
||||||
|
fun:ngx_alloc
|
||||||
|
fun:ngx_event_process_init
|
||||||
|
fun:ngx_worker_process_init
|
||||||
|
fun:ngx_worker_process_cycle
|
||||||
|
fun:ngx_spawn_process
|
||||||
|
fun:ngx_start_worker_processes
|
||||||
|
fun:ngx_master_process_cycle
|
||||||
|
fun:main
|
||||||
|
}
|
||||||
|
{
|
||||||
|
<nginx false positive>
|
||||||
|
Memcheck:Param
|
||||||
|
socketcall.sendmsg(msg.msg_iov[i])
|
||||||
|
fun:__sendmsg_nocancel
|
||||||
|
fun:ngx_write_channel
|
||||||
|
fun:ngx_pass_open_channel
|
||||||
|
fun:ngx_start_worker_processes
|
||||||
|
fun:ngx_master_process_cycle
|
||||||
|
fun:main
|
||||||
|
}
|
||||||
|
|
||||||
|
# similar to http://trac.nginx.org/nginx/ticket/369
|
||||||
|
{
|
||||||
|
<nginx false positive>
|
||||||
|
Memcheck:Param
|
||||||
|
pwrite64(buf)
|
||||||
|
obj:/lib/x86_64-linux-gnu/libpthread-2.15.so
|
||||||
|
fun:ngx_write_file
|
||||||
|
fun:ngx_write_chain_to_file
|
||||||
|
fun:ngx_write_chain_to_temp_file
|
||||||
|
fun:ngx_event_pipe_write_chain_to_temp_file
|
||||||
|
fun:ngx_event_pipe
|
||||||
|
fun:ngx_http_upstream_process_upstream
|
||||||
|
fun:ngx_http_upstream_process_header
|
||||||
|
fun:ngx_http_upstream_handler
|
||||||
|
fun:ngx_epoll_process_events
|
||||||
|
fun:ngx_process_events_and_timers
|
||||||
|
fun:ngx_worker_process_cycle
|
||||||
|
}
|
||||||
|
# Mentioned in https://github.com/pagespeed/ngx_pagespeed/issues/103
|
||||||
|
# Assuming a false postives as the issue is closed.
|
||||||
|
{
|
||||||
|
<nginx false positive>
|
||||||
|
Memcheck:Param
|
||||||
|
write(buf)
|
||||||
|
obj:/lib/x86_64-linux-gnu/libpthread-2.15.so
|
||||||
|
fun:ngx_log_error_core
|
||||||
|
fun:ngx_http_parse_complex_uri
|
||||||
|
fun:ngx_http_process_request_uri
|
||||||
|
fun:ngx_http_process_request_line
|
||||||
|
fun:ngx_http_wait_request_handler
|
||||||
|
fun:ngx_epoll_process_events
|
||||||
|
fun:ngx_process_events_and_timers
|
||||||
|
fun:ngx_worker_process_cycle
|
||||||
|
fun:ngx_spawn_process
|
||||||
|
fun:ngx_start_worker_processes
|
||||||
|
fun:ngx_master_process_cycle
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extra suppresions for testing in release mode:
|
||||||
|
|
||||||
|
{
|
||||||
|
<re2 uninitialised value in optimized code>
|
||||||
|
Memcheck:Cond
|
||||||
|
fun:_ZN3re24Prog8OptimizeEv
|
||||||
|
...
|
||||||
|
}
|
||||||
|
{
|
||||||
|
<re2 uninitialised value in optimized code>
|
||||||
|
Memcheck:Value8
|
||||||
|
fun:_ZN3re24Prog8OptimizeEv
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
<re2 uninitialised value in optimized code>
|
||||||
|
Memcheck:Cond
|
||||||
|
fun:_ZN3re2L4AddQEPNS_9SparseSetEi
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
<re2 uninitialised value in optimized code>
|
||||||
|
Memcheck:Value8
|
||||||
|
fun:_ZN3re2L4AddQEPNS_9SparseSetEi
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
<re2 uninitialized value in optimized code>
|
||||||
|
Memcheck:Value8
|
||||||
|
fun:_ZN3re23DFA10AddToQueueEPNS0_5WorkqEij
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
<re2 uninitialized value in optimized code>
|
||||||
|
Memcheck:Cond
|
||||||
|
fun:_ZN3re23DFA10AddToQueueEPNS0_5WorkqEij
|
||||||
|
...
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user