Compare commits

...

485 Commits

Author SHA1 Message Date
Otto van der Schaaf 16032274b0 save state 2017-05-30 10:44:09 +02:00
Otto van der Schaaf 5631800479 Don't respond with an entitybody to HEAD requests for html (#1376)
Mind r->header_only when processing the response body.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1375
2017-02-07 12:02:43 +01:00
Jeff Kaufman a7d1f91dc3 standby: add standby mode (#1365)
* standby: add standby mode

Add standby mode for ngx_pagespeed, equivalent to "off" in mod_pagespeed.

With this change "off" is deprecated, and people should use "unplugged" instead.

* Update mps to include test file

* update mps

* update mps

* update mps
2017-01-25 13:24:15 -05:00
Jeff Kaufman 61b949c5e5 devel: simplify ngx_pagespeed development flow (#1363)
* provide scripts/rebuild.sh so you don't have to run make commands in
  two directories
* make test/run_tests.sh able to run with no arguments by setting good defaults.
2017-01-20 09:29:34 -05:00
Jeff Kaufman 5b307745ce fix TEST_TO_RUN in ngx_pagespeed (#1364)
Eventually we'll convert remote_config_system_test.sh and nginx_system_test.sh
to use run_test, but until then when TEST_TO_RUN is specified we should skip
the tests in those files and just run system/system_test.sh
2017-01-20 09:28:54 -05:00
Jeff Kaufman f78058b6c4 Allow use of "unplugged" without crashing (#1362)
* update mps

* stop crashing when unplugged

* formatting fixes
2017-01-19 13:48:01 -05:00
Jeff Kaufman 8a0b080229 install: add --additional-nginx-configure-arguments option (#1344)
Instead of requiring people to answer a prompt to specify which additional
arguments they would like nginx to be built with, allow people to specify
arguments like this on the command line.  The quoting is not ideal, since
it's important to pass spaces etc properly all the way through to the
underlying commands, but I give an example in the help text.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1340
2017-01-03 07:07:50 -05:00
Jeff Kaufman cb56136fe1 travis: send emails to new pagespeed-ci group instead of individual devs (#1341) 2016-12-19 13:45:56 -05:00
Jeff Kaufman a4ac43e4d4 travis: get it building and passing tests (#1339)
* travis: get it building and passing tests

I initially planned to get this working on Ubuntu 12, but decided it wasn't
worth it and switched to Ubuntu 14 (Trusty).  Now it passes tests on Travis, so
I've added other people's emails back to the set of people to send emails to.

Also update mps while we're at it.

* update mps

* update mps

* ngx_pagespeed depends on luuid

* update mps
2016-12-19 13:21:33 -05:00
Jeff Kaufman 80c4b7e97b config: use Release binaries when building with --with-debug if that's all that's available (#1332)
* config: use Release binaries when building with --with-debug if that's all that's available

* prompt the user before going ahead and using release binaries

* exit 1, reword message
2016-12-14 10:13:45 -05:00
Jeff Kaufman 0c7d64221c licensing: correct bash license comments (#1336)
A few bash files were missing license comments
2016-12-12 13:40:41 -05:00
Jeff Kaufman 68185b8605 installer: allow --dynamic-module to be used with tags (#1334)
* installer: allow --dynamic-module to be used with tags

A user-friendly check with dynamic module building tries to warn people early if the version of ngx_pagespeed they're building is too old to be compiled as a dynamic module, but this can't work with tags.  If we're given something other than a numeric version number, don't try to perform this check.

Fixes https://github.com/pagespeed/mod_pagespeed/issues/1443
2016-12-08 15:14:12 -05:00
hillsp 7f225e2e70 Add format_binary_url.sh (#1331) 2016-12-06 13:16:29 -05:00
Jeff Kaufman 4d728fc081 branch-names: now that trunk-tracking is master, update references (#1330) 2016-12-06 12:01:50 -05:00
hillsp a399e04a00 Delete prepare_psol.sh (#1310)
Replaced with install/build_psol.sh  in mod_pagespeed.
2016-12-06 11:43:13 -05:00
Jeff Kaufman 247a821564 install: add support for building psol from source and setting up for development (#1313)
* adds support for `--psol-from-source` so you don't need binary modules, and `--devel` so you can run our tests without going and getting all our dependencies
* adds submodules for testing: mod_pagespeed, ngx_cache_purge etc
* adds support for running as:
```
git clone git@github.com:pagespeed/ngx_pagespeed.git
cd ngx_pagespeed/
git checkout <branch>
scripts/build_ngx_pagespeed.sh [options]
```
* depends on the scripts @hillsp is working on so that we can just check out mod_pagespeed and ask it to build and rebuild itself
* adds colors to output to make it easier to read
2016-12-06 09:21:42 -05:00
hillsp f7502b1b40 Mark CentralControllerPort as Experimental (#1326) 2016-11-30 14:43:55 -05:00
Joshua Marantz 617f0e6bee Add a new server-name to help test a repro for broken pagespeed resources (#1324)
after ipro-recorded optimations.

for https://github.com/pagespeed/mod_pagespeed/issues/1145
and https://github.com/pagespeed/ngx_pagespeed/issues/1319 .
2016-11-21 14:11:56 -05:00
hillsp 42115f54da Need clone --recursive 2016-11-21 10:49:59 -05:00
hillsp 3d9f2aee37 First pass at modernising travis.yml 2016-11-21 10:38:05 -05:00
Joshua Marantz d77c7eac17 test config for disabling rewriters in ajax (#1320) 2016-11-14 08:09:44 -05:00
Jeff Kaufman 97134d951e test: run_tests.sh should just assume 8050 and 8051 (#1315)
Right now run_tests.sh assumes it has 8053 and 9991 without causing any
problems.  Start assuming we have 8050 and 8051 as well instead of
requiring people to pass them in.
2016-11-03 14:58:05 -04:00
Jeff Kaufman 17e4162334 remote-config: renaming paths to be more informative (#1312) 2016-11-03 07:03:31 -04:00
Jeff Kaufman d70dcbc4d0 remote-config: use one port for testing, against a new python server (#1293)
* remote-config: use one port for testing, against a new python-based server

* properly reference remote configu urls
2016-11-01 12:29:25 -05:00
Sen Jiang 62c66e2c9c Fix non-zero exit code even if the script succeed (#1302)
The script succeeded but the exit code is 1 because it's not a dryrun so the last command failed.
2016-10-25 09:35:01 -05:00
Jeff Kaufman 09478cac70 installer: reference the --no-deps-check option properly (#1305) 2016-10-24 12:00:27 -05:00
hillsp 14b4723326 Fix sparsehash path (#1300) 2016-10-20 13:55:21 -04:00
Maks Orlovich ad41e72a83 Our config tests need to be compiled with --std=c++11 now (#1295) 2016-10-13 14:50:41 -04:00
Jeff Kaufman 7a54f88ae8 config: give full path to autoconf.err if 'checking for psol' fails. (#1294) 2016-10-13 10:42:24 -04:00
Jeff Kaufman e7be591e91 testing: check_flushing needs to know the host name (#1292) 2016-10-12 18:02:56 -04:00
Jeff Kaufman 711b6a4954 install: fix quoting (#1291)
We want to parse $additional_configure_args into an array the way the
shell would, which we're using eval for.  But because we were missing
quotes whitespace was being stripped.  Basically:

    $ function lines() { for x in "$@"; do echo "$x"; done; }

    $ lines a "b   c" d
    a
    b   c
    d

    $ a='a "b   c" d'
    $ eval e=($a)
    $ eval f=("$a")

    $ lines "${e[@]}"
    a
    b c
    d

    $ lines "${f[@]}"
    a
    b   c
    d

We were doing this like e when we should have been doing it like f.
2016-10-12 12:22:37 -04:00
hillsp 916ff52307 Fix travis.yaml for new DEPS file 2016-10-07 21:44:32 -04:00
Jeff Kaufman cd004c6d0c tests: check flushing changed its arguments (#1288) 2016-10-07 15:51:24 -04:00
Jeff Kaufman 0fd456fa57 build_ngx_pagespeed: handle quoted arguments (#1286)
* build_ngx_pagespeed: handle quoted arguments

If you enter --with-cc-opt='-arg1 -arg2' when the script asks for
additional arguments we want that to remain as one chunk all the way
through to being a single argument to ./configure
2016-10-05 08:26:04 -04:00
Jeff Kaufman 3b226aab7e install: default to latest-beta (#1283)
* install: default to latest-beta

* latest stable instead
2016-10-03 15:16:24 -04:00
hillsp 90627b1fbd Add controller tests for nginx (#1280) 2016-09-26 13:55:22 -04:00
Jeff Kaufman 6cb4b8dde3 We need -lstdc++ to come after psol.a (#1273) (#1274) 2016-09-24 16:04:52 -04:00
Jeff Kaufman d2af4962e6 load-from-file: config for testing load from file with a low size limit (#1268)
nginx side of the fix for https://github.com/pagespeed/mod_pagespeed/issues/1386
2016-09-23 18:20:26 -04:00
Jeff Kaufman b997d79ea7 install: add script to install nginx_pagespeed (#1263)
install: add script to install nginx_pagespeed

Automated version of the instructions on https://developers.google.com/speed/pagespeed/module/build_ngx_pagespeed_from_source

Tested on fresh vms of debian8, centos 6 and 7, rhel 6 and 7, and ubuntu lts 12, 14, and 16

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1262
2016-09-21 07:48:03 -04:00
Joshua Marantz 0baa230bd7 Add default setting for whether to test with a controller port. (#1278)
* Add default setting for whether to test with a controller port.

* Use RUN_CONTROLLER_TEST, which will actually be defaulted in
system/system_test.sh.  Comment out the controller port configuration
in the default nginx template.

* Finish up the conditionalization of the babysitter tests.

* Run the reload tests even with the controller off.

* clean up the diffs a little.
2016-09-20 15:42:47 -04:00
Joshua Marantz 1118910228 the remote config test is in a separate script now, so run it from the master test script (#1260) 2016-09-19 19:25:24 -04:00
hillsp 7584be2668 Work-around broken GCE Ubuntu repo 2016-09-15 16:23:11 -04:00
hillsp c8f8aff23f Add GLOBAL_STATISTICS_URL variable (#1270) 2016-09-12 13:52:06 -04:00
Otto van der Schaaf 76eeec5972 special-responses: fix for hanging sometimes on special responses (#1238)
After calling ngx_http_filter_finalize_request return NGX_DONE
as we are still in pre-access phase. This bug shows up when the
"special" response is generated from, for example, php as opposed
to a static file.

Second part of the fix for
https://github.com/pagespeed/ngx_pagespeed/issues/1146
2016-09-07 10:49:53 +02:00
hillsp 2d24ec68f1 Additional suppressions for new RE2 (#1266) 2016-09-06 10:07:40 -04:00
Maks Orlovich 269ed10ed5 Also look for headers in /url in mod_pagespeed tree (#1264)
This is needed because the current GURL implementation there --- and hence
google_url.h needs an extra compat header that's there.
2016-09-02 15:11:50 -04:00
Jeff Kaufman 94dde75a86 combine-ids: add configuration for system test (#1259) 2016-09-01 15:04:03 -04:00
Joshua Marantz 9b47332d9c allow sloppy exit (#1258)
* set up a test subdir with cc:public

* allow 'adding function to sequence' warnings on shutdown, without breaking the nginx debug tests
2016-08-29 17:06:26 -04:00
Egor Suvorov 4b7a7cc15e Make NgxMessageHandler::FileMessage() add data into internal buffer as well (#1255) 2016-08-25 15:10:46 -04:00
Jeff Kaufman f8f32efb97 Test shm checkpointing. Relies on shm checkpointing implementation in mod_pagespeed. (#930) 2016-08-23 07:46:20 -04:00
Otto van der Schaaf 3015cf0372 Allow processing of script variablies in more options (#1239)
All directory- and process- scoped options are allowed with this
change, when "ProcessScriptVariables all" is specified.

Option list compiled from:
https://docs.google.com/spreadsheets/d/1qJSUZqd2Te-4SDtm1Av6u-AckNv_oHEp1qdaUjNqZoM/edit#gid=0
2016-08-10 21:04:47 +02:00
Jeffrey Crowell 8644e5d83d Update .travis.yml 2016-08-09 17:45:19 -04:00
Jeff Kaufman 7fd0f3ee2f rewrite-options: don't turn on CoreFilters just because of query params (#1228)
Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1190
2016-08-04 10:44:46 -07:00
Jeffrey Crowell a919a926f4 nginx side of https://github.com/pagespeed/mod_pagespeed/issues/1371 (#1235)
nginx side of the change
https://github.com/pagespeed/mod_pagespeed/issues/1371
2016-08-03 13:09:22 -05:00
Jeff Kaufman ed5a43ef72 rewrite-domains: add test configuration for rewriting static assets (#1223)
Needed for fixing https://github.com/pagespeed/mod_pagespeed/issues/1350
2016-08-02 11:46:20 -07:00
Jeff Kaufman ee27b5bd7a json: add content-type and cache-control for example json file (#1224) 2016-07-18 11:15:31 -04:00
Otto van der Schaaf 572f59299e Check options->IsAllowed() before rewriting html. (#1225)
Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1226
2016-07-15 20:41:19 +02:00
Otto van der Schaaf ebe7c61f4f Make ngx_pagespeed behave like mod_pagespeed with regard to Flushing (#1217)
This change makes ngx_pagespeed listen to the FollowFlushes option.
When set to on (=default), ngx_pagespeed will forward incoming flushes
to ProxyFetch. When writing output, we'll now also set the flush flag on
the buffers we are about to send downstream.

Companion to mps commit: https://github.com/pagespeed/mod_pagespeed/commit/02de03e825bbd1f8d4ad4e1a1bef5263a16f3857
2016-07-12 12:26:38 -04:00
Otto van der Schaaf e542347a20 Fix for when there is only server-level configuration (#1218)
When there is no top-level configuration but only server configuration,
we don't have main options to set and consider. This prevents
a NULL dereference in that case. (Later on we'll writes out a message
about why we cannot startup with this configuration).
2016-07-06 16:13:05 +02:00
Otto van der Schaaf b1d9fbf544 Fix segfault when there's no http{} block in nginx.conf (#1221)
Should fix https://github.com/pagespeed/ngx_pagespeed/issues/1220
2016-07-06 16:12:04 +02:00
Jeff Kaufman 44626a4121 url-valued-attributes: tests for mod_pagespeed/f2f0075 2016-06-24 16:54:23 -04:00
Joshua Marantz 271b0c1f15 set up a test subdir with cc:public (#1215) 2016-06-16 09:54:06 -04:00
hillsp 1bb10ec599 Suppress controller warnings in test, fix up kill signals (#1210)
* Suppress controller warnings in test, fix up kill signals

* Switch valgrind shutdown to QUIT
2016-06-10 14:54:49 -04:00
Jeffrey Crowell c4fc99c5ae README.md: fix link in travis badge 2016-06-08 13:06:25 -04:00
Jeffrey Crowell 4c09bac0c4 svn of depot_tools is going away, migrate to git. (#1211)
for some reason we were still using the svn for travis here, but git for everything else...
2016-06-08 13:05:22 -04:00
Maks Orlovich 03d69e53b1 Update for API change: kProcessScope is about to become kLegacyProcessScope (#1205)
The renaming is to make it clear that kProcessScopeStrict (aka what
ngx_pagespeed does for everything already) is what new code should be
using, rather than current kProcessScope/upcoming kLegacyProcessScope
which does weird backwards compatible things in mod_pagespeed.
2016-05-30 12:52:41 -04:00
Maks Orlovich 15c6f7c345 Make sure RewriteDriverFactory::default_options gets the top-level proces-scope options. (#1203)
Needed for ImageMaxRewritesAtOnce to work with latest revisions.
2016-05-20 10:07:24 -04:00
Joshua Marantz d7f48d88c6 Pass the install-path into Makefile (#1200)
* Pass the install-path into Makefile, rather than having the Makefile
depend on PWD.

* Move the double-quotes be before the value, to be consistent with other
Makefiles.
2016-05-16 13:32:28 -04:00
Steve Hill fd26b873e9 Remove stray -q on pgrep. 2016-05-13 17:47:09 -04:00
hillsp d6c395151f Fix nginx_system_test so that it doesn't wait for verify_nginx_release.sh (#1199)
or wait indefinitely if it can't kill nginx.
2016-05-13 16:06:38 -04:00
Joshua Marantz dab6b8ac04 During system-tests, don't write into the source-controlled htdocs area. (#1197)
Instead, use a new (not-yet-committed) target in Makefile.tests to build
a mirror htdocs in test/tmp/root that sym-links the large readonly
section and deep copies the test areas for purge and flush tests.
2016-05-13 08:44:14 -04:00
hillsp 77cd95b552 Fix IPRO and missing Content-Length headers in 32-bit builds. (#1196) 2016-05-11 13:34:00 -04:00
Joshua Marantz be7837507f respect purge requests when serving ipro requests from ngx_pagespeed (#1193)
* respect purge requests when serving ipro requests from ngx_pagespeed

* Add TODO to share common base with ApacheFetch.
2016-05-11 11:08:04 -04:00
Jeffrey Crowell 7094df4c11 add build status indicator for trunk-tracking (#1195) 2016-05-11 07:56:34 -07:00
Nikolay Kolev 76bc257af6 Removed the redundant bracket. (#1189) 2016-05-05 14:44:59 -04:00
Jeffrey Crowell 3208d56aa4 add travis to trunk-tracking branch (#1186)
* add travis to trunk-tracking branch
2016-05-02 16:14:16 -04:00
hillsp 090ec03a68 System test updates for CentralControllerPort. (#1182) 2016-04-28 15:45:29 -04:00
Maks Orlovich e885e02a3c Fix build with recent nginx which lacks NGX_CONF_MULTI (#1185) 2016-04-26 15:37:26 -04:00
Jeffrey Crowell 6f5042020b fix up the description in the run_tests.sh (#1176)
run_tests had the wrong invocation of the script in the comments. fix
that.
2016-04-11 16:52:02 -04:00
Jeff Kaufman f3063e2daa Companion to mps change to set s-maxage on unoptimized ipro resources (#1171) 2016-04-07 16:02:02 -04:00
Otto van der Schaaf 56ee9ff24e Fix for async waits vs client aborts and HTTP/2 RST_FRAMES
This change makes nginx close the request when we receive a close

event or RST_STREAM while waiting for an async PSOL op to complete

by setting a read event handler, as inspired by the limit request

module from nginx.



Should fix https://github.com/pagespeed/ngx_pagespeed/issues/1146
2016-04-07 10:35:19 -04:00
hillsp b290a4c8a3 Merge pull request #1170 from pagespeed/cheesy_115698600
Add grpc headers to search path.
2016-04-04 17:54:12 -04:00
Jeff Kaufman 297b4ab34b handle additional warnings 2016-03-29 10:07:09 -04:00
Joshua Marantz b975ae59df Merge pull request #1164 from pagespeed/jmarantz-remove-cache-html
remove a no-longer-needed arg to ProxyFetchFactory::InitiatePropertyC…
2016-03-28 13:51:33 -04:00
Joshua Marantz c0e917801d remove a no-longer-needed arg to ProxyFetchFactory::InitiatePropertyCacheLookup 2016-03-28 13:42:28 -04:00
Maks Orlovich a3bc2cae03 Merge pull request #1157 from pagespeed/morlovich-cpp11-on
Turn on C++11 for all compilers, not just clang.
2016-03-17 10:02:40 -04:00
Maks Orlovich 7fe4e09076 Turn on C++11 for all compilers, not just clang.
Explain why we do it via config.make better.
Remove partial workaround for config.make not invoked for dynamic modules,
nginx dev fixes the root issue, and the workaround is insufficient anyway.
2016-03-16 15:42:42 -04:00
Jeff Kaufman ee20289863 Merge pull request #1156 from pagespeed/jefftk-psauxww
controller: don't fail tests when running in emacs
2016-03-15 17:05:10 -04:00
Jeff Kaufman c3f2858e31 controller: don't fail tests when running in emacs
Apparently, when running in emacs and piped into another command, ps limits
it's output to COLUMNS making check_process_names fail.  Telling ps to use
wide, wide output with 'ww' fixes this.

Additionally, use check_from so that if this test does fail we can debug
it better, seeing what grep was looking at.
2016-03-15 16:36:52 -04:00
Otto van der Schaaf 59005bec88 Merge pull request #1150 from pagespeed/oschaaf-trunk-tracking-issue-1148
NgxFetch: Log url and error when url parsing fails.
2016-03-11 14:53:00 +01:00
Otto van der Schaaf 6634754dba NgxFetch: Log url and error when url parsing fails.
Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1148
2016-03-11 14:34:24 +01:00
Jeff Kaufman a9142f0003 Merge pull request #1105 from pagespeed/oschaaf-trunk-tracking-issue-1064
vary-header: Emit a single vary header in the IPRO flow
2016-03-08 06:21:46 -08:00
Jeff Kaufman 8efb831ba4 Support centralized process changes in github.com/pagespeed/mod_pagespeed/commit/9bf7523 2016-03-07 16:14:43 -05:00
huibaolin fcbe51efaf Merge pull request #1145 from pagespeed/huibao-webp
Add system tests for image format, quality, and response in IPRO
2016-03-07 11:41:53 -05:00
Kees Spoelstra 08e284f9cb Strip subresource hints pagespeed automatic system test configuration
Corresponding changes for:
- pull https://github.com/pagespeed/mod_pagespeed/pull/1204
- issue Strip subresource hints #973 https://github.com/pagespeed/mod_pagespeed/issues/973
2016-03-07 10:50:59 -05:00
Huibao Lin 8582bab69c Add system tests for image format, quality, and response in IPRO 2016-03-07 09:58:44 -05:00
Jeff Kaufman 5264647a65 Merge pull request #1139 from pagespeed/oschaaf-trunk-tracking-issue-1138
IPRO: Copy the cache control value to ensure a correct lifetime
2016-03-03 11:15:10 -05:00
Otto van der Schaaf 85d0db2550 IPRO: Copy the cache control value to ensure a correct lifetime
Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1138
2016-03-02 23:42:36 +01:00
hillsp 8e25b58597 Merge pull request #1130 from pagespeed/cheesy_115114559
Update protobuf path for non chromium version
2016-02-23 15:07:37 -05:00
Steve Hill 6eee387802 Update protobuf path for non chromium version 2016-02-22 17:52:55 -05:00
huibaolin 2315173946 Merge pull request #1125 from pagespeed/huibao-webp
Allow varying on Accept header for ipro-for-browser.example.com
2016-02-19 15:54:52 -05:00
Huibao Lin 54bd8bf4f8 For backward compatibility, only allow varying on Accept header for ipro-for-browser.example.com 2016-02-18 11:29:27 -05:00
Jeffrey Crowell 60f91becb7 Merge pull request #1122 from pagespeed/oschaaf-trunk-tracking-issue-1120
Fix shutdown when ngx_pagespeed is completely disabled.
2016-02-17 10:29:39 -05:00
Jeffrey Crowell d959f01848 Merge pull request #1115 from pagespeed/oschaaf-trunk-tracking-dynamic-modules
Support building ngx_pagespeed as a dynamic module
2016-02-16 11:00:53 -05:00
Otto van der Schaaf f60c754d82 Fix shutdown when ngx_pagespeed is completely disabled.
Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1120
2016-02-15 10:54:53 +01:00
Otto van der Schaaf 09f53881de Support building ngx_pagespeed as a dynamic module.
As of 1.9.11, nginx supports loading dynamic modules
This change makes us support building ngx_pagespeed.so

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1116
2016-02-13 00:10:39 +01:00
Prayag Verma 929c5c5908 Fix a typo
`neet` → `need`
2016-02-11 13:18:13 -05:00
Piotr Sikora 064ced104d Fix build with nginx-1.9.11+.
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
2016-02-10 15:03:45 -05:00
Maks Orlovich a73dc7ba74 Merge pull request #1103 from pagespeed/morlovich-ua-tweak-for-fontservice
Adjust our UA string to fix to make it compatible with fonts.g.c parsing on IE11.
2016-02-08 16:18:21 -05:00
Otto van der Schaaf b081bb7aec vary-header: Emit a single vary header in the IPRO flow
The report from some time ago mentioned three Vary: headers,
but I can now only reproduce two using trunk-tracking plus the
original repro-configuration.

This fix unflags r->gzip_vary as set by the gzip module when PSOL
hands us Vary: Accept-Encoding, to make sure that nginx's core
header filter doesn't append another one.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1064
2016-01-28 03:37:01 +01:00
Maks Orlovich 0a60e0ef8b Adjust our UA string to fix to make it compatible with fonts.google.com parsing on IE11.
Counterpart of:
https://github.com/pagespeed/mod_pagespeed/commit/f3639e84c0196a5f5151ff5e54ad57285db09b37
2016-01-27 09:16:49 -05:00
Maks Orlovich 1926c78ca2 Merge pull request #1102 from pagespeed/morlovich-no-more-spdy-specific-config
Adjust to library API change: no more spdy-specific config.
2016-01-25 15:33:35 -05:00
Maks Orlovich c3598134ee Adjust to library API change: no more spdy-specific config. 2016-01-25 12:33:29 -05:00
Jeff Kaufman 43f09a877b Merge pull request #1101 from pagespeed/oschaaf-trunk-tracking-basefetch-valgrind
Fix valgrind complaint caused by NgxBaseFetch
2016-01-25 11:05:37 -05:00
Jeff Kaufman d023bb35f6 Merge pull request #1098 from pagespeed/oschaaf-trunk-tracking-rzero-crash
Eliminate CHECK that fails (rarely) during the IPRO lookup.
2016-01-22 10:12:17 -05:00
Otto van der Schaaf 60c1f4cc4e Fix valgrind complaint caused by NgxBaseFetch
We should not use r->connection after we finalize the request.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1100
2016-01-22 16:06:42 +01:00
Otto van der Schaaf b88e067c6d Eliminate CHECK that fails (rarely) during the IPRO lookup.
Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1096
2016-01-21 22:08:43 +01:00
Jeff Kaufman b214fb43e3 Merge pull request #1061 from pagespeed/oschaaf-trunk-tracking-add-resource-header
AddResourceHeader: Add test configuration
2016-01-19 13:26:01 -05:00
Joshua Marantz 9e6048f771 Merge pull request #1092 from pagespeed/jmarantz-ipro-flow-cache-not-flaky
remove 'IPRO flow uses cache as expected' from flaky-list, ...
2016-01-05 15:11:46 -05:00
Maks Orlovich 653875cb68 Merge pull request #1076 from pagespeed/morlovich-h2-bit
Store whether h2 is in use in RequestContext.
2016-01-05 12:35:51 -05:00
Joshua Marantz a512d95258 remove 'IPRO flow uses cache as expected' from flaky-list, but strip out 'Fetch timed out' from log-warning check 2016-01-05 11:46:35 -05:00
Otto van der Schaaf a4441220b1 Merge pull request #1085 from pagespeed/oschaaf-trunk-tracking-internal-redirect-crasher
Fix crasher on 404 .pagespeed. resources w/a custom location
2016-01-04 22:03:05 +01:00
Jeffrey Crowell 374ee1c750 Merge pull request #1089 from pagespeed/crowell-reapply-744
reapply:  location-header: tweak location header handling
2015-12-31 10:54:29 -05:00
Jeffrey Crowell 059dd20b10 reapply: location-header: tweak location header handling
- Fix potentially sending the location header into PSOL twice.
- Be more thorough when unsetting the location header

Attempts to fix #725

from oschaaf
2015-12-31 10:46:39 -05:00
Otto van der Schaaf 1964ef5219 Fix crasher on 404 .pagespeed. resources w/a custom location
- Fix nginx-side flow so we handle .pagespeed. resources ok
  when they will land on a customized 404 internal location.
- Additionally, check for a wiped request context and make sure
  we do not dereference a null pointer, which is what hurt in
  the flow we entered above as the IPRO lookup still was
  generating events while the nginx side request context was
  gone.
- Also, as a preliminary measure, do not check fail when we
  receive a stale event originating from a NgxBaseFetch that
  is no longer associated with our request context.
  Do log a warning so we'll hear about this happening either
  through system test failures or a bug report.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1081
2015-12-28 15:59:13 +01:00
Jeff Kaufman 56a5d41ec3 Restore dropped fix for #957
@rfnx fixed #957 in acb89a, but this was accidentally merged to master
instead of trunk-tracking.  I checked for this sort of problem as part
of the 1.10 release, but missed this commit.  Restored.

Fixes #1054
2015-12-18 15:01:15 -05:00
Jeff Kaufman 7ee1efe0dd Merge pull request #1071 from pagespeed/oschaaf-trunk-tracking-log-debug-noise
log: initialize logging earlier
2015-12-17 11:36:34 -05:00
Maks Orlovich eb2a81ee79 Store whether h2 is in use in RequestContext. 2015-12-15 09:29:02 -05:00
Otto van der Schaaf 37e1c3618a log: initialize logging earlier
It turns out to be possible to initialize logging earlier by
grabbing the log from a global ngx_cycle structure.

This makes us start logging earlier, yet loses the
"No threading detected ..." messages both from stderr and
in error.log when nginx initially starts.

With this change, these messages will now be logged as we start
logging earlier:

"
flush
.
"

These originate from SystemCachePath::CacheKey which appends
newlines to the key, and the resulting cache key ends up being
logged. We might want to change that, because the resulting
lines in error.log look weird and might raise questions.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/895
2015-12-11 12:02:21 +01:00
Jeffrey Crowell df498ea788 Merge pull request #1067 from pagespeed/crowell-fix-gcc5
add flags for new GCC on config tests
2015-12-10 15:45:47 -05:00
Jeffrey Crowell 4b4d353156 add flags for new GCC on config tests
closes #1066
2015-12-10 15:41:44 -05:00
Maks Orlovich c9d4912746 Merge pull request #1050 from pagespeed/morlovich-compiler-req
Add compiler version checks for what we want to support going forward.

Also make us actually build with clang (the log_message_handler.cc change
and config.make change)
2015-12-09 14:50:11 -05:00
Otto van der Schaaf 2b74f6bed3 AddResourceHeader: Add test configuration
nps side of https://github.com/pagespeed/mod_pagespeed/pull/1200
2015-12-09 04:35:24 +01:00
Maks Orlovich f1a6cd0ade Whitespace tweak 2015-12-07 10:01:23 -05:00
Joshua Marantz 0c01c0644e Merge pull request #1057 from pagespeed/jmarantz-2-pass-ipro
suppress errors on new 2-pass and 3-pass ipro tests
2015-12-02 16:45:48 -05:00
Joshua Marantz 14aa4fd962 suppress errors on new 2-pass and 3-pass ipro tests 2015-12-02 15:01:37 -05:00
Joshua Marantz 36a7ff9543 Merge pull request #1056 from pagespeed/jmarantz-no-error-on-slow-ReadFile
do not consider it a test failure to get a slow ReadFile operation.
2015-12-02 08:31:34 -05:00
Joshua Marantz 706577a34b do not consider it a test failure to get a slow ReadFile operation. 2015-12-02 08:27:47 -05:00
Otto van der Schaaf 6703b2d76e Merge pull request #1055 from pagespeed/oschaaf-trunk-tracking-location-header-handling
location-header: Be careful with headers_out->location
2015-12-01 18:56:53 +01:00
Otto van der Schaaf 40c05b4a4f location-header: Be careful with headers_out->location
Only set headers_out->location when the upstream originally did
as well. If the Location: header value involved starts with "/"
nginx will absolutify it, ignoring any X-Forwarded-Proto header
in the process.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/819
(Confirmed: https://github.com/pagespeed/ngx_pagespeed/issues/1029)
Hopefully fixes https://github.com/pagespeed/ngx_pagespeed/issues/711
2015-12-01 18:55:02 +01:00
Maks Orlovich bc875647f1 Add compiler version checks for what we want to support going forward,
and make us actually build with clang (the log_message_handler.cc change
and config.make change)
2015-11-25 13:44:13 -05:00
Maks Orlovich f88a0763fd Merge pull request #1048 from pagespeed/morlovich-buildflag
Pass in -D_GLIBCXX_USE_CXX11_ABI=0, so people using gcc-5.x can use our psol.a
2015-11-25 08:56:16 -05:00
Maks Orlovich 239ca9aa80 Pass in -D_GLIBCXX_USE_CXX11_ABI=0, so people using gcc-5.x can use psol.a
we built with 4.8

See issue 942
2015-11-24 15:16:06 -05:00
Jeff Kaufman 37c51d3b9e Merge pull request #1042 from pagespeed/jefftk-content-experiment
Add ContentExperiment support
2015-11-24 11:46:04 -05:00
Jeff Kaufman 2468257e2d Add ContentExperiment support 2015-11-20 16:39:02 -05:00
Jeff Kaufman 4628e1c0ea Merge pull request #1035 from pagespeed/jefftk-script-var-testing
Support script variables in ShardDomain
2015-11-19 11:01:41 -08:00
Jeff Kaufman 7f98ab448b Merge pull request #1047 from pagespeed/jefftk-ngx-brotli
Fix interaction with ngx_brotli module.
2015-11-18 11:20:17 -08:00
Piotr Sikora 103c479fbb Fix interaction with ngx_brotli module.
Reported by George Liu (eva2000) on GitHub (issue #1021).

Signed-off-by: Piotr Sikora <piotrsikora@google.com>

Conflicts:
	config
2015-11-16 18:26:30 -05:00
Jeffrey Crowell 887bd8fa98 Merge pull request #1046 from pagespeed/crowell_content_encoding
add content_encoding to headers_out
2015-11-16 11:09:04 -05:00
Jeffrey Crowell 804f234268 add remaining shortcuts to headers_out_t
this change is required for gzip cache change going into mod_pagespeed.
2015-11-16 10:56:23 -05:00
Jeff Kaufman ea82f0de19 Support script variables in ShardDomain 2015-11-02 10:08:00 -05:00
Jeff Kaufman 5f312820e5 Merge pull request #974 from pagespeed/jefftk-handler-restrictions
Add support for blocking access to our handlers.
2015-11-02 08:18:10 -05:00
Jeff Kaufman 7efac4ac4e Merge pull request #1028 from pagespeed/oschaaf-trunk-tracking-issue-1015
IPRO+MPD: Make In-Place-Resource-Optimization with MapProxyDomain work
2015-10-28 13:30:04 -04:00
Otto van der Schaaf 634b813071 IPRO+MPD: Make In-Place-Resource-Optimization with MapProxyDomain work
Fixes https://github.com/pagespeed/ngx_pagespeed/issues/1015

Pull with MPS Side for this change:
https://github.com/pagespeed/mod_pagespeed/pull/1161
2015-10-27 18:11:35 +01:00
Joshua Marantz d30972985b Merge pull request #1026 from pagespeed/jmarantz-remove-set-ua
Don't call RewriteDriver::SetUserAgent on the UA in the request-headers.
2015-10-22 15:17:15 -04:00
Joshua Marantz 3a6e833eae Don't call RewriteDriver::SetUserAgent on the UA in the request-headers.
RewriteDriver::SetRequestHeaders already pulls the UA from the request-headers.
2015-10-22 14:19:00 -04:00
Joshua Marantz 90c8ac8a12 Revert "Don't call RewriteDriver::SetUserAgent as the user-agent is already in the request-headers"
This reverts commit 6ccc1c513b.
2015-10-22 14:13:01 -04:00
Joshua Marantz 6ccc1c513b Don't call RewriteDriver::SetUserAgent as the user-agent is already in the request-headers 2015-10-22 13:20:00 -04:00
Jeff Kaufman fe47eeb4f3 Add support for blocking access to our handlers.
Nginx side of the fix for https://github.com/pagespeed/mod_pagespeed/issues/1088
2015-09-18 09:03:01 -04:00
Joshua Marantz e42f61e263 Merge pull request #1002 from pagespeed/jmarantz-log-slow-file-ops
ignore errors about slow file operations
2015-07-31 17:01:39 -04:00
Joshua Marantz 8bac32c669 ignore errors about slow file operations, which can occur when running valgrind tests 2015-07-31 16:57:20 -04:00
Jeffrey Crowell 4bef2af22c Merge pull request #995 from pagespeed/crowell-disable-sendfile
add test servers for sending x-sendfile and x-accel-redirect
2015-07-23 17:34:58 -04:00
Jeffrey Crowell 52bd966edd add test servers for sending x-sendfile and x-accel-redirect 2015-07-23 13:34:25 -04:00
Jeff Kaufman 0f7a1f4503 Merge pull request #994 from pagespeed/jefftk-allow-script-variables
config: whitelist a few more directives for script variables
2015-07-23 10:36:57 -04:00
Jeff Kaufman 7f477d6575 config: whitelist a few more directives for script variables
When configuring downstream caching if you have an origin with multiple caches in front of it you might want to choose how you handle requests in response to which cache you're getting them from.  Whitelist DownstreamCachePurgeLocationPrefix, DownstreamCachePurgeMethod, and DownstreamCacheRewrittenPercentageThreshold for scripting so this is possible.
2015-07-22 10:32:41 -04:00
Jan-Willem Maessen cc10f15f53 Fix pagespeed_libraries_generator.sh to fetch pagespeed_libraries.conf from github rather than svn. 2015-07-09 10:18:51 -04:00
Jeffrey Crowell 9ee745c2ef Revert "temporarily comment tests using modpagespeed.com"
This reverts commit 5337e4b558.

closes #984
2015-07-07 13:15:33 -04:00
Jeffrey Crowell 5337e4b558 temporarily comment tests using modpagespeed.com
revert this commit when modpagespeed.com is back up
2015-07-06 12:36:44 -04:00
jmarantz b31bf7b090 Merge pull request #967 from pagespeed/jmarantz-psoff-dir-on
nginx system test changes to repro issue https://github.com/pagespeed…
2015-05-19 11:12:14 -04:00
Joshua Marantz 8464a00a77 nginx system test changes to repro issue https://github.com/pagespeed/mod_pagespeed/issues/1077 2015-05-18 09:46:12 -04:00
Jeff Kaufman b048ceb858 Merge pull request #966 from pagespeed/jefftk-doneandsetheaders
Handle DoneAndSetHeaders() new second argument that wants to know whe…
2015-05-15 10:33:32 -04:00
Jeff Kaufman 0fbdf3ee97 Handle DoneAndSetHeaders() new second argument that wants to know whether the response is complete. 2015-05-14 15:26:10 -04:00
Jeffrey Crowell a9d85960b5 add psol tar.gz to gitignore 2015-05-13 11:57:32 -04:00
Jeffrey Crowell cd19284062 initialize uninitialized variables. 2015-04-01 15:45:22 -04:00
Jeffrey Crowell c2a756049e add support for nginx 1.7.11 --with-threads 2015-04-01 15:10:26 -04:00
Maks Orlovich 6b2999dfd4 Merge pull request #944 from pagespeed/morlovich-api-adjust-InitiatePropertyCacheLookup
Adjust to API change to InitiatePropertyCacheLookup
2015-04-01 14:08:33 -04:00
Maks Orlovich 5658c20327 Adjust to API change to InitiatePropertyCacheLookup
The last argument was not actually used, and hence was removed.
2015-03-30 17:02:58 -04:00
Jeffrey Crowell ec2dea84fe Merge pull request #943 from pagespeed/crowell-rm_unused_variable
move 'type' variable to inside an #if statement
2015-03-30 14:34:48 -04:00
Jeffrey Crowell e206e871aa move 'type' variable to inside an #if statement
removes an unused variable when compile without NGX_DEBUG, allows for
building with -Werror.
2015-03-30 14:33:33 -04:00
Jeff Kaufman f4fd9a3f7c Merge pull request #935 from pagespeed/jefftk-system-public
system/public/ was moved to system/, update our references.
2015-03-18 17:04:21 -07:00
Jeff Kaufman cf88925f1e system/public/ was moved to system/, update our references. 2015-03-13 14:38:16 -04:00
Jeff Kaufman 5ea8fb9f3e Merge pull request #934 from pagespeed/jefftk-automatic-moved
Moved `automatic/` into `pagespeed/` and got rid of the `public/` hierarchy.
2015-03-13 10:44:08 -04:00
Jeff Kaufman cd31a6b129 Move automatic/public to automatic/. 2015-03-13 09:59:52 -04:00
Jeff Kaufman 137792e88f Change references from net/instaweb/automatic to pagespeed/automatic. 2015-03-13 09:30:14 -04:00
Jeffrey Crowell 91cd587e68 Merge pull request #932 from pagespeed/crowell_rm-test-grep
rm "unexpected response" grep from system test
2015-03-05 14:42:05 -05:00
Otto van der Schaaf e9608b03b7 Merge pull request #931 from pagespeed/oschaaf-trunk-tracking-native-fetcher-more-fixes
native-fetcher: fixes
2015-03-05 20:35:21 +01:00
Jeffrey Crowell 6e1a9a73a5 rm "unexpected response" grep from system test 2015-03-05 14:02:55 -05:00
Otto van der Schaaf 3875acf392 native-fetcher: fixes
- Native fetching broke in https://github.com/pagespeed/ngx_pagespeed/pull/925
  Make changes so we can do early-stage fetches in the startup process
  to fix that.
- Properly cancel out any pending fetches upon ShutDown()
- Decline fetching after ShutDown(), decline fetching when Init()
  failed.
2015-03-05 14:43:29 +01:00
Jeffrey Crowell 4dd70b40ef Merge pull request #925 from pagespeed/crowell_rconfig
Port remote configuration option to nginx.
2015-03-04 13:26:04 -05:00
Jeffrey Crowell 88d9b5241d Merge remote-tracking branch 'origin/trunk-tracking' into crowell_rconfig 2015-02-25 16:47:48 -05:00
Otto van der Schaaf 23905f8ce9 Merge pull request #922 from pagespeed/oschaaf-trunk-tracking-native-fetcher-fixes
native-fetcher: fix a few bugs
2015-02-25 21:13:02 +01:00
Otto van der Schaaf effe857083 native-fetcher: Fix a few bugs
- Add handling for header only responses
- Fixup nginx i/o handling
- Fix issues in parser state
- Revert timeout for native fetcher dns resolve to 10 seconds
- Ignore warning that gets logged with this change in tests during
  fetching from a host that refuses connections.

Should help stabilizing (valgrind) test runs some more.
2015-02-25 21:03:01 +01:00
Jeffrey Crowell 599a3bca5c update to match apache for hostnames 2015-02-24 17:36:08 -05:00
Jeffrey Crowell c26313e7ab Port remote configuration option to nginx. 2015-02-23 11:25:17 -05:00
Otto van der Schaaf bcba22dd95 Merge pull request #919 from pagespeed/oschaaf-trunk-tracking-native-fetcher-pull-755
Call async_fetch_->Done after all usages.
2015-02-18 13:38:17 +01:00
Otto van der Schaaf 1ea7e3e568 Merge pull request #917 from pagespeed/oschaaf-trunk-tracking-native-fetcher-deflake
native-fetcher: bump dns timeout to deflake running the tests
2015-02-17 21:27:32 +01:00
Jeff Kaufman 34341251f6 Merge pull request #908 from pagespeed/oschaaf-trunk-tracking-shutdown-system-test-failure
shutdown: fix system test failure in error.log sanity check
2015-02-17 13:28:56 -05:00
Vasily Chekalkin d1f2a43a71 Call async_fetch_->Done after all usages.
AsyncFetch::Done will delete itself. Accessing
async_fetch_->extra_respond_headers() will crash nginx.
2015-02-17 12:18:30 +01:00
Otto van der Schaaf 58b1264745 native-fetcher: bump dns timeout to deflake running the tests
Nginx sometimes receives an expected response from 8.8.8.8 when
resolving host names, and the subsequent retry doesn't finish up
in 10 seconds. Bumping the timeout helps, but does not fully
explain why nginx is sometimes receiving an unexpected response.
I'll create a separate issue for investigating that.
2015-02-17 11:05:34 +01:00
Otto van der Schaaf 8b6fdf56ef shutdown: fix system test failure in error.log sanity check
- Should shut down with a clean valgrind and sane logging for the
  current test workload.
- Minor cleanup
2015-02-13 21:00:43 +01:00
Otto van der Schaaf 93d70feb3b Merge pull request #907 from pagespeed/oschaaf-trunk-tracking-test-reload
configuration-reload-test: wait for the new worker to get ready
2015-02-12 20:05:27 +01:00
Otto van der Schaaf 62c8947b2d configuration-reload-test: wait for the new worker to get ready
After sending a SIGHUP, wait for the new worker process with the
new configuration to handle further requests, or else the tests
running after that might get confused when the new worker becomes
active with fresh shared mem statistics and shared mem cache.
2015-02-12 18:08:18 +01:00
Otto van der Schaaf 22749d7222 Merge pull request #906 from pagespeed/oschaaf-trunk-tracking-module-position
module-position: optional switch to install at HTTP_AUX_FILTER_MODULES
2015-02-12 17:09:23 +01:00
Otto van der Schaaf a8141eadd3 module-position: optional switch to install at HTTP_AUX_FILTER_MODULES
This change adds a flag to optionally position the module at HTTP_AUX_FILTER_MODULES
instead of just in front of the gzip module. Doing so allows header module(s) to
fully manipulate any response headers before they are send to the user-agent.
With https://github.com/pagespeed/ngx_pagespeed/pull/880, SSI no longer hangs,
and other modules using subrequests should not do so either. SSI subrequests are
not optimized when ngx_pagespeed runs at HTTP_AUX_FILTER_MODULES, so the test for
it is added to the expected failures when the tests are run for this module position.

To build with the module respositioned:
  POSITION_AUX=true ./configure ......
The same variable can be set before running the system tests, in which case it will
perform additional header tests and add the SSI test to the expected failures.
2015-02-12 16:23:11 +01:00
Otto van der Schaaf 2d28ff38e8 Merge pull request #899 from pagespeed/oschaaf-trunk-tracking-shutdown
trunk-tracking-shutdown: improve shutdown code
2015-02-10 23:52:33 +01:00
Otto van der Schaaf d7f1c0dc48 Shutdown: improve shutdown handling
- Fix valgrind errors
- Add a test to make sure all logged output looks sane by whitelisting
  current errors/warnings.
- Stop our nginx test instances after we are done testing.
- Add tests for shutting down and reloading configuration under high
  load (depends on ab).
- Reduce the number of keepalive requests in the keepalive tests to speed
  up test runs.
- Fix exiting with open file descriptors, fix cleanup in nginx's cache
  manager/loader processes
- Attempt to finish up queued up NgxBaseFetches/requests on shutdown/reload
- Under valgrind the blocking rewrite started failing after adding a test
  for reloading configuration under high load.
  I've added it to the expected failures for valgrind, looking into this
  is up next.
- Decline in ps_resource_handler when nginx is quitting. This makes us
  more reliable on continued stress during shutdown/reload.
2015-02-10 23:13:44 +01:00
Jeffrey Crowell 737e9396f5 Merge pull request #892 from pagespeed/crowell-fix-888
Replace CHECK with return failure and log.
2015-01-30 10:28:04 -05:00
Jeffrey Crowell 81029dafa6 Replace CHECK with return failure and log.
Fixes #888 along with
https://code.google.com/p/modpagespeed/source/detail?r=4533
2015-01-30 10:23:00 -05:00
Otto van der Schaaf 001cd2dc4c Merge pull request #889 from pagespeed/oschaaf-trunk-tracking-content-handler-error-responses
content-handling-errors: fall back to nginx's default handling
2015-01-27 16:50:04 +01:00
Otto van der Schaaf 3efebb7948 content-handling-errors: fall back to nginx's default handling
This change passes on non succesful status codes for pagespeed
resources and other places where we act as a content handler to
nginx. This has two benefits:
- Instead of a blank page, the user agent receives a formatted
  and (hopefully customized and informative) response.
- Header modules are able to operate on that response, which was
  requested in https://github.com/pagespeed/ngx_pagespeed/issues/612#issuecomment-58855816
2015-01-26 22:13:15 +01:00
Otto van der Schaaf 02b67b79ad Merge pull request #885 from pagespeed/oschaaf-trunk-tracking-release-early
Release base fetch early, eliminate write_pending and fetch_done
2015-01-26 16:46:30 +01:00
Otto van der Schaaf d0858790e4 Merge pull request #884 from pagespeed/oschaaf-trunk-tracking-base-fetch
base-fetch: prevent unused constructions and prop. cache lookups
2015-01-23 20:09:45 +01:00
Otto van der Schaaf 4d945b1c59 Release base fetch early, eliminate write_pending and fetch_done
Get rid of write_pending & fetch_done flags on the request context.
Assume that having ctx->base_fetch set means we have outstanding
work and thus we are not done yet, for simplicity.
This also means we'll release the base fetch earlier which seems
like a good idea to me.
2015-01-23 15:07:14 +01:00
Otto van der Schaaf 7d965aced7 Merge pull request #880 from pagespeed/oschaaf-trunk-tracking-run-posted-requests
posted-requests: run posted requests when appropriate
2015-01-21 19:47:13 +01:00
Otto van der Schaaf a5411a1c7c base-fetch: prevent unused constructions and prop. cache lookups
- Don't construct `NgxBaseFetch` instances and call `Done(false)` later when it turns out it wasn't needed.
- Track the purpose of the base fetch instead of just wether it is an IPRO lookup or not for more informational tracing
  as well as avoiding constructing base fetches when their purpose isn't know yet.
- Don't initiate a property cache lookup when we won't need it (`ProxyFetchFactory::InitiatePropertyCacheLookup`)
- Improve IPRO handling of `NgxBaseFetch` and make it clearer. Indicate we want to supress further events when the
  base fetch was used to lookup an IPRO url, and the result was not indicative of something we can respond with to the
  browser.
- Remove unused `RequestRouting` constants
2015-01-20 02:19:47 +01:00
Otto van der Schaaf 8a1260a1d1 posted-requests: run posted requests when appropriate
Request termination code relies on posted requests being run.
One of the things this fixes is that we won't hang when configured
to run before the SSI module.

Avoids trouble when changing the module order, which helps
https://github.com/pagespeed/ngx_pagespeed/issues/612
2015-01-19 10:28:00 +01:00
Otto van der Schaaf f2e7b15d9c Merge pull request #879 from pagespeed/oschaaf-trunk-tracking-server-header
server-header: improve handling of server header
2015-01-17 20:28:34 +01:00
Otto van der Schaaf 5bc61a7092 server-header: improve handling of server header
- Fixes an issue in the html flow that would prevent overriding the
value of the 'Server' response-header.
- Add tests that ensure we emit a single and correct server header
in all flows when not overriding it.
- Add tests that ensure overriding the 'Server' response header
works. The resource and IPRO flow are added to the expected failures
as those are not working yet (and will be adressed in a follow-up).

Fixed https://github.com/pagespeed/ngx_pagespeed/issues/864 (html flow)
2015-01-17 20:27:45 +01:00
Otto van der Schaaf 03819f4e4a Merge pull request #876 from pagespeed/oschaaf-single-fd-fixed
Oschaaf single fd fixed
2015-01-16 15:53:06 +01:00
Otto van der Schaaf 7ef61d2580 base-fetch-leak: Shut down NgxEventConnection before deleting it
Shutdown will drain the pipe and process the last events which
will give nginx the opportunity to run the cleanup handlers on the
associated requests.
2015-01-10 22:45:04 +01:00
Otto van der Schaaf a73c096950 Revert "Merge pull request #872 from pagespeed/jefftk-revert-834"
This reverts commit 7bd90f7b3a, reversing
changes made to 58228564dd.
2015-01-10 22:07:21 +01:00
Jeff Kaufman 7bd90f7b3a Merge pull request #872 from pagespeed/jefftk-revert-834
Revert "NgxConnection: single event mechanism
2015-01-09 10:25:12 -05:00
Jeff Kaufman 73981ffe1a Revert "NgxConnection: single event mechanism for NgxFetch and NgxBaseFetch"
This reverts commit 5dfe42f3d3.
2015-01-08 13:02:19 -05:00
Jeff Kaufman 58228564dd Merge pull request #869 from pagespeed/jefftk-system-moved
mod_pagespeed moved the location of the system directory; update our includes
2015-01-06 09:50:11 -05:00
Jeff Kaufman 340c86a49e mod_pagespeed moved the location of the system directory; update our includes 2015-01-06 09:22:56 -05:00
Otto van der Schaaf abdafc7aa4 Merge pull request #834 from pagespeed/oschaaf-single-pipe2
NgxConnection: single event mechanism for NgxFetch and NgxBaseFetch
2014-12-30 21:52:07 +01:00
Jan-Willem Maessen 8cf10873d1 Merge pull request #863 from pagespeed/jmaessen-ngx-message-handler-fix
Make ngx_message_handler work with new message_handler api.
2014-12-19 16:13:26 -05:00
Jan-Willem Maessen 2496716e36 Make ngx_message_handler work with new message_handler api. 2014-12-19 15:11:55 -05:00
Jeff Kaufman af364344e9 Merge pull request #862 from pagespeed/jefftk-rmdir
testing: give '-p' to mkdir
2014-12-17 12:55:44 -05:00
Jeff Kaufman 9da45910c7 rm won't remove the containing directory if a file is removed out from under it, which means the directory will still be there but will be empty. This is not a problem, so pass '-p' to not fail on already existing directories. 2014-12-17 12:50:23 -05:00
Otto van der Schaaf 5dfe42f3d3 NgxConnection: single event mechanism for NgxFetch and NgxBaseFetch
Abstract the pipe communication into NgxEventConnection, for reuse
by NgxBaseFetch and NgxUrlAsyncFetcher.

Based on Chai's earlier work, but with a few fixes discovered
while working on this and SPDY module compatibility

- Uses less file descriptors, I expect this to be faster but need
  measurement is needed to back that.
- Fixed NgxUrlAsyncFetcher actually shutting down its fetchers.
- Fixes a bug where we wouldn't clean idle pooled NgxConnections.
- Fixes a bug for requests that are finalized mid-IPRO lookup.
- Makes us use ngx_handle_read_event/ngx_del_event
2014-12-14 02:29:40 +01:00
Jeff Kaufman bff15040be Merge pull request #857 from pagespeed/jefftk-upstream-check-failure-function
Upstream the change to check_failures_and_exit, moving it to mod_pagespeed
2014-12-04 15:42:31 -05:00
Jeff Kaufman 3c5c5076de Upstream the change to check_failures_and_exit, moving it to mod_pagespeed 2014-12-04 13:22:13 -05:00
Jeff Kaufman eab4f8672f Merge pull request #852 from pagespeed/jefftk-move-tests-to-system
Move duplicate tests from the nginx-specific system test to system
2014-12-02 20:12:52 -05:00
Jeff Kaufman 852e376130 Move duplicate tests from the nginx-specific system test to system/system_test
As system/system_test.sh is in the mod_pagespeed repo, this is just a bunch of
deletes.
2014-12-02 15:11:23 -05:00
Jeff Kaufman b7529a8d9a Merge pull request #855 from pagespeed/jefftk-fix-tempdir
Rework parallization separation
2014-12-02 13:34:03 -05:00
Jeff Kaufman 5dd93fffae Rework parallization separation 2014-12-01 10:49:08 -05:00
Jeff Kaufman 48d23f10ba Merge pull request #851 from pagespeed/jefftk-fix-url-purging
Fix error with url cache purging test.  Followup to #850.
2014-11-17 11:25:03 -05:00
Jeff Kaufman f924bc72d9 Fix error with url cache purging test. Followup to #850. 2014-11-17 11:19:51 -05:00
Otto van der Schaaf 1aff187d0e Merge pull request #850 from pagespeed/oschaaf-trunk-tracking-script-filters-test
script-filters: Add a test for modifying filters via script variables
2014-11-14 16:03:22 +01:00
Jeff Kaufman 3b64df255a Merge pull request #849 from pagespeed/jefftk-prioritize-critical-css-test
testing: allow the prioritize_critical_css post test to fail
2014-11-14 10:02:49 -05:00
Otto van der Schaaf 0eeeca6e47 script-filters: Add a test for modifying filters via script variables
As requested via https://github.com/pagespeed/ngx_pagespeed/pull/822
2014-11-14 15:56:13 +01:00
Jeff Kaufman 6f68ba2f68 testing: allow the prioritize_critical_css post test to fail 2014-11-14 08:56:37 -05:00
Otto van der Schaaf e6e70c32a8 Merge pull request #822 from pagespeed/oschaaf-trunk-tracking-script-filters
script-filters: Allow using script variables in Enable/DisableFilters
2014-11-06 22:35:44 +01:00
Jeffrey Crowell a3e20a05e2 Merge pull request #846 from pagespeed/oschaaf-trunk-tracking-conf-multi-typo
NGX_CONF_MULTI: Typo
2014-11-04 13:46:55 -05:00
Otto van der Schaaf e28255e2ef NGX_CONF_MULTI: Typo
Fix accidental double pipe symbol.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/843
2014-11-04 13:29:49 +01:00
Otto van der Schaaf 10ac8ae4a3 Merge pull request #798 from pagespeed/oschaaf-trunk-tracking-conf-multi
older-nginx-versions: Add NGX_CONF_MULTI to ps_command flags.
2014-10-30 15:13:27 +01:00
Jeffrey Crowell 1b3ca08e22 Merge pull request #841 from pagespeed/crowell-tengine-stable-support
Check type of resolver_ctx->addrs.
2014-10-29 14:59:51 -04:00
Jeffrey Crowell de5bc5d943 Check type of resolver_ctx->addrs.
Check the type of resolver_ctx->addrs and make sure that it is
ngx_addr_t* instead of in_addr_t*. addresses issue #839
2014-10-29 14:49:55 -04:00
Otto van der Schaaf afd0f01686 script-filters: Allow using script variables in Enable/DisableFilters
To support a non-evil way (if-in-location) of tuning SPDY specific
configuration, allow scripting of Enable/DisableFilters in nginx.conf
2014-10-10 17:33:44 +02:00
Otto van der Schaaf 0cdb81fab4 Merge pull request #795 from pagespeed/oschaaf-native-fetcher-remove-check
native-fetcher: remove a DCHECK that possibly fires on shutdown.
2014-10-06 17:04:56 +02:00
hillsp b492d3966e Merge pull request #811 from pagespeed/cheesy-device-matching
Support minor PSOL API change for matches_device_type
2014-09-22 17:38:06 -04:00
Steve Hill 232c05a81d Merge remote-tracking branch 'origin/trunk-tracking' into cheesy-device-matching 2014-09-19 18:17:20 -04:00
Steve Hill adbe2cb359 Remove unit tests; They are now in system_test.sh 2014-09-19 18:14:18 -04:00
Jeffrey Crowell 88370cf54d Merge pull request #809 from pagespeed/crowell-update-config
Merge config from 1.9.32.1
2014-09-19 10:47:08 -04:00
Jeffrey Crowell b43a973071 Merge config from 1.9.32.1 2014-09-19 10:30:38 -04:00
Steve Hill a524127d49 PSOL API change and unit tests for matches_device_type 2014-09-18 18:22:46 -04:00
Otto van der Schaaf 53a6de6da8 Merge pull request #797 from pagespeed/oschaaf-finalized-requests-fix
connection_read_handler: fix potential double free
2014-09-15 16:26:29 +02:00
Otto van der Schaaf 66f1b9aa9b older-nginx-versions: Add NGX_CONF_MULTI to ps_command flags.
Older nginx versions don't allow 'pagespeed' configuration
directives to appear in blocks other then http{} without it.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/786
2014-09-14 09:19:13 +02:00
Otto van der Schaaf 6903286aa4 connection_read_handler: fix potential double free
In connection_read_handler(), make sure we act accordingly when
r->connection->error is set (indicating the the current request has
been finalized).

Reproduction of what happens when we don't: enable IPRO+SPDY, and
rapidly refresh a page with chrome. These rapid abortions will
eventually trigger a segfault/hang/misc bad behaviour.
2014-09-13 16:30:34 +02:00
Otto van der Schaaf 46dc39f5a9 Merge pull request #794 from pagespeed/oschaaf-ipro-race
IPRO: Fix a race in processing writes() from NgxBaseFetch
2014-09-12 16:33:29 +02:00
Otto van der Schaaf 7d8fefe780 native-fetcher: remove a DCHECK that possibly fires on shutdown. 2014-09-11 23:33:22 +02:00
Otto van der Schaaf 43d1706e2f IPRO: Fix a race in processing writes() from NgxBaseFetch
For FetchInPlaceResource, NgxBaseFetch would send two bytes down its
pipe, one upon HeaderComplete() and one upon HandleDone(). We need
only one to resume processing on the nginx side.

There is a race between ps_connection_read_handler() and processing
of the byte send by NgxBaseFetch::HandleDone().
ps_connection_read_handler() clears the pipe when the request is
finalized, and also drains it on each event - so two writes could be
processed as one when lucky, masking the problem).

One concrete problem this solved for me was that SPDY + IPRO +
proxy_pass would segfault, hang, and/or pass on 5xx/404 responses
from IPRO lookup fetches to the browser, next to alerts about
r->count being zero in nginx's error.log

Might fix https://github.com/pagespeed/ngx_pagespeed/issues/788
Fixes https://github.com/pagespeed/ngx_pagespeed/issues/792
2014-09-11 23:14:41 +02:00
Otto van der Schaaf 622d088a3e Merge pull request #790 from pagespeed/oschaaf-trunk-tracking-native-fetcher-keepalive
native fetcher: Support http keep-alive
2014-09-05 17:29:22 +02:00
Otto van der Schaaf 0290f52a88 native fetcher: Support http keep-alive
Based on @dinic his work, add keep-alive support for the native fetcher.
Adds a new option, usable at the http{} level in configuration:

pagespeed NativeFetcherMaxKeepaliveRequests 50;

The default value is 100 (aligned to nginx). Setting the value to 1 turns off
keep-alive requests altogether).

Most notable changes:
- Request keep-alive by adding the appropriate request header
- Fixes connections getting reused while they are servicing other requests:
- Remove connection from the pool of available connections for keepalive when applicable
- Disable keepalive in more appropriate situations
- Response parsing fixes
- Remove connections that timeout from the k.a. pool
- Add a few sanity (D)CHECKS
- Emit debug messages for traceability
- Fix for ignoring ipv6 addresses returned from dns queries when ipv6 is enabled.
- Bump the fetch timeout in test configuration to deflake tests that require dns
  lookups (which will be done via 8.8.8.8 currently for the native fetcher)
2014-09-05 17:23:16 +02:00
Maks Orlovich c94146a54d Merge pull request #791 from pagespeed/morlovich-trunk-tracking-remove-deprecated-headers
Remove use of deprecated forwarding headers
2014-09-04 16:06:52 -04:00
Maks Orlovich f3a1cb6cf4 Remove use of deprecated forwarding headers 2014-09-04 09:16:05 -04:00
jmarantz 5a23347e64 Merge pull request #785 from pagespeed/jmarantz-error-option-format
Implement NgxServerContext::FormatOption so we can indicate nginx formatting in error messages
2014-08-29 16:32:43 -04:00
Joshua Marantz 7ce289346a Override the method used to specify the format for conf files, so we can put an accurate error message in the admin GUI, and test it 2014-08-29 09:13:43 -04:00
jmarantz 6b4a9dc487 Merge pull request #784 from pagespeed/jmarantz-fgrep-for-counts
use fgrep for counting ".pagespeed."
2014-08-27 09:47:46 -04:00
Joshua Marantz a3f2e4766c use fgrep for counting ".pagespeed.", rather than grep with backslashed dot, which matches too much 2014-08-26 15:02:10 -04:00
jmarantz ab0a5e4b65 Merge pull request #782 from pagespeed/jmarantz-start-test-resets-wget-args
Assume WGET_ARGS is cleared on every start_test
2014-08-23 13:20:34 -04:00
Joshua Marantz a458a65d4e Update system test to be compatible with a helper-script update that makes start_test clear WGET_ARGS, making test stanzas more independent 2014-08-20 12:59:04 -04:00
Jeff Kaufman d00911b00f Merge pull request #775 from pagespeed/jefftk-clearer-test-flake-error
testing: make it clearer why test flake in Issue #774 happens
2014-08-14 11:34:50 -04:00
Jeff Kaufman ed80427ae6 Merge pull request #761 from pagespeed/jefftk-adding-comments
Add some comments and a few style fixes.
2014-08-14 10:29:22 -04:00
Jeff Kaufman f556ca4926 Add some comments and a few style fixes. 2014-08-14 09:52:13 -04:00
Jeff Kaufman cad618dff7 testing: make it clearer why test flake in Issue #774 happens 2014-08-13 13:53:22 -04:00
Jeff Kaufman a906411367 Merge pull request #773 from pagespeed/jefftk-nginx-message-color
testing: direct port of r4146 to fix message color issue
2014-08-13 10:51:37 -04:00
Jeff Kaufman e6c5bc1b2e testing: direct port of r4146 to fix message color issue 2014-08-13 10:13:13 -04:00
Otto van der Schaaf d6d3b90ea3 Merge pull request #769 from pagespeed/oschaaf-large-beacon-posts
beacon response body processing from temp file
2014-08-12 17:57:34 +02:00
Otto van der Schaaf d7afd2acbc beacon response body processing from temp file
Add support for processing beacon posts with data sizes that exceed
the default or configured client_body_buffer_size, plus a system test
to ensure it.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/752
2014-08-12 07:46:30 +02:00
Maks Orlovich 05f6993801 Merge pull request #772 from pagespeed/morlovich-fix-metadata-form-test
Port over test adjustment.

This is just a straight port of relevant portion of https://code.google.com/p/modpagespeed/source/detail?r=4140
2014-08-11 16:45:32 -04:00
Maks Orlovich fe63bbf53f Port over test adjustment. 2014-08-11 16:26:20 -04:00
Otto van der Schaaf c7aa72d9c5 Merge pull request #767 from pagespeed/oschaaf-issue-757
rewriting-posts: Support POST responses for html
2014-08-07 16:28:51 +02:00
Otto van der Schaaf 8f6bb0c9e3 rewriting-posts: Support POST responses for html
Allow rewriting html responses to POST requests

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/757
2014-08-07 16:02:23 +02:00
Otto van der Schaaf 84f2a1884e Merge pull request #765 from pagespeed/oschaaf-trunk-tracking-script-support
script-variables: Support LoadFromFileXXX
2014-08-05 16:45:19 +02:00
Otto van der Schaaf da83f73f19 script-variables: Support LoadFromFileXXX
Based on 75a4481 from master.

Add support for script variables in LoadFromFileXXX configuration to trunk-tracking,
which can be enabled by adding "pagespeed ProcessScriptVariables on" in
the http{} block.
Also adds a helpful comment to ps_dollar().

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/549
Docs: https://github.com/pagespeed/ngx_pagespeed/wiki/Script-variables-in-LoadFromFile-configuration

Resolved conflicts:
	src/ngx_rewrite_driver_factory.h
	src/ngx_rewrite_options.cc
	test/nginx_system_test.sh
2014-08-05 00:51:07 +02:00
jmarantz 2bfc05b4c6 Merge pull request #763 from pagespeed/jmarantz-http-200-ok-function
use a new helper method to verify HTTP response codes are 200 OK
2014-08-04 11:00:03 -04:00
jmarantz ea9e209687 Merge pull request #764 from pagespeed/jmarantz-systest-exit-on-error
Make script execute properly in the context of 'set -e'
2014-08-04 10:04:03 -04:00
Joshua Marantz c073a3120b remove debug comments 2014-08-04 10:02:31 -04:00
Joshua Marantz 5e3b2f23a5 Make script execute properly in the context of 'set -e' 2014-08-01 09:29:08 -04:00
Joshua Marantz f41ecf4010 use a new helper method to verify HTTP response codes are 200 OK 2014-08-01 09:19:40 -04:00
Jeff Kaufman 34a62db9cf Merge pull request #760 from pagespeed/sligocki-request-context-set-options
Set options for RequestContexts in ngx_pagespeed.
2014-07-30 09:53:00 -04:00
Jeffrey Crowell b0efa9f982 Merge pull request #758 from pagespeed/crowell-debug-filter-safe-to-print
add safe_to_print on nginx rewrite options
2014-07-29 16:58:10 -04:00
Shawn Ligocki fb00ac373b Set options for RequestContexts in ngx_pagespeed. 2014-07-29 16:05:27 -04:00
Jeffrey Crowell 9550629768 add safe_to_print on nginx rewrite options 2014-07-29 14:58:06 -04:00
Shawn Ligocki 26a5deb341 Merge pull request #756 from pagespeed/sligocki-in-place-api-change
Fix InPlaceResourceRecorder constructor to remove two arguments passed in through options now.
2014-07-29 13:09:44 -04:00
Shawn Ligocki 7bcd5aadde Fix InPlaceResourceRecorder constructor to remove two arguments passed in through options now. 2014-07-28 18:02:17 -04:00
matterbury 594ba13606 Merge pull request #751 from pagespeed/matterbury-unauthorized-debug
Test the new debug messages for unauthorized domains.
2014-07-09 14:40:24 -04:00
Matt Atterbury 9d0b896737 Test the new debug messages for unauthorized domains. 2014-07-08 09:17:06 -04:00
Jud Porter 89f6465288 Merge pull request #748 from pagespeed/jud-ipv6-smoke-test
Fix smoke test on systems with ipv6 localhost
2014-07-02 13:37:23 -04:00
Jud Porter eb11cfe0cf Add ipv6 listen directives to smoke test config server blocks. 2014-07-02 10:57:40 -04:00
Jud Porter 7a0e45d025 Ignore "Hostname was NOT found in DNS cache" message generated by more recent versions of curl. 2014-07-02 10:49:23 -04:00
jmarantz 3cf731ee24 Merge pull request #743 from pagespeed/jmarantz-nginx-purge-method
Fix PURGE method support and testing to ngx_pagespeed
2014-07-01 17:44:38 -04:00
Joshua Marantz 1a4ffcf335 Fix PURGE method support and testing to ngx_pagespeed 2014-06-30 09:49:10 -04:00
Jeff Kaufman 72c7e584f7 Merge pull request #740 from pagespeed/jefftk-unused-function
Remove unused function.  Fixes #739.
2014-06-30 11:26:07 +01:00
Jeff Kaufman 08f69913dc Merge pull request #738 from pagespeed/jefftk-fix-style
style: minor fixes, mostly as a followup to #665
2014-06-27 17:15:11 -04:00
Jud Porter f2d6bcf3ac Merge pull request #742 from pagespeed/jud-exit-status
Have manual ngx_pagespeed runs return exit code 0.
2014-06-27 16:55:30 -04:00
Jud Porter 2c89815084 Have manual ngx_pagespeed runs return exit code 0. 2014-06-27 16:54:31 -04:00
Jeff Kaufman e55b062c17 Remove unused function. Fixes #739. 2014-06-27 10:22:58 -04:00
Jeff Kaufman 62ef051844 style: minor fixes, mostly as a followup to #665 2014-06-24 15:50:19 -04:00
Jeff Kaufman 36b07ca209 Merge pull request #665 from We-Amp/keesspoelstra-gzip-enable-trunk
gzip: enabling gzip on "pagespeed on"
2014-06-24 07:20:12 -04:00
Jeff Kaufman 1280cd0dfa Merge pull request #734 from pagespeed/jefftk-move-doc-to-devsite
readme: reference doc on developers.google.com instead of duplicating it
2014-06-23 10:38:43 -04:00
Jeffrey Crowell a06551a97d Merge pull request #735 from pagespeed/crowell-accept-invalid-signatures
add tests for accepting invalid signatures.
2014-06-20 16:36:42 -04:00
Jeffrey Crowell 679618f998 remove signature tests that live in automatic/system_test.sh 2014-06-20 11:24:30 -04:00
Jeffrey Crowell fb9b355715 rename REGEX to URL_REGEX in test 2014-06-20 10:56:31 -04:00
Jeffrey Crowell f71ac7dd0c add accept-invalid-signatures tests for transition to signed resources 2014-06-20 10:51:31 -04:00
Jeff Kaufman 19f479a6b6 readme: reference doc on developers.google.com instead of duplicating it. 2014-06-20 10:19:53 -04:00
xqyin 7431946d23 Merge pull request #733 from pagespeed/xqyin-refactor-message-handler3
Make NgxMessageHandler inherit to SystemMessageHandler
2014-06-20 10:17:54 -04:00
Cathy Yin 0d760dbf31 Make NgxMessageHandler inherit to SystemMessageHandler. Move SharedCircularBuffer things to SystemMessageHandler. 2014-06-19 15:56:03 -04:00
Cathy Yin e9d7b2ad01 Merge remote-tracking branch 'origin/trunk-tracking' into xqyin-refactor-message-handler2 2014-06-19 13:55:25 -04:00
jmarantz 0d89df0e80 Merge pull request #732 from pagespeed/jmarantz-cache-purge
add support for cache purge requests via GET from admin or PURGE method....
2014-06-19 13:44:27 -04:00
Cathy Yin 218d74f206 Make NginxMessageHandler inherit to a new class SystemMessageHandler. Move SharedCircularBuffer related operations there. 2014-06-19 13:06:53 -04:00
Jeff Kaufman bcefd56941 Merge pull request #720 from pagespeed/jefftk-lff-ipro
testing: a server block for testing load from file with ipro
2014-06-19 11:20:33 -04:00
Jeff Kaufman 676344bc8a testing: a server block for testing load from file with ipro 2014-06-19 10:01:33 -04:00
Joshua Marantz 7293f649d1 add support for cache purge requests via GET from admin or PURGE method. PURGE doesn't quite work yet, so we skip testing that one. 2014-06-19 09:34:40 -04:00
Jeff Kaufman 10f5093bf6 Merge pull request #731 from pagespeed/jefftk-thread-config
options: support setting NumRewriteThreads
2014-06-18 15:08:42 -04:00
Jeff Kaufman 357eb92683 options: move global option parsing to system/ 2014-06-18 15:08:08 -04:00
Jeff Kaufman a6c6d13392 Support setting NumRewriteThreads and NumExpensiveRewriteThreads
Several rewrite driver factory options are duplicated between apache and nginx.  Instead of duplicating this one too, a PSOL change moves them into system/, and this change takes advantage of that move.
2014-06-16 11:25:39 -04:00
xqyin 9007e582ad Merge pull request #727 from pagespeed/xqyin-refactor-admin-site
Change SystemServerContext::kStatistics to AdminSite::kStatistics
2014-06-11 14:55:42 -04:00
Cathy Yin 1ca04d514c Change SystemServerContext::kStatistics to AdminSite::kStatistics. 2014-06-11 14:01:15 -04:00
Kees Spoelstra 8e08b2b7e0 this adds the following configuration on "pagespeed on"
gzip on;
gzip_proxied any;
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/html;
gzip_types text/javascript;
gzip_types text/plain;
gzip_types text/xml;
gzip_http_version 1.0;

If any explicit gzip configuration is detected the gzip configuration
set by pagespeed is rolled back completely and the explicit gzip
configuration is used.

To enable/disable gzip with pagespeed the following commands can be used:

pagespeed gzip on;
pagespeed gzip off;

We test the nesting of the gzip configuration (pagespeed gzip on/off and
pagespeed on/off)
Ideally we need to test all the content types as well and the rollback in
case of an explicit gzip configuration, but to do this we need to be able
to map a custom directory into the nginx tests this and seperate nginx
config files.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/238
2014-06-11 17:40:52 +02:00
Kees Spoelstra ad1a1594d6 this adds the following configuration on "pagespeed on"
gzip on;
gzip_proxied any;
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/html;
gzip_types text/javascript;
gzip_types text/plain;
gzip_types text/xml;
gzip_http_version 1.0;

If any explicit gzip configuration is detected the gzip configuration
set by pagespeed is rolled back completely and the explicit gzip
configuration is used.

To enable/disable gzip with pagespeed the following commands can be used:

pagespeed gzip on;
pagespeed gzip off;
2014-06-11 17:28:25 +02:00
jmarantz d5e37d2d2e Merge pull request #726 from pagespeed/jmarantz-remove-spew-and-extra-read
make check-from greps be silent, and remove extra 'read'
2014-06-11 11:28:21 -04:00
Joshua Marantz 4bceb402a6 make check-from greps be silent, and remove extra 'read' that was causing smoke tests to apparently hang 2014-06-11 10:48:42 -04:00
Jeffrey Crowell 80a50fe9d8 Merge pull request #724 from pagespeed/crowell-signed-urls
signed-urls tests added.
2014-06-10 17:16:30 -04:00
Jeffrey Crowell 28192a509e update nginx_system_test to use signed resources. 2014-06-10 16:41:41 -04:00
Jeff Kaufman 9331815350 Merge pull request #721 from pagespeed/oschaaf-lff-ipro-trunk-tracking
ipro-lff: Prevent handing out 200/OK when we can't rewrite in place
2014-06-05 15:22:51 -04:00
Otto van der Schaaf 727d339dfd ipro-lff: Prevent handing out 200/OK when we can't rewrite in place
PSOL change for in_place_rewrite_context.cc
- Reorder setting the status code so we actually change the
  ResponseHeaders that we are using to serve
- Prevent non-error http status codes from being served up.

As noted by @jeffkaufman, to prevent a potential lifetime issue with
ResponseHeaders, remove the call to ps_release_base_fetch() in
ps_decline_request().

PSOL patch:
```diff
--- ../rewriter/in_place_rewrite_context.cc	(revision 4020)
+++ ../rewriter/in_place_rewrite_context.cc	(working copy)
@@ -127,9 +127,20 @@
       // to us.
       streaming_ = false;
       set_request_headers(NULL);
+      // If we cannot rewrite in-place, we should not serve a 200/OK.
+      // Serve kNotFound instead to fall back to the server's native
+      // method of serving the url and indicate we don't want it recorded
+      // either.
+      // TODO(oschaaf): When the resource is loaded via LoadFromFile,
+      // this code gets repeatedly hit for the same url. That might
+      // become a drag when the file in question is very large and popular.
+      // Marking urls that end up in this flow as not cachable in the http cache
+      // at this point had no effect (for the LoadFromFile flow at least).
+      if (!response_headers()->IsErrorStatus()) {
+	response_headers()->set_status_code(HttpStatus::kNotFound);
+      }
       set_response_headers(NULL);
       set_extra_response_headers(NULL);
-      response_headers()->set_status_code(HttpStatus::kNotFound);
       SharedAsyncFetch::HandleDone(false);
     }
   }
```
2014-06-05 15:46:53 +02:00
jmarantz b3e5297dc3 Merge pull request #717 from pagespeed/jmarantz-psol-library-from-env-var2
Allow the path to the PSOL library to be specified by an env var.
2014-06-03 18:01:40 -06:00
Joshua Marantz 639a01015c fix indentation 2014-06-03 19:59:44 -04:00
Kees Spoelstra 29a43196e8 gzip: enabling gzip on "pagespeed on"
this adds the following configuration on "pagespeed on"
gzip  on;
gzip_proxied any;
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/html;
gzip_types text/javascript;
gzip_types text/plain;
gzip_types text/xml;
gzip_http_version 1.0;

If an explicit configuration is detected the gzip configuration
set by pagespeed on is rollbacked

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/238
2014-06-03 23:29:31 +02:00
matterbury 0b20c91217 Merge pull request #718 from pagespeed/matterbury-move-redirection-tests
Move redirection tests to the common test script.
2014-06-03 11:27:16 -04:00
Matt Atterbury d654062516 Move redirection tests to the common test script. 2014-06-02 09:30:34 -04:00
Joshua Marantz b6991fd107 Allow the path to the PSOL library to be specified by an env var. This was already doc'd in a comment in 'config' but did not work. 2014-05-31 07:58:50 -04:00
Jeff Kaufman bf042f8af9 Merge pull request #715 from pagespeed/jefftk-move-contrnet-length-test
headers: content length is now tested in common code
2014-05-30 09:28:11 -04:00
Jeff Kaufman 22950666e0 headers: content length is now tested in common code 2014-05-29 15:19:58 -04:00
xqyin 96f185d472 Merge pull request #709 from pagespeed/xqyin-color-messages
Color messages in the message_history page. Add system test for this change.
2014-05-28 17:39:05 -04:00
Jeff Kaufman c9a106b4b0 readme: with 1.8 we need different default config 2014-05-28 16:33:01 -04:00
Jeff Kaufman 00080ff728 readme: 1.7.30.4 -> 1.8.31.2 2014-05-28 16:13:01 -04:00
Cathy Yin b6098ce302 Color the messages in message_history page. Add corresponding system test for this change. 2014-05-28 09:42:14 -04:00
Jeff Kaufman 36d285a354 Merge pull request #707 from pagespeed/jefftk-fix-static-asset-prefix
options: support StaticAssetPrefix
2014-05-27 11:35:39 -04:00
Matt Atterbury 149d1c7a5c Moved cookie option tests to common test script. 2014-05-27 09:59:59 -04:00
Matt Atterbury 9e9bf76164 Added system test for sticky options. 2014-05-27 09:59:59 -04:00
Matt Atterbury 09bc3b0aba Added query parameter to make the other query parameters 'sticky' by returning cookies that set them so are passed in subsequent requests. 2014-05-27 09:59:59 -04:00
Jeff Kaufman 502abb2f10 options: support StaticAssetPrefix 2014-05-23 14:09:49 -04:00
matterbury 08bdfb8c65 Merge pull request #700 from pagespeed/matterbury-sticky-options
Added query parameter to make the other query parameters 'sticky' ...
2014-05-20 14:16:47 -04:00
Matt Atterbury 8a8f62fefa Moved cookie option tests to common test script. 2014-05-19 09:27:26 -04:00
Matt Atterbury 94ab5c33f8 Added system test for sticky options. 2014-05-16 12:01:57 -04:00
Matt Atterbury 0e766e4096 Merge remote-tracking branch 'origin/trunk-tracking' into matterbury-sticky-options
if it merges an updated upstream into a topic branch.
2014-05-16 12:00:33 -04:00
Jeff Kaufman a7fdc86744 Merge pull request #701 from pagespeed/jefftk-move-settings-to-server-scope
move settings to server scope

Allow you to set `MessagesPath`, `StatisticsPath`, `AdminPath`, or `ConsolePath`  in a `server {}` block.
2014-05-12 09:34:39 -04:00
Jeff Kaufman aed13fc578 Allow admin paths to be set at server scope. 2014-05-12 09:12:52 -04:00
Matt Atterbury cd753a22a7 Added query parameter to make the other query parameters 'sticky' by returning cookies that set them so are passed in subsequent requests. 2014-05-12 08:26:32 -04:00
matterbury 6af5774ef8 Merge pull request #688 from pagespeed/matterbury-queryparams
Rename QueryParams::Parse to ParseFromUrl. Add a wrapper that takes an untrusted string.
2014-04-30 10:05:01 -04:00
Matt Atterbury 117994993a Rename QueryParams::Parse to ParseFromUrl. Add a wrapper that takes an untrusted string. 2014-04-30 09:59:34 -04:00
Jeffrey Crowell 5487b7350c Merge pull request #684 from pagespeed/crowell-requst-option-override
add ngx test support for RequestOptionOverride option
2014-04-28 13:53:41 -04:00
Jeffrey Crowell 261b602f83 add ngx test support for RequestOptionOverride option 2014-04-25 11:48:29 -04:00
Jeff Kaufman ae3cf7a425 Merge branch 'master' into trunk-tracking 2014-04-25 08:27:36 -04:00
Jeff Kaufman b4af0738a5 readme: use nginx 1.6.0 2014-04-25 08:27:26 -04:00
Jeff Kaufman ff049a55c3 Merge pull request #681 from pagespeed/jefftk-psol-dep
dependencies: include psol as a dependency
2014-04-24 14:04:24 -04:00
Jeff Kaufman 0772787ad4 dependencies: include psol as a dependency 2014-04-24 13:30:17 -04:00
jmarantz 7eedc2ce3c Merge pull request #680 from pagespeed/jmarantz-clean-proactive
clean up the conf file overrides to turn off proactive resource
2014-04-24 11:21:20 -04:00
Joshua Marantz 7af665b5dd clean up the conf file overrides to turn off proactive resource
fetching and compressed cache.  the compressed cache was ok but
proactive resource fetching consistently fails system tests in nginx
2014-04-24 11:16:27 -04:00
Jeff Kaufman 8136a15352 Merge pull request #678 from pagespeed/jefftk-update-trunk-tracking
port r3968 which is supposed to be just a test that a bug isn't present...
2014-04-23 15:46:59 -04:00
Jeff Kaufman 31024cfc24 trunk-tracking: also turn off ProactiveResourceFreshening until we fix PSOL. 2014-04-23 15:25:49 -04:00
Jeff Kaufman 703fda7eba port r3968 which is supposed to be just a test that a bug isn't present, but in ngx_pagespeed actually triggers that bug. This needs to be fixed, but is out of scope for a trunk-tracking update. 2014-04-23 14:56:25 -04:00
Jeff Kaufman d4bc40007e Merge pull request #677 from pagespeed/jefftk-update-trunk-tracking
trunk-tracking: update from r3949 to r3967
2014-04-23 14:11:50 -04:00
Jeff Kaufman f2e2ab6056 port r3966 by turning off CompressMetadataCache which breaks ipro 2014-04-23 13:22:14 -04:00
Jeff Kaufman e06a65e7e6 port 3967 which adds a fetch_until to the prioritize critical css test 2014-04-23 10:20:31 -04:00
Jeff Kaufman 3231949e03 port r3964 which handles options in request cookies 2014-04-23 10:10:48 -04:00
Jeff Kaufman f5713996f2 Merge branch 'trunk-tracking' of github.com:pagespeed/ngx_pagespeed into trunk-tracking 2014-04-23 09:15:57 -04:00
Jeff Kaufman 185632583b Merge pull request #675 from pagespeed/jefftk-update-trunk-tracking
trunk tracking: update from r3934 to r3949
2014-04-23 09:15:45 -04:00
Jeff Kaufman c5dbfa16cd trunk-tracking: fix comment 2014-04-23 09:14:58 -04:00
Jeff Kaufman 33b2e82ec6 trunk-tracking: port tests for r3948, PageSpeed=... not ModPagespeed=... 2014-04-22 17:56:09 -04:00
Jeff Kaufman b87ffce5ba trunk-tracking: port r3945 which made the location of static assets configurable 2014-04-22 17:55:57 -04:00
Jeff Kaufman 7d5fc11afd trunk-tracking: port tests for r3937, url-valued attributes overriding spec 2014-04-22 17:38:51 -04:00
Jeff Kaufman 7cba7ba4f4 trunk-tracking: port tests for r3935 which changes image lazyloading 2014-04-22 17:38:51 -04:00
Jeff Kaufman cf434f71cc trunk-tracking: port r3937 which supports custom url-valued attributes overriding spec-defined ones 2014-04-22 16:37:13 -04:00
Jeff Kaufman ba8c149a88 Merge pull request #670 from pagespeed/oschaaf-downstream-cache-headers
downstream-caching-headers: make nginx 1.5.9+ pass tests as well
2014-04-21 17:07:23 -04:00
Jeff Kaufman f5bac604a1 Merge pull request #671 from pagespeed/oschaaf-downstream-cache-test
downstream-cache-test: deflake the test
2014-04-21 10:27:53 -04:00
Otto van der Schaaf f18faa3ae1 downstream-cache-test: deflake the test
As suggested by Anupama, deflake the test by only allowing beaconing
when explitly requested by http request from tests.

Html with beacons in it will bypass the proxy cache.
2014-04-20 00:24:32 +02:00
Otto van der Schaaf 070ae2aad2 downstream-caching-headers: make nginx 1.5.9+ pass tests as well
- Fix a mistake I made in https://github.com/pagespeed/ngx_pagespeed/pull/653
  This is the primary reason the test starts failing, the base fetch
  handled `kPreserveOnlyCacheControl` in the wrong way.
- Use `ps_set_cache_control` when copying a Cache-Control header
  to nginx, as `r->headers_out.cache_control` is where modules running
  after us might expect it
- Exclude a few more lines from curl's verbose output in the keep-
  alive tests that I came accross when testing on ubuntu 13.10
  Desktop.

Note that this does not deflake the downstream cache test yet, I will
look at that in a follow-up.
2014-04-19 22:58:09 +02:00
Jeff Kaufman 674c70e32c Merge pull request #669 from pagespeed/morlovich-trunk-tracking-ssl-tests
Port over the basic HTTPS fetching test.
2014-04-17 16:36:01 -04:00
Maks Orlovich b4ef143a88 Port over the basic HTTPS fetching test. 2014-04-17 16:20:10 -04:00
Jeff Kaufman ffdc3c8fd6 Merge pull request #667 from pagespeed/jefftk-merge-master-to-tt
trunk-tracking: merge in master
2014-04-17 15:21:19 -04:00
Jeff Kaufman af10fc3ddb trunk-tracking: merge in master 2014-04-17 15:16:43 -04:00
Jeff Kaufman e9a099f9c5 Merge pull request #666 from pagespeed/jefftk-update-trunk-tracking
trunk-tracking: update from r3924 to r3934
2014-04-17 10:43:46 -04:00
Jeff Kaufman e4a2933c58 trunk-tracking: update from r3924 to r3934
There aren't actually any changes required from r3924 to r3934 but the admin
work from previous versions wasn't completely ported before.

This change:
 * adds support for /pagespeed_admin and /pagespeed_global_admin
 * removes NgxPagespeedConsoleAsyncFetch using NgxBaseFetch instead
 * adds options StatisticsPath, GlobalStatisticsPath, ConsolePath,
   MessagesPath, AdminPath, and GlobalAdminPath which allow site owners to
   control what path these are served under
 * changes /ngx_pagespeed_statistics etc from default-on to default-off,
   requiring explicit path configuration to function
 * does not fix the problem where trunk-tracking fails tests on 1.5 post #653
2014-04-17 10:10:20 -04:00
Jeff Kaufman 2601232457 Merge pull request #655 from pagespeed/oschaaf-native-fetcher-resolve-timeout
native-fetcher: fix CHECK failure on DNS timeout
2014-04-14 07:28:42 -04:00
Otto van der Schaaf a3e1810a6a Merge pull request #653 from pagespeed/oschaaf-downstream-caching-headers
downstream-caching: Fix pagespeed resource response headers
2014-04-10 21:56:01 +02:00
Otto van der Schaaf 72f3c79fec downstream-caching: Fix pagespeed resource response headers
- Make kPreserveOnlyCacheControl do what it says on the tin
- Serve pagespeed resources with the response headers computed
  by PSOL regardless of whether downstream caching is configured.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/652
2014-04-10 21:42:48 +02:00
Otto van der Schaaf 323e820fde Merge pull request #658 from pagespeed/oschaaf-configure-wnoerror
nginx-gridfs: Add configure option to build with wno-error
2014-04-09 20:38:57 +02:00
Otto van der Schaaf a9a7bf56ac Merge pull request #659 from pagespeed/jud-trunk-tracking
trunk-tracking: update from r3895 to r3924
2014-04-08 21:58:16 +02:00
Jud Porter 2358f957cb trunk-tracking: update from r3895 to r3924 2014-04-08 14:51:04 -04:00
Otto van der Schaaf 7d72a7c89a nginx-gridfs: Add configure option to build with wno-error
Some modules add things to CFLAGS that will make ngx_pagespeed emit
warnings at compile time. For example, nginx-gridfs will add
`--std=c99` - which is no good for ngx_pagespeed.

@peterbowey mentioned that -wno-error fixes the build -- so
to work around, make configure add `-wno-error` when used like
this: `WNO_ERROR=YES ./configure`
On my system, that results in a succesfull build when nginx-gridfs
is added to the module mix.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/626
2014-04-08 13:10:58 +02:00
Otto van der Schaaf 8830724580 native-fetcher: fix CHECK failure on DNS timeout
Make sure we clear the timeout event associated with resolving
a hostname in `CallbackDone()`, which would otherwise end up
calling `CallbackDone()` a second time upon firing.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/625
2014-04-06 09:17:45 +02:00
Otto van der Schaaf c2d07a8d5a Merge pull request #651 from pagespeed/morlovich-trunk-tracking-upto-r3895
trunk tracking upto r3895
2014-04-02 18:53:04 +02:00
Maks Orlovich c3bff67637 Fix improper cache key on write for IPRO of resources with PageSpeed params
We need to be writing with the base name, with params stripped.
This was causing a test to "flake" under valgrind, since with it we got
to the test showing the bug slowly enough for the entry written out by
an earlier test under proper URL to expire.
2014-04-02 18:41:08 +02:00
Maks Orlovich 5a1a29ee8b trunk-tracking: update from r3872 to r3895
Squash-merge of @morlovich's work on this.

Note that this does not yet incorprorate the new
pagespeed_admin handler from r3891
2014-04-02 18:39:08 +02:00
Jeff Kaufman 61025c5e4f if: support pagespeed directives in location if blocks 2014-03-31 10:35:05 -04:00
Otto van der Schaaf d3e7900704 Merge pull request #648 from pagespeed/jmaessen-trunk-tracking
trunk-tracking: update from r3852 to r3872
note that it will only compile against mod_pagespeed r3872 if you first patch in r3889
2014-03-28 22:37:31 +01:00
Jan-Willem Maessen 85e19c962b trunk-tracking: update from r3852 to r3872 2014-03-27 10:59:13 -04:00
Otto van der Schaaf 20fd7d18dd Merge pull request #646 from pagespeed/oschaaf-chunked-transfer
content-length: fix pagespeed/ipro resource content-lengths
2014-03-26 08:53:50 +01:00
Otto van der Schaaf 4667aa1fc3 content-length: fix pagespeed/ipro resource content-lengths
Makes life downstream easier and more efficient
2014-03-25 21:29:28 +01:00
Jeff Kaufman 6ced8c0f65 Merge pull request #641 from pagespeed/jefftk-if-block
if: support pagespeed directives in location if blocks
2014-03-25 13:16:27 -04:00
Jeff Kaufman bfaf4268cf Merge pull request #639 from pagespeed/jefftk-trunk-tracking
trunk-tracking: update from r3827 to r3852
2014-03-19 16:57:28 -04:00
Jeff Kaufman 78cf39f9b3 if: support pagespeed directives in location if blocks 2014-03-19 16:46:48 -04:00
Jeff Kaufman 215071a383 trunk-tracking: update from r3827 to r3852
* port EnrollExperiment tests.
* tricky changes to get gzip+ipro working properly.
* reduce code duplication by calling copy_response_headers_from_ngx instead
  of reimplementing it.
* port Vary: Accept test changes.
2014-03-18 16:58:50 -04:00
Jeff Kaufman 630f7d848b lint: fix lint errors 2014-03-18 10:38:58 -04:00
Huibao Lin d90245af69 trunk-tracking: merge changes in from master:
* release: prepare 1.7.30.3
* Don't call chown() when initializing config dirs unless owner != worker user.
* Update README.md
* release: build against backported change
* release: udpate version number 1.7.30.3 to 1.7.30.4
2014-03-18 10:38:28 -04:00
Jeff Kaufman f25569690a merge commit: merge 1.7.30.4 into master 2014-03-14 10:15:42 -04:00
huibaolin 707d671826 Change version 1.7.30.3 to 1.7.30.4 2014-03-14 08:16:38 -04:00
Jeff Kaufman f8b87ea436 Merge pull request #636 from pagespeed/huibao-prepare-1.7.30.4-release
release: update version number 1.7.30.3 to 1.7.30.4
2014-03-13 10:37:21 -04:00
Huibao Lin 86d840f76e release: udpate version number 1.7.30.3 to 1.7.30.4 2014-03-13 10:27:21 -04:00
Jeff Kaufman 0110d33fa7 Merge pull request #635 from pagespeed/huibao-prepare-1.7.30.4-release
release: build against backported change
2014-03-13 10:26:16 -04:00
Huibao Lin 497594ba7f release: build against backported change 2014-03-13 10:18:57 -04:00
Jeff Kaufman 336352df38 Merge pull request #633 from pnommensen/patch-2
readme: use nginx 1.4.6
2014-03-07 13:17:42 -05:00
Patrick Nommensen 0edd405eb8 Update README.md
Don't know how I missed that.
2014-03-07 10:16:43 -08:00
Jeff Kaufman d004c4d916 Merge pull request #632 from pnommensen/patch-2
1.4.5 to 1.4.6 update
2014-03-07 11:32:01 -05:00
Jeff Kaufman c754cf1be0 trunk-tracking: update from r3811 to r3927 2014-03-07 11:18:35 -05:00
Patrick Nommensen 091ef6399b version update
1.4.5 to 1.4.6 http://nginx.org/en/CHANGES-1.4
2014-03-06 23:25:13 -08:00
Jeff Kaufman 9e4d26da5e Merge pull request #629 from pagespeed/jmaessen-trunk-tracking
trunk-tracking: update from r3784 to r3811
2014-03-03 16:56:15 -05:00
Jan-Willem Maessen 027d481817 trunk-tracking: update from r3784 to r3811
The big change here is Vary: headers, which are no longer being stripped from the pagespeed response.  Take a look; it might be we want to be smart about merging these headers with the original request's Vary: headers.
2014-02-27 19:41:23 -05:00
Jeff Kaufman 67106e920e apr: call SystemRewriteDriverFactory::InitApr()
squash-merge of morlovich's #601.
2014-02-20 09:13:56 -05:00
Jeff Kaufman 9699caeab5 Merge pull request #623 from pnommensen/patch-1
Update README.md
2014-02-20 09:12:04 -05:00
Patrick Nommensen c371d516a8 Update README.md
nginx version update
2014-02-20 00:04:21 -08:00
Jeff Kaufman 207eb2d131 Merge pull request #622 from pagespeed/jefftk-trunk-tracking
trunk-tracking: update from r3770 to r3784
2014-02-19 12:58:40 -05:00
Jeff Kaufman d9e2142f31 trunk-tracking: update from r3770 to r3784
* r3772 changed the format of unauthorized resource inlining config
* r3776 changed query param handling, but due to Jud's nice work in
  #616 needed no changes.
* r3780 huibao's refactoring lets us remove some duplicate code
* r3783 changes header passing with ipro
* Also cleaned up error messages for unknown options.
2014-02-19 10:53:48 -05:00
Jeff Kaufman bf6c6c0e9b Merge pull request #621 from jart/dont-chown
Security Fix: Don't call chown() unless necessary.
2014-02-18 14:32:32 -05:00
Justine Tunney e8dd9fd3c3 Don't call chown() when initializing config dirs unless owner != worker user. 2014-02-15 22:32:55 -05:00
Jud Porter 33d006625e Merge pull request #616 from pagespeed/jud-trunk-tracking
trunk-tracking: update from r3736 to r3770
2014-02-11 16:43:33 -05:00
Anupama Dutta 2dcaa95278 trunk-tracking: update from r3736 to r3770
Updated global_only options to include the correct APACHE_CONFIG_OPTIONX directives.
Removed repeated tests for prioritize_critical_css basic functionality.
Added new tests, mostly downstream caching tests and related pagespeed.conf updates. Also added missing pagespeed.conf updates for downstream caching.
Added support for checking option scope.
2014-02-11 16:40:07 -05:00
Jeff Kaufman f5252b569a trunk-tracking: update from r3715 to r3736
Squash-merge of Jan's #608 and Otto's #611.

* r3726:
  * Updated closure compiler flags for static JS files.
* r3729:
  * Centralize parsing of FetchHttps in SystemRewriteOptions so ngx_pagespeed
    can get it too.
  * To keep the helpful error_message from SerfUrlAsyncFetcher, wire it through
    RewriteOptions as a new-fangled error_detail.
* r3735:
  * Follow-up changes for downstream caching integration with beaconing
    dependent filters: If a downstream cache rebeaconing key is configured, we
    should instrument the page only if the key present in the PS-ShouldBeacon
    header matches the one in the configuration. This allows us to send no-cache
    headers for anything that carries the right beaconing key, and continue to
    send out the original cache control headers in other cases where downstream
    caching is enabled.
* Native fetcher: fortify handling of content length (and absense).
* Native fetcher: fail when the stream terminates before having
  completely parsed the headers.
* Tests: Rename `test_filter` -> `start_test` in ngx_system_test.sh for
  a test.
* Tests: Move blockingrewrite key to the http {} block.
* Tests: Update localhost -> 127.0.0.1. The native fetcher uses
  dns to resolve, and won't be able to retreive an ip for
  localhost.
* Tests: Allow outstanding proxy fetches some time to finish
  when running under valgrind, before terminating nginx.
* Valgrind: Add suppressions to make testing a release build pass.

This pull update was extra work because the valgrind and native fetcher flows
had rotted a bit.  We need to make sure to test them with every update.
2014-01-31 10:07:36 -05:00
Jeff Kaufman 64eaa2a659 Merge pull request #602 from tcpper/fix_ngx_fetch_content_length
fix bug in NgxFetch#content_length_
2014-01-30 11:25:52 -08:00
Jeff Kaufman 4783144e7d Merge branch 'master' into trunk-tracking 2014-01-24 16:56:26 -05:00
Jeff Kaufman 83205c9c31 Merge pull request #606 from pagespeed/oschaaf-multiple-experiment-cookies
Experiments: fix sending out multiple experiment cookies
2014-01-24 13:12:27 -08:00
Otto van der Schaaf 625e762961 Experiments: fix sending out multiple experiment cookies
Only classify people into an experiment when we are rewriting html.
Fixes https://github.com/pagespeed/ngx_pagespeed/issues/586
2014-01-24 22:09:31 +01:00
Jeff Kaufman c20affe323 Merge pull request #605 from pagespeed/oschaaf-date-header
Date header: use current date when we don't get one handed over
2014-01-24 08:47:00 -08:00
Otto van der Schaaf 7a9e6de802 Date header: use current date when we don't get one handed over
When the content generator does not supply us with a date header,
we need to create one ourselves and set it to the current date.

Fixes:
https://github.com/pagespeed/ngx_pagespeed/issues/604 (duplicate)
https://github.com/pagespeed/ngx_pagespeed/issues/577
2014-01-24 16:49:37 +01:00
Huibao Lin 96cf9a22f7 Update to 1.7.30.3 release 2014-01-16 18:37:36 -05:00
Jeff Kaufman ab83a70a35 Merge pull request #599 from eezis/docfix
Added a missing 'cd ~' command to the README
2014-01-16 13:30:44 -08:00
Ernest Ezis 658b2cf7a9 Added the missing 'cd ~' command to the '3. Download and build nginx:' section 2014-01-16 12:45:14 -07:00
Jeff Kaufman 092bbf2862 Merge pull request #597 from pagespeed/jefftk-update-trunk-tracking
trunk-tracking: update from r3696 to r3714
2014-01-16 07:18:31 -08:00
tcpper 6ccb815df3 fix bug in NgxFetch#content_length_ 2014-01-16 21:06:12 +08:00
Jeff Kaufman f04c533df0 trunk-tracking: update from r3696 to r3714
https://code.google.com/p/modpagespeed/source/detail?r=3697
 * system test improvements

https://code.google.com/p/modpagespeed/source/detail?r=3699
 * moved some config from location block to server block
 * system test improvements

https://code.google.com/p/modpagespeed/source/detail?r=3707
 * tests for OptimizeForBandwidth
   * had to switch tests from directory blocks to server+location blocks

https://code.google.com/p/modpagespeed/source/detail?r=3708
 * update to a test that had never been ported

* ngx_pagespeed.cc:
  * change in signature of FindIgnoreCase

https://code.google.com/p/modpagespeed/source/detail?r=3689
 * Was apparently skipped with #591.
2014-01-15 13:18:47 -05:00
Jeff Kaufman 8468e4849a Merge branch 'master' into trunk-tracking 2014-01-08 10:51:42 -05:00
Jeff Kaufman df5736609d native-fetcher: add support for FetchProxy
The native fetcher previously ignored FetchProxy settings; now it doesn't.

Squash-merge of tcpper's #590.
2014-01-08 10:51:24 -05:00
Jeff Kaufman 7fbb2c61ee readme: release 1.7.30.2 2014-01-06 16:51:41 -05:00
Jeff Kaufman af772c2fe8 Merge pull request #592 from pagespeed/jefftk-better-configure-error
config: point people to obj/autoconf.err when psol isn't detected
2014-01-03 03:33:47 -08:00
Jeff Kaufman a4bd9b9c13 config: point people to obj/autoconf.err when psol isn't detected by ./configure 2014-01-02 23:09:42 -05:00
Jeff Kaufman f87d0f7ae2 Merge pull request #591 from pagespeed/jud-trunk-tracking
Updates to trunk tracking branch.
2014-01-02 13:43:11 -08:00
Jud Porter 501742cb56 trunk-tracking: update from r3677 to r3696.
Add inline unauthorized resources test and fix rendered image dimensions test.
2014-01-02 16:42:10 -05:00
Jeff Kaufman a669be99b1 Merge branch 'master' into trunk-tracking 2014-01-02 16:25:23 -05:00
Jeff Kaufman 328d3afc9b Merge pull request #583 from pagespeed/jefftk-support-purge
native-fetcher: support non-GET request methods like PURGE
2013-12-20 07:11:55 -08:00
Jeff Kaufman 2681c24ee0 native-fetcher: fix to work with nginx 1.5.8+
nginx 1.5.8 changed the resolver api, which the native fetcher uses.

Fixes #578.

Squash-merge of @dinic's #581.
2013-12-19 12:46:53 -05:00
Jeff Kaufman f86f47fda4 native-fetcher: support non-GET request methods like PURGE 2013-12-19 11:38:46 -05:00
Jeff Kaufman 179c81afa3 test: don't run downstream caching test with native fetcher 2013-12-19 11:03:53 -05:00
Jeff Kaufman 8d7eb20c89 Merge pull request #575 from pagespeed/dec9-trunk-tracking-updates
Trunk tracking updates to sync to PSOl r3677.
2013-12-13 07:14:30 -08:00
Anupama Dutta 1fe6c54b94 Trunk tracking updates to sync to PSOl r3677.
Includes minor additions to test only.

Trunk tracking updates to sync to PSOl r3677.

Trunk tracking update to sync to PSOL r3677

Includes minor additions to test only.
2013-12-12 22:27:27 -05:00
Jeff Kaufman 1667879202 Merge pull request #571 from morlovich/morlovich-trunk-tracking-20131125
Trunk tracking update for up to r3646
2013-12-02 07:45:08 -08:00
Maks Orlovich 0076e45677 Port over ModPagespeed r3635: RespectXForwardedProto is vhost-scope 2013-11-27 12:59:47 -05:00
Jeff Kaufman 1f3560ea21 backport header-only fix
Was: trunk-tracking: update to r3632 from 1.7.30.1
2013-11-26 16:39:52 -05:00
Jeff Kaufman 54352bff72 trunk-tracking: update to r3632 from 1.7.30.1 2013-11-26 16:37:30 -05:00
Maks Orlovich 329985659c Fix flakey test
It doesn't make sense to fetch_until the uncombined URL and then
grep for combined one: you might just get entirely unoptimized
output and fail the test. Instead wait for the combining to happen,
and make sure it combined the right # of things.
2013-11-25 16:32:31 -05:00
Maks Orlovich db870f7023 Update to pagespeed_automatic.ca more symbols + symbol renaming
This make it possible to build w/o disabling SSL, makes us need
less extra .a + .cc files, but does mean that APR can't be used
directly (since it got renamed), so just use PosixTimer where it was
used.
2013-11-25 15:36:30 -05:00
Jeff Kaufman ed14455412 valgrind: unflake cache purging test
Fixes #569.
2013-11-25 14:38:24 -05:00
Jeff Kaufman be4d263d10 valgrind: suppressions file might not be in current directory 2013-11-25 10:23:25 -05:00
Jeff Kaufman 0bafd6b7e0 Merge pull request #565 from pagespeed/oschaaf-valgrind
Valgrind: Add an automated test
2013-11-25 07:03:33 -08:00
Otto van der Schaaf 9bbe912bd7 Valgrind: Add an automated test
This makes nginx run in the background under valgrind,
with both a master and a child process.
Valgrind errors will be redirected to `valgrind.log`.
When `USE_VALGRIND` is set, all system tests will be run under valgrind,
and at the end a new test is appended which ensures no valgrind errors
where encountered.

It is also worth noting that:
- There is a new file, `valgrind.sup`, which contains a few suppressions.
- Some tests behave flakey under valgrind. For now these are appended
  to the expected failures (when under valgrind only).
- 'Possibly lost' errors are all suppressed to get the amount of false
  positives manageable.
2013-11-21 21:26:15 +01:00
Jeff Kaufman b78eb8a939 Merge pull request #567 from pagespeed/oschaaf-304-timeout
system-tests: Test keepalive behaviour after a 304 response
2013-11-21 11:05:18 -08:00
Otto van der Schaaf e082a01912 system-tests: Test keepalive behaviour after a 304 response 2013-11-20 23:15:14 +01:00
Jeff Kaufman fa5815e1e8 Merge pull request #560 from pagespeed/jefftk-fix-messages
messages: unbreak /ngx_pagespeed_messages
2013-11-12 11:51:57 -08:00
Jeff Kaufman f12af2f03b messages: unbreak /ngx_pagespeed_messages
The shared circular buffer wasn't hooked up fully, which meant loading
/ngx_pagespeed_messages didn't work.  This fixes that and adds a test.

I also noticed while adding this that the 'Handling of large files' test
wasn't set up properly, so I converted that to use start_test.

Fixing that exposed another bug where the 'Handling of large files' test
was actually failing but being marked as an expected failure by being
grouped in with the test above.  Adding `pagespeed MaxHtmlParseBytes 5000`
to the appropriate location made it test what it was supposed to be testing
again, and the underlying feature wasn't broken.
2013-11-12 13:11:12 -05:00
Jeff Kaufman e22fae46bc readme: use release 2013-11-08 11:41:53 -05:00
Jeff Kaufman 53a599fbd4 readme: recommend tmpfs for file cache 2013-11-08 11:36:16 -05:00
43 changed files with 7641 additions and 3458 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
test/tmp test/tmp
psol/ psol/
psol-*.tar.gz psol-*.tar.gz
*.*.*.*.tar.gz
nginx
+18
View File
@@ -0,0 +1,18 @@
[submodule "testing-dependencies/mod_pagespeed"]
path = testing-dependencies/mod_pagespeed
url = https://github.com/pagespeed/mod_pagespeed.git
[submodule "testing-dependencies/ngx_cache_purge"]
path = testing-dependencies/ngx_cache_purge
url = https://github.com/FRiCKLE/ngx_cache_purge.git
[submodule "testing-dependencies/nginx"]
path = testing-dependencies/nginx
url = https://github.com/nginx/nginx.git
[submodule "testing-dependencies/set-misc-nginx-module"]
path = testing-dependencies/set-misc-nginx-module
url = https://github.com/openresty/set-misc-nginx-module
[submodule "testing-dependencies/ngx_devel_kit"]
path = testing-dependencies/ngx_devel_kit
url = https://github.com/simpl/ngx_devel_kit
[submodule "testing-dependencies/headers-more-nginx-module"]
path = testing-dependencies/headers-more-nginx-module
url = https://github.com/openresty/headers-more-nginx-module
+33
View File
@@ -0,0 +1,33 @@
language: c++
env:
global:
- MAKEFLAGS=-j3
# By default travis loads submodules serially, but we can load them in parallel
# if we install an updated git and use --jobs. Some timing numbers:
# serial: 257s
# jobs=4: 182s (29s to install new git, 153s to run the downloads)
# jobs=8: 179s (29s to install new git, 150s to run the downloads)
# We can't use --depth=1, though, because github doesn't have
# allowReachableSHA1InWant set.
#
# TODO(jefftk): once we're running on a server with git 2.8 or later we can have
# --jobs without installing a new git.
git:
submodules: false
before_install:
- sudo add-apt-repository --yes ppa:git-core/ppa
- sudo apt-get update
- sudo apt-get install git
- git submodule update --init --recursive --jobs=8
install:
scripts/build_ngx_pagespeed.sh --devel --assume-yes
script:
test/run_tests.sh $PWD/testing-dependencies/mod_pagespeed/ \
$PWD/nginx/sbin/nginx
dist: trusty
sudo: required
compiler:
- gcc
notifications:
email:
- pagespeed-ci@googlegroups.com
+4
View File
@@ -0,0 +1,4 @@
In a release this file would contain the URL to download the pre-compiled PSOL
binary, but on development branches (like this one) you have to build PSOL from
source yourself. See:
https://github.com/pagespeed/ngx_pagespeed/wiki/Building-PSOL-From-Source
+8 -101
View File
@@ -1,5 +1,7 @@
![ngx_pagespeed](https://lh6.googleusercontent.com/-qufedJIJq7Y/UXEvVYxyYvI/AAAAAAAADo8/JHDFQhs91_c/s401/04_ngx_pagespeed.png) ![ngx_pagespeed](https://lh6.googleusercontent.com/-qufedJIJq7Y/UXEvVYxyYvI/AAAAAAAADo8/JHDFQhs91_c/s401/04_ngx_pagespeed.png)
[![Build Status](https://travis-ci.org/pagespeed/ngx_pagespeed.svg?branch=master)](https://travis-ci.org/pagespeed/ngx_pagespeed)
ngx_pagespeed speeds up your site and reduces page load time by automatically ngx_pagespeed speeds up your site and reduces page load time by automatically
applying web performance best practices to pages and associated assets (CSS, applying web performance best practices to pages and associated assets (CSS,
JavaScript, images) without requiring you to modify your existing content or JavaScript, images) without requiring you to modify your existing content or
@@ -19,93 +21,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.3-beta.zip
$ unzip v1.7.30.3-beta.zip # or unzip v1.7.30.3-beta
$ cd ngx_pagespeed-1.7.30.3-beta/
$ wget https://dl.google.com/dl/page-speed/psol/1.7.30.3.tar.gz
$ tar -xzvf 1.7.30.3.tar.gz # expands to psol/
```
3. Download and build nginx:
```bash
$ # check http://nginx.org/en/download.html for the latest version
$ wget http://nginx.org/download/nginx-1.4.4.tar.gz
$ tar -xvzf nginx-1.4.4.tar.gz
$ cd nginx-1.4.4/
$ ./configure --add-module=$HOME/ngx_pagespeed-1.7.30.3-beta
$ make
$ sudo make install
```
If this doesn't work see the [build
troubleshooting](https://github.com/pagespeed/ngx_pagespeed/wiki/Build-Troubleshooting) page.
This will use a binary PageSpeed Optimization Library, but it's also possible to
[build PSOL from
source](https://github.com/pagespeed/ngx_pagespeed/wiki/Building-PSOL-From-Source).
Note: ngx_pagespeed currently doesn't support Windows or MacOS because the
underlying PSOL library doesn't.
## 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.3-...
```
Looking at the source of a few pages you should see various changes, such as
urls being replaced with new ones like `yellow.css.pagespeed.ce.lzJ8VcVi1l.css`.
For complete documentation, see [Using
PageSpeed](https://developers.google.com/speed/pagespeed/module/using).
There are extensive system tests which cover most of ngx_pagespeed's
functionality. Consider [testing your
installation](https://github.com/pagespeed/ngx_pagespeed/wiki/Testing).
For feedback, questions, and to follow For feedback, questions, and to follow
the progress of the project: the progress of the project:
@@ -114,20 +38,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;
```
+230 -62
View File
@@ -17,42 +17,40 @@
# PSOL_BINARY: absolute path to pagespeed_automatic.a # PSOL_BINARY: absolute path to pagespeed_automatic.a
mod_pagespeed_dir="${MOD_PAGESPEED_DIR:-unset}" mod_pagespeed_dir="${MOD_PAGESPEED_DIR:-unset}"
position_aux="${POSITION_AUX:-unset}"
if [ "$mod_pagespeed_dir" = "unset" ] ; then if [ "$mod_pagespeed_dir" = "unset" ] ; then
mod_pagespeed_dir="$ngx_addon_dir/psol/include" mod_pagespeed_dir="$ngx_addon_dir/psol/include"
build_from_source=false build_from_source=false
if [ ! -e "$mod_pagespeed_dir" ] ; then if [ ! -e "$mod_pagespeed_dir" ] ; then
echo "ngx_pagespeed: pagespeed optimization library not found:" echo "ngx_pagespeed: pagespeed optimization library not found:"
echo ""
echo " You need to separately download the pagespeed library:" psol_binary_url="$($ngx_addon_dir/scripts/format_binary_url.sh \
echo "" $ngx_addon_dir/PSOL_BINARY_URL)"
echo " $ cd /path/to/ngx_pagespeed" if [[ "$psol_binary_url" != https://* ]]; then
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.7.30.3.tar.gz" echo "
echo " $ tar -xzvf 1.7.30.3.tar.gz # expands to psol/" This is a development branch of ngx_pagespeed, which means there is no
echo "" precompiled PSOL library available to link against. Either build from a
echo " Or see the installation instructions:" release tag, like latest-beta, or build PSOL from source:
echo " https://github.com/pagespeed/ngx_pagespeed#how-to-build" https://github.com/pagespeed/ngx_pagespeed/wiki/Building-PSOL-From-Source"
exit 1 exit 1
fi fi
echo "
You need to separately download the pagespeed library:
$ cd $ngx_addon_dir
$ wget $psol_binary_url
$ tar -xzvf $(basename $psol_binary_url) # expands to psol/
Or see the installation instructions:
https://developers.google.com/speed/pagespeed/module/build_ngx_pagespeed_from_source"
exit 1
fi
else 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`
@@ -79,19 +77,39 @@ fi
if [ "$NGX_DEBUG" = "YES" ]; then if [ "$NGX_DEBUG" = "YES" ]; then
buildtype=Debug buildtype=Debug
# If we're using a psol tarball that doesn't contain Debug/ (which is the case
# from 1.12 onward) then this will be overriden to buildtype=Release below.
else else
buildtype=Release buildtype=Release
fi fi
# If the compiler is gcc, we want to use g++ to link, if at all possible,
# so that -static-libstdc++ works.
# Annoyingly, the feature test doesn't even use $LINK for linking, so that
# needs an explicit -lstdc++
pagespeed_libs=
ps_maybe_gpp_base=`basename $CC| sed s/gcc/g++/`
ps_maybe_gpp="`dirname $CC`/$ps_maybe_gpp_base"
if [ -n "$NGX_GCC_VER" -a \( -x "$ps_maybe_gpp" \) ]; then
LINK=$ps_maybe_gpp
fi
pagespeed_libs="-lstdc++"
# The compiler needs to know that __sync_add_and_fetch_4 is ok, # The compiler needs to know that __sync_add_and_fetch_4 is ok,
# and this requires an instruction that didn't exist on i586 or i386. # and this requires an instruction that didn't exist on i586 or i386.
if [ "$uname_arch" = "i686" ]; then 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" # For now, standardize on gcc-4.x ABI --- if we don't set this, people building
# with new gcc defaulting to gcc-5 C++11 ABI will have build trouble linking
# to our libpsol.a
# See https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
CFLAGS="$CFLAGS -D_GLIBCXX_USE_CXX11_ABI=0"
CC_OLD_TEST_FLAGS="$CC_TEST_FLAGS"
CC_TEST_FLAGS="$CC_TEST_FLAGS -D_GLIBCXX_USE_CXX11_ABI=0 --std=c++11"
case "$NGX_GCC_VER" in case "$NGX_GCC_VER" in
4.8*) 4.8*)
@@ -111,39 +129,79 @@ case "$NGX_GCC_VER" in
;; ;;
esac esac
# workaround for a bug in nginx-1.9.11, see:
# http://hg.nginx.org/nginx/rev/ff1e625ae55b
NGX_VERSION=`grep nginx_version src/core/nginx.h | sed -e 's/^.* \(.*\)$/\1/'`
if [ "$NGX_VERSION" = "1009011" ]; then
CFLAGS="$CFLAGS -Wno-write-strings"
fi
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/pagespeed/automatic/pagespeed_automatic.a"
else
if ! [ -d "$ngx_addon_dir/psol/lib/$buildtype" ]; then
echo "
You have set --with-debug for building nginx, but precompiled Debug binaries for
PSOL, which ngx_pagespeed depends on, aren't available. If you're trying to
debug PSOL you need to build it from source. If you just want to run nginx with
debug-level logging you can use the Release binaries."
echo -n "
Use the available Release binaries?"
read -p " [Y/n] " yn
if [[ "$yn" == N* || "$yn" == n* ]]; then
echo "Cancelled."
exit 1
fi
buildtype=Release
fi
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 \
$mod_pagespeed_dir/third_party/google-sparsehash/src \ $mod_pagespeed_dir/third_party/google-sparsehash/src/src \
$mod_pagespeed_dir/third_party/google-sparsehash/gen/arch/$os_name/$arch_name/include \ $mod_pagespeed_dir/third_party/google-sparsehash/gen/arch/$os_name/$arch_name/include \
$mod_pagespeed_dir/third_party/protobuf/src \ $mod_pagespeed_dir/third_party/grpc/src/include \
$mod_pagespeed_dir/third_party/protobuf/src/src \
$mod_pagespeed_dir/third_party/re2/src \ $mod_pagespeed_dir/third_party/re2/src \
$mod_pagespeed_dir/out/$buildtype/obj/gen \ $mod_pagespeed_dir/out/$buildtype/obj/gen \
$mod_pagespeed_dir/out/$buildtype/obj/gen/protoc_out/instaweb \ $mod_pagespeed_dir/out/$buildtype/obj/gen/protoc_out/instaweb \
$mod_pagespeed_dir/third_party/apr/src/include \ $mod_pagespeed_dir/third_party/apr/src/include \
$mod_pagespeed_dir/third_party/aprutil/src/include \ $mod_pagespeed_dir/third_party/aprutil/src/include \
$mod_pagespeed_dir/third_party/apr/gen/arch/$os_name/$arch_name/include \ $mod_pagespeed_dir/third_party/apr/gen/arch/$os_name/$arch_name/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 \
$mod_pagespeed_dir/url"
ngx_feature_path="$pagespeed_include" ngx_feature_path="$pagespeed_include"
if $build_from_source ; then pagespeed_libs="$psol_binary $pagespeed_libs -lrt -pthread -lm -luuid"
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;
net_instaweb::StringWriter write_to_string(&output_buffer); net_instaweb::StringWriter write_to_string(&output_buffer);
@@ -164,53 +222,163 @@ ngx_feature_test="
# Test whether we have pagespeed and can compile and link against it. # Test whether we have pagespeed and can compile and link against it.
. "$ngx_addon_dir/cpp_feature" . "$ngx_addon_dir/cpp_feature"
if [ $ngx_found = yes ]; then if [ $ngx_found = no ]; then
cat << END
$0: error: module ngx_pagespeed requires the pagespeed optimization library.
Look in $PWD/$NGX_AUTOCONF_ERR for more details.
END
exit 1
fi
ps_src="$ngx_addon_dir/src" ps_src="$ngx_addon_dir/src"
ngx_addon_name=ngx_pagespeed ngx_addon_name=ngx_pagespeed
NGX_ADDON_DEPS="$NGX_ADDON_DEPS \ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
$ps_src/log_message_handler.h \ $ps_src/log_message_handler.h \
$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_event_connection.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 \
NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ $psol_binary"
NPS_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_event_connection.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 \ # Save our sources in a separate var since we may need it in config.make
$mod_pagespeed_dir/out/$buildtype/obj/gen/data2c_out/instaweb/net/instaweb/apache/install/mod_pagespeed_example/mod_pagespeed_console_css_out.cc \ PS_NGX_SRCS="$NGX_ADDON_SRCS \
$mod_pagespeed_dir/out/$buildtype/obj/gen/data2c_out/instaweb/net/instaweb/apache/install/mod_pagespeed_example/mod_pagespeed_console_html_out.cc \ $NPS_SRCS"
$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 and Brotli.
HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES |\ if echo $HTTP_FILTER_MODULES | grep ngx_http_brotli_filter_module >/dev/null; then
sed "s/$HTTP_GZIP_FILTER_MODULE/$HTTP_GZIP_FILTER_MODULE $ngx_addon_name/") next=ngx_http_brotli_filter_module
# Make the etag header filter run immediately after gzip. elif [ $HTTP_GZIP = YES ]; then
HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES |\ next=ngx_http_gzip_filter_module
sed "s/$HTTP_GZIP_FILTER_MODULE/ngx_pagespeed_etag_filter $HTTP_GZIP_FILTER_MODULE/") else
next=ngx_http_range_header_filter_module
fi
if [ -n "$ngx_module_link" ]; then
# nginx-1.9.11+
ngx_module_type=HTTP_FILTER
ngx_module_name="ngx_pagespeed ngx_pagespeed_etag_filter"
ngx_module_incs="$ngx_feature_path"
ngx_module_deps=
ngx_module_srcs="$NPS_SRCS"
ngx_module_libs="$ngx_feature_libs"
ngx_module_order="ngx_http_range_header_filter_module\
ngx_pagespeed_etag_filter\
ngx_http_gzip_filter_module \
ngx_http_brotli_filter_module \
ngx_pagespeed \
ngx_http_postpone_filter_module \
ngx_http_ssi_filter_module \
ngx_http_charset_filter_module \
ngx_http_xslt_filter_module \
ngx_http_image_filter_module \
ngx_http_sub_filter_module \
ngx_http_addition_filter_module \
ngx_http_gunzip_filter_module \
ngx_http_userid_filter_module \
ngx_http_headers_filter_module"
. auto/module
if [ $ngx_module_link != DYNAMIC ]; then
# ngx_module_order doesn't work with static modules,
# so we must re-order filters here.
if [ "$position_aux" = "true" ] ; then
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
else
HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES \
| sed "s/ngx_pagespeed//" \
| sed "s/$next/$next ngx_pagespeed/")
fi
# Make the etag header filter run immediately before range header filter.
HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES \
| sed "s/ngx_pagespeed_etag_filter//" \
| sed "s/ngx_http_range_header_filter_module/ngx_http_range_header_filter_module ngx_pagespeed_etag_filter/")
else
if [ "$position_aux" = "true" ] ; then
ngx_module_type=HTTP_AUX_FILTER
ngx_module_order=""
fi
fi
else
CORE_LIBS="$CORE_LIBS $pagespeed_libs" CORE_LIBS="$CORE_LIBS $pagespeed_libs"
CORE_INCS="$CORE_INCS $pagespeed_include" CORE_INCS="$CORE_INCS $pagespeed_include"
NGX_ADDON_SRCS="$PS_NGX_SRCS"
if [ "$position_aux" = "true" ] ; then
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
else else
HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES | sed "s/$next/$next $ngx_addon_name/")
fi
# Make the etag header filter run immediately before range header filter.
HTTP_FILTER_MODULES=$(echo $HTTP_FILTER_MODULES |\
sed "s/ngx_http_range_header_filter_module/ngx_http_range_header_filter_module ngx_pagespeed_etag_filter/")
fi
echo "List of modules (in reverse order of applicability): "$HTTP_FILTER_MODULES
# Test whether the compiler is compatible
ngx_feature="psol-compiler-compat"
ngx_feature_name=""
ngx_feature_run=no
ngx_feature_incs=""
ngx_feature_path=""
ngx_feature_libs="-lstdc++"
ngx_feature_test="
#if defined(__clang__) && defined(__GLIBCXX__)
// See https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning
// for a list of various values of __GLIBCXX__. Note that they're not monotonic
// with respect to version numbers.
#if __GLIBCXX__ == 20120322 || __GLIBCXX__ == 20120614
#error \"clang is using libstdc++ 4.7.0 or 4.7.1, which can cause binary incompatibility.\"
#endif
#endif
#if !defined(__clang__) && defined(__GNUC__)
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
#error \"GCC < 4.8 no longer supported. Please use gcc >= 4.8 or clang >= 3.3\"
#endif
#endif
#if defined(__clang__)
#if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3)
#error \"Please use gcc >= 4.8 or clang >= 3.3\"
#endif
#endif
"
. "$ngx_addon_dir/cpp_feature"
if [ $ngx_found = no ]; then
cat << END cat << END
$0: error: module ngx_pagespeed requires the pagespeed optimization library $0: error: module ngx_pagespeed requires gcc >= 4.8 or clang >= 3.3.
See https://developers.google.com/speed/pagespeed/module/build_ngx_pagespeed_from_source for some recommendations.
Look in $PWD/$NGX_AUTOCONF_ERR for more details.
END END
exit 1 exit 1
fi fi
have=NGX_PAGESPEED . auto/have have=NGX_PAGESPEED . auto/have
CC_TEST_FLAGS="$CC_OLD_TEST_FLAGS"
+7
View File
@@ -0,0 +1,7 @@
# Since nginx build system doesn't normally do C++, there is no CXXFLAGS for us
# to touch, and compilers are understandably unhappy with --std=c++11 on C
# files. Hence, we hack the makefile to add it for just our sources.
for ps_src_file in $PS_NGX_SRCS; do
ps_obj_file="$NGX_OBJS/addon/src/`basename $ps_src_file .cc`.o"
echo "$ps_obj_file : CFLAGS += --std=c++11" >> $NGX_MAKEFILE
done
+808
View File
@@ -0,0 +1,808 @@
#!/bin/bash
#
# Copyright 2016 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.
function usage() {
echo "
Usage: build_ngx_pagespeed.sh [options]
Installs ngx_pagespeed and its dependencies. Can optionally build and install
nginx as well. Can be run either as:
bash <(curl -f -L -sS https://ngxpagespeed.com/install) [options]
Or:
git clone git@github.com:pagespeed/ngx_pagespeed.git
cd ngx_pagespeed/
git checkout <branch>
scripts/build_ngx_pagespeed.sh [options]
Options:
-v, --ngx-pagespeed-version <ngx_pagespeed version>
What version of ngx_pagespeed to build. Valid options include:
* latest-beta
* latest-stable
* a version number, such as 1.11.33.4
If you don't specify a version, defaults to latest-stable unless --devel
is specified, in which case it defaults to master.
This option doesn't make sense if we're running within an existing
ngx_pagespeed checkout.
-n, --nginx-version <nginx version>
What version of nginx to build. If not set, this script only prepares the
ngx_pagespeed module, and expects you to handle including it when you
build nginx.
If you pass in 'latest' then this script scrapes the nginx download page
and attempts to determine the latest version automatically.
-m, --dynamic-module
Build ngx_pagespeed as a dynamic module.
-b, --builddir <directory>
Where to build. Defaults to \$HOME.
-p, --no-deps-check
By default, this script checks for the packages it depends on and tries to
install them. If you have installed dependencies from source or are on a
non-deb non-rpm system, this won't work. In that case, install the
dependencies yourself and pass --no-deps-check.
-s, --psol-from-source
Build PSOL from source instead of downloading a pre-built binary module.
-l, --devel
Sets up a development environment in ngx_pagespeed/nginx, building with
testing-only dependencies. Includes --psol-from-source, conflicts with
--nginx-version. Uses a 'git clone' checkout for ngx_pagespeed and nginx
instead of downloading a tarball.
-t, --build-type
When building PSOL from source, what to tell it for BUILD_TYPE. Defaults
to 'Release' unless --devel is set in which case it defaults to 'Debug'.
-y, --assume-yes
Assume the answer to all prompts is 'yes, please continue'. Intended for
automated usage, such as buildbots.
-a, --additional-nginx-configure-arguments
When running ./configure for nginx, you may want to specify additional
arguments, such as --with-http_ssl_module. By default this script will
pause and prompt you for them, but this option lets you pass them in. For
example, you might do:
-a '--with-http_ssl_module --with-cc-opt=\"-I /usr/local/include\"'
-d, --dryrun
Don't make any changes to the system, just print what changes you
would have made.
-h, --help
Print this message and exit."
}
RED=31
GREEN=32
YELLOW=33
function begin_color() {
color="$1"
echo -e -n "\e[${color}m"
}
function end_color() {
echo -e -n "\e[0m"
}
function echo_color() {
color="$1"
shift
begin_color "$color"
echo "$@"
end_color
}
function error() {
local error_message="$@"
echo_color "$RED" -n "Error: " >&2
echo "$@" >&2
}
# Prints an error message and exits with an error code.
function fail() {
error "$@"
# Normally I'd use $0 in "usage" here, but since most people will be running
# this via curl, that wouldn't actually give something useful.
echo >&2
echo "For usage information, run this script with --help" >&2
exit 1
}
function status() {
echo_color "$GREEN" "$@"
}
# Intended to be called as:
# bash <(curl dl.google.com/.../build_ngx_pagespeed.sh) <args>
# If we set -e or -u then users of this script will see it silently exit on
# failure. Instead we need to check the exit status of each command manually.
# The run function handles exit-status checking for system-changing commands.
# Additionally, this allows us to easily have a dryrun mode where we don't
# actually make any changes.
INITIAL_ENV=$(printenv | sort)
function run() {
if "$DRYRUN"; then
echo_color "$YELLOW" -n "would run"
echo " $@"
env_differences=$(comm -13 <(echo "$INITIAL_ENV") <(printenv | sort))
if [ -n "$env_differences" ]; then
echo " with the following additional environment variables:"
echo "$env_differences" | sed 's/^/ /'
fi
else
if ! "$@"; then
error "Failure running '$@', exiting."
exit 1
fi
fi
}
function redhat_is_installed() {
local package_name="$1"
rpm -qa $package_name | grep -q .
}
function debian_is_installed() {
local package_name="$1"
dpkg -l $package_name | grep ^ii | grep -q .
}
function version_sort() {
# We'd rather use sort -V, but that's not available on Centos 5. This works
# for versions in the form A.B.C.D or shorter, which is enough for our use.
sort -t '.' -k 1,1 -k 2,2 -k 3,3 -k 4,4 -g
}
# Compare two numeric versions in the form "A.B.C". Works with version numbers
# having up to four components, since that's enough to handle both nginx (3) and
# ngx_pagespeed (4).
function version_older_than() {
local test_version="$1"
local compare_to="$2"
local older_version=$(echo $@ | tr ' ' '\n' | version_sort | head -n 1)
test "$older_version" != "$compare_to"
}
function determine_latest_nginx_version() {
# Scrape nginx's download page to try to find the most recent nginx version.
nginx_download_url="https://nginx.org/en/download.html"
function report_error() {
fail "
Couldn't automatically determine the latest nginx version: failed to $@
$nginx_download_url"
}
nginx_download_page=$(curl -sS --fail "$nginx_download_url") || \
report_error "download"
download_refs=$(echo "$nginx_download_page" | \
grep -o '/download/nginx-[0-9.]*[.]tar[.]gz') || \
report_error "parse"
versions_available=$(echo "$download_refs" | \
sed -e 's~^/download/nginx-~~' -e 's~\.tar\.gz$~~') || \
report_error "extract versions from"
latest_version=$(echo "$versions_available" | version_sort | tail -n 1) || \
report_error "determine latest version from"
if version_older_than "$latest_version" "1.11.4"; then
fail "
Expected the latest version of nginx to be at least 1.11.4 but found
$latest_version on $nginx_download_url"
fi
echo "$latest_version"
}
# Usage:
# install_dependencies install_pkg_cmd is_pkg_installed_cmd dep1 dep2 ...
#
# install_pkg_cmd is a command to install a dependency
# is_pkg_installed_cmd is a command that returns true if the dependency is
# already installed
# each dependency is a package name
function install_dependencies() {
local install_pkg_cmd="$1"
local is_pkg_installed_cmd="$2"
shift 2
local missing_dependencies=""
for package_name in "$@"; do
if ! $is_pkg_installed_cmd $package_name; then
missing_dependencies+="$package_name "
fi
done
if [ -n "$missing_dependencies" ]; then
status "Detected that we're missing the following depencencies:"
echo " $missing_dependencies"
status "Installing them:"
run sudo $install_pkg_cmd $missing_dependencies
fi
}
function gcc_too_old() {
# We need gcc >= 4.8
local gcc_major_version=$(gcc -dumpversion | awk -F. '{print $1}')
if [ "$gcc_major_version" -lt 4 ]; then
return 0 # too old
elif [ "$gcc_major_version" -gt 4 ]; then
return 1 # plenty new
fi
# It's gcc 4.x, check if x >= 8:
local gcc_minor_version=$(gcc -dumpversion | awk -F. '{print $2}')
test "$gcc_minor_version" -lt 8
}
function continue_or_exit() {
if "$ASSUME_YES"; then
return
fi
local prompt="$1"
echo_color "$YELLOW" -n "$prompt"
read -p " [Y/n] " yn
if [[ "$yn" == N* || "$yn" == n* ]]; then
echo "Cancelled."
exit 0
fi
}
# If a string is very simple we don't need to quote it. But we should quote
# everything else to be safe.
function needs_quoting() {
echo "$@" | grep -q '[^a-zA-Z0-9./_=-]'
}
function escape_for_quotes() {
echo "$@" | sed -e 's~\\~\\\\~g' -e "s~'~\\\\'~g"
}
function quote_arguments() {
local argument_str=""
for argument in "$@"; do
if [ -n "$argument_str" ]; then
argument_str+=" "
fi
if needs_quoting "$argument"; then
argument="'$(escape_for_quotes "$argument")'"
fi
argument_str+="$argument"
done
echo "$argument_str"
}
function build_ngx_pagespeed() {
getopt --test
if [ "$?" != 4 ]; then
# Even Centos 5 and Ubuntu 10 LTS have new-style getopt, so I don't expect
# this to be hit in practice on systems that are actually able to run
# PageSpeed.
fail "Your version of getopt is too old. Exiting with no changes made."
fi
opts=$(getopt -o v:n:mb:pslt:ya:dh \
--longoptions ngx-pagespeed-version:,nginx-version:,dynamic-module \
--longoptions buildir:,no-deps-check,psol-from-source,devel,build-type: \
--longoptions assume-yes,additional-nginx-configure-arguments:,dryrun,help \
-n "$(basename "$0")" -- "$@")
if [ $? != 0 ]; then
usage
exit 1
fi
eval set -- "$opts"
NPS_VERSION="DEFAULT"
NGINX_VERSION=""
BUILDDIR="$HOME"
DO_DEPS_CHECK=true
PSOL_FROM_SOURCE=false
DEVEL=false
BUILD_TYPE=""
ASSUME_YES=false
DRYRUN=false
DYNAMIC_MODULE=false
while true; do
case "$1" in
-v | --ngx-pagespeed-version) shift
NPS_VERSION="$1"
shift
;;
-n | --nginx-version) shift
NGINX_VERSION="$1"
shift
;;
-m | --dynamic-module) shift
DYNAMIC_MODULE=true
;;
-b | --builddir) shift
BUILDDIR="$1"
shift
;;
-p | --no-deps-check) shift
DO_DEPS_CHECK=false
;;
-s | --psol-from-source) shift
PSOL_FROM_SOURCE=true
;;
-l | --devel) shift
DEVEL=true
;;
-t | --build-type) shift
BUILD_TYPE="$1"
shift
;;
-y | --assume-yes) shift
ASSUME_YES="true"
;;
-a | --additional-nginx-configure-arguments) shift
ADDITIONAL_NGINX_CONFIGURE_ARGUMENTS="$1"
shift
;;
-d | --dryrun) shift
DRYRUN="true"
;;
-h | --help) shift
usage
exit 0
;;
--) shift
break
;;
*)
echo "Invalid argument: $1"
usage
exit 1
;;
esac
done
USE_GIT_CHECKOUT="$DEVEL"
ALREADY_CHECKED_OUT=false
if [ -e PSOL_BINARY_URL ]; then
status "Detected that we're running in an existing ngx_pagespeed checkout."
USE_GIT_CHECKOUT=true
ALREADY_CHECKED_OUT=true
fi
if "$ALREADY_CHECKED_OUT"; then
if [ "$NPS_VERSION" != "DEFAULT" ]; then
fail \
"The --ngx-pagespeed-version argument doesn't make sense when running within an existing checkout."
fi
elif [ "$NPS_VERSION" = "DEFAULT" ]; then
if "$DEVEL"; then
NPS_VERSION="master"
else
NPS_VERSION="latest-stable"
fi
fi
if [ ! -d "$BUILDDIR" ]; then
fail "Told to build in $BUILDDIR, but that directory doesn't exist."
fi
BUILD_NGINX=false
if [ -n "$NGINX_VERSION" ]; then
BUILD_NGINX=true
fi
if "$DEVEL"; then
PSOL_FROM_SOURCE=true
BUILD_NGINX=true
if [ -n "$NGINX_VERSION" ]; then
fail \
"The --devel argument conflicts with --nginx. In devel mode we use the version of nginx that's included as a submodule."
fi
if "$DYNAMIC_MODULE"; then
fail "Can't currently build a dynamic module in --devel mode."
fi
fi
if "$PSOL_FROM_SOURCE" && [ -z "$BUILD_TYPE" ]; then
if "$DEVEL"; then
BUILD_TYPE="Debug"
else
BUILD_TYPE="Release"
fi
elif [ -n "$BUILD_TYPE" ]; then
fail "Setting --build-type requires --psol-from-source or --devel."
fi
if [ "$NGINX_VERSION" = "latest" ]; then
# When this function fails it prints the debugging information needed first
# to stderr.
NGINX_VERSION=$(determine_latest_nginx_version) || exit 1
fi
if "$DYNAMIC_MODULE"; then
# Check that ngx_pagespeed and nginx are recent enough to support dynamic
# modules. Unfortunately NPS_VERSION might be a tag, in which case we don't
# know. If it's not a numeric version number, then assume it's recent
# enough and if it's not they'll get an ugly compilation error later.
# Luckily 1.10.33.5 was a while ago now.
#
# I'd like to use =~ here, but they changed syntax between v3 and v4 (quotes
# moved from mandatory to optional to prohibited).
if [[ "${NPS_VERSION#*[^0-9.]}" = "$NPS_VERSION" ]] &&
version_older_than "$NPS_VERSION" "1.10.33.5"; then
fail "
You're trying to build ngx_pagespeed $NPS_VERSION as a dynamic module, but
ngx_pagespeed didn't add support for dynamic modules until 1.10.33.5."
fi
if [ ! -z "NGINX_VERSION" ]; then
if version_older_than "$NGINX_VERSION" "1.9.13"; then
fail "
You're trying to build nginx $NGINX_VERSION as a dynamic module but nginx didn't
add support for dynamic modules in a way compatible with ngx_pagespeed until
1.9.13."
fi
fi
fi
if "$DRYRUN"; then
TEMPDIR="/tmp/output-of-mktemp"
else
TEMPDIR=$(mktemp -d)
function cleanup_tempdir {
rm -rf "$TEMPDIR"
}
trap cleanup_tempdir EXIT
fi
extra_flags=()
# Now make sure our dependencies are installed.
if "$DO_DEPS_CHECK"; then
if [ -f /etc/debian_version ]; then
status "Detected debian-based distro."
install_dependencies "apt-get install" debian_is_installed \
"build-essential zlib1g-dev libpcre3 libpcre3-dev unzip"
if gcc_too_old; then
if [ ! -e /usr/lib/gcc-mozilla/bin/gcc ]; then
status "Detected that gcc is older than 4.8. Installing gcc-mozilla"
status "which installs gcc-4.8 into /usr/lib/gcc-mozilla/ and doesn't"
status "affect your global gcc installation."
run sudo apt-get install gcc-mozilla
fi
extra_flags=("--with-cc=/usr/lib/gcc-mozilla/bin/gcc" \
"--with-ld-opt=-static-libstdc++")
fi
elif [ -f /etc/redhat-release ]; then
status "Detected redhat-based distro."
install_dependencies "yum install" redhat_is_installed \
"gcc-c++ pcre-devel zlib-devel make unzip wget"
if gcc_too_old; then
if [ ! -e /opt/rh/devtoolset-2/root/usr/bin/gcc ]; then
redhat_major_version=$(
cat /etc/redhat-release | grep -o -E '[0-9]+' | head -n 1)
if [ "$redhat_major_version" == 5 ]; then
slc_version=5
elif [ "$redhat_major_version" == 6 ]; then
slc_version=6
else
fail "
Unexpected major version $redhat_major_version in /etc/redhat-release:
$(cat /etc/redhat-release) Expected 5 or 6."
fi
status "Detected that gcc is older than 4.8. Scientific Linux"
status "provides a gcc package that installs gcc-4.8 into /opt/ and"
status "doesn't affect your global gcc installation."
slc_key="https://linux.web.cern.ch/linux/scientific6/docs/repository/"
slc_key+="cern/slc6X/i386/RPM-GPG-KEY-cern"
slc_key_out="$TEMPDIR/RPM-GPG-KEY-cern"
run sudo wget "$slc_key" -O "$slc_key_out"
run sudo rpm --import "$slc_key_out"
repo_fname="/etc/yum.repos.d/slc${slc_version}-devtoolset.repo"
if [ -e "$repo_fname" ]; then
fail "Expected $repo_fname not to exist; aborting."
fi
repo_url="https://linux.web.cern.ch/linux/scientific${slc_version}/"
repo_url+="/docs/repository/cern/devtoolset/"
repo_url+="slc${slc_version}-devtoolset.repo"
run sudo wget -O "$repo_fname" "$repo_url"
run sudo yum install devtoolset-2-gcc-c++ devtoolset-2-binutils
fi
extra_flags=("--with-cc=/opt/rh/devtoolset-2/root/usr/bin/gcc")
fi
else
fail "
This doesn't appear to be a deb-based distro or an rpm-based one. Not going to
be able to install dependencies. Please install dependencies manually and rerun
with --no-deps-check."
fi
status "Operating system dependencies are all set."
else
status "Not checking whether operating system dependencies are installed."
fi
function delete_if_already_exists() {
if "$DRYRUN"; then return; fi
local directory="$1"
if [ -d "$directory" ]; then
if [ ${#directory} -lt 8 ]; then
fail "
Not deleting $directory; name is suspiciously short. Something is wrong."
fi
continue_or_exit "OK to delete $directory?"
run rm -rf "$directory"
fi
}
# In general, the zip github builds for tag foo unzips to ngx_pagespeed-foo,
# but it looks like they special case vVERSION tags to ngx_pagespeed-VERSION
if [[ "$NPS_VERSION" =~ ^[0-9]*[.][0-9]*[.][0-9]*[.][0-9]*$ ]]; then
# We've been given a numeric version number. This has an associated tag
# in the form vVERSION-beta.
tag_name="v${NPS_VERSION}-beta"
nps_downloaded_fname="ngx_pagespeed-${NPS_VERSION}-beta"
else
# We've been given a tag name, like latest-beta. Download that directly.
tag_name="$NPS_VERSION"
nps_downloaded_fname="ngx_pagespeed-${NPS_VERSION}"
fi
install_dir="this-only-makes-sense-in-devel-mode"
if "$USE_GIT_CHECKOUT"; then
# We're either doing a --devel build, or someone is running us from an
# existing git checkout.
nps_module_dir="$PWD"
install_dir="$nps_module_dir"
if "$ALREADY_CHECKED_OUT"; then
run cd "$nps_module_dir"
else
status "Checking out ngx_pagespeed..."
run git clone "git@github.com:pagespeed/ngx_pagespeed.git" \
"$nps_module_dir"
run cd "$nps_module_dir"
run git checkout "$tag_name"
fi
submodules_dir="$nps_module_dir/testing-dependencies"
if "$DEVEL"; then
status "Downloading dependencies..."
run git submodule update --init --recursive
if [[ "$CONTINUOUS_INTEGRATION" != true ]]; then
status "Switching submodules over to git protocol."
# This lets us push to github by public key.
for config in $(find .git/ -name config) ; do
run sed -i s~https://github.com/~git@github.com:~ $config ;
done
fi
fi
else
nps_baseurl="https://github.com/pagespeed/ngx_pagespeed/archive"
nps_downloaded="$TEMPDIR/$nps_downloaded_fname.zip"
status "Downloading ngx_pagespeed..."
run wget "$nps_baseurl/$tag_name.zip" -O "$nps_downloaded"
nps_module_dir="$BUILDDIR/$nps_downloaded_fname"
delete_if_already_exists "$nps_module_dir"
status "Extracting ngx_pagespeed..."
run unzip -q "$nps_downloaded" -d "$BUILDDIR"
run cd "$nps_module_dir"
fi
MOD_PAGESPEED_DIR=""
PSOL_BINARY=""
if "$PSOL_FROM_SOURCE"; then
MOD_PAGESPEED_DIR="$PWD/testing-dependencies/mod_pagespeed"
git submodule update --init --recursive -- "$MOD_PAGESPEED_DIR"
run pushd "$MOD_PAGESPEED_DIR"
if "$DEVEL"; then
if [ ! -d "$HOME/apache2" ]; then
run install/build_development_apache.sh 2.2 prefork
fi
cd devel
run make apache_debug_psol
PSOL_BINARY="$MOD_PAGESPEED_DIR/out/$BUILD_TYPE/pagespeed_automatic.a"
else
run install/build_psol.sh --skip_tests --skip_packaging
PSOL_BINARY="$MOD_PAGESPEED_DIR/pagespeed/automatic/pagespeed_automatic.a"
fi
run popd
else
# Now we need to figure out what precompiled version of PSOL to build
# ngx_pagespeed against.
if "$DRYRUN"; then
psol_url="https://psol.example.com/cant-get-psol-version-in-dry-run.tar.gz"
elif [ -e PSOL_BINARY_URL ]; then
# Releases after 1.11.33.4 there is a PSOL_BINARY_URL file that tells us
# where to look.
psol_url="$(scripts/format_binary_url.sh PSOL_BINARY_URL)"
if [[ "$psol_url" != https://* ]]; then
fail "Got bad psol binary location information: $psol_url"
fi
else
# For past releases we have to grep it from the config file. The url has
# always looked like this, and the config file has contained it since
# before we started tagging our ngx_pagespeed releases.
psol_url="$(grep -o \
"https://dl.google.com/dl/page-speed/psol/[0-9.]*.tar.gz" config)"
if [ -z "$psol_url" ]; then
fail "Couldn't find PSOL url in $PWD/config"
fi
fi
status "Downloading PSOL binary..."
run wget "$psol_url"
status "Extracting PSOL..."
run tar -xzf $(basename "$psol_url") # extracts to psol/
fi
if "$DYNAMIC_MODULE"; then
add_module="--add-dynamic-module=$nps_module_dir"
else
add_module="--add-module=$nps_module_dir"
fi
configure_args=("$add_module" "${extra_flags[@]}")
if "$DEVEL"; then
configure_args=("${configure_args[@]}"
"--prefix=$install_dir/nginx"
"--add-module=$submodules_dir/ngx_cache_purge"
"--add-module=$submodules_dir/ngx_devel_kit"
"--add-module=$submodules_dir/set-misc-nginx-module"
"--add-module=$submodules_dir/headers-more-nginx-module"
"--with-ipv6"
"--with-http_v2_module")
if [ "$BUILD_TYPE" = "Debug" ]; then
configure_args=("${configure_args[@]}" "--with-debug")
fi
fi
echo
if ! "$BUILD_NGINX"; then
# Just prepare the module for them to install.
status "ngx_pagespeed is ready to be built against nginx."
echo "When running ./configure:"
if "$PSOL_FROM_SOURCE"; then
echo " Set the following environment variables:"
echo " MOD_PAGESPEED_DIR=$MOD_PAGESPEED_DIR"
echo " PSOL_BINARY=$PSOL_BINARY"
fi
echo " Give ./configure the following arguments:"
echo " $(quote_arguments "${configure_args[@]}")"
echo
if [ ${#extra_flags[@]} -eq 0 ]; then
echo "If this is for integration with an already-built nginx, make sure"
echo "to include any other arguments you originally passed to"
echo "./configure. You can see these with 'nginx -V'."
else
echo "Note: because we need to set $(quote_arguments "${extra_flags[@]}")"
echo "on this platform, if you want to integrate ngx_pagespeed with an"
echo "already-built nginx you're going to need to rebuild your nginx with"
echo "those flags set."
fi
else
if "$DEVEL"; then
# Use the nginx we loaded as a submodule
nginx_dir="$submodules_dir/nginx"
configure_location="auto"
else
# Download and build the specified nginx version.
nginx_leaf="nginx-${NGINX_VERSION}.tar.gz"
nginx_fname="$TEMPDIR/$nginx_leaf"
status "Downloading nginx..."
run wget "http://nginx.org/download/$nginx_leaf" -O "$nginx_fname"
nginx_dir="$BUILDDIR/nginx-${NGINX_VERSION}/"
delete_if_already_exists "$nginx_dir"
status "Extracting nginx..."
run tar -xzf "$nginx_fname" --directory "$BUILDDIR"
configure_location="."
fi
run cd "$nginx_dir"
configure=("$configure_location/configure" "${configure_args[@]}")
additional_configure_args=""
if [ -z "${ADDITIONAL_NGINX_CONFIGURE_ARGUMENTS+x}" ]; then
if ! "$ASSUME_YES"; then
echo "About to build nginx. Do you have any additional ./configure"
echo "arguments you would like to set? For example, if you would like"
echo "to build nginx with https support give --with-http_ssl_module"
echo "If you don't have any, just press enter."
read -p "> " additional_configure_args
fi
else
additional_configure_args="$ADDITIONAL_NGINX_CONFIGURE_ARGUMENTS"
fi
if [ -n "$additional_configure_args" ]; then
# Split additional_configure_args respecting any internal quotation.
# Otherwise things like --with-cc-opt='-foo -bar' won't work.
eval additional_configure_args=("$additional_configure_args")
configure=("${configure[@]}" "${additional_configure_args[@]}")
fi
echo "About to configure nginx with:"
echo " $(quote_arguments "${configure[@]}")"
continue_or_exit "Does this look right?"
MOD_PAGESPEED_DIR="$MOD_PAGESPEED_DIR" \
PSOL_BINARY="$PSOL_BINARY" \
run "${configure[@]}"
if ! "$DEVEL"; then
continue_or_exit "Build nginx?"
fi
run make
if "$DEVEL"; then
run make install
status "Nginx installed with ngx_pagespeed, and set up for development."
echo "To run tests:"
echo " cd $nps_module_dir"
echo " test/run_tests.sh"
echo
echo "To rebuild after changes:"
echo " scripts/rebuild.sh"
else
continue_or_exit "Install nginx?"
run sudo make install
echo
if "$DYNAMIC_MODULE"; then
echo "Nginx installed with ngx_pagespeed support available as a"
echo "loadable module."
echo
echo "To load the ngx_pagespeed module, you'll need to add:"
echo " load_module \"modules/ngx_pagespeed.so\";"
echo "at the top of your main nginx configuration file."
else
echo "Nginx installed with ngx_pagespeed support compiled-in."
fi
echo
echo "If this is a new installation you probably need an init script to"
echo "manage starting and stopping the nginx service. See:"
echo " http://wiki.nginx.org/InitScripts"
echo
echo "You'll also need to configure ngx_pagespeed if you haven't yet:"
echo " https://developers.google.com/speed/pagespeed/module/configuration"
fi
fi
if "$DRYRUN"; then
echo_color "$YELLOW" "[this was a dry run; your system is unchanged]"
fi
}
# Start running things from a call at the end so if this script is executed
# after a partial download it doesn't do anything.
build_ngx_pagespeed "$@"
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
#
# Copyright 2016 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.
set -e
set -u
if [ $# -ne 1 ]; then
echo "Usage: $(basename $0) <url_file>" >&2
exit 1
fi
url_file=$1
if [ ! -e "$url_file" ]; then
echo "Url file '$url_file' missing!" >&2
fi
# The size names must match install/build_psol.sh in mod_pagespeed
if [ "$(uname -m)" = x86_64 ]; then
bit_size_name=x64
else
bit_size_name=ia32
fi
sed -e 's/$BIT_SIZE_NAME\b/'$bit_size_name'/g' $url_file
+16 -2
View File
@@ -1,5 +1,19 @@
#!/bin/bash #!/bin/bash
# #
# 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.
#
# Converts pagespeed_libraries.conf from Apache-format to Nginx-format, # Converts pagespeed_libraries.conf from Apache-format to Nginx-format,
# supporting the canonicalize_javascript_libraries filter. # supporting the canonicalize_javascript_libraries filter.
# Inspired by https://github.com/pagespeed/ngx_pagespeed/issues/532 # Inspired by https://github.com/pagespeed/ngx_pagespeed/issues/532
@@ -13,9 +27,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;"
-94
View File
@@ -1,94 +0,0 @@
#!/bin/bash
#
# Copyright 2012 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: jefftk@google.com (Jeff Kaufman)
#
# Usage:
# scripts/prepare_psol.sh /path/to/mod_pagespeed/src
#
# Creates a directory psol/ and copies headers and a few source files from a
# depot_tools (glient) checkout into psol/include. Along with creating
# binaries, this is a step in preparing psol.tar.gz for distribution.
#
set -u # check for undefined variables
set -e # exit on failed commands
if [ "$(basename "$PWD")" != "ngx_pagespeed" ] ; then
echo "$(basename $0) must be invoked from the ngx_pagespeed directory"
exit 1
fi
if [ $# -ne 1 ] ; then
echo "Usage: $(basename $0) /path/to/mod_pagespeed/src"
exit 1
fi
MOD_PAGESPEED_SRC="$1"
if [ "$(basename "$(dirname "$MOD_PAGESPEED_SRC")")/$( \
basename "$MOD_PAGESPEED_SRC")" != "mod_pagespeed/src" ] ; then
echo "Usage: $(basename $0) /path/to/mod_pagespeed/src"
exit 1
fi
if [ -e psol ] ; then
echo "A psol/ directory already exists. Move it somewhere else and rerun."
exit 1
fi
mkdir psol/
# Copy over the .h files, plus a few selected .cc and .c files.
rsync -arvz "$MOD_PAGESPEED_SRC/" "psol/include/" --prune-empty-dirs \
--exclude=".svn" \
--exclude=".git" \
--include='*.h' \
--include='*/' \
--include="apr_thread_compatible_pool.cc" \
--include="serf_url_async_fetcher.cc" \
--include="apr_mem_cache.cc" \
--include="key_value_codec.cc" \
--include="apr_memcache2.c" \
--include="loopback_route_fetcher.cc" \
--include="add_headers_fetcher.cc" \
--include="console_css_out.cc" \
--include="console_out.cc" \
--include="dense_hash_map" \
--include="dense_hash_set" \
--include="sparse_hash_map" \
--include="sparse_hash_set" \
--include="sparsetable" \
--include="mod_pagespeed_console_out.cc" \
--include="mod_pagespeed_console_css_out.cc" \
--include="mod_pagespeed_console_html_out.cc" \
--exclude='*'
mkdir -p psol/lib/Debug/linux/ia32
mkdir -p psol/lib/Debug/linux/x64
mkdir -p psol/lib/Release/linux/ia32
mkdir -p psol/lib/Release/linux/x64
# Log that we did this.
SVN_REVISION="$(svn info $MOD_PAGESPEED_SRC | grep Revision | awk '{print $2}')"
SVN_TAG="$(svn info $MOD_PAGESPEED_SRC | grep URL | awk -F/ '{print $(NF-1)}')"
DATE="$(date +%F)"
echo "${DATE}: Copied from mod_pagespeed ${SVN_TAG}@r${SVN_REVISION} ($USER)" \
>> psol/include_history.txt
echo
echo "Output is in psol/include. Now put binaries in psol/lib following"
echo "https://github.com/pagespeed/ngx_pagespeed/wiki/Building-Release-Binaries"
echo "and then you can distribute PSOL."
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
#
# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Usage: scripts/rebuild.sh
#
# After building with "scripts/build_ngx_pagespeed.sh --devel", if you make
# changes to ngx_pagespeed you'll need to rebuild it. The underlying commands
# aren't complicated, but it's faster to work if it's automated.
set -e # exit script if any command returns an error
set -u # exit the script if any variable is uninitialized
this_dir="$(dirname $0)"
cd "$this_dir/.."
nps_dir="$PWD"
cd "$nps_dir/testing-dependencies/mod_pagespeed/devel"
make apache_debug_psol
cd "$nps_dir/testing-dependencies/nginx/"
make
make install
+5 -5
View File
@@ -29,7 +29,7 @@
#include "base/debug/stack_trace.h" #include "base/debug/stack_trace.h"
#include "base/logging.h" #include "base/logging.h"
#include "net/instaweb/public/version.h" #include "net/instaweb/public/version.h"
#include "net/instaweb/util/public/string_util.h" #include "pagespeed/kernel/base/string_util.h"
// Make sure we don't attempt to use LOG macros here, since doing so // Make sure we don't attempt to use LOG macros here, since doing so
// would cause us to go into an infinite log loop. // would cause us to go into an infinite log loop.
@@ -38,7 +38,7 @@
namespace { namespace {
ngx_log_t* log = NULL; ngx_log_t* ngx_log = NULL;
ngx_uint_t GetNgxLogLevel(int severity) { ngx_uint_t GetNgxLogLevel(int severity) {
switch (severity) { switch (severity) {
@@ -78,7 +78,7 @@ bool LogMessageHandler(int severity, const char* file, int line,
message.resize(last_msg_character_index); message.resize(last_msg_character_index);
} }
ngx_log_error(this_log_level, log, 0, "[ngx_pagespeed %s] %s", ngx_log_error(this_log_level, ngx_log, 0, "[ngx_pagespeed %s] %s",
net_instaweb::kModPagespeedVersion, net_instaweb::kModPagespeedVersion,
message.c_str()); message.c_str());
@@ -99,12 +99,12 @@ namespace log_message_handler {
void Install(ngx_log_t* log_in) { void Install(ngx_log_t* log_in) {
log = log_in; ngx_log = log_in;
logging::SetLogMessageHandler(&LogMessageHandler); logging::SetLogMessageHandler(&LogMessageHandler);
// All VLOG(2) and higher will be displayed as DEBUG logs if the nginx log // All VLOG(2) and higher will be displayed as DEBUG logs if the nginx log
// level is DEBUG. // level is DEBUG.
if (log->log_level >= NGX_LOG_DEBUG) { if (ngx_log->log_level >= NGX_LOG_DEBUG) {
logging::SetMinLogLevel(-2); logging::SetMinLogLevel(-2);
} }
} }
+223 -43
View File
@@ -12,40 +12,193 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*
* Author: jefftk@google.com (Jeff Kaufman)
*/ */
// Author: jefftk@google.com (Jeff Kaufman) #include "ngx_pagespeed.h" // Must come first, see comments in CollectHeaders.
#include <unistd.h> //for usleep
#include "ngx_base_fetch.h" #include "ngx_base_fetch.h"
#include "ngx_event_connection.h"
#include "ngx_list_iterator.h" #include "ngx_list_iterator.h"
#include "ngx_pagespeed.h" #include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/http/public/response_headers.h"
#include "net/instaweb/rewriter/public/rewrite_stats.h" #include "net/instaweb/rewriter/public/rewrite_stats.h"
#include "net/instaweb/util/public/google_message_handler.h" #include "pagespeed/kernel/base/google_message_handler.h"
#include "net/instaweb/util/public/message_handler.h" #include "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/posix_timer.h"
#include "pagespeed/kernel/http/response_headers.h"
namespace net_instaweb { namespace net_instaweb {
NgxBaseFetch::NgxBaseFetch(ngx_http_request_t* r, int pipe_fd, const char kHeadersComplete = 'H';
const char kFlush = 'F';
const char kDone = 'D';
NgxEventConnection* NgxBaseFetch::event_connection = NULL;
int NgxBaseFetch::active_base_fetches = 0;
NgxBaseFetch::NgxBaseFetch(StringPiece url,
ngx_http_request_t* r,
NgxServerContext* server_context, NgxServerContext* server_context,
const RequestContextPtr& request_ctx, const RequestContextPtr& request_ctx,
PreserveCachingHeaders preserve_caching_headers) PreserveCachingHeaders preserve_caching_headers,
NgxBaseFetchType base_fetch_type,
const RewriteOptions* options)
: AsyncFetch(request_ctx), : AsyncFetch(request_ctx),
url_(url.data(), url.size()),
request_(r), request_(r),
server_context_(server_context), server_context_(server_context),
options_(options),
need_flush_(false),
done_called_(false), done_called_(false),
last_buf_sent_(false), last_buf_sent_(false),
pipe_fd_(pipe_fd),
references_(2), references_(2),
handle_error_(true), base_fetch_type_(base_fetch_type),
preserve_caching_headers_(preserve_caching_headers) { preserve_caching_headers_(preserve_caching_headers),
detached_(false),
suppress_(false) {
if (pthread_mutex_init(&mutex_, NULL)) CHECK(0); if (pthread_mutex_init(&mutex_, NULL)) CHECK(0);
__sync_add_and_fetch(&NgxBaseFetch::active_base_fetches, 1);
} }
NgxBaseFetch::~NgxBaseFetch() { NgxBaseFetch::~NgxBaseFetch() {
pthread_mutex_destroy(&mutex_); pthread_mutex_destroy(&mutex_);
__sync_add_and_fetch(&NgxBaseFetch::active_base_fetches, -1);
}
bool NgxBaseFetch::Initialize(ngx_cycle_t* cycle) {
CHECK(event_connection == NULL) << "event connection already set";
event_connection = new NgxEventConnection(ReadCallback);
return event_connection->Init(cycle);
}
void NgxBaseFetch::Terminate() {
if (event_connection != NULL) {
GoogleMessageHandler handler;
PosixTimer timer;
int64 timeout_us = Timer::kSecondUs * 30;
int64 end_us = timer.NowUs() + timeout_us;
static unsigned int sleep_microseconds = 100;
handler.Message(
kInfo,"NgxBaseFetch::Terminate rounding up %d active base fetches.",
NgxBaseFetch::active_base_fetches);
// Try to continue processing and get the active base fetch count to 0
// untill the timeout expires.
// TODO(oschaaf): This needs more work.
while (NgxBaseFetch::active_base_fetches > 0 && end_us > timer.NowUs()) {
event_connection->Drain();
usleep(sleep_microseconds);
}
if (NgxBaseFetch::active_base_fetches != 0) {
handler.Message(
kWarning,"NgxBaseFetch::Terminate timed out with %d active base fetches.",
NgxBaseFetch::active_base_fetches);
}
// Close down the named pipe.
event_connection->Shutdown();
delete event_connection;
event_connection = NULL;
}
}
const char* BaseFetchTypeToCStr(NgxBaseFetchType type) {
switch(type) {
case kPageSpeedResource:
return "ps resource";
case kHtmlTransform:
return "html transform";
case kAdminPage:
return "admin page";
case kIproLookup:
return "ipro lookup";
case kPageSpeedProxy:
return "pagespeed proxy";
}
CHECK(false);
return "can't get here";
}
// TODO(oschaaf): replace the ngx_log_error with VLOGS or pass in a
// MessageHandler and use that.
void NgxBaseFetch::ReadCallback(const ps_event_data& data) {
NgxBaseFetch* base_fetch = reinterpret_cast<NgxBaseFetch*>(data.sender);
ngx_http_request_t* r = base_fetch->request();
bool detached = base_fetch->detached();
#if (NGX_DEBUG) // `type` is unused if NGX_DEBUG isn't set, needed for -Werror.
const char* type = BaseFetchTypeToCStr(base_fetch->base_fetch_type_);
#endif
int refcount = base_fetch->DecrementRefCount();
#if (NGX_DEBUG)
ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0,
"pagespeed [%p] event: %c. bf:%p (%s) - refcnt:%d - det: %c", r,
data.type, base_fetch, type, refcount, detached ? 'Y': 'N');
#endif
// If we ended up destructing the base fetch, or the request context is
// detached, skip this event.
if (refcount == 0 || detached) {
return;
}
ps_request_ctx_t* ctx = ps_get_request_context(r);
// If our request context was zeroed, skip this event.
// See https://github.com/pagespeed/ngx_pagespeed/issues/1081
if (ctx == NULL) {
// Should not happen normally, when it does this message will cause our
// system tests to fail.
ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0,
"pagespeed [%p] skipping event: request context gone", r);
return;
}
// Normally we expect the sender to equal the active NgxBaseFetch instance.
DCHECK(data.sender == ctx->base_fetch);
// If someone changed our request context or NgxBaseFetch, skip processing.
if (data.sender != ctx->base_fetch) {
ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0,
"pagespeed [%p] skipping event: event originating from disassociated"
" NgxBaseFetch instance.", r);
return;
}
int rc;
bool run_posted = true;
// If we are unlucky enough to have our connection finalized mid-ipro-lookup,
// we must enter a different flow. Also see ps_in_place_check_header_filter().
if ((ctx->base_fetch->base_fetch_type_ != kIproLookup)
&& r->connection->error) {
ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0,
"pagespeed [%p] request already finalized %d", r, r->count);
rc = NGX_ERROR;
run_posted = false;
} else {
rc = ps_base_fetch::ps_base_fetch_handler(r);
}
#if (NGX_DEBUG)
ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0,
"pagespeed [%p] ps_base_fetch_handler() returned %d for %c",
r, rc, data.type);
#endif
ngx_connection_t* c = r->connection;
ngx_http_finalize_request(r, rc);
if (run_posted) {
// See http://forum.nginx.org/read.php?2,253006,253061
ngx_http_run_posted_requests(c);
}
} }
void NgxBaseFetch::Lock() { void NgxBaseFetch::Lock() {
@@ -75,8 +228,11 @@ ngx_int_t NgxBaseFetch::CopyBufferToNginx(ngx_chain_t** link_ptr) {
return NGX_AGAIN; return NGX_AGAIN;
} }
int rc = string_piece_to_buffer_chain( int rc = string_piece_to_buffer_chain(request_->pool, buffer_, link_ptr,
request_->pool, buffer_, link_ptr, done_called_ /* send_last_buf */); done_called_ /* send_last_buf */,
need_flush_);
need_flush_ = false;
if (rc != NGX_OK) { if (rc != NGX_OK) {
return rc; return rc;
} }
@@ -104,33 +260,37 @@ 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) {
// nginx defines _FILE_OFFSET_BITS to 64, which changes the size of off_t.
// If a standard header is accidentally included before the nginx header,
// on a 32-bit system off_t will be 4 bytes and we don't assign all the
// bits of content_length_n. Sanity check that did not happen.
// This could use static_assert, but this file is not built with --std=c++11.
bool sanity_check_off_t[sizeof(off_t) == 8 ? 1 : -1] __attribute__ ((unused));
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_);
} }
void NgxBaseFetch::RequestCollection() { void NgxBaseFetch::RequestCollection(char type) {
int rc; if (suppress_) {
char c = 'A'; // What byte we write is arbitrary. return;
while (true) {
rc = write(pipe_fd_, &c, 1);
if (rc == 1) {
break;
} else if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
// TODO(jefftk): is this rare enough that spinning isn't a problem? Could
// we get into a case where the pipe fills up and we spin forever?
} else {
perror("NgxBaseFetch::RequestCollection");
break;
} }
// We must optimistically increment the refcount, and decrement it
// when we conclude we failed. If we only increment on a successfull write,
// there's a small chance that between writing and adding to the refcount
// both pagespeed and nginx will release their refcount -- destructing
// this NgxBaseFetch instance.
IncrementRefCount();
if (!event_connection->WriteEvent(type, this)) {
DecrementRefCount();
} }
} }
@@ -138,43 +298,63 @@ 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 ((base_fetch_type_ != kIproLookup) || 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. RequestCollection(kHeadersComplete); // Headers available.
// For the IPRO lookup, supress notification of the nginx side here.
// If we send both the headerscomplete 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.
if (base_fetch_type_ == kIproLookup && !status_ok) {
suppress_ = true;
}
} }
bool NgxBaseFetch::HandleFlush(MessageHandler* handler) { bool NgxBaseFetch::HandleFlush(MessageHandler* handler) {
RequestCollection(); // A new part of the response body is available. Lock();
need_flush_ = true;
Unlock();
RequestCollection(kFlush); // A new part of the response body is available
return true; return true;
} }
void NgxBaseFetch::Release() { int NgxBaseFetch::DecrementRefCount() {
DecrefAndDeleteIfUnreferenced(); return DecrefAndDeleteIfUnreferenced();
} }
void NgxBaseFetch::DecrefAndDeleteIfUnreferenced() { int NgxBaseFetch::IncrementRefCount() {
return __sync_add_and_fetch(&references_, 1);
}
int NgxBaseFetch::DecrefAndDeleteIfUnreferenced() {
// Creates a full memory barrier. // Creates a full memory barrier.
if (__sync_add_and_fetch(&references_, -1) == 0) { int r = __sync_add_and_fetch(&references_, -1);
if (r == 0) {
delete this; delete this;
} }
return r;
} }
void NgxBaseFetch::HandleDone(bool success) { void NgxBaseFetch::HandleDone(bool success) {
// TODO(jefftk): it's possible that instead of locking here we can just modify // TODO(jefftk): it's possible that instead of locking here we can just modify
// CopyBufferToNginx to only read done_called_ once. // CopyBufferToNginx to only read done_called_ once.
CHECK(!done_called_) << "Done already called!";
Lock(); Lock();
done_called_ = true; done_called_ = true;
Unlock(); Unlock();
RequestCollection(kDone);
close(pipe_fd_); // Indicates to nginx that we're done with the rewrite.
pipe_fd_ = -1;
DecrefAndDeleteIfUnreferenced(); DecrefAndDeleteIfUnreferenced();
} }
bool NgxBaseFetch::IsCachedResultValid(const ResponseHeaders& headers) {
return OptionsAwareHTTPCacheCallback::IsCacheValid(
url_, *options_, request_context(), headers);
}
} // namespace net_instaweb } // namespace net_instaweb
+86 -22
View File
@@ -17,22 +17,35 @@
// Author: jefftk@google.com (Jeff Kaufman) // Author: jefftk@google.com (Jeff Kaufman)
// //
// Collects output from pagespeed and buffers it until nginx asks for it. // Collects output from pagespeed and buffers it until nginx asks for it.
// Notifies nginx via pipe to call CollectAccumulatedWrites() on flush. // Notifies nginx via NgxEventConnection to call ReadCallback() when
// the headers are computed, when a flush should be performed, and when done.
// //
// - nginx creates a base fetch and passes it to a new proxy fetch. // - nginx creates a base fetch and passes it to a new proxy fetch.
// - The proxy fetch manages rewriting and thread complexity, and through // - The proxy fetch manages rewriting and thread complexity, and through
// several chained steps passes rewritten html to HandleWrite(). // several chained steps passes rewritten html to HandleWrite().
// - Written data is buffered. // - Written data is buffered.
// - When Flush() is called the base fetch writes a byte to a pipe nginx is // - When HandleHeadersComplete(), HandleFlush(), or HandleDone() is called by
// watching so nginx knows to call CollectAccumulatedWrites() to pick up the // PSOL, events are written to NgxEventConnection which will end up being
// rewritten html. // handled by ReadCallback() on nginx's thread.
// - When Done() is called the base fetch closes the pipe, which tells nginx to // When applicable, request processing will be continued via a call to
// make a final call to CollectAccumulatedWrites(). // ps_base_fetch_handler().
// - ps_base_fetch_handler() will pull the header and body bytes from PSOL
// via CollectAccumulatedWrites() and write those to the module's output.
// //
// This class is referred two in two places: the proxy fetch and nginx's // This class is referred to in three places: the proxy fetch, nginx's request,
// request. It must stay alive until both are finished. The proxy fetch will // and pending events written to the associated NgxEventConnection. It must stay
// call Done() to indicate this; nginx will call Release(). Once both Done() // alive until the proxy fetch and nginx request are finished, and no more
// and Release() have been called this class will delete itself. // events are pending.
// - The proxy fetch will call Done() to indicate this.
// - nginx will call Detach() when the associated request is handled
// completely (e.g. the request context is about to be destroyed).
// - ReadCallback() will call DecrementRefCount() on instances associated to
// events it handles.
//
// When the last reference is dropped, this class will delete itself.
//
// TODO(jmarantz): consider sharing the cache-invalidation infrastructure
// with ApacheFetch, using a common base class.
#ifndef NGX_BASE_FETCH_H_ #ifndef NGX_BASE_FETCH_H_
#define NGX_BASE_FETCH_H_ #define NGX_BASE_FETCH_H_
@@ -45,22 +58,46 @@ extern "C" {
#include "ngx_pagespeed.h" #include "ngx_pagespeed.h"
#include "ngx_event_connection.h"
#include "ngx_server_context.h" #include "ngx_server_context.h"
#include "net/instaweb/http/public/async_fetch.h" #include "net/instaweb/http/public/async_fetch.h"
#include "net/instaweb/http/public/headers.h" #include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/util/public/string.h" #include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/http/headers.h"
namespace net_instaweb { namespace net_instaweb {
enum NgxBaseFetchType {
kIproLookup,
kHtmlTransform,
kPageSpeedResource,
kAdminPage,
kPageSpeedProxy
};
class NgxBaseFetch : public AsyncFetch { class NgxBaseFetch : public AsyncFetch {
public: public:
NgxBaseFetch(ngx_http_request_t* r, int pipe_fd, NgxBaseFetch(StringPiece url, ngx_http_request_t* r,
NgxServerContext* server_context, NgxServerContext* server_context,
const RequestContextPtr& request_ctx, const RequestContextPtr& request_ctx,
PreserveCachingHeaders preserve_caching_headers); PreserveCachingHeaders preserve_caching_headers,
NgxBaseFetchType base_fetch_type,
const RewriteOptions* options);
virtual ~NgxBaseFetch(); virtual ~NgxBaseFetch();
// Statically initializes event_connection, require for PSOL and nginx to
// communicate.
static bool Initialize(ngx_cycle_t* cycle);
// Attempts to finish up request processing queued up in the named pipe and
// PSOL for a fixed amount of time. If time is up, a fast and rough shutdown
// is attempted.
// Statically terminates and NULLS event_connection.
static void Terminate();
static void ReadCallback(const ps_event_data& data);
// Puts a chain in link_ptr if we have any output data buffered. Returns // Puts a chain in link_ptr if we have any output data buffered. Returns
// NGX_OK on success, NGX_ERROR on errors. If there's no data to send, sends // NGX_OK on success, NGX_ERROR on errors. If there's no data to send, sends
// data only if Done() has been called. Indicates the end of output by // data only if Done() has been called. Indicates the end of output by
@@ -77,9 +114,24 @@ class NgxBaseFetch : public AsyncFetch {
// time for resource fetches. Not called at all for proxy fetches. // time for resource fetches. Not called at all for proxy fetches.
ngx_int_t CollectHeaders(ngx_http_headers_out_t* headers_out); ngx_int_t CollectHeaders(ngx_http_headers_out_t* headers_out);
// Called by nginx when it's done with us. // Called by nginx to decrement the refcount.
void Release(); int DecrementRefCount();
void set_handle_error(bool x) { handle_error_ = x; }
// Called by pagespeed to increment the refcount.
int IncrementRefCount();
// Detach() is called when the nginx side releases this base fetch. It
// sets detached_ to true and decrements the refcount. We need to know
// this to be able to handle events which nginx request context has been
// released while the event was in-flight.
void Detach() { detached_ = true; DecrementRefCount(); }
bool detached() { return detached_; }
ngx_http_request_t* request() { return request_; }
NgxBaseFetchType base_fetch_type() { return base_fetch_type_; }
bool IsCachedResultValid(const ResponseHeaders& headers) override;
private: private:
virtual bool HandleWrite(const StringPiece& sp, MessageHandler* handler); virtual bool HandleWrite(const StringPiece& sp, MessageHandler* handler);
@@ -89,7 +141,7 @@ class NgxBaseFetch : public AsyncFetch {
// Indicate to nginx that we would like it to call // Indicate to nginx that we would like it to call
// CollectAccumulatedWrites(). // CollectAccumulatedWrites().
void RequestCollection(); void RequestCollection(char type);
// Lock must be acquired first. // Lock must be acquired first.
// Returns: // Returns:
@@ -105,20 +157,32 @@ class NgxBaseFetch : public AsyncFetch {
// Called by Done() and Release(). Decrements our reference count, and if // Called by Done() and Release(). Decrements our reference count, and if
// it's zero we delete ourself. // it's zero we delete ourself.
void DecrefAndDeleteIfUnreferenced(); int DecrefAndDeleteIfUnreferenced();
static NgxEventConnection* event_connection;
// Live count of NgxBaseFetch instances that are currently in use.
static int active_base_fetches;
GoogleString url_;
ngx_http_request_t* request_; ngx_http_request_t* request_;
GoogleString buffer_; GoogleString buffer_;
NgxServerContext* server_context_; NgxServerContext* server_context_;
const RewriteOptions* options_;
bool need_flush_;
bool done_called_; bool done_called_;
bool last_buf_sent_; bool last_buf_sent_;
int pipe_fd_;
// How many active references there are to this fetch. Starts at two, // How many active references there are to this fetch. Starts at two,
// decremented once when Done() is called and once when Release() is called. // decremented once when Done() is called and once when Detach() is called.
// Incremented for each event written by pagespeed for this NgxBaseFetch, and
// decremented on the nginx side for each event read for it.
int references_; int references_;
pthread_mutex_t mutex_; pthread_mutex_t mutex_;
bool handle_error_; NgxBaseFetchType base_fetch_type_;
PreserveCachingHeaders preserve_caching_headers_; PreserveCachingHeaders preserve_caching_headers_;
// Set to true just before the nginx side releases its reference
bool detached_;
bool suppress_;
DISALLOW_COPY_AND_ASSIGN(NgxBaseFetch); DISALLOW_COPY_AND_ASSIGN(NgxBaseFetch);
}; };
+172
View File
@@ -0,0 +1,172 @@
/*
* 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: oschaaf@we-amp.com (Otto van der Schaaf)
extern "C" {
#include <ngx_channel.h>
}
#include "ngx_event_connection.h"
#include "pagespeed/kernel/base/google_message_handler.h"
#include "pagespeed/kernel/base/message_handler.h"
namespace net_instaweb {
NgxEventConnection::NgxEventConnection(callbackPtr callback)
: event_handler_(callback) {
}
bool NgxEventConnection::Init(ngx_cycle_t* cycle) {
int file_descriptors[2];
if (pipe(file_descriptors) != 0) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "pagespeed: pipe() failed");
return false;
}
if (ngx_nonblocking(file_descriptors[0]) == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
ngx_nonblocking_n "pagespeed: pipe[0] failed");
} else if (ngx_nonblocking(file_descriptors[1]) == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
ngx_nonblocking_n "pagespeed: pipe[1] failed");
} else if (!CreateNgxConnection(cycle, file_descriptors[0])) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
"pagespeed: failed to create connection.");
} else {
pipe_read_fd_ = file_descriptors[0];
pipe_write_fd_ = file_descriptors[1];
return true;
}
close(file_descriptors[0]);
close(file_descriptors[1]);
return false;
}
bool NgxEventConnection::CreateNgxConnection(ngx_cycle_t* cycle,
ngx_fd_t pipe_fd) {
// pipe_fd (the read side of the pipe will end up as c->fd on the
// underlying ngx_connection_t that gets created here)
ngx_int_t rc = ngx_add_channel_event(cycle, pipe_fd, NGX_READ_EVENT,
&NgxEventConnection::ReadEventHandler);
return rc == NGX_OK;
}
void NgxEventConnection::ReadEventHandler(ngx_event_t* ev) {
ngx_connection_t* c = static_cast<ngx_connection_t*>(ev->data);
ngx_int_t result = ngx_handle_read_event(ev, 0);
if (result != NGX_OK) {
CHECK(false) << "pagespeed: ngx_handle_read_event error: " << result;
}
if (ev->timedout) {
ev->timedout = 0;
return;
}
if (!NgxEventConnection::ReadAndNotify(c->fd)) {
// This was copied from ngx_channel_handler(): for epoll, we need to call
// ngx_del_conn(). Sadly, no documentation as to why.
if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
ngx_del_conn(c, 0);
}
ngx_close_connection(c);
ngx_del_event(ev, NGX_READ_EVENT, 0);
}
}
// Deserialize ps_event_data's from the pipe as they become available.
// Subsequently do some bookkeeping, cleanup, and error checking to keep
// the mess out of ps_base_fetch_handler.
bool NgxEventConnection::ReadAndNotify(ngx_fd_t fd) {
while (true) {
// We read only one ps_event_data at a time for now:
// We can end up recursing all the way and end up calling ourselves here.
// If that happens in the middle of looping over multiple ps_event_data's we
// have obtained with read(), the results from the next read() will make us
// process events out of order. Which can give headaches.
// Alternatively, we could maintain a queue to make sure we process in
// sequence
ps_event_data data;
ngx_int_t size = read(fd, static_cast<void*>(&data), sizeof(data));
if (size == -1) {
if (errno == EINTR) {
continue;
// TODO(oschaaf): should we worry about spinning here?
} else if (ngx_errno == EAGAIN || ngx_errno == EWOULDBLOCK) {
return true;
}
}
if (size <= 0) {
return false;
}
data.connection->event_handler_(data);
return true;
}
}
bool NgxEventConnection::WriteEvent(void* sender) {
return WriteEvent('X' /* Anything char is fine */, sender);
}
bool NgxEventConnection::WriteEvent(char type, void* sender) {
ssize_t size = 0;
ps_event_data data;
ngx_memzero(&data, sizeof(data));
data.type = type;
data.sender = sender;
data.connection = this;
while (true) {
size = write(pipe_write_fd_,
static_cast<void*>(&data), sizeof(data));
if (size == sizeof(data)) {
return true;
} else if (size == -1) {
// TODO(oschaaf): should we worry about spinning here?
if (ngx_errno == EINTR || ngx_errno == EAGAIN
|| ngx_errno == EWOULDBLOCK) {
continue;
} else {
return false;
}
} else {
CHECK(false) << "pagespeed: unexpected return value from write(): "
<< size;
}
}
CHECK(false) << "Should not get here";
return false;
}
// Reads and processes what is available in the pipe.
void NgxEventConnection::Drain() {
NgxEventConnection::ReadAndNotify(pipe_read_fd_);
}
void NgxEventConnection::Shutdown() {
close(pipe_write_fd_);
close(pipe_read_fd_);
}
} // namespace net_instaweb
+84
View File
@@ -0,0 +1,84 @@
/*
* 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: oschaaf@we-amp.com (Otto van der Schaaf)
//
// NgxEventConnection implements a means to send events from other threads to
// nginx's event loop, and is implemented by a named pipe under the hood.
// A single instance is used by NgxBaseFetch, and one instance is created per
// NgxUrlAsyncFetcher when native fetching is on.
#ifndef NGX_EVENT_CONNECTION_H_
#define NGX_EVENT_CONNECTION_H_
extern "C" {
#include <ngx_http.h>
}
#include <pthread.h>
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/http/headers.h"
namespace net_instaweb {
class NgxEventConnection;
// Represents a single event that can be written to or read from the pipe.
// Technically, sender is the only data we need to send. type and connection are
// included to provide a means to trace the events along with some more
// info.
typedef struct {
char type;
void* sender;
NgxEventConnection* connection;
} ps_event_data;
// Handler signature for receiving events
typedef void (*callbackPtr)(const ps_event_data&);
// Abstracts a connection to nginx through which events can be written.
class NgxEventConnection {
public:
explicit NgxEventConnection(callbackPtr handler);
// Creates the file descriptors and ngx_connection_t required for event
// messaging between pagespeed and nginx.
bool Init(ngx_cycle_t* cycle);
// Shuts down the underlying file descriptors and connection created in Init()
void Shutdown();
// Constructs a ps_event_data and writes it to the underlying named pipe.
bool WriteEvent(char type, void* sender);
// Convenience overload for clients that have a single event type.
bool WriteEvent(void* sender);
// Reads and processes what is available in the named pipe's buffer.
void Drain();
private:
static bool CreateNgxConnection(ngx_cycle_t* cycle, ngx_fd_t pipe_fd);
static void ReadEventHandler(ngx_event_t* e);
static bool ReadAndNotify(ngx_fd_t fd);
callbackPtr event_handler_;
// We own these file descriptors
ngx_fd_t pipe_write_fd_;
ngx_fd_t pipe_read_fd_;
DISALLOW_COPY_AND_ASSIGN(NgxEventConnection);
};
} // namespace net_instaweb
#endif // NGX_EVENT_CONNECTION_H_
+480 -158
View File
@@ -24,42 +24,240 @@
// - The read handler parses the response. Add the response to the buffer at // - The read handler parses the response. Add the response to the buffer at
// last. // last.
// TODO(oschaaf): Currently the first applicable connection is picked from the
// pool when re-using connections. Perhaps it would be worth it to pick the one
// that was active the longest time ago to keep a larger pool available.
// TODO(oschaaf): style: reindent namespace according to google C++ style guide
// TODO(oschaaf): Retry mechanism for failures on a re-used k-a connection.
// Currently we don't think it's going to be an issue, see the comments at
// https://github.com/pagespeed/ngx_pagespeed/pull/781.
extern "C" { extern "C" {
#include <nginx.h> #include <nginx.h>
} }
#include "ngx_fetch.h" #include "ngx_fetch.h"
#include "net/instaweb/util/public/basictypes.h"
#include "base/logging.h" #include "base/logging.h"
#include <algorithm> #include <algorithm>
#include <string> #include <string>
#include <typeinfo>
#include <vector> #include <vector>
#include "net/instaweb/util/public/scoped_ptr.h"
#include "net/instaweb/http/public/async_fetch.h" #include "net/instaweb/http/public/async_fetch.h"
#include "net/instaweb/http/public/inflating_fetch.h" #include "net/instaweb/http/public/inflating_fetch.h"
#include "net/instaweb/http/public/request_headers.h"
#include "net/instaweb/http/public/response_headers.h"
#include "net/instaweb/http/public/response_headers_parser.h"
#include "net/instaweb/public/version.h" #include "net/instaweb/public/version.h"
#include "net/instaweb/public/global_constants.h" #include "net/instaweb/public/global_constants.h"
#include "net/instaweb/util/public/condvar.h" #include "pagespeed/kernel/base/basictypes.h"
#include "net/instaweb/util/public/message_handler.h" #include "pagespeed/kernel/base/condvar.h"
#include "net/instaweb/util/public/pool.h" #include "pagespeed/kernel/base/message_handler.h"
#include "net/instaweb/util/public/pool_element.h" #include "pagespeed/kernel/base/pool.h"
#include "net/instaweb/util/public/statistics.h" #include "pagespeed/kernel/base/pool_element.h"
#include "net/instaweb/util/public/string_writer.h" #include "pagespeed/kernel/base/scoped_ptr.h"
#include "net/instaweb/util/public/string_util.h" #include "pagespeed/kernel/base/statistics.h"
#include "net/instaweb/util/public/thread_system.h" #include "pagespeed/kernel/base/string_writer.h"
#include "net/instaweb/util/public/timer.h" #include "pagespeed/kernel/base/string_util.h"
#include "net/instaweb/util/public/writer.h" #include "pagespeed/kernel/base/thread_system.h"
#include "pagespeed/kernel/base/timer.h"
#include "pagespeed/kernel/base/writer.h"
#include "pagespeed/kernel/http/request_headers.h"
#include "pagespeed/kernel/http/response_headers.h"
#include "pagespeed/kernel/http/response_headers_parser.h"
namespace net_instaweb { namespace net_instaweb {
NgxConnection::NgxConnectionPool NgxConnection::connection_pool;
PthreadMutex NgxConnection::connection_pool_mutex;
// Default keepalive 60s.
const int64 NgxConnection::keepalive_timeout_ms = 60000;
const GoogleString NgxConnection::ka_header =
StrCat("keep-alive ",
Integer64ToString(NgxConnection::keepalive_timeout_ms));
NgxConnection::NgxConnection(MessageHandler* handler,
int max_keepalive_requests) {
c_ = NULL;
max_keepalive_requests_ = max_keepalive_requests;
handler_ = handler;
// max_keepalive_requests specifies the number of http requests that are
// allowed to be performed over a single connection. So, a
// max_keepalive_requests of 1 effectively disables keepalive.
keepalive_ = max_keepalive_requests_ > 1;
}
NgxConnection::~NgxConnection() {
CHECK(c_ == NULL) << "NgxConnection: Underlying connection should be NULL";
}
void NgxConnection::Terminate() {
for (NgxConnectionPool::iterator p = connection_pool.begin();
p != connection_pool.end(); ++p) {
NgxConnection* nc = *p;
ngx_close_connection(nc->c_);
nc->c_ = NULL;
delete nc;
}
connection_pool.Clear();
}
NgxConnection* NgxConnection::Connect(ngx_peer_connection_t* pc,
MessageHandler* handler,
int max_keepalive_requests) {
NgxConnection* nc;
{
ScopedMutex lock(&NgxConnection::connection_pool_mutex);
for (NgxConnectionPool::iterator p = connection_pool.begin();
p != connection_pool.end(); ++p) {
nc = *p;
if (ngx_memn2cmp(static_cast<u_char*>(nc->sockaddr_),
reinterpret_cast<u_char*>(pc->sockaddr),
nc->socklen_, pc->socklen) == 0) {
CHECK(nc->c_->idle) << "Pool should only contain idle connections!";
nc->c_->idle = 0;
nc->c_->log = pc->log;
nc->c_->read->log = pc->log;
nc->c_->write->log = pc->log;
if (nc->c_->pool != NULL) {
nc->c_->pool->log = pc->log;
}
if (nc->c_->read->timer_set) {
ngx_del_timer(nc->c_->read);
}
connection_pool.Remove(nc);
ngx_log_error(NGX_LOG_DEBUG, pc->log, 0,
"NgxFetch: re-using connection %p (pool size: %l)",
nc, connection_pool.size());
return nc;
}
}
}
int rc = ngx_event_connect_peer(pc);
if (rc == NGX_ERROR || rc == NGX_DECLINED || rc == NGX_BUSY) {
return NULL;
}
// NgxConnection deletes itself if NgxConnection::Close()
nc = new NgxConnection(handler, max_keepalive_requests);
nc->SetSock(reinterpret_cast<u_char*>(pc->sockaddr), pc->socklen);
nc->c_ = pc->connection;
return nc;
}
void NgxConnection::Close() {
bool removed_from_pool = false;
{
ScopedMutex lock(&NgxConnection::connection_pool_mutex);
for (NgxConnectionPool::iterator p = connection_pool.begin();
p != connection_pool.end(); ++p) {
if (*p == this) {
// When we get here, that means that the connection either has timed
// out or has been closed remotely.
connection_pool.Remove(this);
ngx_log_error(NGX_LOG_DEBUG, c_->log, 0,
"NgxFetch: removed connection %p (pool size: %l)",
this, connection_pool.size());
removed_from_pool = true;
break;
}
}
}
max_keepalive_requests_--;
if (c_->read->timer_set) {
ngx_del_timer(c_->read);
}
if (c_->write->timer_set) {
ngx_del_timer(c_->write);
}
if (!keepalive_ || max_keepalive_requests_ <= 0 || removed_from_pool) {
ngx_close_connection(c_);
c_ = NULL;
delete this;
return;
}
ngx_add_timer(c_->read, static_cast<ngx_msec_t>(
NgxConnection::keepalive_timeout_ms));
c_->data = this;
c_->read->handler = NgxConnection::IdleReadHandler;
c_->write->handler = NgxConnection::IdleWriteHandler;
c_->idle = 1;
// This connection should not be associated with current fetch.
c_->log = ngx_cycle->log;
c_->read->log = ngx_cycle->log;
c_->write->log = ngx_cycle->log;
if (c_->pool != NULL) {
c_->pool->log = ngx_cycle->log;
}
// Allow this connection to be re-used, by adding it to the connection pool.
{
ScopedMutex lock(&NgxConnection::connection_pool_mutex);
connection_pool.Add(this);
ngx_log_error(NGX_LOG_DEBUG, c_->log, 0,
"NgxFetch: Added connection %p (pool size: %l - "
" max_keepalive_requests_ %d)",
this, connection_pool.size(), max_keepalive_requests_);
}
}
void NgxConnection::IdleWriteHandler(ngx_event_t* ev) {
ngx_connection_t* c = static_cast<ngx_connection_t*>(ev->data);
u_char buf[1];
int n = c->recv(c, buf, 1);
if (c->write->timedout) {
DCHECK(false) << "NgxFetch: write timeout not expected." << n;
}
if (n == NGX_AGAIN) {
return;
}
}
void NgxConnection::IdleReadHandler(ngx_event_t* ev) {
ngx_connection_t* c = static_cast<ngx_connection_t*>(ev->data);
NgxConnection* nc = static_cast<NgxConnection*>(c->data);
if (c->read->timedout) {
nc->set_keepalive(false);
nc->Close();
return;
}
char buf[1];
int n;
// not a timeout event, we should check connection
n = recv(c->fd, buf, 1, MSG_PEEK);
if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
nc->set_keepalive(false);
nc->Close();
return;
}
return;
}
nc->set_keepalive(false);
nc->Close();
}
NgxFetch::NgxFetch(const GoogleString& url, NgxFetch::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)
: str_url_(url), : str_url_(url),
fetcher_(NULL), fetcher_(NULL),
@@ -70,7 +268,9 @@ namespace net_instaweb {
fetch_start_ms_(0), fetch_start_ms_(0),
fetch_end_ms_(0), fetch_end_ms_(0),
done_(false), done_(false),
content_length_(0) { content_length_(-1),
content_length_known_(false),
resolver_ctx_(NULL) {
ngx_memzero(&url_, sizeof(url_)); ngx_memzero(&url_, sizeof(url_));
log_ = log; log_ = log;
pool_ = NULL; pool_ = NULL;
@@ -83,17 +283,24 @@ namespace net_instaweb {
ngx_del_timer(timeout_event_); ngx_del_timer(timeout_event_);
} }
if (connection_ != NULL) { if (connection_ != NULL) {
ngx_close_connection(connection_); connection_->Close();
connection_ = NULL;
} }
if (pool_ != NULL) { if (pool_ != NULL) {
ngx_destroy_pool(pool_); ngx_destroy_pool(pool_);
pool_ = NULL;
} }
} }
// This function is called by NgxUrlAsyncFetcher::StartFetch. // This function is called by NgxUrlAsyncFetcher::StartFetch.
bool NgxFetch::Start(NgxUrlAsyncFetcher* fetcher) { bool NgxFetch::Start(NgxUrlAsyncFetcher* fetcher) {
fetcher_ = fetcher; fetcher_ = fetcher;
return Init(); bool ok = Init();
if (ok) {
ngx_log_error(NGX_LOG_DEBUG, log_, 0, "NgxFetch %p: initialized",
this);
} // else Init() will have emitted a reason
return ok;
} }
// Create the pool, parse the url, add the timeout event and // Create the pool, parse the url, add the timeout event and
@@ -108,7 +315,9 @@ namespace net_instaweb {
} }
if (!ParseUrl()) { if (!ParseUrl()) {
message_handler_->Message(kError, "NgxFetch: ParseUrl() failed"); message_handler_->Message(kError,
"NgxFetch: ParseUrl() failed for [%s]:%s",
str_url_.c_str(), url_.err);
return false; return false;
} }
@@ -119,20 +328,23 @@ namespace net_instaweb {
"NgxFetch: ngx_pcalloc failed for timeout"); "NgxFetch: ngx_pcalloc failed for timeout");
return false; return false;
} }
timeout_event_->data = this; timeout_event_->data = this;
timeout_event_->handler = NgxFetchTimeout; timeout_event_->handler = NgxFetch::TimeoutHandler;
timeout_event_->log = log_; timeout_event_->log = log_;
ngx_add_timer(timeout_event_, fetcher_->fetch_timeout_); ngx_add_timer(timeout_event_, fetcher_->fetch_timeout_);
r_ = static_cast<ngx_http_request_t*>(ngx_pcalloc(pool_, r_ = static_cast<ngx_http_request_t*>(
sizeof(ngx_http_request_t))); ngx_pcalloc(pool_, sizeof(ngx_http_request_t)));
if (r_ == NULL) { if (r_ == NULL) {
message_handler_->Message(kError, message_handler_->Message(kError,
"NgxFetch: ngx_pcalloc failed for timer"); "NgxFetch: ngx_pcalloc failed for timer");
return false; return false;
} }
status_ = static_cast<ngx_http_status_t*>(ngx_pcalloc(pool_, status_ = static_cast<ngx_http_status_t*>(
sizeof(ngx_http_status_t))); ngx_pcalloc(pool_, sizeof(ngx_http_status_t)));
if (status_ == NULL) { if (status_ == NULL) {
message_handler_->Message(kError, message_handler_->Message(kError,
"NgxFetch: ngx_pcalloc failed for status"); "NgxFetch: ngx_pcalloc failed for status");
@@ -142,19 +354,26 @@ namespace net_instaweb {
// The host is either a domain name or an IP address. First check // The host is either a domain name or an IP address. First check
// if it's a valid IP address and only if that fails fall back to // if it's a valid IP address and only if that fails fall back to
// using the DNS resolver. // using the DNS resolver.
GoogleString s_ipaddress(reinterpret_cast<char*>(url_.host.data),
url_.host.len); // Maybe we have a Proxy.
ngx_url_t* tmp_url = &url_;
if (fetcher_->proxy_.url.len != 0) {
tmp_url = &fetcher_->proxy_;
}
GoogleString s_ipaddress(reinterpret_cast<char*>(tmp_url->host.data),
tmp_url->host.len);
ngx_memzero(&sin_, sizeof(sin_)); ngx_memzero(&sin_, sizeof(sin_));
sin_.sin_family = AF_INET; sin_.sin_family = AF_INET;
sin_.sin_port = htons(url_.port); sin_.sin_port = htons(tmp_url->port);
sin_.sin_addr.s_addr = inet_addr(s_ipaddress.c_str()); sin_.sin_addr.s_addr = inet_addr(s_ipaddress.c_str());
if (sin_.sin_addr.s_addr == INADDR_NONE) { if (sin_.sin_addr.s_addr == INADDR_NONE) {
// inet_addr returned INADDR_NONE, which means the hostname // inet_addr returned INADDR_NONE, which means the hostname
// isn't a valid IP address. Check DNS. // isn't a valid IP address. Check DNS.
ngx_resolver_ctx_t temp; ngx_resolver_ctx_t temp;
temp.name.data = url_.host.data; temp.name.data = tmp_url->host.data;
temp.name.len = url_.host.len; temp.name.len = tmp_url->host.len;
resolver_ctx_ = ngx_resolve_start(fetcher_->resolver_, &temp); resolver_ctx_ = ngx_resolve_start(fetcher_->resolver_, &temp);
if (resolver_ctx_ == NULL || resolver_ctx_ == NGX_NO_RESOLVER) { if (resolver_ctx_ == NULL || resolver_ctx_ == NGX_NO_RESOLVER) {
// TODO(oschaaf): this spams the log, but is useful in the fetcher's // TODO(oschaaf): this spams the log, but is useful in the fetcher's
@@ -163,17 +382,21 @@ namespace net_instaweb {
kError, "NgxFetch: Couldn't start resolving, " kError, "NgxFetch: Couldn't start resolving, "
"is there a proper resolver configured in nginx.conf?"); "is there a proper resolver configured in nginx.conf?");
return false; return false;
} else {
ngx_log_error(NGX_LOG_DEBUG, log_, 0,
"NgxFetch %p: start resolve for: %s",
this, s_ipaddress.c_str());
} }
resolver_ctx_->data = this; resolver_ctx_->data = this;
resolver_ctx_->name.data = url_.host.data; resolver_ctx_->name.data = tmp_url->host.data;
resolver_ctx_->name.len = url_.host.len; resolver_ctx_->name.len = tmp_url->host.len;
#if (nginx_version < 1005008) #if (nginx_version < 1005008)
resolver_ctx_->type = NGX_RESOLVE_A; resolver_ctx_->type = NGX_RESOLVE_A;
#endif #endif
resolver_ctx_->handler = NgxFetchResolveDone; resolver_ctx_->handler = NgxFetch::ResolveDoneHandler;
resolver_ctx_->timeout = fetcher_->resolver_timeout_; resolver_ctx_->timeout = fetcher_->resolver_timeout_;
if (ngx_resolve_name(resolver_ctx_) != NGX_OK) { if (ngx_resolve_name(resolver_ctx_) != NGX_OK) {
@@ -197,6 +420,9 @@ namespace net_instaweb {
// This function should be called only once. The only argument is sucess or // This function should be called only once. The only argument is sucess or
// not. // not.
void NgxFetch::CallbackDone(bool success) { void NgxFetch::CallbackDone(bool success) {
ngx_log_error(NGX_LOG_DEBUG, log_, 0, "NgxFetch %p: CallbackDone: %s",
this, success ? "OK":"FAIL");
if (async_fetch_ == NULL) { if (async_fetch_ == NULL) {
LOG(FATAL) LOG(FATAL)
<< "BUG: NgxFetch callback called more than once on same fetch" << "BUG: NgxFetch callback called more than once on same fetch"
@@ -205,16 +431,40 @@ namespace net_instaweb {
return; return;
} }
release_resolver();
if (timeout_event_ && timeout_event_->timer_set) { if (timeout_event_ && timeout_event_->timer_set) {
ngx_del_timer(timeout_event_); ngx_del_timer(timeout_event_);
timeout_event_ = NULL; timeout_event_ = NULL;
} }
if (connection_) {
ngx_close_connection(connection_); if (connection_ != NULL) {
connection_ = NULL; // Connection will be re-used only on responses that specify
// 'Connection: keep-alive' in their headers.
bool keepalive = false;
if (success) {
ConstStringStarVector v;
if (async_fetch_->response_headers()->Lookup(
StringPiece(HttpAttributes::kConnection), &v)) {
for (size_t i = 0; i < v.size(); i++) {
if (*v[i] == "keep-alive") {
keepalive = true;
break;
} else if (*v[i] == "close") {
break;
}
}
}
ngx_log_error(NGX_LOG_DEBUG, log_, 0,
"NgxFetch %p: connection %p attempt keep-alive: %s",
this, connection_, keepalive ? "Yes":"No");
} }
async_fetch_->Done(success); connection_->set_keepalive(keepalive);
connection_->Close();
connection_ = NULL;
}
if (fetcher_ != NULL) { if (fetcher_ != NULL) {
if (fetcher_->track_original_content_length() if (fetcher_->track_original_content_length()
@@ -225,7 +475,7 @@ namespace net_instaweb {
} }
fetcher_->FetchComplete(this); fetcher_->FetchComplete(this);
} }
async_fetch_->Done(success);
async_fetch_ = NULL; async_fetch_ = NULL;
} }
@@ -263,58 +513,66 @@ namespace net_instaweb {
return false; return false;
} }
str_url_.copy(reinterpret_cast<char*>(url_.url.data), str_url_.length(), 0); str_url_.copy(reinterpret_cast<char*>(url_.url.data), str_url_.length(), 0);
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; return NgxUrlAsyncFetcher::ParseUrl(&url_, pool_);
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;
} }
// Issue a request after the resolver is done // Issue a request after the resolver is done
void NgxFetch::NgxFetchResolveDone(ngx_resolver_ctx_t* resolver_ctx) { void NgxFetch::ResolveDoneHandler(ngx_resolver_ctx_t* resolver_ctx) {
NgxFetch* fetch = static_cast<NgxFetch*>(resolver_ctx->data); NgxFetch* fetch = static_cast<NgxFetch*>(resolver_ctx->data);
NgxUrlAsyncFetcher* fetcher = fetch->fetcher_;
if (resolver_ctx->state != NGX_OK) { if (resolver_ctx->state != NGX_OK) {
if (fetch->timeout_event() != NULL && fetch->timeout_event()->timer_set) { if (fetch->timeout_event() != NULL && fetch->timeout_event()->timer_set) {
ngx_del_timer(fetch->timeout_event()); ngx_del_timer(fetch->timeout_event());
fetch->set_timeout_event(NULL); fetch->set_timeout_event(NULL);
} }
fetch->message_handler()->Message( fetch->message_handler()->Message(
kWarning, "NgxFetch: failed to resolve host [%.*s]", kWarning, "NgxFetch %p: failed to resolve host [%.*s]", fetch,
static_cast<int>(resolver_ctx->name.len), resolver_ctx->name.data); static_cast<int>(resolver_ctx->name.len), resolver_ctx->name.data);
fetch->CallbackDone(false); fetch->CallbackDone(false);
ngx_resolve_name_done(resolver_ctx);
return; return;
} }
ngx_uint_t i;
// Find the first ipv4 address. We don't support ipv6 yet.
for (i = 0; i < resolver_ctx->naddrs; i++) {
// Old versions of nginx and tengine have a different definition of addrs,
// work around to make sure we are using the right type (ngx_addr_t*).
ngx_addr_t* ngx_addrs = reinterpret_cast<ngx_addr_t*>(resolver_ctx->addrs);
if (typeid(*ngx_addrs) == typeid(*resolver_ctx->addrs)) {
if (reinterpret_cast<struct sockaddr_in*>(ngx_addrs[i].sockaddr)
->sin_family == AF_INET) {
break;
}
} else {
// We're using an old version that uses in_addr_t* for addrs.
break;
}
}
// If no suitable ipv4 address was found, we fail.
if (i == resolver_ctx->naddrs) {
if (fetch->timeout_event() != NULL && fetch->timeout_event()->timer_set) {
ngx_del_timer(fetch->timeout_event());
fetch->set_timeout_event(NULL);
}
fetch->message_handler()->Message(
kWarning, "NgxFetch %p: no suitable address for host [%.*s]", fetch,
static_cast<int>(resolver_ctx->name.len), resolver_ctx->name.data);
fetch->CallbackDone(false);
}
ngx_memzero(&fetch->sin_, sizeof(fetch->sin_)); ngx_memzero(&fetch->sin_, sizeof(fetch->sin_));
#if (nginx_version < 1005008) #if (nginx_version < 1005008)
fetch->sin_.sin_addr.s_addr = resolver_ctx->addrs[0]; fetch->sin_.sin_addr.s_addr = resolver_ctx->addrs[i];
#else #else
struct sockaddr_in* sin; struct sockaddr_in* sin;
sin = reinterpret_cast<struct sockaddr_in*>( sin = reinterpret_cast<struct sockaddr_in*>(
resolver_ctx->addrs[0].sockaddr); resolver_ctx->addrs[i].sockaddr);
fetch->sin_.sin_family = sin->sin_family; fetch->sin_.sin_family = sin->sin_family;
fetch->sin_.sin_addr.s_addr = sin->sin_addr.s_addr; fetch->sin_.sin_addr.s_addr = sin->sin_addr.s_addr;
#endif #endif
@@ -322,14 +580,18 @@ namespace net_instaweb {
fetch->sin_.sin_family = AF_INET; fetch->sin_.sin_family = AF_INET;
fetch->sin_.sin_port = htons(fetch->url_.port); fetch->sin_.sin_port = htons(fetch->url_.port);
// Maybe we have Proxy
if (0 != fetcher->proxy_.url.len) {
fetch->sin_.sin_port = htons(fetcher->proxy_.port);
}
char* ip_address = inet_ntoa(fetch->sin_.sin_addr); char* ip_address = inet_ntoa(fetch->sin_.sin_addr);
fetch->message_handler()->Message( ngx_log_error(NGX_LOG_DEBUG, fetch->log_, 0,
kInfo, "NgxFetch: Resolved host [%.*s] to [%s]", "NgxFetch %p: Resolved host [%V] to [%s]", fetch,
static_cast<int>(resolver_ctx->name.len), resolver_ctx->name.data, &resolver_ctx->name, ip_address);
ip_address);
ngx_resolve_name_done(resolver_ctx); fetch->release_resolver();
if (fetch->InitRequest() != NGX_OK) { if (fetch->InitRequest() != NGX_OK) {
fetch->message_handler()->Message(kError, "NgxFetch: InitRequest failed"); fetch->message_handler()->Message(kError, "NgxFetch: InitRequest failed");
@@ -337,7 +599,7 @@ namespace net_instaweb {
} }
} }
// prepare the send data for this fetch, and hook write event. // Prepare the request data for this fetch, and hook the write event.
int NgxFetch::InitRequest() { int NgxFetch::InitRequest() {
in_ = ngx_create_temp_buf(pool_, 4096); in_ = ngx_create_temp_buf(pool_, 4096);
if (in_ == NULL) { if (in_ == NULL) {
@@ -352,7 +614,20 @@ namespace net_instaweb {
bool have_host = false; bool have_host = false;
GoogleString port; GoogleString port;
size = sizeof("GET ") - 1 + url_.uri.len + sizeof(" HTTP/1.0\r\n") - 1; response_handler = NgxFetch::HandleStatusLine;
int rc = Connect();
if (rc == NGX_AGAIN || rc == NGX_OK) {
if (connection_->keepalive()) {
request_headers->Add(HttpAttributes::kConnection,
NgxConnection::ka_header);
}
const char* method = request_headers->method_string();
size_t method_len = strlen(method);
size = (method_len +
1 /* for the space */ +
url_.uri.len +
sizeof(" HTTP/1.0\r\n") - 1);
for (int i = 0; i < request_headers->NumAttributes(); i++) { for (int i = 0; i < request_headers->NumAttributes(); i++) {
// if no explicit host header is given in the request headers, // if no explicit host header is given in the request headers,
@@ -363,8 +638,7 @@ namespace net_instaweb {
// name: value\r\n // name: value\r\n
size += request_headers->Name(i).length() size += request_headers->Name(i).length()
+ request_headers->Value(i).length() + request_headers->Value(i).length() + 4; // 4 for ": \r\n"
+ 4; // for ": \r\n"
} }
if (!have_host) { if (!have_host) {
@@ -380,7 +654,8 @@ namespace net_instaweb {
return NGX_ERROR; return NGX_ERROR;
} }
out_->last = ngx_cpymem(out_->last, "GET ", 4); out_->last = ngx_cpymem(out_->last, method, method_len);
out_->last = ngx_cpymem(out_->last, " ", 1);
out_->last = ngx_cpymem(out_->last, url_.uri.data, url_.uri.len); out_->last = ngx_cpymem(out_->last, url_.uri.data, url_.uri.len);
out_->last = ngx_cpymem(out_->last, " HTTP/1.0\r\n", 11); out_->last = ngx_cpymem(out_->last, " HTTP/1.0\r\n", 11);
@@ -403,16 +678,14 @@ namespace net_instaweb {
} }
*(out_->last++) = CR; *(out_->last++) = CR;
*(out_->last++) = LF; *(out_->last++) = LF;
response_handler = NgxFetchHandleStatusLine;
int rc = Connect();
if (rc == NGX_AGAIN) { if (rc == NGX_AGAIN) {
return NGX_OK; return NGX_OK;
}
} else if (rc < NGX_OK) { } else if (rc < NGX_OK) {
return rc; return rc;
} }
CHECK(rc == NGX_OK);
NgxFetchWrite(connection_->write); NgxFetch::ConnectionWriteHandler(connection_->c_->write);
return NGX_OK; return NGX_OK;
} }
@@ -429,103 +702,114 @@ namespace net_instaweb {
pc.log = fetcher_->log_; pc.log = fetcher_->log_;
pc.rcvbuf = -1; pc.rcvbuf = -1;
int rc = ngx_event_connect_peer(&pc);
if (rc == NGX_ERROR || rc == NGX_DECLINED || rc == NGX_BUSY) { connection_ = NgxConnection::Connect(&pc, message_handler(),
return rc; fetcher_->max_keepalive_requests_);
ngx_log_error(NGX_LOG_DEBUG, fetcher_->log_, 0,
"NgxFetch %p Connect() connection %p for [%s]",
this, connection_, str_url());
if (connection_ == NULL) {
return NGX_ERROR;
} }
connection_ = pc.connection; connection_->c_->write->handler = NgxFetch::ConnectionWriteHandler;
connection_->write->handler = NgxFetchWrite; connection_->c_->read->handler = NgxFetch::ConnectionReadHandler;
connection_->read->handler = NgxFetchRead; connection_->c_->data = this;
connection_->data = this;
// Timer set in Init() is still in effect. // Timer set in Init() is still in effect.
return rc; return NGX_OK;
} }
// When the fetch sends the request completely, it will hook the read event, // When the fetch sends the request completely, it will hook the read event,
// and prepare to parse the response. // and prepare to parse the response. Timer set in Init() is still in effect.
void NgxFetch::NgxFetchWrite(ngx_event_t* wev) { void NgxFetch::ConnectionWriteHandler(ngx_event_t* wev) {
ngx_connection_t* c = static_cast<ngx_connection_t*>(wev->data); ngx_connection_t* c = static_cast<ngx_connection_t*>(wev->data);
NgxFetch* fetch = static_cast<NgxFetch*>(c->data); NgxFetch* fetch = static_cast<NgxFetch*>(c->data);
ngx_buf_t* out = fetch->out_; ngx_buf_t* out = fetch->out_;
bool ok = true;
while (out->pos < out->last) { while (wev->ready && out->pos < out->last) {
int n = c->send(c, out->pos, out->last - out->pos); int n = c->send(c, out->pos, out->last - out->pos);
ngx_log_error(NGX_LOG_DEBUG, fetch->log_, 0,
"NgxFetch %p: ConnectionWriteHandler "
"send result %d", fetch, n);
if (n >= 0) { if (n >= 0) {
out->pos += n; out->pos += n;
} else if (n == NGX_AGAIN) { } else if (n == NGX_AGAIN) {
if (ngx_handle_write_event(c->write, 0) != NGX_OK) { break;
fetch->CallbackDone(false);
}
// Timer set in Init() is still in effect.
return;
} else { } else {
c->error = 1; ok = false;
fetch->CallbackDone(false); break;
return;
} }
} }
if (ngx_handle_read_event(c->read, 0) != NGX_OK) { if (ok) {
if (out->pos == out->last) {
ok = ngx_handle_read_event(c->read, 0) == NGX_OK;
} else {
ok = ngx_handle_write_event(c->write, 0) == NGX_OK;
}
}
if (!ok) {
fetch->message_handler()->Message(
kWarning, "NgxFetch %p: failed to hook next event", fetch);
c->error = 1; c->error = 1;
fetch->CallbackDone(false); fetch->CallbackDone(false);
} }
return;
} }
void NgxFetch::NgxFetchRead(ngx_event_t* rev) { // Timer set in Init() is still in effect.
void NgxFetch::ConnectionReadHandler(ngx_event_t* rev) {
ngx_connection_t* c = static_cast<ngx_connection_t*>(rev->data); ngx_connection_t* c = static_cast<ngx_connection_t*>(rev->data);
NgxFetch* fetch = static_cast<NgxFetch*>(c->data); NgxFetch* fetch = static_cast<NgxFetch*>(c->data);
bool ok = true;
for (;;) { while(rev->ready) {
int n = c->recv( int n = c->recv(
c, fetch->in_->start, fetch->in_->end - fetch->in_->start); c, fetch->in_->start, fetch->in_->end - fetch->in_->start);
ngx_log_error(NGX_LOG_DEBUG, fetch->log_, 0,
"NgxFetch %p: ConnectionReadHandler "
"recv result %d", fetch, n);
if (n == NGX_AGAIN) { if (n == NGX_AGAIN) {
break; break;
} } else if (n == 0) {
// If the content length was not known, we assume that we have read
if (n == 0) { // all if we at least parsed the headers.
// connection is closed prematurely by remote server, // If we do know the content length, having a mismatch on the bytes read
// or the content-length was 0 // will be interpreted as an error.
fetch->CallbackDone(fetch->content_length_ == 0); ok = (fetch->content_length_known_ && fetch->content_length_ == fetch->bytes_received_)
return; || fetch->parser_.headers_complete();
fetch->done_ = true;
break;
} else if (n > 0) { } else if (n > 0) {
fetch->in_->pos = fetch->in_->start; fetch->in_->pos = fetch->in_->start;
fetch->in_->last = fetch->in_->start + n; fetch->in_->last = fetch->in_->start + n;
if (!fetch->response_handler(c)) { ok = fetch->response_handler(c);
fetch->CallbackDone(false); if (fetch->done_ || !ok) {
return;
}
if (fetch->done_) {
fetch->CallbackDone(true);
return;
}
}
if (!rev->ready) {
break; break;
} }
} }
if (fetch->done_) {
fetch->CallbackDone(true);
return;
} }
if (ngx_handle_read_event(rev, 0) != NGX_OK) { if (!ok) {
fetch->CallbackDone(false);
} else if (fetch->done_) {
fetch->CallbackDone(true);
} else if (ngx_handle_read_event(rev, 0) != NGX_OK) {
fetch->CallbackDone(false); fetch->CallbackDone(false);
} }
// Timer set in Init() is still in effect.
} }
// Parse the status line: "HTTP/1.1 200 OK\r\n" // Parse the status line: "HTTP/1.1 200 OK\r\n"
bool NgxFetch::NgxFetchHandleStatusLine(ngx_connection_t* c) { bool NgxFetch::HandleStatusLine(ngx_connection_t* c) {
NgxFetch* fetch = static_cast<NgxFetch*>(c->data); NgxFetch* fetch = static_cast<NgxFetch*>(c->data);
ngx_log_error(NGX_LOG_DEBUG, fetch->log_, 0,
"NgxFetch %p: Handle status line", fetch);
// This function only works after Nginx-1.1.4. Before nginx-1.1.4, // This function only works after Nginx-1.1.4. Before nginx-1.1.4,
// ngx_http_parse_status_line didn't save http_version. // ngx_http_parse_status_line didn't save http_version.
ngx_int_t n = ngx_http_parse_status_line(fetch->r_, fetch->in_, ngx_int_t n = ngx_http_parse_status_line(fetch->r_, fetch->in_,
@@ -537,65 +821,102 @@ namespace net_instaweb {
} else if (n == NGX_AGAIN) { // not completed } else if (n == NGX_AGAIN) { // not completed
return true; return true;
} }
ResponseHeaders* response_headers = ResponseHeaders* response_headers =
fetch->async_fetch_->response_headers(); fetch->async_fetch_->response_headers();
response_headers->SetStatusAndReason( response_headers->SetStatusAndReason(
static_cast<HttpStatus::Code>(fetch->get_status_code())); static_cast<HttpStatus::Code>(fetch->get_status_code()));
response_headers->set_major_version(fetch->get_major_version()); response_headers->set_major_version(fetch->get_major_version());
response_headers->set_minor_version(fetch->get_minor_version()); response_headers->set_minor_version(fetch->get_minor_version());
fetch->set_response_handler(NgxFetchHandleHeader);
fetch->in_->pos += n;
fetch->set_response_handler(NgxFetch::HandleHeader);
if ((fetch->in_->last - fetch->in_->pos) > 0) {
return fetch->response_handler(c); return fetch->response_handler(c);
} }
return true;
}
// Parse the HTTP headers // Parse the HTTP headers
bool NgxFetch::NgxFetchHandleHeader(ngx_connection_t* c) { bool NgxFetch::HandleHeader(ngx_connection_t* c) {
NgxFetch* fetch = static_cast<NgxFetch*>(c->data); NgxFetch* fetch = static_cast<NgxFetch*>(c->data);
char* data = reinterpret_cast<char*>(fetch->in_->pos); char* data = reinterpret_cast<char*>(fetch->in_->pos);
size_t size = fetch->in_->last - fetch->in_->pos; size_t size = fetch->in_->last - fetch->in_->pos;
size_t n = fetch->parser_.ParseChunk(StringPiece(data, size), size_t n = fetch->parser_.ParseChunk(StringPiece(data, size),
fetch->message_handler_); fetch->message_handler_);
ngx_log_error(NGX_LOG_DEBUG, fetch->log_, 0,
"NgxFetch %p: Handle headers", fetch);
if (n > size) { if (n > size) {
return false; return false;
} else if (fetch->parser_.headers_complete()) { } else if (fetch->parser_.headers_complete()) {
int64 content_length = -1; // TODO(oschaaf): We should also check if the request method was HEAD
fetch->async_fetch_->response_headers()->FindContentLength( // - but I don't think PSOL uses that at this point.
&content_length); if (fetch->get_status_code() == 304 || fetch->get_status_code() == 204) {
fetch->content_length_ = content_length; fetch->done_ = true;
if (fetch->fetcher_->track_original_content_length()) { } else if (fetch->async_fetch_->response_headers()->FindContentLength(
&fetch->content_length_)) {
if (fetch->content_length_ < 0) {
fetch->message_handler_->Message(
kError, "Negative content-length in response header");
return false;
} else {
fetch->content_length_known_ = true;
if (fetch->content_length_ == 0) {
fetch->done_ = true;
}
}
}
if (fetch->fetcher_->track_original_content_length()
&& fetch->content_length_known_) {
fetch->async_fetch_->response_headers()->SetOriginalContentLength( fetch->async_fetch_->response_headers()->SetOriginalContentLength(
content_length); fetch->content_length_);
} }
fetch->in_->pos += n; fetch->in_->pos += n;
fetch->set_response_handler(NgxFetchHandleBody); if (!fetch->done_) {
fetch->set_response_handler(NgxFetch::HandleBody);
if ((fetch->in_->last - fetch->in_->pos) > 0) {
return fetch->response_handler(c); return fetch->response_handler(c);
} }
}
} else {
fetch->in_->pos += n;
}
return true; return true;
} }
// Read the response body // Read the response body
bool NgxFetch::NgxFetchHandleBody(ngx_connection_t* c) { bool NgxFetch::HandleBody(ngx_connection_t* c) {
NgxFetch* fetch = static_cast<NgxFetch*>(c->data); NgxFetch* fetch = static_cast<NgxFetch*>(c->data);
char* data = reinterpret_cast<char*>(fetch->in_->pos); char* data = reinterpret_cast<char*>(fetch->in_->pos);
size_t size = fetch->in_->last - fetch->in_->pos; size_t size = fetch->in_->last - fetch->in_->pos;
if (size == 0) {
return true;
}
fetch->bytes_received_add(static_cast<int64>(size)); fetch->bytes_received_add(size);
ngx_log_error(NGX_LOG_DEBUG, fetch->log_, 0,
"NgxFetch %p: Handle body (%d bytes)", fetch, size);
if ( fetch->async_fetch_->Write(StringPiece(data, size), if ( fetch->async_fetch_->Write(StringPiece(data, size),
fetch->message_handler()) ) { fetch->message_handler()) ) {
fetch->content_length_ -= size; if (fetch->bytes_received_ == fetch->content_length_) {
if (fetch->content_length_ <= 0) {
fetch->done_ = true; fetch->done_ = true;
} }
fetch->in_->pos += size;
} else {
ngx_log_error(NGX_LOG_DEBUG, fetch->log_, 0,
"NgxFetch %p: async fetch write failure", fetch);
return false;
}
return true; return true;
} }
return false;
}
void NgxFetch::NgxFetchTimeout(ngx_event_t* tev) { void NgxFetch::TimeoutHandler(ngx_event_t* tev) {
NgxFetch* fetch = static_cast<NgxFetch*>(tev->data); NgxFetch* fetch = static_cast<NgxFetch*>(tev->data);
ngx_log_error(NGX_LOG_DEBUG, fetch->log_, 0,
"NgxFetch %p: TimeoutHandler called", fetch);
fetch->CallbackDone(false); fetch->CallbackDone(false);
} }
@@ -604,7 +925,7 @@ namespace net_instaweb {
ConstStringStarVector v; ConstStringStarVector v;
RequestHeaders* request_headers = async_fetch_->request_headers(); RequestHeaders* request_headers = async_fetch_->request_headers();
if (request_headers->Lookup(HttpAttributes::kUserAgent, &v)) { if (request_headers->Lookup(HttpAttributes::kUserAgent, &v)) {
for (int i = 0, n = v.size(); i < n; i++) { for (size_t i = 0, n = v.size(); i < n; i++) {
if (i != 0) { if (i != 0) {
user_agent += " "; user_agent += " ";
} }
@@ -619,11 +940,12 @@ namespace net_instaweb {
user_agent += "NgxNativeFetcher"; user_agent += "NgxNativeFetcher";
} }
GoogleString version = StrCat( GoogleString version = StrCat(
" ", kModPagespeedSubrequestUserAgent, " (", kModPagespeedSubrequestUserAgent,
"/" MOD_PAGESPEED_VERSION_STRING "-" LASTCHANGE_STRING); "/" MOD_PAGESPEED_VERSION_STRING "-" LASTCHANGE_STRING ")");
if (!StringPiece(user_agent).ends_with(version)) { if (!StringPiece(user_agent).ends_with(version)) {
user_agent += version; user_agent += version;
} }
request_headers->Add(HttpAttributes::kUserAgent, user_agent); request_headers->Add(HttpAttributes::kUserAgent, user_agent);
} }
} // namespace net_instaweb } // namespace net_instaweb
+79 -16
View File
@@ -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.
@@ -30,24 +39,72 @@ extern "C" {
#include "ngx_url_async_fetcher.h" #include "ngx_url_async_fetcher.h"
#include <vector> #include <vector>
#include "net/instaweb/util/public/basictypes.h"
#include "net/instaweb/util/public/pool.h"
#include "net/instaweb/util/public/string.h"
#include "net/instaweb/http/public/url_async_fetcher.h" #include "net/instaweb/http/public/url_async_fetcher.h"
#include "net/instaweb/http/public/response_headers.h" #include "pagespeed/kernel/base/basictypes.h"
#include "net/instaweb/http/public/response_headers_parser.h" #include "pagespeed/kernel/base/pool.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/http/response_headers.h"
#include "pagespeed/kernel/http/response_headers_parser.h"
#include "pagespeed/kernel/thread/pthread_mutex.h"
namespace net_instaweb { 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 NgxConnection : public PoolElement<NgxConnection> {
public:
NgxConnection(MessageHandler* handler, int max_keepalive_requests);
~NgxConnection();
void SetSock(u_char *sockaddr, socklen_t socklen) {
socklen_ = socklen;
ngx_memcpy(&sockaddr_, sockaddr, socklen);
}
// Close ensures that NgxConnection deletes itself at the appropriate time,
// which can be after receiving a non-keepalive response, or when the remote
// server closes the connection when the NgxConnection is pooled and idle.
void Close();
// Once keepalive is disabled, it can't be toggled back on.
void set_keepalive(bool k) { keepalive_ = keepalive_ && k; }
bool keepalive() { return keepalive_; }
typedef Pool<NgxConnection> NgxConnectionPool;
static NgxConnection* Connect(ngx_peer_connection_t* pc,
MessageHandler* handler,
int max_keepalive_requests);
static void IdleWriteHandler(ngx_event_t* ev);
static void IdleReadHandler(ngx_event_t* ev);
// Terminate will cleanup any idle connections upon shutdown.
static void Terminate();
static NgxConnectionPool connection_pool;
static PthreadMutex connection_pool_mutex;
// c_ is owned by NgxConnection and freed in ::Close()
ngx_connection_t* c_;
static const int64 keepalive_timeout_ms;
static const GoogleString ka_header;
private:
int max_keepalive_requests_;
bool keepalive_;
socklen_t socklen_;
u_char sockaddr_[NGX_SOCKADDRLEN];
MessageHandler* handler_;
DISALLOW_COPY_AND_ASSIGN(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 +140,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 +160,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 +184,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 +199,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);
+403
View File
@@ -0,0 +1,403 @@
/*
* 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_(0) { }
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;
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_ = 1;
} 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;
}
}
}
}
}
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_INFO, 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
+124
View File
@@ -0,0 +1,124 @@
/*
* 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 "pagespeed/kernel/base/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_;
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_
+21 -67
View File
@@ -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/debug.h"
#include "net/instaweb/util/public/shared_circular_buffer.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/abstract_mutex.h"
#include "pagespeed/kernel/base/debug.h"
#include "pagespeed/kernel/base/posix_timer.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/base/time_util.h"
#include "pagespeed/kernel/sharedmem/shared_circular_buffer.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,65 +88,29 @@ ngx_uint_t NgxMessageHandler::GetNgxLogLevel(MessageType type) {
return NGX_LOG_ALERT; return NGX_LOG_ALERT;
} }
void NgxMessageHandler::set_buffer(SharedCircularBuffer* buff) { void NgxMessageHandler::MessageSImpl(MessageType type,
ScopedMutex lock(mutex_.get()); const GoogleString& message) {
buffer_ = buff;
}
void NgxMessageHandler::MessageVImpl(MessageType type, const char* msg,
va_list args) {
ngx_uint_t log_level = GetNgxLogLevel(type);
GoogleString formatted_message = Format(msg, args);
if (log_ != NULL) { if (log_ != NULL) {
ngx_uint_t log_level = GetNgxLogLevel(type);
ngx_log_error(log_level, log_, 0/*ngx_err_t*/, "[%s %s] %s", ngx_log_error(log_level, log_, 0/*ngx_err_t*/, "[%s %s] %s",
kModuleName, kModPagespeedVersion, formatted_message.c_str()); kModuleName, kModPagespeedVersion, message.c_str());
} else { } else {
GoogleMessageHandler::MessageVImpl(type, msg, args); GoogleMessageHandler::MessageSImpl(type, message);
}
AddMessageToBuffer(type, message);
} }
// Prepare a log message for the SharedCircularBuffer only. void NgxMessageHandler::FileMessageSImpl(
// Prepend time and severity to message. MessageType type, const char* file, int line, const GoogleString& 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,
int line, const char* msg,
va_list args) {
ngx_uint_t log_level = GetNgxLogLevel(type);
GoogleString formatted_message = Format(msg, args);
if (log_ != NULL) { if (log_ != NULL) {
ngx_uint_t log_level = GetNgxLogLevel(type);
ngx_log_error(log_level, log_, 0/*ngx_err_t*/, "[%s %s] %s:%d:%s", ngx_log_error(log_level, log_, 0/*ngx_err_t*/, "[%s %s] %s:%d:%s",
kModuleName, kModPagespeedVersion, file, line, kModuleName, kModPagespeedVersion, file, line,
formatted_message.c_str()); message.c_str());
} else { } else {
GoogleMessageHandler::FileMessageVImpl(type, file, line, msg, args); GoogleMessageHandler::FileMessageSImpl(type, file, line, message);
} }
} AddMessageToBuffer(type, file, line, message);
// 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
+14 -32
View File
@@ -18,66 +18,48 @@
#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/util/public/basictypes.h" #include "pagespeed/kernel/base/basictypes.h"
#include "net/instaweb/util/public/google_message_handler.h" #include "pagespeed/kernel/base/message_handler.h"
#include "net/instaweb/util/public/message_handler.h" #include "pagespeed/kernel/base/string.h"
#include "net/instaweb/util/public/scoped_ptr.h" #include "pagespeed/kernel/base/string_util.h"
#include "net/instaweb/util/public/string.h" #include "pagespeed/system/system_message_handler.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 MessageSImpl(MessageType type, const GoogleString& message);
virtual void FileMessageVImpl(MessageType type, const char* filename, virtual void FileMessageSImpl(MessageType type, const char* file,
int line, const char* msg, va_list args); int line, const GoogleString& message);
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);
+1105 -740
View File
File diff suppressed because it is too large Load Diff
+23 -7
View File
@@ -34,8 +34,8 @@ extern "C" {
} }
#include "base/logging.h" #include "base/logging.h"
#include "net/instaweb/http/public/response_headers.h" #include "pagespeed/kernel/base/string_util.h"
#include "net/instaweb/util/public/string_util.h" #include "pagespeed/kernel/http/response_headers.h"
namespace net_instaweb { namespace net_instaweb {
@@ -52,7 +52,7 @@ class InPlaceResourceRecorder;
// NGX_DECLINED immediately unless send_last_buf. // NGX_DECLINED immediately unless send_last_buf.
ngx_int_t string_piece_to_buffer_chain( ngx_int_t string_piece_to_buffer_chain(
ngx_pool_t* pool, StringPiece sp, ngx_pool_t* pool, StringPiece sp,
ngx_chain_t** link_ptr, bool send_last_buf); ngx_chain_t** link_ptr, bool send_last_buf, bool send_flush);
StringPiece str_to_string_piece(ngx_str_t s); StringPiece str_to_string_piece(ngx_str_t s);
@@ -84,15 +84,11 @@ enum PreserveCachingHeaders {
typedef struct { typedef struct {
NgxBaseFetch* base_fetch; NgxBaseFetch* base_fetch;
ngx_connection_t* pagespeed_connection;
ngx_http_request_t* r; ngx_http_request_t* r;
bool html_rewrite; bool html_rewrite;
bool in_place; bool in_place;
bool write_pending;
bool fetch_done;
PreserveCachingHeaders preserve_caching_headers; PreserveCachingHeaders preserve_caching_headers;
// for html rewrite // for html rewrite
@@ -103,8 +99,20 @@ 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;
// We need to remember if the upstream had headers_out->location set, because
// we should mirror that when we write it back. nginx may absolutify
// Location: headers that start with '/' without regarding X-Forwarded-Proto.
bool location_field_set;
bool psol_vary_accept_only;
bool follow_flushes;
} ps_request_ctx_t; } ps_request_ctx_t;
ps_request_ctx_t* ps_get_request_context(ngx_http_request_t* r);
void copy_request_headers_from_ngx(const ngx_http_request_t* r, void copy_request_headers_from_ngx(const ngx_http_request_t* r,
RequestHeaders* headers); RequestHeaders* headers);
@@ -117,6 +125,14 @@ 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 ps_base_fetch {
ngx_int_t ps_base_fetch_handler(ngx_http_request_t* r);
} // namespace ps_base_fetch
} // namespace net_instaweb } // namespace net_instaweb
#endif // NGX_PAGESPEED_H_ #endif // NGX_PAGESPEED_H_
+84 -43
View File
@@ -26,31 +26,30 @@
#include "ngx_server_context.h" #include "ngx_server_context.h"
#include "ngx_url_async_fetcher.h" #include "ngx_url_async_fetcher.h"
#include "net/instaweb/http/public/content_type.h"
#include "net/instaweb/http/public/rate_controller.h" #include "net/instaweb/http/public/rate_controller.h"
#include "net/instaweb/http/public/rate_controlling_url_async_fetcher.h" #include "net/instaweb/http/public/rate_controlling_url_async_fetcher.h"
#include "net/instaweb/http/public/wget_url_fetcher.h" #include "net/instaweb/http/public/wget_url_fetcher.h"
#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/serf_url_async_fetcher.h"
#include "net/instaweb/system/public/system_caches.h"
#include "net/instaweb/system/public/system_rewrite_options.h"
#include "net/instaweb/util/public/google_message_handler.h"
#include "net/instaweb/util/public/null_shared_mem.h"
#include "net/instaweb/util/public/posix_timer.h"
#include "net/instaweb/util/public/property_cache.h" #include "net/instaweb/util/public/property_cache.h"
#include "net/instaweb/util/public/scheduler_thread.h" #include "pagespeed/kernel/base/google_message_handler.h"
#include "net/instaweb/util/public/shared_circular_buffer.h" #include "pagespeed/kernel/base/null_shared_mem.h"
#include "net/instaweb/util/public/shared_mem_statistics.h" #include "pagespeed/kernel/base/posix_timer.h"
#include "net/instaweb/util/public/slow_worker.h" #include "pagespeed/kernel/base/stdio_file_system.h"
#include "net/instaweb/util/public/stdio_file_system.h" #include "pagespeed/kernel/base/string.h"
#include "net/instaweb/util/public/string.h" #include "pagespeed/kernel/base/string_util.h"
#include "net/instaweb/util/public/string_util.h" #include "pagespeed/kernel/base/thread_system.h"
#include "net/instaweb/util/public/thread_system.h" #include "pagespeed/kernel/http/content_type.h"
#include "pagespeed/kernel/sharedmem/shared_circular_buffer.h"
#include "pagespeed/kernel/sharedmem/shared_mem_statistics.h"
#include "pagespeed/kernel/thread/pthread_shared_mem.h" #include "pagespeed/kernel/thread/pthread_shared_mem.h"
#include "pagespeed/kernel/thread/scheduler_thread.h"
#include "pagespeed/kernel/thread/slow_worker.h"
#include "pagespeed/system/in_place_resource_recorder.h"
#include "pagespeed/system/serf_url_async_fetcher.h"
#include "pagespeed/system/system_caches.h"
#include "pagespeed/system/system_rewrite_options.h"
namespace net_instaweb { namespace net_instaweb {
@@ -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),
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_mode_(ProcessScriptVariablesMode::kOff),
process_script_variables_set_(false),
shut_down_(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);
@@ -144,23 +147,17 @@ NamedLockManager* NgxRewriteDriverFactory::DefaultLockManager() {
RewriteOptions* NgxRewriteDriverFactory::NewRewriteOptions() { RewriteOptions* NgxRewriteDriverFactory::NewRewriteOptions() {
NgxRewriteOptions* options = new NgxRewriteOptions(thread_system()); NgxRewriteOptions* options = new NgxRewriteOptions(thread_system());
// TODO(jefftk): figure out why using SetDefaultRewriteLevel like
// mod_pagespeed does in mod_instaweb.cc:create_dir_config() isn't enough here
// -- if you use that instead then ngx_pagespeed doesn't actually end up
// defaulting CoreFilters.
// See: https://github.com/pagespeed/ngx_pagespeed/issues/1190
options->SetRewriteLevel(RewriteOptions::kCoreFilters); options->SetRewriteLevel(RewriteOptions::kCoreFilters);
return options; return options;
} }
void NgxRewriteDriverFactory::InitStaticAssetManager( RewriteOptions* NgxRewriteDriverFactory::NewRewriteOptionsForQuery() {
StaticAssetManager* static_asset_manager) { return new NgxRewriteOptions(thread_system());
static_asset_manager->set_library_url_prefix(kStaticAssetPrefix);
}
bool NgxRewriteDriverFactory::InitNgxUrlAsyncFetchers() {
log_ = ngx_cycle->log;
for (size_t i = 0; i < ngx_url_async_fetchers_.size(); ++i) {
if (!ngx_url_async_fetchers_[i]->Init()) {
return false;
}
}
return true;
} }
bool NgxRewriteDriverFactory::CheckResolver() { bool NgxRewriteDriverFactory::CheckResolver() {
@@ -177,11 +174,24 @@ 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;
} }
void NgxRewriteDriverFactory::ShutDown() {
if (!shut_down_) {
shut_down_ = true;
SystemRewriteDriverFactory::ShutDown();
}
}
void NgxRewriteDriverFactory::ShutDownMessageHandlers() { void NgxRewriteDriverFactory::ShutDownMessageHandlers() {
ngx_message_handler_->set_buffer(NULL); ngx_message_handler_->set_buffer(NULL);
ngx_html_parse_message_handler_->set_buffer(NULL); ngx_html_parse_message_handler_->set_buffer(NULL);
@@ -206,9 +216,19 @@ void NgxRewriteDriverFactory::StartThreads() {
threads_started_ = true; threads_started_ = true;
} }
void NgxRewriteDriverFactory::LoggingInit(ngx_log_t* log) { void NgxRewriteDriverFactory::SetMainConf(NgxRewriteOptions* main_options) {
// Propagate process-scope options from the copy we had during nginx option
// parsing to our own.
if (main_options != NULL) {
default_options()->MergeOnlyProcessScopeOptions(*main_options);
}
}
void NgxRewriteDriverFactory::LoggingInit(
ngx_log_t* log, bool may_install_crash_handler) {
log_ = log;
net_instaweb::log_message_handler::Install(log); net_instaweb::log_message_handler::Install(log);
if (install_crash_handler_) { if (may_install_crash_handler && install_crash_handler()) {
NgxMessageHandler::InstallCrashHandler(log); NgxMessageHandler::InstallCrashHandler(log);
} }
ngx_message_handler_->set_log(log); ngx_message_handler_->set_log(log);
@@ -218,12 +238,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.
@@ -244,4 +266,23 @@ void NgxRewriteDriverFactory::InitStats(Statistics* statistics) {
InPlaceResourceRecorder::InitStats(statistics); InPlaceResourceRecorder::InitStats(statistics);
} }
void NgxRewriteDriverFactory::PrepareForkedProcess(const char* name) {
ngx_pid = ngx_getpid(); // Needed for logging to have the right PIDs.
SystemRewriteDriverFactory::PrepareForkedProcess(name);
}
void NgxRewriteDriverFactory::NameProcess(const char* name) {
SystemRewriteDriverFactory::NameProcess(name);
// Superclass set status with prctl. Nginx has a helper function for setting
// argv[0] as well, so let's use that. We'll show up as:
//
// nginx: pagespeed $name
char name_for_setproctitle[32];
snprintf(name_for_setproctitle, sizeof(name_for_setproctitle),
"pagespeed %s", name);
ngx_setproctitle(name_for_setproctitle);
}
} // namespace net_instaweb } // namespace net_instaweb
+50 -51
View File
@@ -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,14 +32,9 @@ extern "C" {
#include <set> #include <set>
#include "apr_pools.h" #include "pagespeed/kernel/base/md5_hasher.h"
#include "net/instaweb/system/public/system_rewrite_driver_factory.h" #include "pagespeed/kernel/base/scoped_ptr.h"
#include "net/instaweb/util/public/md5_hasher.h" #include "pagespeed/system/system_rewrite_driver_factory.h"
#include "net/instaweb/util/public/scoped_ptr.h"
// TODO(oschaaf): We should reparent ApacheRewriteDriverFactory and
// NgxRewriteDriverFactory to a new class OriginRewriteDriverFactory and factor
// out as much as possible.
namespace net_instaweb { namespace net_instaweb {
@@ -46,16 +45,20 @@ class NgxUrlAsyncFetcher;
class SharedCircularBuffer; class SharedCircularBuffer;
class SharedMemRefererStatistics; class SharedMemRefererStatistics;
class SlowWorker; class SlowWorker;
class StaticAssetManager;
class Statistics; class Statistics;
class SystemThreadSystem; class SystemThreadSystem;
enum ProcessScriptVariablesMode {
kOff,
kLegacyRestricted,
kAll
};
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();
@@ -66,12 +69,10 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
virtual Timer* DefaultTimer(); virtual Timer* DefaultTimer();
virtual NamedLockManager* DefaultLockManager(); virtual NamedLockManager* DefaultLockManager();
// Create a new RewriteOptions. In this implementation it will be an // Create a new RewriteOptions. In this implementation it will be an
// NgxRewriteOptions. // NgxRewriteOptions, and it will have CoreFilters explicitly set.
virtual RewriteOptions* NewRewriteOptions(); virtual RewriteOptions* NewRewriteOptions();
// Initializes the StaticAssetManager. virtual RewriteOptions* NewRewriteOptionsForQuery();
virtual void InitStaticAssetManager( virtual ServerContext* NewDecodingServerContext();
StaticAssetManager* static_asset_manager);
bool InitNgxUrlAsyncFetchers();
// Check resolver configured or not. // Check resolver configured or not.
bool CheckResolver(); bool CheckResolver();
@@ -80,7 +81,8 @@ 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();
virtual void ShutDown();
// 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.
@@ -95,20 +97,8 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
InitStats(statistics); InitStats(statistics);
} }
void set_main_conf(NgxRewriteOptions* main_conf) { main_conf_ = main_conf; } void SetMainConf(NgxRewriteOptions* 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,46 +112,49 @@ 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) {
native_fetcher_max_keepalive_requests_ = x;
}
ProcessScriptVariablesMode process_script_variables() {
return process_script_variables_mode_;
} }
// We use a beacon handler to collect data for critical images, void LoggingInit(ngx_log_t* log, bool may_install_crash_handler);
// css, etc., so filters should be configured accordingly.
//
// TODO(jefftk): move to SystemRewriteDriverFactory
virtual bool UseBeaconResultsInFilters() const {
return true;
}
void LoggingInit(ngx_log_t* log);
virtual void ShutDownMessageHandlers(); virtual void ShutDownMessageHandlers();
virtual void SetCircularBuffer(SharedCircularBuffer* buffer); virtual void SetCircularBuffer(SharedCircularBuffer* buffer);
bool SetProcessScriptVariables(ProcessScriptVariablesMode mode) {
if (!process_script_variables_set_) {
process_script_variables_mode_ = mode;
process_script_variables_set_ = true;
return true;
}
return false;
}
virtual void PrepareForkedProcess(const char* name);
virtual void NameProcess(const char* name);
private: private:
Timer* timer_; Timer* timer_;
// main_conf will have only options set in the main block. It may be NULL,
// and we do not take ownership.
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 +162,12 @@ 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_;
ProcessScriptVariablesMode process_script_variables_mode_;
bool process_script_variables_set_;
bool shut_down_;
DISALLOW_COPY_AND_ASSIGN(NgxRewriteDriverFactory); DISALLOW_COPY_AND_ASSIGN(NgxRewriteDriverFactory);
}; };
+356 -73
View File
@@ -30,14 +30,57 @@ extern "C" {
#include "net/instaweb/public/version.h" #include "net/instaweb/public/version.h"
#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 "pagespeed/kernel/base/message_handler.h"
#include "net/instaweb/util/public/timer.h" #include "pagespeed/kernel/base/timer.h"
#include "pagespeed/system/system_caches.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,36 @@ 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, kProcessScopeStrict,
"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,
kProcessScopeStrict,
"Set the global admin path. Ex: /pagespeed_global_admin",
false);
MergeSubclassProperties(ngx_properties_); MergeSubclassProperties(ngx_properties_);
@@ -94,17 +157,53 @@ 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 kLegacyProcessScope as kProcessScopeStrict, failing to start
// if an option is out of place.
return option->scope() == kLegacyProcessScope ? 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")) { EnabledEnum enabled;
set_enabled(RewriteOptions::kEnabledOn); if (!ParseFromString(directive, &enabled)) {
} else if (IsDirective(directive, "off")) {
set_enabled(RewriteOptions::kEnabledOff);
} else if (IsDirective(directive, "unplugged")) {
set_enabled(RewriteOptions::kEnabledUnplugged);
} else {
return RewriteOptions::kOptionNameUnknown; return RewriteOptions::kOptionNameUnknown;
} }
if (enabled == RewriteOptions::kEnabledOff) {
// In ngx_pagespeed, for historical reasons, we treat "off" as "unplugged".
// Also, "off" is deprecated and people should be using "standby" or
// "unplugged" now depending on which sense they want. See comment on
// RewriteOptions::EnabledEnum.
enabled = RewriteOptions::kEnabledUnplugged;
}
set_enabled(enabled);
return RewriteOptions::kOptionOk; return RewriteOptions::kOptionOk;
} }
@@ -144,10 +243,27 @@ 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,
ProcessScriptVariablesMode script_mode) {
CHECK_GE(n_args, 1); CHECK_GE(n_args, 1);
StringPiece directive = args[0]; StringPiece directive = args[0];
@@ -158,94 +274,186 @@ 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.");
}
bool compile_scripts = false;
if (script_mode != ProcessScriptVariablesMode::kOff) {
// In the old mode we only allowed a few, so restrict to those.
compile_scripts =
StringCaseStartsWith(directive, "LoadFromFile") ||
StringCaseEqual(directive, "EnableFilters") ||
StringCaseEqual(directive, "DisableFilters") ||
StringCaseEqual(directive, "DownstreamCachePurgeLocationPrefix") ||
StringCaseEqual(directive, "DownstreamCachePurgeMethod") ||
StringCaseEqual(directive,
"DownstreamCacheRewrittenPercentageThreshold") ||
StringCaseEqual(directive, "ShardDomain");
// In the new behaviour we also allow scripting of query- and directory-
// scoped options.
compile_scripts |=
script_mode == ProcessScriptVariablesMode::kAll &&
(GetOptionScope(directive) <= RewriteOptions::kDirectoryScope ||
(StringCaseEqual(directive, "Allow") ||
StringCaseEqual(directive, "BlockingRewriteRefererUrls") ||
StringCaseEqual(directive, "Disallow") ||
StringCaseEqual(directive, "DistributableFilters") ||
StringCaseEqual(directive, "Domain") ||
StringCaseEqual(directive, "ExperimentVariable") ||
StringCaseEqual(directive, "ExperimentSpec") ||
StringCaseEqual(directive, "ForbidFilters") ||
StringCaseEqual(directive, "RetainComment") ||
StringCaseEqual(directive, "CustomFetchHeader") ||
StringCaseEqual(directive, "MapOriginDomain") ||
StringCaseEqual(directive, "MapProxyDomain") ||
StringCaseEqual(directive, "MapRewriteDomain") ||
StringCaseEqual(directive, "UrlValuedAttribute") ||
StringCaseEqual(directive, "Library")));
}
ScriptLine* script_line;
script_line = NULL;
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, ProcessScriptVariablesMode mode;
&NgxRewriteDriverFactory::set_use_native_fetcher); if (StringCaseEqual(arg, "all")) {
} else if (IsDirective(directive, "RateLimitBackgroundFetches")) { mode = ProcessScriptVariablesMode::kAll;
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>( } else if (StringCaseEqual(arg, "on")) {
arg, driver_factory, mode = ProcessScriptVariablesMode::kLegacyRestricted;
&NgxRewriteDriverFactory::set_rate_limit_background_fetches); } else if (StringCaseEqual(arg, "off")) {
} else if (IsDirective(directive, "ForceCaching")) { mode = ProcessScriptVariablesMode::kOff;
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
arg, driver_factory,
&SystemRewriteDriverFactory::set_force_caching);
} else if (IsDirective(directive, "ListOutstandingUrlsOnError")) {
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
arg, driver_factory,
&SystemRewriteDriverFactory::list_outstanding_urls_on_error);
} else if (IsDirective(directive, "TrackOriginalContentLength")) {
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
arg, driver_factory,
&SystemRewriteDriverFactory::set_track_original_content_length);
} else { } else {
result = ParseAndSetOptionFromName1(directive, args[1], &msg, handler); return const_cast<char*>(
"pagespeed ProcessScriptVariables: invalid value");
}
if (driver_factory->SetProcessScriptVariables(mode)) {
result = RewriteOptions::kOptionOk;
} else {
return const_cast<char*>(
"pagespeed ProcessScriptVariables: can only be set once");
}
} else {
return const_cast<char*>(
"ProcessScriptVariables is only allowed at the top level");
}
} else {
result = ParseAndSetOptionFromName1(directive, arg, &msg, handler);
if (result == RewriteOptions::kOptionNameUnknown) {
result = driver_factory->ParseAndSetOption1(
directive,
arg,
scope >= RewriteOptions::kLegacyProcessScope,
&msg,
handler);
}
} }
} else if (n_args == 3) { } 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 {
bool ok = driver_factory->caches()->CreateShmMetadataCache(
args[1].as_string(), kb, &msg);
result = ok ? kOptionOk : kOptionValueInvalid;
}
} else {
result = ParseAndSetOptionFromName2(directive, args[1], args[2], result = ParseAndSetOptionFromName2(directive, args[1], args[2],
&msg, handler); &msg, handler);
if (result == RewriteOptions::kOptionNameUnknown) {
result = driver_factory->ParseAndSetOption2(
directive,
args[1],
args[2],
scope >= RewriteOptions::kLegacyProcessScope,
&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,9 +461,84 @@ 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*/,
ProcessScriptVariablesMode::kOff);
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;
} }
+126 -4
View File
@@ -27,20 +27,91 @@ extern "C" {
#include <ngx_http.h> #include <ngx_http.h>
} }
#include <vector>
#include "ngx_rewrite_driver_factory.h"
#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 "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/ref_counted_ptr.h"
#include "pagespeed/kernel/base/stl_util.h" // for STLDeleteElements
#include "pagespeed/system/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,9 +126,19 @@ 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, ProcessScriptVariablesMode script_mode);
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;
@@ -67,6 +148,30 @@ class NgxRewriteOptions : public SystemRewriteOptions {
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 +213,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);
+28 -9
View File
@@ -27,15 +27,16 @@ extern "C" {
#include "ngx_rewrite_driver_factory.h" #include "ngx_rewrite_driver_factory.h"
#include "ngx_rewrite_options.h" #include "ngx_rewrite_options.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h" #include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/system/public/add_headers_fetcher.h" #include "pagespeed/system/add_headers_fetcher.h"
#include "net/instaweb/system/public/loopback_route_fetcher.h" #include "pagespeed/system/loopback_route_fetcher.h"
#include "net/instaweb/system/public/system_request_context.h" #include "pagespeed/system/system_request_context.h"
namespace net_instaweb { namespace net_instaweb {
NgxServerContext::NgxServerContext( NgxServerContext::NgxServerContext(
NgxRewriteDriverFactory* factory, StringPiece hostname, int port) NgxRewriteDriverFactory* factory, StringPiece hostname, int port)
: SystemServerContext(factory, hostname, port) { : SystemServerContext(factory, hostname, port),
ngx_http2_variable_index_(NGX_ERROR) {
} }
NgxServerContext::~NgxServerContext() { } NgxServerContext::~NgxServerContext() { }
@@ -48,7 +49,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*>(
@@ -70,10 +71,28 @@ SystemRequestContext* NgxServerContext::NewRequestContext(
local_ip.len = 0; local_ip.len = 0;
} }
return new SystemRequestContext(thread_system()->NewMutex(), SystemRequestContext* ctx = new SystemRequestContext(
timer(), thread_system()->NewMutex(), timer(),
local_port, ps_determine_host(r), local_port, str_to_string_piece(local_ip));
str_to_string_piece(local_ip));
// See if http2 is in use.
if (ngx_http2_variable_index_ >= 0) {
ngx_http_variable_value_t* val =
ngx_http_get_indexed_variable(r, ngx_http2_variable_index_);
if (val != NULL && val->valid) {
StringPiece str_val(reinterpret_cast<char*>(val->data), val->len);
if (str_val == "h2" || str_val == "h2c") {
ctx->set_using_http2(true);
}
}
}
return ctx;
}
GoogleString NgxServerContext::FormatOption(StringPiece option_name,
StringPiece args) {
return StrCat("pagespeed ", option_name, " ", args, ";");
} }
} // namespace net_instaweb } // namespace net_instaweb
+16 -3
View File
@@ -22,7 +22,7 @@
#define NGX_SERVER_CONTEXT_H_ #define NGX_SERVER_CONTEXT_H_
#include "ngx_message_handler.h" #include "ngx_message_handler.h"
#include "net/instaweb/system/public/system_server_context.h" #include "pagespeed/system/system_server_context.h"
extern "C" { extern "C" {
#include <ngx_http.h> #include <ngx_http.h>
@@ -40,8 +40,9 @@ class NgxServerContext : public SystemServerContext {
NgxRewriteDriverFactory* factory, StringPiece hostname, int port); NgxRewriteDriverFactory* factory, StringPiece hostname, int port);
virtual ~NgxServerContext(); virtual ~NgxServerContext();
// We expect to use ProxyFetch with HTML. // We don't allow ProxyFetch to fetch HTML via MapProxyDomain. We will call
virtual bool ProxiesHtml() const { return true; } // set_trusted_input() on any ProxyFetches we use to transform internal HTML.
virtual bool ProxiesHtml() const { return false; }
// Call only when you need an NgxRewriteOptions. If you don't need // Call only when you need an NgxRewriteOptions. If you don't need
// nginx-specific behavior, call global_options() instead which doesn't // nginx-specific behavior, call global_options() instead which doesn't
@@ -55,8 +56,20 @@ class NgxServerContext : public SystemServerContext {
return dynamic_cast<NgxMessageHandler*>(message_handler()); return dynamic_cast<NgxMessageHandler*>(message_handler());
} }
virtual GoogleString FormatOption(StringPiece option_name, StringPiece args);
void set_ngx_http2_variable_index(ngx_int_t idx) {
ngx_http2_variable_index_ = idx;
}
ngx_int_t ngx_http2_variable_index() const {
return ngx_http2_variable_index_;
}
private: private:
NgxRewriteDriverFactory* ngx_factory_; NgxRewriteDriverFactory* ngx_factory_;
// what index the "http2" var is, or NGX_ERROR.
ngx_int_t ngx_http2_variable_index_;
DISALLOW_COPY_AND_ASSIGN(NgxServerContext); DISALLOW_COPY_AND_ASSIGN(NgxServerContext);
}; };
+107 -132
View File
@@ -31,22 +31,22 @@ extern "C" {
#include <map> #include <map>
#include <set> #include <set>
#include "net/instaweb/util/public/basictypes.h"
#include "net/instaweb/http/public/async_fetch.h" #include "net/instaweb/http/public/async_fetch.h"
#include "net/instaweb/http/public/inflating_fetch.h" #include "net/instaweb/http/public/inflating_fetch.h"
#include "net/instaweb/http/public/request_headers.h"
#include "net/instaweb/http/public/response_headers.h"
#include "net/instaweb/http/public/response_headers_parser.h"
#include "net/instaweb/public/version.h" #include "net/instaweb/public/version.h"
#include "net/instaweb/util/public/condvar.h" #include "pagespeed/kernel/base/basictypes.h"
#include "net/instaweb/util/public/message_handler.h" #include "pagespeed/kernel/base/condvar.h"
#include "net/instaweb/util/public/pool.h" #include "pagespeed/kernel/base/message_handler.h"
#include "net/instaweb/util/public/pool_element.h" #include "pagespeed/kernel/base/pool.h"
#include "net/instaweb/util/public/statistics.h" #include "pagespeed/kernel/base/pool_element.h"
#include "net/instaweb/util/public/string_util.h" #include "pagespeed/kernel/base/statistics.h"
#include "net/instaweb/util/public/thread_system.h" #include "pagespeed/kernel/base/string_util.h"
#include "net/instaweb/util/public/timer.h" #include "pagespeed/kernel/base/thread_system.h"
#include "net/instaweb/util/public/writer.h" #include "pagespeed/kernel/base/timer.h"
#include "pagespeed/kernel/base/writer.h"
#include "pagespeed/kernel/http/request_headers.h"
#include "pagespeed/kernel/http/response_headers.h"
#include "pagespeed/kernel/http/response_headers_parser.h"
namespace net_instaweb { namespace net_instaweb {
@@ -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,23 +64,30 @@ 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),
event_connection_(NULL) {
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;
pool_ = NULL; pool_ = NULL;
command_connection_ = NULL;
pipe_fd_ = -1;
resolver_ = resolver; resolver_ = resolver;
// If init fails, set shutdown_ so no fetches will be attempted.
if (!Init(const_cast<ngx_cycle_t*>(ngx_cycle))) {
shutdown_ = true;
message_handler_->Message(
kError, "NgxUrlAsyncFetcher failed to init, fetching disabled.");
}
} }
NgxUrlAsyncFetcher::~NgxUrlAsyncFetcher() { NgxUrlAsyncFetcher::~NgxUrlAsyncFetcher() {
DCHECK(shutdown_) << "Shut down before destructing NgxUrlAsyncFetcher.";
message_handler_->Message( message_handler_->Message(
kInfo, kInfo,
"Destruct NgxUrlAsyncFetcher with [%d] active fetchers", "Destruct NgxUrlAsyncFetcher with [%d] active fetchers",
@@ -87,25 +95,48 @@ namespace net_instaweb {
CancelActiveFetches(); CancelActiveFetches();
active_fetches_.DeleteAll(); active_fetches_.DeleteAll();
NgxConnection::Terminate();
if (pool_ != NULL) { if (pool_ != NULL) {
ngx_destroy_pool(pool_); ngx_destroy_pool(pool_);
pool_ = NULL; pool_ = NULL;
} }
if (command_connection_ != NULL) {
ngx_close_connection(command_connection_);
command_connection_ = NULL;
}
if (pipe_fd_ != -1) {
close(pipe_fd_);
pipe_fd_ = -1;
}
if (mutex_ != NULL) { if (mutex_ != NULL) {
delete mutex_; delete mutex_;
mutex_ = NULL; mutex_ = NULL;
} }
} }
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
@@ -120,9 +151,13 @@ namespace net_instaweb {
// Create the pool for fetcher, create the pipe, add the read event for main // Create the pool for fetcher, create the pipe, add the read event for main
// thread. It should be called in the worker process. // thread. It should be called in the worker process.
bool NgxUrlAsyncFetcher::Init() { bool NgxUrlAsyncFetcher::Init(ngx_cycle_t* cycle) {
log_ = ngx_cycle->log; log_ = cycle->log;
CHECK(event_connection_ == NULL) << "event connection already set";
event_connection_ = new NgxEventConnection(ReadCallback);
if (!event_connection_->Init(cycle)) {
return false;
}
if (pool_ == NULL) { if (pool_ == NULL) {
pool_ = ngx_create_pool(4096, log_); pool_ = ngx_create_pool(4096, log_);
if (pool_ == NULL) { if (pool_ == NULL) {
@@ -132,50 +167,15 @@ namespace net_instaweb {
} }
} }
int pipe_fds[2]; if (proxy_.url.len == 0) {
int rc = pipe(pipe_fds);
if (rc != 0) {
ngx_log_error(NGX_LOG_ERR, log_, 0, "pipe() failed");
return false;
}
if (ngx_nonblocking(pipe_fds[0]) == -1) {
ngx_log_error(NGX_LOG_ERR, log_, 0, "nonblocking pipe[0] failed");
return false;
}
if (ngx_nonblocking(pipe_fds[1]) == -1) {
ngx_log_error(NGX_LOG_ERR, log_, 0, "nonblocking pipe[1] failed");
return false;
}
pipe_fd_ = pipe_fds[1];
command_connection_ = ngx_get_connection(pipe_fds[0], log_);
if (command_connection_ == NULL) {
close(pipe_fds[1]);
close(pipe_fds[0]);
pipe_fd_ = -1;
return false;
}
command_connection_->recv = ngx_recv;
command_connection_->send = ngx_send;
command_connection_->recv_chain = ngx_recv_chain;
command_connection_->send_chain = ngx_send_chain;
command_connection_->log = log_;
command_connection_->read->log = log_;
command_connection_->write->log = log_;
command_connection_->data = this;
command_connection_->read->handler = CommandHandler;
ngx_add_event(command_connection_->read, NGX_READ_EVENT, 0);
if (url_.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;
@@ -183,7 +183,28 @@ namespace net_instaweb {
void NgxUrlAsyncFetcher::ShutDown() { void NgxUrlAsyncFetcher::ShutDown() {
shutdown_ = true; shutdown_ = true;
SendCmd('S'); if (!pending_fetches_.empty()) {
for (Pool<NgxFetch>::iterator p = pending_fetches_.begin(),
e = pending_fetches_.end(); p != e; p++) {
NgxFetch* fetch = *p;
fetch->CallbackDone(false);
}
pending_fetches_.DeleteAll();
}
if (!active_fetches_.empty()) {
for (Pool<NgxFetch>::iterator p = active_fetches_.begin(),
e = active_fetches_.end(); p != e; p++) {
NgxFetch* fetch = *p;
fetch->CallbackDone(false);
}
active_fetches_.Clear();
}
if (event_connection_ != NULL) {
event_connection_->Shutdown();
delete event_connection_;
event_connection_ = NULL;
}
} }
// It's called in the rewrite thread. All the fetches are started at // It's called in the rewrite thread. All the fetches are started at
@@ -191,58 +212,35 @@ 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); // Don't accept new fetches when shut down. This flow is also entered when
// we did not initialize properly in ::Init().
if (shutdown_) {
async_fetch->Done(false);
return;
}
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');
}
// send command to nginx main thread // TODO(oschaaf): thread safety on written vs shutdown.
// 'F' : start a fetch // It is possible that shutdown() is called after writing an event? In that
// 'S' : shutdown the fetcher // case, this could (rarely) fail when it shouldn't.
bool NgxUrlAsyncFetcher::SendCmd(const char command) { bool written = event_connection_->WriteEvent(this);
int rc; CHECK(written || shutdown_) << "NgxUrlAsyncFetcher: event write failure";
while (true) {
rc = write(pipe_fd_, &command, 1);
if (rc == 1) {
return true;
} else if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
// TODO(junmin): It's rare. But it need be fixed.
} else {
return false;
}
}
return true;
} }
// 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::ReadCallback(const ps_event_data& data) {
char command;
int rc;
ngx_connection_t* c = static_cast<ngx_connection_t*>(cmdev->data);
NgxUrlAsyncFetcher* fetcher = static_cast<NgxUrlAsyncFetcher*>(c->data);
do {
rc = read(c->fd, &command, 1);
} while (rc == -1 && errno == EINTR);
CHECK(rc == -1 || rc == 0 || rc == 1);
if (rc == -1 || rc == 0) {
// EAGAIN
return;
}
std::vector<NgxFetch*> to_start; std::vector<NgxFetch*> to_start;
NgxUrlAsyncFetcher* fetcher = reinterpret_cast<NgxUrlAsyncFetcher*>(
data.sender);
switch (command) {
// All the new fetches are appended in the pending_fetches.
// Start all these fetches.
case 'F':
fetcher->mutex_->Lock(); fetcher->mutex_->Lock();
fetcher->completed_fetches_.DeleteAll(); fetcher->completed_fetches_.DeleteAll();
for (Pool<NgxFetch>::iterator p = fetcher->pending_fetches_.begin(), for (Pool<NgxFetch>::iterator p = fetcher->pending_fetches_.begin(),
e = fetcher->pending_fetches_.end(); p != e; p++) { e = fetcher->pending_fetches_.end(); p != e; p++) {
NgxFetch* fetch = *p; NgxFetch* fetch = *p;
@@ -255,29 +253,6 @@ namespace net_instaweb {
for (size_t i = 0; i < to_start.size(); i++) { for (size_t i = 0; i < to_start.size(); i++) {
fetcher->StartFetch(to_start[i]); fetcher->StartFetch(to_start[i]);
} }
CHECK(ngx_handle_read_event(cmdev, 0) == NGX_OK);
break;
// Shutdown all the fetches.
case 'S':
if (!fetcher->pending_fetches_.empty()) {
fetcher->pending_fetches_.DeleteAll();
}
if (!fetcher->active_fetches_.empty()) {
for (Pool<NgxFetch>::iterator p = fetcher->active_fetches_.begin(),
e = fetcher->active_fetches_.end(); p != e; p++) {
NgxFetch* fetch = *p;
fetch->CallbackDone(false);
}
fetcher->active_fetches_.Clear();
}
CHECK(ngx_del_event(cmdev, NGX_READ_EVENT, 0) == NGX_OK);
break;
default:
break;
}
return; return;
} }
+18 -13
View File
@@ -33,11 +33,14 @@ extern "C" {
} }
#include <vector> #include <vector>
#include "ngx_event_connection.h"
#include "net/instaweb/http/public/url_async_fetcher.h" #include "net/instaweb/http/public/url_async_fetcher.h"
#include "net/instaweb/util/public/basictypes.h" #include "pagespeed/kernel/base/basictypes.h"
#include "net/instaweb/util/public/pool.h" #include "pagespeed/kernel/base/pool.h"
#include "net/instaweb/util/public/string.h" #include "pagespeed/kernel/base/string.h"
#include "net/instaweb/util/public/thread_system.h" #include "pagespeed/kernel/base/thread_system.h"
namespace net_instaweb { namespace net_instaweb {
@@ -53,27 +56,27 @@ 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 // intializations which can't be done in the master process
bool Init(); bool Init(ngx_cycle_t* cycle);
// shutdown all the fetches. // shutdown all the fetches.
virtual void ShutDown(); virtual void ShutDown();
// the read handler in the main thread
static void ReadCallback(const ps_event_data& data);
virtual bool SupportsHttps() const { return false; } virtual bool SupportsHttps() const { return false; }
virtual void Fetch(const GoogleString& url, virtual void Fetch(const GoogleString& url,
MessageHandler* message_handler, MessageHandler* message_handler,
AsyncFetch* callback); AsyncFetch* callback);
// send the command from the current thread to main thread
bool SendCmd(const char command);
// the read handler in the main thread
static void CommandHandler(ngx_event_t* cmdev);
bool StartFetch(NgxFetch* fetch); bool StartFetch(NgxFetch* fetch);
// Remove the completed fetch from the active fetch set, and put it into a // Remove the completed fetch from the active fetch set, and put it into a
@@ -115,13 +118,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_;
@@ -135,12 +139,13 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
ngx_pool_t* pool_; ngx_pool_t* pool_;
ngx_log_t* log_; ngx_log_t* log_;
ngx_connection_t* command_connection_; // the command pipe
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_;
NgxEventConnection* event_connection_;
DISALLOW_COPY_AND_ASSIGN(NgxUrlAsyncFetcher); DISALLOW_COPY_AND_ASSIGN(NgxUrlAsyncFetcher);
}; };
Executable → Regular
+719 -1288
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+33 -10
View File
@@ -23,10 +23,19 @@
# Exits with status 2 if command line args are wrong. # Exits with status 2 if command line args are wrong.
# #
# Usage: # Usage:
# ./run_tests.sh primary_port secondary_port mod_pagespeed_dir # ./run_tests.sh
# Example: # Or:
# ./run_tests.sh 8050 8051 /path/to/mod_pagespeed # ./run_tests.sh /path/to/mod_pagespeed /path/to/nginx/binary
# #
# If you built ngx_pagespeed with "scripts/build_ngx_pagespeed.sh --devel" then
# you don't need to pass any arguments to run_tests.sh. Otherwise, you'll need
# to tell it where to find a mod_pagespeed checkout (for example html files etc)
# and the nginx binary to test.
#
# By default the test script uses several ports. If you have a port conflict
# and need to override one you can do that by setting the relevant environment
# variable. For example:
# PRIMARY_PORT=1234 ./run_tests.sh /.../mod_pagespeed /.../nginx/binary
# Normally we test only with the native fetcher off. Set # Normally we test only with the native fetcher off. Set
# TEST_NATIVE_FETCHER=true to also test the native fetcher, set # TEST_NATIVE_FETCHER=true to also test the native fetcher, set
@@ -43,26 +52,37 @@ RUN_TESTS=${RUN_TESTS:-true}
# true. # true.
USE_VALGRIND=${USE_VALGRIND:-false} USE_VALGRIND=${USE_VALGRIND:-false}
if [ "$#" -ne 4 ] ; then if [ "$#" -eq 0 ]; then
echo "Usage: $0 primary_port secondary_port mod_pagespeed_dir" MOD_PAGESPEED_DIR="testing-dependencies/mod_pagespeed/"
echo " nginx_executable" NGINX_EXECUTABLE="nginx/sbin/nginx"
elif [ "$#" -eq 2 ]; then
MOD_PAGESPEED_DIR="$1"
NGINX_EXECUTABLE="$2"
else
echo "Usage: $0 [mod_pagespeed_dir nginx_executable]"
exit 2 exit 2
fi fi
PRIMARY_PORT="$1" : ${PRIMARY_PORT:=8050}
SECONDARY_PORT="$2" : ${SECONDARY_PORT:=8051}
MOD_PAGESPEED_DIR="$3" : ${CONTROLLER_PORT:=8053}
NGINX_EXECUTABLE="$4" : ${RCPORT:=9991}
: ${PAGESPEED_TEST_HOST:=selfsigned.modpagespeed.com}
: ${PHP_PORT:=9000}
this_dir="$( cd $(dirname "$0") && pwd)" this_dir="$( cd $(dirname "$0") && pwd)"
function run_test_checking_failure() { function run_test_checking_failure() {
"$MOD_PAGESPEED_DIR/install/start_php.sh" "$PHP_PORT"
USE_VALGRIND="$USE_VALGRIND" \ USE_VALGRIND="$USE_VALGRIND" \
PRIMARY_PORT="$PRIMARY_PORT" \ PRIMARY_PORT="$PRIMARY_PORT" \
SECONDARY_PORT="$SECONDARY_PORT" \ SECONDARY_PORT="$SECONDARY_PORT" \
MOD_PAGESPEED_DIR="$MOD_PAGESPEED_DIR" \ MOD_PAGESPEED_DIR="$MOD_PAGESPEED_DIR" \
NGINX_EXECUTABLE="$NGINX_EXECUTABLE" \ NGINX_EXECUTABLE="$NGINX_EXECUTABLE" \
PAGESPEED_TEST_HOST="$PAGESPEED_TEST_HOST" \
RUN_TESTS="$RUN_TESTS" \ RUN_TESTS="$RUN_TESTS" \
CONTROLLER_PORT="$CONTROLLER_PORT" \
RCPORT="$RCPORT" \
bash "$this_dir/nginx_system_test.sh" bash "$this_dir/nginx_system_test.sh"
STATUS=$? STATUS=$?
echo "With $@ setup." echo "With $@ setup."
@@ -73,6 +93,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
+193
View File
@@ -0,0 +1,193 @@
# 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
...
}
{
<re2 uninitialized value in optimized code>
Memcheck:Value8
fun:_ZNK3re210SparseSetTIvE8containsEi
...
}
{
<re2 uninitialized value in optimized code>
Memcheck:Cond
fun:_ZNK3re210SparseSetTIvE8containsEi
...
}
{
<re2 uninitialized value in optimized code>
Memcheck:Value8
fun:_ZNK3re211SparseArrayIiE9has_indexEi
...
}
{
<re2 uninitialized value in optimized code>
Memcheck:Cond
fun:_ZNK3re211SparseArrayIiE9has_indexEi
...
}