Compare commits

...

136 Commits

Author SHA1 Message Date
Jeffrey Crowell b5dc1083f4 Readd pthread_mutex.h include on ngx_fetch.cc.
Messed up the merge of 0290f52a88 originally, add the include back.
2014-10-27 14:51:45 -04:00
Otto van der Schaaf ab9929e5a5 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)

Conflicts:
	src/ngx_fetch.cc
2014-10-24 16:23:45 -04:00
Jeffrey Crowell 9832a049fe release: version 1.9.32.1 -> 1.9.32.2 2014-10-24 15:49:48 -04:00
Otto van der Schaaf ccd800a0b1 Merge pull request #818 from pagespeed/oschaaf-fix-stdio-logging
logging: init logging early, hand ProxyFetchFactory correct server log
2014-10-16 15:58:57 +02:00
Otto van der Schaaf e2e21474ce logging: init logging early, hand ProxyFetchFactory correct server log
- Prevent logging to stdout/stderr, make sure we log to error.log for
early messages during initialization. Note that nginx is still working
to setup its logging configuration, so these early messages will go
through its defaults. Which means that only warnings or worse will pass
for early logging messages.
- Make sure we init ProxyFetchFactories's NgxMessageHandler to the correct
server{} specific log so it will write to the error_log configured
in the server{} block instead of the global error_log.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/808
Helps https://github.com/pagespeed/ngx_pagespeed/issues/817
2014-10-01 11:09:20 +02:00
Otto van der Schaaf 7680a159a7 Merge pull request #814 from pagespeed/oschaaf-gcc-4.1.2-segfault
gcc-4.1.2-segfault: Make sure we init all ps_request_ctx_t members
2014-09-26 16:23:30 +02:00
Otto van der Schaaf 7aa5bc4a99 gcc-4.1.2-segfault: Make sure we init all ps_request_ctx_t members
When built with gcc-4.1.2, this change prevents segmentation faults
caused by undefined behaviour via uninitialized members.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/813
2014-09-26 00:17:11 +02:00
Jeffrey Crowell 462acc9eee update version number in the config file 2014-09-17 11:10:56 -04:00
Jeffrey Crowell 4678a62be8 Fix config file based on trunk-tracking instead of master 2014-09-17 11:05:55 -04:00
Jeffrey Crowell 525e331c0c Fix config file
Config was improperly merged from master, fixing.
2014-09-17 10:26:11 -04:00
Otto van der Schaaf dc40c902ec 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-15 10:37:42 -04:00
Otto van der Schaaf 6a8a1c5bf7 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-12 10:59:16 -04:00
Jeffrey Crowell 5bcd9e277e release: version 1.8.31.4 -> 1.9.32.1 2014-09-11 13:47:00 -04:00
Jeffrey Crowell 554577bbf2 Merge branch 'master' into HEAD
Preparing for 1.9.32.1 release

Conflicts:
	config
	src/ngx_pagespeed.cc
	src/ngx_rewrite_driver_factory.h
	src/ngx_rewrite_options.cc
	test/nginx_system_test.sh
	test/pagespeed_test.conf.template
2014-09-11 13:45:22 -04:00
Jeffrey Crowell 458a2f5236 Merge pull request #789 from gmszone/patch-1
Update config
2014-09-03 09:59:38 -04:00
Phodal Huang 71e89efc64 Update config 2014-09-02 13:49:49 +08: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
Otto van der Schaaf bbdfb5b429 Merge pull request #744 from pagespeed/oschaaf-double-location
location-header: tweak location header handling
2014-07-16 00:50:25 +02: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
Otto van der Schaaf 1f02f368e1 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 https://github.com/pagespeed/ngx_pagespeed/issues/725
2014-06-30 00:54:58 +02:00
Otto van der Schaaf 0c1cbbdf64 Merge pull request #736 from pagespeed/oschaaf-lff-script-support
script-variables: Support LoadFromFileXXX
2014-06-28 00:01:03 +02:00
Otto van der Schaaf 75a4481750 script-variables: Support LoadFromFileXXX
Add support for script variables in LoadFromFileXXX configuration,
which can be enabled by adding "pagespeed ProcessScriptVariables on" in
the http{} block.

Note that tests currently can't pass because of a failing unrelated test:
"start_test PageSpeed CSS loaded in fallback mode is always chunked"
I have tested this by commenting that test, but re-enabled the test before
making the pull to keep the diff clean.

Fixes https://github.com/pagespeed/ngx_pagespeed/issues/549
Docs: https://github.com/pagespeed/ngx_pagespeed/wiki/Script-variables-in-LoadFromFile-configuration
2014-06-27 23:55:34 +02: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 b1e188bdb6 readme: reference doc on developers.google.com instead of duplicating it.
Conflicts:
	README.md
2014-06-23 10:41:47 -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 cf434f71cc trunk-tracking: port r3937 which supports custom url-valued attributes overriding spec-defined ones 2014-04-22 16:37:13 -04:00
22 changed files with 2592 additions and 1069 deletions
+6 -98
View File
@@ -19,90 +19,15 @@ optimizations, see our <a href="http://ngxpagespeed.com">demonstration site</a>.
## How to build
Because nginx does not support dynamic loading of modules, you need to compile
nginx from source to add ngx_pagespeed. Alternatively, if you're using Tengine you can [install ngx_pagespeed without
recompiling Tengine](https://github.com/pagespeed/ngx_pagespeed/wiki/Using-ngx_pagespeed-with-Tengine).
1. Install dependencies:
```bash
# These are for RedHat, CentOS, and Fedora.
$ sudo yum install gcc-c++ pcre-dev pcre-devel zlib-devel make
# These are for Debian. Ubuntu will be similar.
$ sudo apt-get install build-essential zlib1g-dev libpcre3 libpcre3-dev
```
2. Download ngx_pagespeed:
```bash
$ cd ~
$ wget https://github.com/pagespeed/ngx_pagespeed/archive/v1.8.31.4-beta.zip
$ unzip v1.8.31.4-beta.zip # or unzip v1.8.31.4-beta
$ cd ngx_pagespeed-1.8.31.4-beta/
$ wget https://dl.google.com/dl/page-speed/psol/1.8.31.4.tar.gz
$ tar -xzvf 1.8.31.4.tar.gz # expands to psol/
```
3. Download and build nginx:
```bash
$ cd ~
$ # check http://nginx.org/en/download.html for the latest version
$ wget http://nginx.org/download/nginx-1.6.0.tar.gz
$ tar -xvzf nginx-1.6.0.tar.gz
$ cd nginx-1.6.0/
$ ./configure --add-module=$HOME/ngx_pagespeed-1.8.31.4-beta
$ make
$ sudo make install
```
If this doesn't work see the [build
troubleshooting](https://github.com/pagespeed/ngx_pagespeed/wiki/Build-Troubleshooting) page.
This will use a binary PageSpeed Optimization Library, but it's also possible to
[build PSOL from
source](https://github.com/pagespeed/ngx_pagespeed/wiki/Building-PSOL-From-Source).
Note: ngx_pagespeed currently doesn't support Windows or MacOS because the
underlying PSOL library doesn't.
Follow the steps on <a
href="https://developers.google.com/speed/pagespeed/module/build_ngx_pagespeed_from_source">build
ngx_pagespeed from source</a>.
## How to use
In your `nginx.conf`, add to the main or server block:
```nginx
pagespeed on;
pagespeed FileCachePath /var/ngx_pagespeed_cache; # Use tmpfs for best results.
```
In every server block where pagespeed is enabled add:
```apache
# Ensure requests for pagespeed optimized resources go to the pagespeed
# handler and no extraneous headers get set.
location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; }
location ~ "^/pagespeed_static/" { }
location ~ "^/ngx_pagespeed_beacon$" { }
```
To confirm that the module is loaded, fetch a page and check that you see the
`X-Page-Speed` header:
```bash
$ curl -I 'http://localhost:8050/some_page/' | grep X-Page-Speed
X-Page-Speed: 1.8.31.4-...
```
Looking at the source of a few pages you should see various changes, such as
urls being replaced with new ones like `yellow.css.pagespeed.ce.lzJ8VcVi1l.css`.
For complete documentation, see [Using
PageSpeed](https://developers.google.com/speed/pagespeed/module/using).
There are extensive system tests which cover most of ngx_pagespeed's
functionality. Consider [testing your
installation](https://github.com/pagespeed/ngx_pagespeed/wiki/Testing).
Follow the steps on <a
href="https://developers.google.com/speed/pagespeed/module/configuration">PageSpeed
configuration</a>.
For feedback, questions, and to follow
the progress of the project:
@@ -111,20 +36,3 @@ the progress of the project:
list](https://groups.google.com/forum/#!forum/ngx-pagespeed-discuss)
- [ngx-pagespeed-announce mailing
list](https://groups.google.com/forum/#!forum/ngx-pagespeed-announce)
Note: The
[canonicalize_javascript_libraries](https://developers.google.com/speed/pagespeed/module/filter-canonicalize-js)
depends on `pagespeed_libraries.conf` which is distributed in Apache's format.
To convert it to the Nginx format, run:
```bash
$ scripts/pagespeed_libraries_generator.sh > ~/pagespeed_libraries.conf
$ sudo mv ~/pagespeed_libraries.conf /etc/nginx/
```
And then include it in your Nginx configuration by reference:
```nginx
include pagespeed_libraries.conf;
pagespeed EnableFilters canonicalize_javascript_libraries;
```
+33 -27
View File
@@ -27,8 +27,8 @@ if [ "$mod_pagespeed_dir" = "unset" ] ; then
echo " You need to separately download the pagespeed library:"
echo ""
echo " $ cd /path/to/ngx_pagespeed"
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.8.31.4.tar.gz"
echo " $ tar -xzvf 1.8.31.4.tar.gz # expands to psol/"
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.9.32.2.tar.gz"
echo " $ tar -xzvf 1.9.32.2.tar.gz # expands to psol/"
echo ""
echo " Or see the installation instructions:"
echo " https://github.com/pagespeed/ngx_pagespeed#how-to-build"
@@ -39,20 +39,6 @@ else
build_from_source=true
fi
echo "mod_pagespeed_dir=$mod_pagespeed_dir"
echo "build_from_source=$build_from_source"
ngx_feature="psol"
ngx_feature_name=""
ngx_feature_run=no
ngx_feature_incs="
#include \"net/instaweb/htmlparse/public/html_parse.h\"
#include \"net/instaweb/htmlparse/public/html_writer_filter.h\"
#include \"net/instaweb/util/public/string.h\"
#include \"net/instaweb/util/public/string_writer.h\"
#include \"net/instaweb/util/public/null_message_handler.h\"
"
os_name='unknown_os'
arch_name='unknown_arch'
uname_os=`uname`
@@ -113,6 +99,31 @@ if [ "$WNO_ERROR" = "YES" ]; then
CFLAGS="$CFLAGS -Wno-error"
fi
psol_binary="${PSOL_BINARY:-unset}"
if [ "$psol_binary" = "unset" ] ; then
if $build_from_source ; then
psol_binary="\
$mod_pagespeed_dir/net/instaweb/automatic/pagespeed_automatic.a"
else
psol_library_dir="$ngx_addon_dir/psol/lib/$buildtype/$os_name/$arch_name"
psol_binary="$psol_library_dir/pagespeed_automatic.a"
fi
fi
echo "mod_pagespeed_dir=$mod_pagespeed_dir"
echo "build_from_source=$build_from_source"
ngx_feature="psol"
ngx_feature_name=""
ngx_feature_run=no
ngx_feature_incs="
#include \"pagespeed/kernel/base/string.h\"
#include \"pagespeed/kernel/base/string_writer.h\"
#include \"pagespeed/kernel/base/null_message_handler.h\"
#include \"pagespeed/kernel/html/html_parse.h\"
#include \"pagespeed/kernel/html/html_writer_filter.h\"
"
pagespeed_include="\
$mod_pagespeed_dir \
$mod_pagespeed_dir/third_party/chromium/src \
@@ -128,15 +139,7 @@ pagespeed_include="\
$mod_pagespeed_dir/third_party/aprutil/gen/arch/$os_name/$arch_name/include"
ngx_feature_path="$pagespeed_include"
if $build_from_source ; then
psol_library_binaries="\
$mod_pagespeed_dir/net/instaweb/automatic/pagespeed_automatic.a"
else
psol_library_dir="$ngx_addon_dir/psol/lib/$buildtype/$os_name/$arch_name"
psol_library_binaries="$psol_library_dir/pagespeed_automatic.a"
fi
pagespeed_libs="-lstdc++ $psol_library_binaries -lrt -pthread -lm"
pagespeed_libs="-lstdc++ $psol_binary -lrt -pthread -lm"
ngx_feature_libs="$pagespeed_libs"
ngx_feature_test="
GoogleString output_buffer;
@@ -167,18 +170,21 @@ if [ $ngx_found = yes ]; then
$ps_src/ngx_base_fetch.h \
$ps_src/ngx_caching_headers.h \
$ps_src/ngx_fetch.h \
$ps_src/ngx_gzip_setter.h \
$ps_src/ngx_list_iterator.h \
$ps_src/ngx_message_handler.h \
$ps_src/ngx_pagespeed.h \
$ps_src/ngx_rewrite_driver_factory.h \
$ps_src/ngx_rewrite_options.h \
$ps_src/ngx_server_context.h \
$ps_src/ngx_url_async_fetcher.h"
$ps_src/ngx_url_async_fetcher.h \
$psol_binary"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
$ps_src/log_message_handler.cc \
$ps_src/ngx_base_fetch.cc \
$ps_src/ngx_caching_headers.cc \
$ps_src/ngx_fetch.cc \
$ps_src/ngx_gzip_setter.cc \
$ps_src/ngx_list_iterator.cc \
$ps_src/ngx_message_handler.cc \
$ps_src/ngx_pagespeed.cc \
@@ -199,7 +205,7 @@ if [ $ngx_found = yes ]; then
else
cat << END
$0: error: module ngx_pagespeed requires the pagespeed optimization library.
Look in obj/autoconf.err for more details.
Look in objs/autoconf.err for more details.
END
exit 1
fi
+9 -3
View File
@@ -39,7 +39,7 @@ NgxBaseFetch::NgxBaseFetch(ngx_http_request_t* r, int pipe_fd,
last_buf_sent_(false),
pipe_fd_(pipe_fd),
references_(2),
handle_error_(true),
ipro_lookup_(false),
preserve_caching_headers_(preserve_caching_headers) {
if (pthread_mutex_init(&mutex_, NULL)) CHECK(0);
}
@@ -137,14 +137,20 @@ void NgxBaseFetch::HandleHeadersComplete() {
int status_code = response_headers()->status_code();
bool status_ok = (status_code != 0) && (status_code < 400);
if (status_ok || handle_error_) {
if (!ipro_lookup_ || status_ok) {
// If this is a 404 response we need to count it in the stats.
if (response_headers()->status_code() == HttpStatus::kNotFound) {
server_context_->rewrite_stats()->resource_404_count()->Add(1);
}
}
RequestCollection(); // Headers available.
// For the IPRO lookup, supress notification of the nginx side here.
// If we send both this event and the one from done, nasty stuff will happen
// if we loose the race with with the nginx side destructing this base fetch
// instance (and thereby clearing the byte and its pending extraneous event.
if (!ipro_lookup_) {
RequestCollection(); // Headers available.
}
}
bool NgxBaseFetch::HandleFlush(MessageHandler* handler) {
+2 -2
View File
@@ -79,7 +79,7 @@ class NgxBaseFetch : public AsyncFetch {
// Called by nginx when it's done with us.
void Release();
void set_handle_error(bool x) { handle_error_ = x; }
void set_ipro_lookup(bool x) { ipro_lookup_ = x; }
private:
virtual bool HandleWrite(const StringPiece& sp, MessageHandler* handler);
@@ -117,7 +117,7 @@ class NgxBaseFetch : public AsyncFetch {
// decremented once when Done() is called and once when Release() is called.
int references_;
pthread_mutex_t mutex_;
bool handle_error_;
bool ipro_lookup_;
PreserveCachingHeaders preserve_caching_headers_;
DISALLOW_COPY_AND_ASSIGN(NgxBaseFetch);
+806 -474
View File
File diff suppressed because it is too large Load Diff
+19 -10
View File
@@ -16,6 +16,15 @@
// Author: x.dinic@gmail.com (Junmin Xiong)
//
// PageSpeed needs some way to talk to the internet and request resources. For
// example, if it's optimizing www.example.com/index.html and it sees html with
// <img src="//images.example.com/cat.jpg"> and images.example.com is authorized
// for rewriting in the config, then it needs to fetch cat.jpg from
// images.example.com and optimize it. In apache (always) and nginx (by
// default) we use a fetcher called "serf". This works fine, but it does run
// its own event loop. To be more efficient, this is a "native" fetcher that
// uses nginx's event loop.
//
// The fetch is started by the main thread. It will fetch the remote resource
// from the specific url asynchronously.
@@ -42,12 +51,13 @@ namespace net_instaweb {
typedef bool (*response_handler_pt)(ngx_connection_t* c);
class NgxUrlAsyncFetcher;
class NgxConnection;
class NgxFetch : public PoolElement<NgxFetch> {
public:
NgxFetch(const GoogleString& url,
AsyncFetch* async_fetch,
MessageHandler* message_handler,
ngx_msec_t timeout_ms,
ngx_log_t* log);
~NgxFetch();
@@ -103,19 +113,19 @@ class NgxFetch : public PoolElement<NgxFetch> {
response_handler = handler;
}
// Only the Static functions could be used in callbacks.
static void NgxFetchResolveDone(ngx_resolver_ctx_t* ctx);
static void ResolveDoneHandler(ngx_resolver_ctx_t* ctx);
// Write the request.
static void NgxFetchWrite(ngx_event_t* wev);
static void ConnectionWriteHandler(ngx_event_t* wev);
// Wait for the response.
static void NgxFetchRead(ngx_event_t* rev);
static void ConnectionReadHandler(ngx_event_t* rev);
// Read and parse the first status line.
static bool NgxFetchHandleStatusLine(ngx_connection_t* c);
static bool HandleStatusLine(ngx_connection_t* c);
// Read and parse the HTTP headers.
static bool NgxFetchHandleHeader(ngx_connection_t* c);
static bool HandleHeader(ngx_connection_t* c);
// Read the response body.
static bool NgxFetchHandleBody(ngx_connection_t* c);
static bool HandleBody(ngx_connection_t* c);
// Cancel the fetch when it's timeout.
static void NgxFetchTimeout(ngx_event_t* tev);
static void TimeoutHandler(ngx_event_t* tev);
// Add the pagespeed User-Agent.
void FixUserAgent();
@@ -130,7 +140,6 @@ class NgxFetch : public PoolElement<NgxFetch> {
int64 bytes_received_;
int64 fetch_start_ms_;
int64 fetch_end_ms_;
int64 timeout_ms_;
bool done_;
int64 content_length_;
bool content_length_known_;
@@ -143,7 +152,7 @@ class NgxFetch : public PoolElement<NgxFetch> {
ngx_http_request_t* r_;
ngx_http_status_t* status_;
ngx_event_t* timeout_event_;
ngx_connection_t* connection_;
NgxConnection* connection_;
ngx_resolver_ctx_t* resolver_ctx_;
DISALLOW_COPY_AND_ASSIGN(NgxFetch);
+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 "net/instaweb/util/public/basictypes.h"
namespace net_instaweb {
// We need this class because configuration for gzip is in different modules, so
// just saving the command will not work.
class ngx_command_ctx {
public:
ngx_command_ctx() : command_(NULL), module_(NULL) { }
void* GetConfPtr(ngx_conf_t* cf);
char* GetModuleConfPtr(ngx_conf_t* cf);
ngx_command_t* command_;
ngx_module_t* module_;
};
enum gzs_enable_result {
kEnableGZipOk,
kEnableGZipPartial,
kEnableGZipNotEnabled
};
class NgxGZipSetter {
std::vector<ngx_flag_t*> ngx_flags_set_;
std::vector<ngx_uint_t*> ngx_uint_set_;
std::vector<void*> ngx_httptypes_set_;
ngx_command_ctx gzip_command_;
ngx_command_ctx gzip_http_types_command_;
ngx_command_ctx gzip_proxied_command_;
ngx_command_ctx gzip_vary_command_;
ngx_command_ctx gzip_http_version_command_;
bool enabled_;
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_
+3 -35
View File
@@ -56,11 +56,9 @@ extern "C" {
namespace net_instaweb {
NgxMessageHandler::NgxMessageHandler(AbstractMutex* mutex)
: mutex_(mutex),
buffer_(NULL),
NgxMessageHandler::NgxMessageHandler(Timer* timer, AbstractMutex* mutex)
: SystemMessageHandler(timer, mutex),
log_(NULL) {
SetPidString(static_cast<int64>(getpid()));
}
// Installs a signal handler for common crash signals, that tries to print
@@ -73,14 +71,6 @@ void NgxMessageHandler::InstallCrashHandler(ngx_log_t* log) {
signal(SIGSEGV, signal_handler);
}
bool NgxMessageHandler::Dump(Writer* writer) {
// Can't dump before SharedCircularBuffer is set up.
if (buffer_ == NULL) {
return false;
}
return buffer_->Dump(writer, &handler_);
}
ngx_uint_t NgxMessageHandler::GetNgxLogLevel(MessageType type) {
switch (type) {
case kInfo:
@@ -98,11 +88,6 @@ ngx_uint_t NgxMessageHandler::GetNgxLogLevel(MessageType type) {
return NGX_LOG_ALERT;
}
void NgxMessageHandler::set_buffer(SharedCircularBuffer* buff) {
ScopedMutex lock(mutex_.get());
buffer_ = buff;
}
void NgxMessageHandler::MessageVImpl(MessageType type, const char* msg,
va_list args) {
ngx_uint_t log_level = GetNgxLogLevel(type);
@@ -113,25 +98,8 @@ void NgxMessageHandler::MessageVImpl(MessageType type, const char* msg,
} else {
GoogleMessageHandler::MessageVImpl(type, msg, args);
}
// Prepare a log message for the SharedCircularBuffer only.
// Prepend time and severity to message.
// Format is [time] [severity] [pid] message.
GoogleString message;
GoogleString time;
PosixTimer timer;
if (!ConvertTimeToString(timer.NowMs(), &time)) {
time = "?";
}
StrAppend(&message, "[", time, "] ",
"[", MessageTypeToString(type), "] ");
StrAppend(&message, pid_string_, " ", formatted_message, "\n");
{
ScopedMutex lock(mutex_.get());
if (buffer_ != NULL) {
buffer_->Write(message);
}
}
AddMessageToBuffer(type, formatted_message);
}
void NgxMessageHandler::FileMessageVImpl(MessageType type, const char* file,
+3 -24
View File
@@ -24,44 +24,30 @@ extern "C" {
#include <cstdarg>
#include "net/instaweb/system/public/system_message_handler.h"
#include "net/instaweb/util/public/basictypes.h"
#include "net/instaweb/util/public/google_message_handler.h"
#include "net/instaweb/util/public/message_handler.h"
#include "net/instaweb/util/public/scoped_ptr.h"
#include "net/instaweb/util/public/string.h"
#include "net/instaweb/util/public/string_util.h"
namespace net_instaweb {
class AbstractMutex;
class SharedCircularBuffer;
class Timer;
class Writer;
// Implementation of a message handler that uses ngx_log_error()
// logging to emit messages, with a fallback to GoogleMessageHandler
class NgxMessageHandler : public GoogleMessageHandler {
class NgxMessageHandler : public SystemMessageHandler {
public:
explicit NgxMessageHandler(AbstractMutex* mutex);
explicit NgxMessageHandler(Timer* timer, AbstractMutex* mutex);
// Installs a signal handler for common crash signals that tries to print
// out a backtrace.
static void InstallCrashHandler(ngx_log_t* log);
// When NgxRewriteDriver instantiates the NgxMessageHandlers, the
// SharedCircularBuffer and ngx_log_t are not available yet. These
// will later be set in RootInit/Childinit
// Messages logged before that will be passed on to handler_;
void set_buffer(SharedCircularBuffer* buff);
void set_log(ngx_log_t* log) { log_ = log; }
ngx_log_t* log() { return log_; }
void SetPidString(const int64 pid) {
pid_string_ = StrCat("[", Integer64ToString(pid), "]");
}
// Dump contents of SharedCircularBuffer.
bool Dump(Writer* writer);
protected:
virtual void MessageVImpl(MessageType type, const char* msg, va_list args);
@@ -70,13 +56,6 @@ class NgxMessageHandler : public GoogleMessageHandler {
private:
ngx_uint_t GetNgxLogLevel(MessageType type);
scoped_ptr<AbstractMutex> mutex_;
GoogleString pid_string_;
// handler_ is used as a fallback when we can not use ngx_log_errort
// It's also used when calling Dump on the internal SharedCircularBuffer
GoogleMessageHandler handler_;
SharedCircularBuffer* buffer_;
ngx_log_t* log_;
DISALLOW_COPY_AND_ASSIGN(NgxMessageHandler);
+326 -106
View File
@@ -30,6 +30,7 @@
#include "ngx_base_fetch.h"
#include "ngx_caching_headers.h"
#include "ngx_gzip_setter.h"
#include "ngx_list_iterator.h"
#include "ngx_message_handler.h"
#include "ngx_rewrite_driver_factory.h"
@@ -77,17 +78,10 @@
extern ngx_module_t ngx_pagespeed;
// Hacks for debugging.
#define DBG(r, args...) \
ngx_log_error(NGX_LOG_DEBUG, (r)->connection->log, 0, args)
#define PDBG(ctx, args...) \
ngx_log_error(NGX_LOG_DEBUG, (ctx)->r->connection->log, 0, args)
#define CDBG(cf, args...) \
ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, args)
// Unused flag, see
// http://lxr.evanmiller.org/http/source/http/ngx_http_request.h#L130
#define NGX_HTTP_PAGESPEED_BUFFERED 0x08
#define POST_BUF_READ_SIZE 65536
// Needed for SystemRewriteDriverFactory to use shared memory.
#define PAGESPEED_SUPPORT_POSIX_SHARED_MEM
@@ -95,6 +89,8 @@ extern ngx_module_t ngx_pagespeed;
namespace net_instaweb {
const char* kInternalEtagName = "@psol-etag";
bool factory_init_called = false;
// The process context takes care of proactively initialising
// a few libraries for us, some of which are not thread-safe
// when they are initialized lazily.
@@ -105,6 +101,10 @@ StringPiece str_to_string_piece(ngx_str_t s) {
return StringPiece(reinterpret_cast<char*>(s.data), s.len);
}
// Nginx uses memory pools, like Apache, allocating strings a request needs from
// the pool and then throwing it all away when the request finishes. Use this
// when you need to pass a short string to nginx and want it to take ownership
// of the string.
char* string_piece_to_pool_string(ngx_pool_t* pool, StringPiece sp) {
// Need space for the final null.
ngx_uint_t buffer_size = sp.size() + 1;
@@ -119,6 +119,10 @@ char* string_piece_to_pool_string(ngx_pool_t* pool, StringPiece sp) {
return s;
}
// When passing the body of http responses between filters Nginx uses a linked
// list of buffers ("buffer chain"), again like Apache. This constructs one of
// those lists from a StringPiece. This is what you use when you need to pass a
// (potentially) longer string to nginx and want it to take ownership.
ngx_int_t string_piece_to_buffer_chain(
ngx_pool_t* pool, StringPiece sp, ngx_chain_t** link_ptr,
bool send_last_buf) {
@@ -202,9 +206,12 @@ ngx_int_t string_piece_to_buffer_chain(
return NGX_OK;
}
// modified from NgxBaseFetch::CopyHeadersFromTable()
namespace {
// Setting headers in nginx is tricky because it's not just a matter of adding
// them to a list. You also need to remove them if there's already one there,
// as well as setting the shortcut pointers (both upper case and lower case).
//
// Based on ngx_http_add_cache_control.
ngx_int_t ps_set_cache_control(ngx_http_request_t* r, char* cache_control) {
// First strip existing cache-control headers.
@@ -220,7 +227,7 @@ ngx_int_t ps_set_cache_control(ngx_http_request_t* r, char* cache_control) {
// Now add our new cache control header.
if (r->headers_out.cache_control.elts == NULL) {
ngx_int_t rc = ngx_array_init(&r->headers_out.cache_control, r->pool,
1, sizeof(ngx_table_elt_t *));
1, sizeof(ngx_table_elt_t*));
if (rc != NGX_OK) {
return NGX_ERROR;
}
@@ -281,11 +288,6 @@ void copy_response_headers_from_ngx(const ngx_http_request_t* r,
headers->set_status_code(r->headers_out.status);
if (r->headers_out.location != NULL) {
headers->Add(HttpAttributes::kLocation,
str_to_string_piece(r->headers_out.location->value));
}
// Manually copy over the content type because it's not included in
// request_->headers_out.headers.
headers->Add(HttpAttributes::kContentType,
@@ -336,7 +338,7 @@ ngx_int_t copy_response_headers_to_ngx(
if (StringCaseEqual(name_gs, "Cache-Control")) {
continue;
}
} // else we don't preserve any headers
} // else we don't preserve any headers.
ngx_str_t name, value;
@@ -391,8 +393,8 @@ ngx_int_t copy_response_headers_to_ngx(
// content_type_lowcase if we leave it as null.
headers_out->content_type_lowcase = NULL;
continue;
// TODO(oschaaf): are there any other headers we should not try to
// copy here?
// TODO(oschaaf): are there any other headers we should not try to
// copy here?
} else if (STR_EQ_LITERAL(name, "Connection")) {
continue;
} else if (STR_EQ_LITERAL(name, "Keep-Alive")) {
@@ -484,6 +486,7 @@ enum Response {
kConsole,
kMessages,
kAdmin,
kCachePurge,
kGlobalAdmin,
kPagespeedSubrequest,
kNotHeadOrGet,
@@ -534,6 +537,8 @@ void ps_ignore_sigpipe() {
sigaction(SIGPIPE, &act, NULL);
}
// Given a directory path that pagespeed needs, create it and set permissions so
// the worker can access, but only if needed.
char* ps_init_dir(const StringPiece& directive,
const StringPiece& path,
ngx_conf_t* cf) {
@@ -582,11 +587,36 @@ char* ps_init_dir(const StringPiece& directive,
return NULL;
}
#define NGX_PAGESPEED_MAX_ARGS 10
// We support interpretation of nginx variables in some configuration settings,
// but we also need to support literal dollar signs in those same settings.
// Nginx has no good solution for this, so we define $dollar to expand to '$',
// which lets people include literal dollar signs if they need them.
ngx_int_t ps_dollar(
ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) {
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = reinterpret_cast<u_char*>(const_cast<char*>("$"));
v->len = 1;
return NGX_OK;
}
// Parse the configuration option represented by cf and add it to options,
// creating options if necessary.
char* ps_configure(ngx_conf_t* cf,
NgxRewriteOptions** options,
MessageHandler* handler,
net_instaweb::RewriteOptions::OptionScope option_scope) {
ps_main_conf_t* cfg_m = static_cast<ps_main_conf_t*>(
ngx_http_conf_get_module_main_conf(cf, ngx_pagespeed));
if (!factory_init_called) {
// Init logging to nginx's default error_log.
cfg_m->driver_factory->LoggingInit(cf->cycle->log);
cfg_m->driver_factory->Init();
factory_init_called = true;
}
// args[0] is always "pagespeed"; ignore it.
ngx_uint_t n_args = cf->args->nelts - 1;
@@ -601,6 +631,27 @@ char* ps_configure(ngx_conf_t* cf,
args[i] = str_to_string_piece(value[i+1]);
}
if (n_args == 1) {
if (StringCaseEqual(args[0], "on")) {
// safe to call if the setter is disabled
g_gzip_setter.EnableGZipForLocation(cf);
} else if (StringCaseEqual(args[0], "off")) {
g_gzip_setter.SetGZipForLocation(cf, false);
}
}
if (n_args == 2 && args[0].compare("gzip") == 0) {
if (args[1].compare("on") == 0) {
g_gzip_setter.SetGZipForLocation(cf, true);
} else if (args[1].compare("off") == 0) {
g_gzip_setter.SetGZipForLocation(cf, false);
} else {
char* error_message = string_piece_to_pool_string(
cf->pool, StringPiece("Invalid pagespeed gzip setting"));
return error_message;
}
return NGX_CONF_OK;
}
// Some options require the worker process to be able to read and write to
// a specific directory. Generally the master process is root while the
// worker is nobody, so we need to change permissions and create the directory
@@ -616,14 +667,30 @@ char* ps_configure(ngx_conf_t* cf,
// directive yet. That happens below in ParseAndSetOptions().
}
ps_main_conf_t* cfg_m = static_cast<ps_main_conf_t*>(
ngx_http_cycle_get_module_main_conf(cf->cycle, ngx_pagespeed));
if (*options == NULL) {
*options = new NgxRewriteOptions(
cfg_m->driver_factory->thread_system());
}
bool process_script_variables = dynamic_cast<NgxRewriteDriverFactory*>(
cfg_m->driver_factory)->process_script_variables();
if (process_script_variables) {
// To be able to use '$', we map '$ps_dollar' to '$' via a script variable.
ngx_str_t name = ngx_string("ps_dollar");
ngx_http_variable_t* var = ngx_http_add_variable(
cf, &name, NGX_HTTP_VAR_CHANGEABLE);
if (var == NULL) {
return const_cast<char*>(
"Failed to add global configuration variable for '$ps_dollar'");
}
var->get_handler = ps_dollar;
}
const char* status = (*options)->ParseAndSetOptions(
args, n_args, cf->pool, handler, cfg_m->driver_factory, option_scope);
args, n_args, cf->pool, handler, cfg_m->driver_factory, option_scope, cf,
process_script_variables);
// nginx expects us to return a string literal but doesn't mark it const.
return const_cast<char*>(status);
@@ -646,10 +713,8 @@ char* ps_srv_configure(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
char* ps_loc_configure(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
ps_loc_conf_t* cfg_l = static_cast<ps_loc_conf_t*>(
ngx_http_conf_get_module_loc_conf(cf, ngx_pagespeed));
return ps_configure(
cf, &cfg_l->options, cfg_l->handler,
net_instaweb::RewriteOptions::kDirectoryScope);
return ps_configure(cf, &cfg_l->options, cfg_l->handler,
net_instaweb::RewriteOptions::kDirectoryScope);
}
void ps_cleanup_loc_conf(void* data) {
@@ -670,7 +735,16 @@ void ps_cleanup_srv_conf(void* data) {
// from being executed
if (!factory_deleted && cfg_s->server_context != NULL) {
delete cfg_s->server_context->factory();
NgxRewriteDriverFactory* factory = dynamic_cast<NgxRewriteDriverFactory*>(
cfg_s->server_context->factory());
if (!factory_init_called) {
factory->LoggingInit(ngx_cycle->log);
factory->Init();
factory_init_called = true;
}
delete factory;
factory_deleted = true;
}
if (cfg_s->proxy_fetch_factory != NULL) {
@@ -740,6 +814,7 @@ void* ps_create_main_conf(ngx_conf_t* cf) {
new SystemThreadSystem(),
"" /* hostname, not used */,
-1 /* port, not used */);
factory_init_called = false;
ps_set_conf_cleanup_handler(cf, ps_cleanup_main_conf, cfg_m);
return cfg_m;
}
@@ -789,6 +864,16 @@ void ps_merge_options(NgxRewriteOptions* parent_options,
NgxRewriteOptions* child_specific_options = *child_options;
*child_options = parent_options->Clone();
(*child_options)->Merge(*child_specific_options);
if (child_specific_options->clear_inherited_scripts()) {
// We don't want to inherit any inherited script lines from the parent
// options here, so we just stick to the child specific ones.
child_specific_options->CopyScriptLinesTo(*child_options);
} else {
// We append the child specific script lines to the parent's script lines
// so we preserve the order in which they will be executed at request time
child_specific_options->AppendScriptLinesTo(*child_options);
}
delete child_specific_options;
}
}
@@ -830,6 +915,9 @@ char* ps_merge_srv_conf(ngx_conf_t* cf, void* parent, void* child) {
// let it do that, then merge in options we got from the config file.
// Once we do that we're done with cfg_s->options.
cfg_s->server_context->global_options()->Merge(*cfg_s->options);
NgxRewriteOptions* ngx_options = dynamic_cast<NgxRewriteOptions*>(
cfg_s->server_context->global_options());
cfg_s->options->CopyScriptLinesTo(ngx_options);
delete cfg_s->options;
cfg_s->options = NULL;
@@ -1028,7 +1116,6 @@ ngx_int_t ps_decline_request(ngx_http_request_t* r) {
ctx->fetch_done = false;
ctx->write_pending = false;
ps_release_base_fetch(ctx);
ps_set_buffered(r, false);
r->count++;
@@ -1078,6 +1165,9 @@ ngx_int_t ps_base_fetch_filter(ngx_http_request_t* r, ngx_chain_t* in) {
return ctx->fetch_done ? NGX_OK : NGX_AGAIN;
}
// This runs on the nginx event loop in response to seeing the byte PageSpeed
// sent over the pipe to trigger the nginx-side code. Copy whatever is ready
// from PageSpeed out to the browser (headers and/or body).
ngx_int_t ps_base_fetch_handler(ngx_http_request_t* r) {
ps_request_ctx_t* ctx = ps_get_request_context(r);
ngx_int_t rc;
@@ -1102,6 +1192,12 @@ ngx_int_t ps_base_fetch_handler(ngx_http_request_t* r) {
STR_CASE_EQ_LITERAL(header->key, "Last-Modified") ||
STR_CASE_EQ_LITERAL(header->key, "Expires"))))) {
header->hash = 0;
if (STR_CASE_EQ_LITERAL(header->key, "Location")) {
// There's a possible issue with the location header, where setting
// the hash to 0 is not enough. See:
// https://github.com/nginx/nginx/blob/master/src/http/ngx_http_header_filter_module.c#L314
r->headers_out.location = NULL;
}
}
}
} else {
@@ -1139,7 +1235,8 @@ ngx_int_t ps_base_fetch_handler(ngx_http_request_t* r) {
// too much memory in busy servers.
rc = ctx->base_fetch->CollectAccumulatedWrites(&cl);
PDBG(ctx, "CollectAccumulatedWrites, %d", rc);
ngx_log_error(NGX_LOG_DEBUG, ctx->r->connection->log, 0,
"CollectAccumulatedWrites, %d", rc);
if (rc == NGX_ERROR) {
ps_set_buffered(r, false);
@@ -1167,6 +1264,8 @@ void ps_base_fetch_filter_init() {
} // namespace
// Do some bookkeeping, cleanup, and error checking to keep the mess out of
// ps_base_fetch_handler.
void ps_connection_read_handler(ngx_event_t* ev) {
CHECK(ev != NULL);
ngx_connection_t* c = static_cast<ngx_connection_t*>(ev->data);
@@ -1201,6 +1300,15 @@ void ps_connection_read_handler(ngx_event_t* ev) {
rc = read(c->fd, chr, 256);
} while (rc > 0 || (rc == -1 && errno == EINTR)); // Retry on EINTR.
if (r->connection->error) {
ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0,
"pagespeed [%p] request already finalized", r);
ctx->pagespeed_connection = NULL;
ngx_close_connection(c);
ngx_http_finalize_request(r, NGX_ERROR);
return;
}
if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
ctx->pagespeed_connection = NULL;
ngx_close_connection(c);
@@ -1261,10 +1369,6 @@ ngx_int_t ps_create_connection(
// Populate cfg_* with configuration information for this request.
// Thin wrappers around ngx_http_get_module_*_conf and cast.
ps_main_conf_t* ps_get_main_config(ngx_http_request_t* r) {
return static_cast<ps_main_conf_t*>(
ngx_http_get_module_main_conf(r, ngx_pagespeed));
}
ps_srv_conf_t* ps_get_srv_config(ngx_http_request_t* r) {
return static_cast<ps_srv_conf_t*>(
ngx_http_get_module_srv_conf(r, ngx_pagespeed));
@@ -1277,24 +1381,31 @@ ps_loc_conf_t* ps_get_loc_config(ngx_http_request_t* r) {
// Wrapper around GetQueryOptions()
RewriteOptions* ps_determine_request_options(
ngx_http_request_t* r,
const RewriteOptions* domain_options, /* may be null */
RequestHeaders* request_headers,
ResponseHeaders* response_headers,
RequestContextPtr request_context,
ps_srv_conf_t* cfg_s,
GoogleUrl* url) {
// Stripping ModPagespeed query params before the property cache lookup to
// make cache key consistent for both lookup and storing in cache.
//
GoogleUrl* url,
GoogleString* pagespeed_query_params,
GoogleString* pagespeed_option_cookies) {
// Sets option from request headers and url.
RewriteQuery rewrite_query;
if (!cfg_s->server_context->GetQueryOptions(
url, request_headers, response_headers, &rewrite_query)) {
request_context, domain_options, url, request_headers,
response_headers, &rewrite_query)) {
// Failed to parse query params or request headers. Treat this as if there
// were no query params given.
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"ps_route rerquest: parsing headers or query params failed.");
"ps_route request: parsing headers or query params failed.");
return NULL;
}
*pagespeed_query_params =
rewrite_query.pagespeed_query_params().ToEscapedString();
*pagespeed_option_cookies =
rewrite_query.pagespeed_option_cookies().ToEscapedString();
// Will be NULL if there aren't any options set with query params or in
// headers.
return rewrite_query.ReleaseOptions();
@@ -1349,7 +1460,7 @@ bool ps_set_experiment_state_and_cookie(ngx_http_request_t* r,
}
// There are many sources of options:
// - the request (query parameters and headers)
// - the request (query parameters, headers, and cookies)
// - location block
// - global server options
// - experiment framework
@@ -1360,9 +1471,12 @@ bool ps_determine_options(ngx_http_request_t* r,
RequestHeaders* request_headers,
ResponseHeaders* response_headers,
RewriteOptions** options,
RequestContextPtr request_context,
ps_srv_conf_t* cfg_s,
GoogleUrl* url,
GoogleString* pagespeed_query_params,
GoogleString* pagespeed_option_cookies,
bool html_rewrite) {
ps_srv_conf_t* cfg_s = ps_get_srv_config(r);
ps_loc_conf_t* cfg_l = ps_get_loc_config(r);
// Global options for this server. Never null.
@@ -1375,14 +1489,19 @@ bool ps_determine_options(ngx_http_request_t* r,
// Request-specific options, nearly always null. If set they need to be
// rebased on the directory options or the global options.
RewriteOptions* request_options = ps_determine_request_options(
r, request_headers, response_headers, cfg_s, url);
r, directory_options, request_headers, response_headers, request_context,
cfg_s, url, pagespeed_query_params, pagespeed_option_cookies);
bool have_request_options = request_options != NULL;
// Because the caller takes ownership of any options we return, the only
// situation in which we can avoid allocating a new RewriteOptions is if the
// global options are ok as are.
// global options are ok as they are and we don't have script variables we
// need to evaluate at this point.
NgxRewriteOptions* ngx_global_options =
dynamic_cast<NgxRewriteOptions*>(global_options);
if (!have_request_options && directory_options == NULL &&
!global_options->running_experiment()) {
!global_options->running_experiment() &&
ngx_global_options->script_lines().size() == 0) {
return true;
}
@@ -1393,6 +1512,18 @@ bool ps_determine_options(ngx_http_request_t* r,
*options = global_options->Clone();
}
NgxRewriteDriverFactory* ngx_factory = dynamic_cast<NgxRewriteDriverFactory*>(
cfg_s->server_context->factory());
NgxRewriteOptions* ngx_options = dynamic_cast<NgxRewriteOptions*>(*options);
// ExecuteScriptVariables() sets 'pagespeed off' on ngx_options when execution
// fails and then returns false. When that happens we return, as we don't want
// to allow enabling pagespeed by request and execute without the intended
// configuration.
if (!ngx_options->ExecuteScriptVariables(r, cfg_s->handler, ngx_factory)) {
return false;
}
// Modify our options in response to request options if specified.
if (have_request_options) {
(*options)->Merge(*request_options);
@@ -1498,7 +1629,8 @@ void ps_release_base_fetch(ps_request_ctx_t* ctx) {
}
// TODO(chaizhenhua): merge into NgxBaseFetch ctor
ngx_int_t ps_create_base_fetch(ps_request_ctx_t* ctx) {
ngx_int_t ps_create_base_fetch(ps_request_ctx_t* ctx,
RequestContextPtr request_context) {
ngx_http_request_t* r = ctx->r;
ps_srv_conf_t* cfg_s = ps_get_srv_config(r);
int file_descriptors[2];
@@ -1540,8 +1672,7 @@ ngx_int_t ps_create_base_fetch(ps_request_ctx_t* ctx) {
// the BaseFetch ourselves.
ctx->base_fetch = new NgxBaseFetch(
r, file_descriptors[1], cfg_s->server_context,
RequestContextPtr(cfg_s->server_context->NewRequestContext(r)),
ctx->preserve_caching_headers);
request_context, ctx->preserve_caching_headers);
return NGX_OK;
}
@@ -1623,15 +1754,21 @@ RequestRouting::Response ps_route_request(ngx_http_request_t* r,
return RequestRouting::kConsole;
} else if (StringCaseEqual(path, global_options->messages_path())) {
return RequestRouting::kMessages;
} else if (// The admin handlers get everything under a path (/path/*) while
// all the other handlers only get exact matches (/path). So match
// all paths starting with the handler path.
!global_options->admin_path().empty() &&
StringCaseStartsWith(path, global_options->admin_path())) {
} else if (
// The admin handlers get everything under a path (/path/*) while all the
// other handlers only get exact matches (/path). So match all paths
// starting with the handler path.
!global_options->admin_path().empty() &&
StringCaseStartsWith(path, global_options->admin_path())) {
return RequestRouting::kAdmin;
} else if (!global_options->global_admin_path().empty() &&
StringCaseStartsWith(path, global_options->global_admin_path())) {
return RequestRouting::kGlobalAdmin;
} else if (global_options->enable_cache_purge() &&
!global_options->purge_method().empty() &&
(global_options->purge_method() ==
str_to_string_piece(r->method_name))) {
return RequestRouting::kCachePurge;
}
const GoogleString* beacon_url;
@@ -1662,7 +1799,9 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
if (!html_rewrite &&
r->method != NGX_HTTP_GET &&
r->method != NGX_HTTP_HEAD) {
r->method != NGX_HTTP_HEAD &&
r->method != NGX_HTTP_POST &&
response_category != RequestRouting::kCachePurge) {
return NGX_DECLINED;
}
@@ -1677,10 +1816,16 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
copy_request_headers_from_ngx(r, request_headers.get());
copy_response_headers_from_ngx(r, response_headers.get());
RequestContextPtr request_context(
cfg_s->server_context->NewRequestContext(r));
RewriteOptions* options = NULL;
GoogleString pagespeed_query_params;
GoogleString pagespeed_option_cookies;
if (!ps_determine_options(r, request_headers.get(), response_headers.get(),
&options, &url, html_rewrite)) {
&options, request_context, cfg_s, &url,
&pagespeed_query_params, &pagespeed_option_cookies,
html_rewrite)) {
return NGX_ERROR;
}
@@ -1695,6 +1840,8 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
return NGX_DECLINED;
}
request_context->set_options(options->ComputeHttpOptions());
// ps_determine_options modified url, removing any ModPagespeedFoo=Bar query
// parameters. Keep url_string in sync with url.
url.Spec().CopyToString(&url_string);
@@ -1716,7 +1863,8 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
response_category == RequestRouting::kGlobalStatistics ||
response_category == RequestRouting::kConsole ||
response_category == RequestRouting::kAdmin ||
response_category == RequestRouting::kGlobalAdmin;
response_category == RequestRouting::kGlobalAdmin ||
response_category == RequestRouting::kCachePurge;
if (html_rewrite) {
ps_release_base_fetch(ctx);
@@ -1725,12 +1873,19 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
CHECK(ctx == NULL);
ctx = new ps_request_ctx_t();
ctx->base_fetch = NULL;
ctx->pagespeed_connection = NULL;
ctx->r = r;
ctx->write_pending = false;
ctx->html_rewrite = false;
ctx->in_place = false;
ctx->pagespeed_connection = NULL;
ctx->write_pending = false;
ctx->fetch_done = false;
ctx->preserve_caching_headers = kDontPreserveHeaders;
ctx->proxy_fetch = NULL;
ctx->inflater_ = NULL;
ctx->driver = NULL;
ctx->recorder = NULL;
ctx->ipro_response_headers = NULL;
// See build_context_for_request() in mod_instaweb.cc
// TODO(jefftk): Is this the right place to be modifying caching headers for
@@ -1768,8 +1923,8 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
ngx_http_set_ctx(r, ctx, ngx_pagespeed);
}
if (ps_create_base_fetch(ctx)!= NGX_OK) {
// Do not need to release request context.
if (ps_create_base_fetch(ctx, request_context) != NGX_OK) {
// Do not need to release request context 'ctx'.
// http_pool_cleanup will call ps_release_request_context
return NGX_ERROR;
}
@@ -1798,7 +1953,7 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
return ps_async_wait_response(r);
} else if (is_an_admin_handler) {
QueryParams query_params;
query_params.Parse(url.Query());
query_params.ParseFromUrl(url);
PosixTimer timer;
int64 now_ms = timer.NowMs();
@@ -1815,7 +1970,7 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
} else if (response_category == RequestRouting::kConsole) {
cfg_s->server_context->ConsoleHandler(
*cfg_s->server_context->config(),
SystemServerContext::kStatistics,
AdminSite::kStatistics,
query_params,
ctx->base_fetch);
} else if (response_category == RequestRouting::kAdmin ||
@@ -1827,6 +1982,11 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
custom_options == NULL ? cfg_s->server_context->config()
: custom_options.get(),
ctx->base_fetch);
} else if (response_category == RequestRouting::kCachePurge) {
AdminSite* admin_site = cfg_s->server_context->admin_site();
admin_site->PurgeHandler(url_string,
cfg_s->server_context->cache_path(),
ctx->base_fetch);
} else {
CHECK(false);
}
@@ -1844,11 +2004,11 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
if (custom_options.get() == NULL) {
driver = cfg_s->server_context->NewRewriteDriver(
ctx->base_fetch->request_context());
ctx->base_fetch->request_context());
} else {
// NewCustomRewriteDriver takes ownership of custom_options.
driver = cfg_s->server_context->NewCustomRewriteDriver(
custom_options.release(), ctx->base_fetch->request_context());
custom_options.release(), ctx->base_fetch->request_context());
}
StringPiece user_agent = ctx->base_fetch->request_headers()->Lookup1(
@@ -1857,6 +2017,8 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
driver->SetUserAgent(user_agent);
}
driver->SetRequestHeaders(*ctx->base_fetch->request_headers());
driver->set_pagespeed_query_params(pagespeed_query_params);
driver->set_pagespeed_option_cookies(pagespeed_option_cookies);
// TODO(jefftk): FlushEarlyFlow would go here.
@@ -1897,7 +2059,7 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
url_string.c_str());
ctx->in_place = true;
ctx->base_fetch->set_handle_error(false);
ctx->base_fetch->set_ipro_lookup(true);
ctx->driver->FetchInPlaceResource(
url, false /* proxy_mode */, ctx->base_fetch);
@@ -1907,8 +2069,9 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
// NOTE: We are using the below debug message as is for some of our system
// tests. So, be careful about test breakages caused by changing or
// removing this line.
DBG(r, "Passing on content handling for non-pagespeed resource '%s'",
url_string.c_str());
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
"Passing on content handling for non-pagespeed resource '%s'",
url_string.c_str());
ctx->base_fetch->Done(false);
ps_release_base_fetch(ctx);
@@ -1945,8 +2108,7 @@ void ps_send_to_pagespeed(ngx_http_request_t* r,
int num_inflated_bytes = ctx->inflater_->InflateBytes(
buf, kStackBufferSize);
if (num_inflated_bytes < 0) {
cfg_s->handler->Message(kWarning,
"Corrupted inflation");
cfg_s->handler->Message(kWarning, "Corrupted inflation");
} else if (num_inflated_bytes > 0) {
ctx->proxy_fetch->Write(StringPiece(buf, num_inflated_bytes),
cfg_s->handler);
@@ -1970,10 +2132,10 @@ void ps_send_to_pagespeed(ngx_http_request_t* r,
#ifndef ngx_http_clear_etag
// The ngx_http_clear_etag(r) macro was added in 1.3.3. Backport it if it's not
// present.
#define ngx_http_clear_etag(r) \
if (r->headers_out.etag) { \
r->headers_out.etag->hash = 0; \
r->headers_out.etag = NULL; \
#define ngx_http_clear_etag(r) \
if (r->headers_out.etag) { \
r->headers_out.etag->hash = 0; \
r->headers_out.etag = NULL; \
}
#endif
@@ -2060,6 +2222,8 @@ namespace html_rewrite {
ngx_http_output_header_filter_pt ngx_http_next_header_filter;
ngx_http_output_body_filter_pt ngx_http_next_body_filter;
// After pagespeed has had a chance to run, copy the headers it produced to
// nginx so it can send them out to the browser.
ngx_int_t ps_html_rewrite_header_filter(ngx_http_request_t* r) {
ps_srv_conf_t* cfg_s = ps_get_srv_config(r);
if (cfg_s->server_context == NULL) {
@@ -2198,6 +2362,9 @@ namespace in_place {
ngx_http_output_header_filter_pt ngx_http_next_header_filter;
ngx_http_output_body_filter_pt ngx_http_next_body_filter;
// Header filter to support IPRO.
//
// The control flow here is tricky, probably excessively so.
ngx_int_t ps_in_place_check_header_filter(ngx_http_request_t* r) {
ps_request_ctx_t* ctx = ps_get_request_context(r);
@@ -2269,6 +2436,9 @@ ngx_int_t ps_in_place_check_header_filter(ngx_http_request_t* r) {
cache_url.c_str());
const SystemRewriteOptions* options = SystemRewriteOptions::DynamicCast(
ctx->driver->options());
RequestContextPtr request_context(
cfg_s->server_context->NewRequestContext(r));
request_context->set_options(options->ComputeHttpOptions());
RequestHeaders request_headers;
copy_request_headers_from_ngx(r, &request_headers);
// This URL was not found in cache (neither the input resource nor
@@ -2276,14 +2446,12 @@ ngx_int_t ps_in_place_check_header_filter(ngx_http_request_t* r) {
// (or at least a note that it cannot be cached stored there).
// We do that using an Apache output filter.
ctx->recorder = new InPlaceResourceRecorder(
RequestContextPtr(cfg_s->server_context->NewRequestContext(r)),
request_context,
cache_url,
ctx->driver->CacheFragment(),
request_headers.GetProperties(),
options->respect_vary(),
options->ipro_max_response_bytes(),
options->ipro_max_concurrent_recordings(),
options->implicit_cache_ttl_ms(),
server_context->http_cache(),
server_context->statistics(),
message_handler);
@@ -2294,8 +2462,8 @@ ngx_int_t ps_in_place_check_header_filter(ngx_http_request_t* r) {
// to the backend.
} else {
server_context->rewrite_stats()->ipro_not_rewritable()->Add(1);
message_handler->Message(kInfo,
"Could not rewrite resource in-place: %s", url.c_str());
message_handler->Message(
kInfo, "Could not rewrite resource in-place: %s", url.c_str());
}
ctx->driver->Cleanup();
@@ -2307,6 +2475,8 @@ ngx_int_t ps_in_place_check_header_filter(ngx_http_request_t* r) {
return ps_decline_request(r);
}
// If we've decided that we should record this response for future optimization
// with IPRO, then log the bytes as they come through
ngx_int_t ps_in_place_body_filter(ngx_http_request_t* r, ngx_chain_t* in) {
ps_request_ctx_t* ctx = ps_get_request_context(r);
if (ctx == NULL || ctx->recorder == NULL) {
@@ -2319,10 +2489,10 @@ ngx_int_t ps_in_place_body_filter(ngx_http_request_t* r, ngx_chain_t* in) {
InPlaceResourceRecorder* recorder = ctx->recorder;
for (ngx_chain_t* cl = in; cl; cl = cl->next) {
if (ngx_buf_size(cl->buf)) {
CHECK(ngx_buf_in_memory(cl->buf));
StringPiece contents(reinterpret_cast<char*>(cl->buf->pos),
ngx_buf_size(cl->buf));
recorder->Write(contents, recorder->handler());
CHECK(ngx_buf_in_memory(cl->buf));
StringPiece contents(reinterpret_cast<char*>(cl->buf->pos),
ngx_buf_size(cl->buf));
recorder->Write(contents, recorder->handler());
}
if (cl->buf->flush) {
@@ -2382,6 +2552,8 @@ ngx_int_t send_out_headers_and_body(
return ngx_http_output_filter(r, out);
}
// Handle responses where we have the content we need in memory and can just
// send it right out.
ngx_int_t ps_simple_handler(ngx_http_request_t* r,
NgxServerContext* server_context,
RequestRouting::Response response_category) {
@@ -2395,7 +2567,7 @@ ngx_int_t ps_simple_handler(ngx_http_request_t* r,
GoogleUrl url(url_string);
QueryParams query_params;
if (url.IsWebValid()) {
query_params.Parse(url.Query());
query_params.ParseFromUrl(url);
}
GoogleString output;
@@ -2424,7 +2596,7 @@ ngx_int_t ps_simple_handler(ngx_http_request_t* r,
"Please check if it's enabled in pagespeed.conf.\n",
message_handler);
} else {
HtmlKeywords::WritePre(log, &writer, message_handler);
HtmlKeywords::WritePre(log, "", &writer, message_handler);
}
break;
}
@@ -2484,10 +2656,16 @@ void ps_beacon_handler_helper(ngx_http_request_t* r,
ps_srv_conf_t* cfg_s = ps_get_srv_config(r);
CHECK(cfg_s != NULL);
cfg_s->server_context->HandleBeacon(
beacon_data,
user_agent,
RequestContextPtr(cfg_s->server_context->NewRequestContext(r)));
RequestContextPtr request_context(
cfg_s->server_context->NewRequestContext(r));
// TODO(sligocki): Do we want custom options here? It probably doesn't matter
// for beacons.
request_context->set_options(
cfg_s->server_context->global_options()->ComputeHttpOptions());
cfg_s->server_context->HandleBeacon(beacon_data,
user_agent,
request_context);
ps_set_cache_control(r, const_cast<char*>("max-age=0, no-cache"));
@@ -2495,7 +2673,6 @@ void ps_beacon_handler_helper(ngx_http_request_t* r,
// header so wget doesn't hang.
}
// Load the request body into out. ngx_http_read_client_request_body must
// already have been called. Return false on failure, true on success.
bool ps_request_body_to_string_piece(
@@ -2508,13 +2685,32 @@ bool ps_request_body_to_string_piece(
}
if (r->request_body->temp_file) {
// For now raise an error instead of figuring out how to read temporary
// files.
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"ps_request_body_to_string_piece: "
"request body in temporary file unsupported."
"Increase client_body_buffer_size.");
return false;
u_char buf[POST_BUF_READ_SIZE];
int count = 0;
ssize_t ret;
GoogleString tmp;
// Note that we depend on nginx to impose sensible limits on post data.
while ((ret = ngx_read_file(&r->request_body->temp_file->file,
buf, POST_BUF_READ_SIZE, count)) > 0) {
tmp.append(reinterpret_cast<char*>(buf), ret);
count += ret;
}
if (ret < 0) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"ps_request_body_to_string_piece: "
"error reading post body.");
return false;
}
// We have read the complete post body, copy it to a buffer
// from the request's pool.
u_char* data = reinterpret_cast<u_char*>(ngx_palloc(r->pool, count));
memcpy(data, tmp.c_str(), count);
*out = StringPiece(reinterpret_cast<char*>(data), count);
return true;
} else if (r->request_body->bufs->next == NULL) {
// There's just one buffer, so we can simply return a StringPiece pointing
// to this buffer.
@@ -2603,6 +2799,10 @@ void ps_beacon_body_handler(ngx_http_request_t* r) {
}
}
// We need to get the beacon data to ps_beacon_body_handler so it can pass it
// along to SystemServerContext::HandleBeacon, but it might have been POSTed.
// If it's posted we need to make an async call to get the data, otherwise just
// read it out of the query params.
ngx_int_t ps_beacon_handler(ngx_http_request_t* r) {
if (r->method == NGX_HTTP_POST) {
// Use post body. Handler functions are called before the request body has
@@ -2625,8 +2825,12 @@ ngx_int_t ps_beacon_handler(ngx_http_request_t* r) {
}
}
// Handle requests for resources like example.css.pagespeed.ce.LyfcM6Wulf.css
// and for static content like /ngx_pagespeed_static/js_defer.q1EBmcgYOC.js
// Some things pagespeed filters on the way past (html) and other things it
// actually handles, like requests for resources
// (example.css.pagespeed.ce.LyfcM6Wulf.css) and static content
// (/ngx_pagespeed_static/js_defer.q1EBmcgYOC.js). This is called once we know
// we need to handle a resource, and it figures out which particular handler can
// supply it to the user.
ngx_int_t ps_content_handler(ngx_http_request_t* r) {
ps_srv_conf_t* cfg_s = ps_get_srv_config(r);
if (cfg_s->server_context == NULL) {
@@ -2662,6 +2866,7 @@ ngx_int_t ps_content_handler(ngx_http_request_t* r) {
case RequestRouting::kConsole:
case RequestRouting::kAdmin:
case RequestRouting::kGlobalAdmin:
case RequestRouting::kCachePurge:
case RequestRouting::kResource:
return ps_resource_handler(
r, false /* html rewrite */, response_category);
@@ -2672,9 +2877,9 @@ ngx_int_t ps_content_handler(ngx_http_request_t* r) {
}
ngx_int_t ps_phase_handler(ngx_http_request_t* r,
ngx_http_phase_handler_t* ph) {
ngx_http_phase_handler_t* ph) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"pagespeed phase: %ui", r->phase_handler);
"pagespeed phase: %ui", r->phase_handler);
r->write_event_handler = ngx_http_request_empty_handler;
@@ -2696,10 +2901,12 @@ ngx_int_t ps_phase_handler(ngx_http_request_t* r,
namespace fix_headers {
ngx_http_output_header_filter_pt ngx_http_next_header_filter;
// Clear a few headers from html responses.
ngx_int_t ps_html_rewrite_fix_headers_filter(ngx_http_request_t* r) {
ps_request_ctx_t* ctx = ps_get_request_context(r);
if (r != r->main || ctx == NULL || !ctx->html_rewrite
|| ctx->preserve_caching_headers == kPreserveAllCachingHeaders) {
if (r != r->main || ctx == NULL || !ctx->html_rewrite ||
ctx->preserve_caching_headers == kPreserveAllCachingHeaders) {
return ngx_http_next_header_filter(r);
}
if (ctx->preserve_caching_headers == kDontPreserveHeaders) {
@@ -2749,8 +2956,8 @@ ngx_int_t ps_preaccess_handler(ngx_http_request_t* r) {
i = r->phase_handler;
// move handlers before try_files && content phase
while (ph[i + 1].checker != ngx_http_core_try_files_phase
&& ph[i + 1].checker != ngx_http_core_content_phase) {
while (ph[i + 1].checker != ngx_http_core_try_files_phase &&
ph[i + 1].checker != ngx_http_core_content_phase) {
ph[i] = ph[i + 1];
ph[i].next--;
i++;
@@ -2776,6 +2983,14 @@ ngx_int_t ps_etag_filter_init(ngx_conf_t* cf) {
return NGX_OK;
}
// Called before configuration.
ngx_int_t ps_pre_init(ngx_conf_t* cf) {
// Setup an intervention setter for gzip configuration and check
// gzip configuration command signatures.
g_gzip_setter.Init(cf);
return NGX_OK;
}
ngx_int_t ps_init(ngx_conf_t* cf) {
// Only put register pagespeed code to run if there was a "pagespeed"
// configuration option set in the config file. With "pagespeed off" we
@@ -2825,7 +3040,7 @@ ngx_http_module_t ps_etag_filter_module = {
};
ngx_http_module_t ps_module = {
NULL, // preconfiguration
ps_pre_init, // preconfiguration
ps_init, // postconfiguration
ps_create_main_conf,
@@ -2895,10 +3110,15 @@ ngx_int_t ps_init_module(ngx_cycle_t* cycle) {
"UseNativeFetcher is on, please configure a resolver.");
return NGX_ERROR;
}
// Update logging to the configured error_log in the http{} block.
cfg_m->driver_factory->LoggingInit(cycle->log);
cfg_m->driver_factory->RootInit();
} else {
if (!factory_init_called) {
cfg_m->driver_factory->LoggingInit(cycle->log);
cfg_m->driver_factory->Init();
factory_init_called = true;
}
delete cfg_m->driver_factory;
cfg_m->driver_factory = NULL;
}
@@ -2935,11 +3155,11 @@ ngx_int_t ps_init_child_process(ngx_cycle_t* cycle) {
// Some server{} blocks may not have a ServerContext in that case we must
// not instantiate a ProxyFetchFactory.
if (cfg_s->server_context != NULL) {
cfg_s->proxy_fetch_factory = new ProxyFetchFactory(cfg_s->server_context);
ngx_http_core_loc_conf_t* clcf = static_cast<ngx_http_core_loc_conf_t*>(
cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]);
cfg_m->driver_factory->SetServerContextMessageHandler(
cfg_s->server_context, clcf->error_log);
cfg_s->proxy_fetch_factory = new ProxyFetchFactory(cfg_s->server_context);
}
}
+11 -7
View File
@@ -71,17 +71,20 @@ NgxRewriteDriverFactory::NgxRewriteDriverFactory(
NULL /* default shared memory runtime */, hostname, port),
main_conf_(NULL),
threads_started_(false),
use_per_vhost_statistics_(false),
ngx_message_handler_(new NgxMessageHandler(thread_system()->NewMutex())),
ngx_message_handler_(
new NgxMessageHandler(timer(), thread_system()->NewMutex())),
ngx_html_parse_message_handler_(
new NgxMessageHandler(thread_system()->NewMutex())),
install_crash_handler_(false),
new NgxMessageHandler(timer(), thread_system()->NewMutex())),
log_(NULL),
resolver_timeout_(NGX_CONF_UNSET_MSEC),
use_native_fetcher_(false),
// 100 Aligns to nginx's server-side default.
native_fetcher_max_keepalive_requests_(100),
ngx_shared_circular_buffer_(NULL),
hostname_(hostname.as_string()),
port_(port) {
port_(port),
process_script_variables_(false),
process_script_variables_set_(false) {
InitializeDefaultOptions();
default_options()->set_beacon_url("/ngx_pagespeed_beacon");
SystemRewriteOptions* system_options = dynamic_cast<SystemRewriteOptions*>(
@@ -111,6 +114,7 @@ UrlAsyncFetcher* NgxRewriteDriverFactory::AllocateFetcher(
resolver_timeout_,
config->blocking_fetch_timeout_ms(),
resolver_,
native_fetcher_max_keepalive_requests_,
thread_system(),
message_handler());
ngx_url_async_fetchers_.push_back(fetcher);
@@ -208,7 +212,7 @@ void NgxRewriteDriverFactory::StartThreads() {
void NgxRewriteDriverFactory::LoggingInit(ngx_log_t* log) {
net_instaweb::log_message_handler::Install(log);
if (install_crash_handler_) {
if (install_crash_handler()) {
NgxMessageHandler::InstallCrashHandler(log);
}
ngx_message_handler_->set_log(log);
@@ -225,7 +229,7 @@ void NgxRewriteDriverFactory::SetCircularBuffer(
void NgxRewriteDriverFactory::SetServerContextMessageHandler(
ServerContext* server_context, ngx_log_t* log) {
NgxMessageHandler* handler = new NgxMessageHandler(
thread_system()->NewMutex());
timer(), thread_system()->NewMutex());
handler->set_log(log);
// The ngx_shared_circular_buffer_ will be NULL if MessageBufferSize hasn't
// been raised from its default of 0.
+20 -27
View File
@@ -92,18 +92,6 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
void set_main_conf(NgxRewriteOptions* main_conf) { main_conf_ = main_conf; }
bool use_per_vhost_statistics() const {
return use_per_vhost_statistics_;
}
void set_use_per_vhost_statistics(bool x) {
use_per_vhost_statistics_ = x;
}
bool install_crash_handler() const {
return install_crash_handler_;
}
void set_install_crash_handler(bool x) {
install_crash_handler_ = x;
}
void set_resolver(ngx_resolver_t* resolver) {
resolver_ = resolver;
}
@@ -117,16 +105,14 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
void set_use_native_fetcher(bool x) {
use_native_fetcher_ = x;
}
void set_rate_limit_background_fetches(bool x) {
rate_limit_background_fetches_ = x;
int native_fetcher_max_keepalive_requests() {
return native_fetcher_max_keepalive_requests_;
}
// We use a beacon handler to collect data for critical images,
// css, etc., so filters should be configured accordingly.
//
// TODO(jefftk): move to SystemRewriteDriverFactory
virtual bool UseBeaconResultsInFilters() const {
return true;
void set_native_fetcher_max_keepalive_requests(int x) {
native_fetcher_max_keepalive_requests_ = x;
}
bool process_script_variables() {
return process_script_variables_;
}
void LoggingInit(ngx_log_t* log);
@@ -135,6 +121,15 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
virtual void SetCircularBuffer(SharedCircularBuffer* buffer);
bool SetProcessScriptVariables(bool process_script_variables) {
if (!process_script_variables_set_) {
process_script_variables_ = process_script_variables;
process_script_variables_set_ = true;
return true;
}
return false;
}
private:
Timer* timer_;
@@ -143,20 +138,16 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
NgxRewriteOptions* main_conf_;
bool threads_started_;
// If true, we'll have a separate statistics object for each vhost
// (along with a global aggregate), rather than just a single object
// aggregating all of them.
bool use_per_vhost_statistics_;
NgxMessageHandler* ngx_message_handler_;
NgxMessageHandler* ngx_html_parse_message_handler_;
bool install_crash_handler_;
std::vector<NgxUrlAsyncFetcher*> ngx_url_async_fetchers_;
ngx_log_t* log_;
ngx_msec_t resolver_timeout_;
ngx_resolver_t* resolver_;
bool use_native_fetcher_;
bool rate_limit_background_fetches_;
int native_fetcher_max_keepalive_requests_;
typedef std::set<NgxMessageHandler*> NgxMessageHandlerSet;
NgxMessageHandlerSet server_context_message_handlers_;
@@ -166,6 +157,8 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
GoogleString hostname_;
int port_;
bool process_script_variables_;
bool process_script_variables_set_;
DISALLOW_COPY_AND_ASSIGN(NgxRewriteDriverFactory);
};
+209 -63
View File
@@ -31,6 +31,7 @@ extern "C" {
#include "net/instaweb/rewriter/public/file_load_policy.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/system/public/system_caches.h"
#include "net/instaweb/util/public/message_handler.h"
#include "net/instaweb/util/public/timer.h"
namespace net_instaweb {
@@ -71,12 +72,14 @@ const char* const server_only_options[] = {
"LoadFromFileMatch",
"LoadFromFileRule",
"LoadFromFileRuleMatch",
"UseNativeFetcher"
"UseNativeFetcher",
"NativeFetcherMaxKeepaliveRequests"
};
// Options that can only be used in the main (http) option scope.
const char* const main_only_options[] = {
"UseNativeFetcher"
"UseNativeFetcher",
"NativeFetcherMaxKeepaliveRequests"
};
} // namespace
@@ -97,6 +100,7 @@ NgxRewriteOptions::NgxRewriteOptions(ThreadSystem* thread_system)
void NgxRewriteOptions::Init() {
DCHECK(ngx_properties_ != NULL)
<< "Call NgxRewriteOptions::Initialize() before construction";
clear_inherited_scripts_ = false;
InitializeOptions(ngx_properties_);
}
@@ -104,23 +108,27 @@ void NgxRewriteOptions::AddProperties() {
// Nginx-specific options.
add_ngx_option(
"", &NgxRewriteOptions::statistics_path_, "nsp", kStatisticsPath,
kServerScope, "Set the statistics path. Ex: /ngx_pagespeed_statistics");
kServerScope, "Set the statistics path. Ex: /ngx_pagespeed_statistics",
false);
add_ngx_option(
"", &NgxRewriteOptions::global_statistics_path_, "ngsp",
kGlobalStatisticsPath, kProcessScope,
"Set the global statistics path. Ex: /ngx_pagespeed_global_statistics");
"Set the global statistics path. Ex: /ngx_pagespeed_global_statistics",
false);
add_ngx_option(
"", &NgxRewriteOptions::console_path_, "ncp", kConsolePath, kServerScope,
"Set the console path. Ex: /pagespeed_console");
"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");
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");
kServerScope, "Set the admin path. Ex: /pagespeed_admin", false);
add_ngx_option(
"", &NgxRewriteOptions::global_admin_path_, "ngap", kGlobalAdminPath,
kProcessScope, "Set the global admin path. Ex: /pagespeed_global_admin");
kProcessScope, "Set the global admin path. Ex: /pagespeed_global_admin",
false);
MergeSubclassProperties(ngx_properties_);
@@ -250,7 +258,7 @@ const char* ps_error_string_for_option(
const char* NgxRewriteOptions::ParseAndSetOptions(
StringPiece* args, int n_args, ngx_pool_t* pool, MessageHandler* handler,
NgxRewriteDriverFactory* driver_factory,
RewriteOptions::OptionScope scope) {
RewriteOptions::OptionScope scope, ngx_conf_t* cf, bool compile_scripts) {
CHECK_GE(n_args, 1);
StringPiece directive = args[0];
@@ -266,80 +274,139 @@ const char* NgxRewriteOptions::ParseAndSetOptions(
pool, directive, "cannot be set at this scope.");
}
ScriptLine* script_line;
script_line = NULL;
// Only allow script variable support for LoadFromFile for now.
// Note that LoadFromFile should not be scriptable on wildcard hosts,
// as browsers might be able to manipulate its natural use-case: $http_host.
if (!StringCaseStartsWith(directive, "LoadFromFile")) {
compile_scripts = false;
}
if (n_args == 1 && StringCaseEqual(directive, "ClearInheritedScripts")) {
clear_inherited_scripts_ = true;
return NGX_CONF_OK;
}
if (compile_scripts) {
CHECK(cf != NULL);
int i;
// Skip the first arg which is always 'pagespeed'
for (i = 1; i < n_args; i++) {
ngx_str_t script_source;
script_source.len = args[i].as_string().length();
std::string tmp = args[i].as_string();
script_source.data = reinterpret_cast<u_char*>(
const_cast<char*>(tmp.c_str()));
if (ngx_http_script_variables_count(&script_source) > 0) {
ngx_http_script_compile_t* sc =
reinterpret_cast<ngx_http_script_compile_t*>(
ngx_pcalloc(cf->pool, sizeof(ngx_http_script_compile_t)));
sc->cf = cf;
sc->source = &script_source;
sc->lengths = reinterpret_cast<ngx_array_t**>(
ngx_pcalloc(cf->pool, sizeof(ngx_array_t*)));
sc->values = reinterpret_cast<ngx_array_t**>(
ngx_pcalloc(cf->pool, sizeof(ngx_array_t*)));
sc->variables = 1;
sc->complete_lengths = 1;
sc->complete_values = 1;
if (ngx_http_script_compile(sc) != NGX_OK) {
return ps_error_string_for_option(
pool, directive, "Failed to compile script variables");
} else {
if (script_line == NULL) {
script_line = new ScriptLine(args, n_args, scope);
}
script_line->AddScriptAndArgIndex(sc, i);
}
}
}
if (script_line != NULL) {
script_lines_.push_back(RefCountedPtr<ScriptLine>(script_line));
// We have found script variables in the current configuration line, and
// prepared the associated rewriteoptions for that.
// We will defer parsing, validation and processing of this line to
// request time. That means we are done handling this configuration line.
return NGX_CONF_OK;
}
}
GoogleString msg;
OptionSettingResult result;
if (n_args == 1) {
result = ParseAndSetOptions0(directive, &msg, handler);
} else if (n_args == 2) {
StringPiece arg = args[1];
// TODO(morlovich): Remove these special hacks, and handle these via
// ParseAndSetOptionFromEnum1.
if (IsDirective(directive, "UsePerVHostStatistics")) {
if (IsDirective(directive, "UseNativeFetcher")) {
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
arg, driver_factory,
&NgxRewriteDriverFactory::set_use_per_vhost_statistics);
} else if (IsDirective(directive, "InstallCrashHandler")) {
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
arg, driver_factory,
&NgxRewriteDriverFactory::set_install_crash_handler);
} else if (IsDirective(directive, "MessageBufferSize")) {
int message_buffer_size;
bool ok = StringToInt(arg.as_string(), &message_buffer_size);
if (ok && message_buffer_size >= 0) {
driver_factory->set_message_buffer_size(message_buffer_size);
&NgxRewriteDriverFactory::set_use_native_fetcher);
} else if (IsDirective(directive, "NativeFetcherMaxKeepaliveRequests")) {
int max_keepalive_requests;
if (StringToInt(arg, &max_keepalive_requests) &&
max_keepalive_requests > 0) {
driver_factory->set_native_fetcher_max_keepalive_requests(
max_keepalive_requests);
result = RewriteOptions::kOptionOk;
} else {
result = RewriteOptions::kOptionValueInvalid;
}
} else if (IsDirective(directive, "UseNativeFetcher")) {
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
arg, driver_factory,
&NgxRewriteDriverFactory::set_use_native_fetcher);
} else if (IsDirective(directive, "RateLimitBackgroundFetches")) {
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
arg, driver_factory,
&NgxRewriteDriverFactory::set_rate_limit_background_fetches);
} else if (IsDirective(directive, "ForceCaching")) {
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
arg, driver_factory,
&SystemRewriteDriverFactory::set_force_caching);
} else if (IsDirective(directive, "ListOutstandingUrlsOnError")) {
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
arg, driver_factory,
&SystemRewriteDriverFactory::list_outstanding_urls_on_error);
} else if (IsDirective(directive, "TrackOriginalContentLength")) {
result = ParseAndSetOptionHelper<SystemRewriteDriverFactory>(
arg, driver_factory,
&SystemRewriteDriverFactory::set_track_original_content_length);
} else if (IsDirective(directive, "StaticAssetPrefix")) {
driver_factory->set_static_asset_prefix(arg);
result = RewriteOptions::kOptionOk;
} else {
result = ParseAndSetOptionFromName1(directive, arg, &msg, handler);
}
} else if (n_args == 3) {
// Short-term special handling, until this moves to common code.
// TODO(morlovich): Clean this up.
if (StringCaseEqual(directive, "CreateSharedMemoryMetadataCache")) {
int64 kb = 0;
if (!StringToInt64(args[2], &kb) || kb < 0) {
result = RewriteOptions::kOptionValueInvalid;
msg = "size_kb must be a positive 64-bit integer";
} else if (StringCaseEqual("ProcessScriptVariables", args[0])) {
if (scope == RewriteOptions::kProcessScopeStrict) {
if (StringCaseEqual(arg, "on")) {
if (driver_factory->SetProcessScriptVariables(true)) {
result = RewriteOptions::kOptionOk;
} else {
return const_cast<char*>(
"pagespeed ProcessScriptVariables: can only be set once");
}
} else if (StringCaseEqual(arg, "off")) {
if (driver_factory->SetProcessScriptVariables(false)) {
result = RewriteOptions::kOptionOk;
} else {
return const_cast<char*>(
"pagespeed ProcessScriptVariables: can only be set once");
}
} else {
return const_cast<char*>(
"pagespeed ProcessScriptVariables: invalid value");
}
} else {
bool ok = driver_factory->caches()->CreateShmMetadataCache(
args[1].as_string(), kb, &msg);
result = ok ? kOptionOk : kOptionValueInvalid;
return const_cast<char*>(
"ProcessScriptVariables is only allowed at the top level");
}
} else {
result = ParseAndSetOptionFromName2(directive, args[1], args[2],
&msg, handler);
result = ParseAndSetOptionFromName1(directive, arg, &msg, handler);
if (result == RewriteOptions::kOptionNameUnknown) {
result = driver_factory->ParseAndSetOption1(
directive,
arg,
scope >= RewriteOptions::kProcessScope,
&msg,
handler);
}
}
} else if (n_args == 3) {
result = ParseAndSetOptionFromName2(directive, args[1], args[2],
&msg, handler);
if (result == RewriteOptions::kOptionNameUnknown) {
result = driver_factory->ParseAndSetOption2(
directive,
args[1],
args[2],
scope >= RewriteOptions::kProcessScope,
&msg,
handler);
}
} else if (n_args == 4) {
result = ParseAndSetOptionFromName3(
directive, args[1], args[2], args[3], &msg, handler);
} else {
return ps_error_string_for_option(
pool, directive, "not recognized or too many arguments");
result = RewriteOptions::kOptionNameUnknown;
}
switch (result) {
@@ -361,13 +428,92 @@ const char* NgxRewriteOptions::ParseAndSetOptions(
return NULL;
}
// Execute all entries in the script_lines vector, and hand the result off to
// ParseAndSetOptions to obtain the final option values.
bool NgxRewriteOptions::ExecuteScriptVariables(
ngx_http_request_t* r, MessageHandler* handler,
NgxRewriteDriverFactory* driver_factory) {
bool script_error = false;
if (script_lines_.size() > 0) {
std::vector<RefCountedPtr<ScriptLine> >::iterator it;
for (it = script_lines_.begin() ; it != script_lines_.end(); ++it) {
ScriptLine* script_line = it->get();
StringPiece args[NGX_PAGESPEED_MAX_ARGS];
std::vector<ScriptArgIndex*>::iterator cs_it;
int i;
for (i = 0; i < script_line->n_args(); i++) {
args[i] = script_line->args()[i];
}
for (cs_it = script_line->data().begin();
cs_it != script_line->data().end(); cs_it++) {
ngx_http_script_compile_t* script;
ngx_array_t* values;
ngx_array_t* lengths;
ngx_str_t value;
script = (*cs_it)->script();
lengths = *script->lengths;
values = *script->values;
if (ngx_http_script_run(r, &value, lengths->elts, 0, values->elts)
== NULL) {
handler->Message(kError, "ngx_http_script_run error");
script_error = true;
break;
} else {
args[(*cs_it)->index()] = str_to_string_piece(value);
}
}
const char* status = ParseAndSetOptions(args, script_line->n_args(),
r->pool, handler, driver_factory, script_line->scope(), NULL /*cf*/,
false /*compile scripts*/);
if (status != NULL) {
script_error = true;
handler->Message(kWarning,
"Error setting option value from script: '%s'", status);
break;
}
}
}
if (script_error) {
handler->Message(kWarning,
"Script error(s) in configuration, disabling optimization");
set_enabled(RewriteOptions::kEnabledOff);
return false;
}
return true;
}
void NgxRewriteOptions::CopyScriptLinesTo(
NgxRewriteOptions* destination) const {
destination->script_lines_ = script_lines_;
}
void NgxRewriteOptions::AppendScriptLinesTo(
NgxRewriteOptions* destination) const {
destination->script_lines_.insert(destination->script_lines_.end(),
script_lines_.begin(), script_lines_.end());
}
NgxRewriteOptions* NgxRewriteOptions::Clone() const {
NgxRewriteOptions* options = new NgxRewriteOptions(
StrCat("cloned from ", description()), thread_system());
this->CopyScriptLinesTo(options);
options->Merge(*this);
return options;
}
void NgxRewriteOptions::Merge(const RewriteOptions& src) {
SystemRewriteOptions::Merge(src);
}
const NgxRewriteOptions* NgxRewriteOptions::DynamicCast(
const RewriteOptions* instance) {
return dynamic_cast<const NgxRewriteOptions*>(instance);
+92 -3
View File
@@ -27,13 +27,81 @@ extern "C" {
#include <ngx_http.h>
}
#include <vector>
#include "net/instaweb/util/public/message_handler.h"
#include "net/instaweb/util/public/ref_counted_ptr.h"
#include "net/instaweb/util/public/stl_util.h" // for STLDeleteElements
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/system/public/system_rewrite_options.h"
#define NGX_PAGESPEED_MAX_ARGS 10
namespace net_instaweb {
class NgxRewriteDriverFactory;
class ScriptArgIndex {
public:
explicit ScriptArgIndex(ngx_http_script_compile_t* script, int index)
: script_(script), index_(index) {
CHECK(script != NULL);
CHECK(index > 0 && index < NGX_PAGESPEED_MAX_ARGS);
}
virtual ~ScriptArgIndex() {}
ngx_http_script_compile_t* script() { return script_; }
int index() { return index_; }
private:
// Not owned.
ngx_http_script_compile_t* script_;
int index_;
};
// Refcounted, because the ScriptArgIndexes inside data_ can be shared between
// different rewriteoptions.
class ScriptLine : public RefCounted<ScriptLine> {
public:
explicit ScriptLine(StringPiece* args, int n_args,
RewriteOptions::OptionScope scope)
: n_args_(n_args),
scope_(scope) {
for (int i = 0; i < n_args; i++) {
args_[i] = args[i];
}
}
virtual ~ScriptLine() {
STLDeleteElements(&data_);
data_.clear();
}
void AddScriptAndArgIndex(ngx_http_script_compile_t* script,
int script_index) {
CHECK(script != NULL);
CHECK(script_index < NGX_PAGESPEED_MAX_ARGS);
data_.push_back(new ScriptArgIndex(script, script_index));
}
int n_args() { return n_args_;}
StringPiece* args() { return args_;}
RewriteOptions::OptionScope scope() { return scope_; }
std::vector<ScriptArgIndex*>& data() {
return data_;
}
private:
StringPiece args_[NGX_PAGESPEED_MAX_ARGS];
int n_args_;
RewriteOptions::OptionScope scope_;
std::vector<ScriptArgIndex*> data_;
DISALLOW_COPY_AND_ASSIGN(ScriptLine);
};
class NgxRewriteOptions : public SystemRewriteOptions {
public:
// See rewrite_options::Initialize and ::Terminate
@@ -56,12 +124,23 @@ class NgxRewriteOptions : public SystemRewriteOptions {
// on failure.
//
// pool is a memory pool for allocating error strings.
// cf is only required when compile_scripts is true
// when compile_scripts is true, the rewrite_options will be prepared
// for replacing any script $variables encountered in args. when false,
// script variables will be substituted using the prepared rewrite options.
const char* ParseAndSetOptions(
StringPiece* args, int n_args, ngx_pool_t* pool, MessageHandler* handler,
NgxRewriteDriverFactory* driver_factory, OptionScope scope);
NgxRewriteDriverFactory* driver_factory, OptionScope scope,
ngx_conf_t* cf, bool compile_scripts);
bool ExecuteScriptVariables(
ngx_http_request_t* r, MessageHandler* handler,
NgxRewriteDriverFactory* driver_factory);
void CopyScriptLinesTo(NgxRewriteOptions* destination) const;
void AppendScriptLinesTo(NgxRewriteOptions* destination) const;
// Make an identical copy of these options and return it.
virtual NgxRewriteOptions* Clone() const;
virtual void Merge(const RewriteOptions& src);
// Returns a suitably down cast version of 'instance' if it is an instance
// of this class, NULL if not.
@@ -86,6 +165,12 @@ class NgxRewriteOptions : public SystemRewriteOptions {
const GoogleString& global_admin_path() const {
return global_admin_path_.value();
}
const std::vector<RefCountedPtr<ScriptLine> >& script_lines() const {
return script_lines_;
}
const bool& clear_inherited_scripts() const {
return clear_inherited_scripts_;
}
private:
// Helper methods for ParseAndSetOptions(). Each can:
@@ -129,9 +214,10 @@ class NgxRewriteOptions : public SystemRewriteOptions {
const char* id,
StringPiece option_name,
OptionScope scope,
const char* help) {
const char* help,
bool safe_to_print) {
AddProperty(default_value, offset, id, option_name, scope, help,
ngx_properties_);
safe_to_print, ngx_properties_);
}
Option<GoogleString> statistics_path_;
@@ -141,6 +227,9 @@ class NgxRewriteOptions : public SystemRewriteOptions {
Option<GoogleString> admin_path_;
Option<GoogleString> global_admin_path_;
bool clear_inherited_scripts_;
std::vector<RefCountedPtr<ScriptLine> > script_lines_;
// Helper for ParseAndSetOptions. Returns whether the two directives equal,
// ignoring case.
bool IsDirective(StringPiece config_directive, StringPiece compare_directive);
+5
View File
@@ -77,4 +77,9 @@ SystemRequestContext* NgxServerContext::NewRequestContext(
str_to_string_piece(local_ip));
}
GoogleString NgxServerContext::FormatOption(StringPiece option_name,
StringPiece args) {
return StrCat("pagespeed ", option_name, " ", args, ";");
}
} // namespace net_instaweb
+2
View File
@@ -55,6 +55,8 @@ class NgxServerContext : public SystemServerContext {
return dynamic_cast<NgxMessageHandler*>(message_handler());
}
virtual GoogleString FormatOption(StringPiece option_name, StringPiece args);
private:
NgxRewriteDriverFactory* ngx_factory_;
+5 -3
View File
@@ -55,6 +55,7 @@ namespace net_instaweb {
ngx_msec_t resolver_timeout,
ngx_msec_t fetch_timeout,
ngx_resolver_t* resolver,
int max_keepalive_requests,
ThreadSystem* thread_system,
MessageHandler* handler)
: fetchers_count_(0),
@@ -63,7 +64,8 @@ namespace net_instaweb {
byte_count_(0),
thread_system_(thread_system),
message_handler_(handler),
mutex_(NULL) {
mutex_(NULL),
max_keepalive_requests_(max_keepalive_requests) {
resolver_timeout_ = resolver_timeout;
fetch_timeout_ = fetch_timeout;
ngx_memzero(&proxy_, sizeof(proxy_));
@@ -223,7 +225,7 @@ namespace net_instaweb {
AsyncFetch* async_fetch) {
async_fetch = EnableInflation(async_fetch);
NgxFetch* fetch = new NgxFetch(url, async_fetch,
message_handler, fetch_timeout_, log_);
message_handler, log_);
ScopedMutex lock(mutex_);
pending_fetches_.Add(fetch);
SendCmd('F');
@@ -249,7 +251,7 @@ namespace net_instaweb {
// This is the read event which is called in the main thread.
// It will do the real work. Add the work event and start the fetch.
void NgxUrlAsyncFetcher::CommandHandler(ngx_event_t *cmdev) {
void NgxUrlAsyncFetcher::CommandHandler(ngx_event_t* cmdev) {
char command;
int rc;
ngx_connection_t* c = static_cast<ngx_connection_t*>(cmdev->data);
+3 -1
View File
@@ -53,7 +53,8 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
NgxUrlAsyncFetcher(
const char* proxy, ngx_log_t* log, ngx_msec_t resolver_timeout,
ngx_msec_t fetch_timeout, ngx_resolver_t* resolver,
ThreadSystem* thread_system, MessageHandler* handler);
int max_keepalive_requests, ThreadSystem* thread_system,
MessageHandler* handler);
~NgxUrlAsyncFetcher();
@@ -139,6 +140,7 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
ngx_connection_t* command_connection_; // the command pipe
int pipe_fd_; // the write pipe end
ngx_resolver_t* resolver_;
int max_keepalive_requests_;
ngx_msec_t resolver_timeout_;
ngx_msec_t fetch_timeout_;
Executable → Regular
+247 -158
View File
@@ -71,12 +71,12 @@ function keepalive_test() {
if [ -z "$POST_DATA" ]; then
curl -m 2 -S -s -v -H "Accept-Encoding: $accept_encoding" \
-H "Host: $HOST_NAME" $URL $URL $URL $URL $URL > /dev/null \
2>>"$TEST_TMP/$CURL_LOG_FILE"
2>>"$TEST_TMP/$CURL_LOG_FILE" || true
else
curl -X POST --data "$POST_DATA" -m 2 -S -s -v \
-H "Accept-Encoding: $accept_encoding" -H "Host: $HOST_NAME"\
$URL $URL $URL $URL $URL > /dev/null \
2>>"$TEST_TMP/$CURL_LOG_FILE"
2>>"$TEST_TMP/$CURL_LOG_FILE" || true
fi
done
done
@@ -92,13 +92,16 @@ function keepalive_test() {
| grep -v "^\\* Connection.*left intact"\
| grep -v "^} \\[data not shown"\
| grep -v "^\\* upload completely sent off"\
| grep -v "^\\* Found bundle for host"\
| grep -v "^\\* connected"\
| grep -v "^\\* Found bundle for host"\
| grep -v "^\\* Adding handle"\
| grep -v "^\\* Curl_addHandleToPipeline"\
| grep -v "^\\* - Conn "\
| grep -v "^\\* Server "\
| grep -v "^\\* Trying.*\\.\\.\\.")
| grep -v "^\\* Trying.*\\.\\.\\."\
| grep -v "^\\* Hostname was NOT found in DNS cache" \
|| true)
# Nothing should remain after that.
check [ -z "$OUT" ]
@@ -106,7 +109,8 @@ function keepalive_test() {
# Filter the nginx log from our vhost from unimportant messages.
OUT=$(cat "$TEST_TMP/$NGX_LOG_FILE"\
| grep -v "closed keepalive connection$" \
| grep -v ".*Cache Flush.*")
| grep -v ".*Cache Flush.*" \
|| true)
# Nothing should remain after that.
check [ -z "$OUT" ]
@@ -218,24 +222,20 @@ check_rewriting_status() {
else
check_not zgrep -q "pagespeed.ic" $OUT_CONTENTS_FILE
fi
# Reset WGET_ARGS.
WGET_ARGS=""
}
# Helper method that obtains a gzipped response and verifies that rewriting
# has happened. Also takes an extra parameter that identifies extra headers
# to be added during wget.
check_for_rewriting() {
WGET_ARGS="$GZIP_WGET_ARGS $1"
check_rewriting_status true
WGET_ARGS="$GZIP_WGET_ARGS $1" check_rewriting_status true
}
# Helper method that obtains a gzipped response and verifies that no rewriting
# has happened. Also takes an extra parameter that identifies extra headers
# to be added during wget.
check_for_no_rewriting() {
WGET_ARGS="$GZIP_WGET_ARGS $1"
check_rewriting_status false
WGET_ARGS="$GZIP_WGET_ARGS $1" check_rewriting_status false
}
if $RUN_TESTS; then
@@ -250,6 +250,12 @@ else
exit 4
fi
# check_stat in system_test_helpers.sh needs to know whether statstistics are
# enabled, which is always the case for ngx_pagespeed.
statistics_enabled=1
CACHE_FLUSH_TEST="on"
CACHE_PURGE_METHODS="PURGE GET"
# run generic system tests
SYSTEM_TEST_FILE="$MOD_PAGESPEED_DIR/src/net/instaweb/system/system_test.sh"
@@ -404,12 +410,12 @@ check_from "$OUT" egrep -q \
'^X-Page-Speed: [0-9]+[.][0-9]+[.][0-9]+[.][0-9]+-[0-9]+'
start_test pagespeed is defaulting to more than PassThrough
fetch_until $TEST_ROOT/bot_test.html 'grep -c \.pagespeed\.' 2
fetch_until $TEST_ROOT/bot_test.html 'fgrep -c .pagespeed.' 2
start_test 404s are served and properly recorded.
NUM_404=$(scrape_stat resource_404_count)
echo "Initial 404s: $NUM_404"
WGET_ERROR=$($WGET -O /dev/null $BAD_RESOURCE_URL 2>&1)
WGET_ERROR=$(check_not $WGET -O /dev/null $BAD_RESOURCE_URL 2>&1)
check_from "$WGET_ERROR" fgrep -q "404 Not Found"
# Check that the stat got bumped.
@@ -442,16 +448,13 @@ if [ "$HOSTNAME" = "localhost:$PRIMARY_PORT" ] ; then
ALT_STAT_URL=$(echo $STATISTICS_URL | sed s#localhost#$NON_LOCAL_IP#)
echo "wget $ALT_STAT_URL >& $TEMPDIR/alt_stat_url.$$"
wget $ALT_STAT_URL >& "$TEMPDIR/alt_stat_url.$$"
check [ $? = 8 ]
check_error_code 8 wget $ALT_STAT_URL >& "$TEMPDIR/alt_stat_url.$$"
rm -f "$TEMPDIR/alt_stat_url.$$"
ALT_CE_URL="$ALT_STAT_URL.pagespeed.ce.8CfGBvwDhH.css"
wget -O - $ALT_CE_URL >& "$TEMPDIR/alt_ce_url.$$"
check [ $? = 8 ]
wget -O - --header="Host: $HOSTNAME" $ALT_CE_URL >& "$TEMPDIR/alt_ce_url.$$"
check [ $? = 8 ]
check_error_code 8 wget -O - $ALT_CE_URL >& "$TEMPDIR/alt_ce_url.$$"
check_error_code 8 wget -O - --header="Host: $HOSTNAME" $ALT_CE_URL \
>& "$TEMPDIR/alt_ce_url.$$"
rm -f "$TEMPDIR/alt_ce_url.$$"
# Even though we don't have a cookie, we will conservatively avoid
@@ -526,57 +529,55 @@ start_test "Custom statistics paths in server block"
# Served on normal paths by default.
URL="inherit-paths.example.com/ngx_pagespeed_statistics"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_from "$OUT" grep cache_time_us
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
check_from "$OUT" fgrep -q cache_time_us
URL="inherit-paths.example.com/ngx_pagespeed_message"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_from "$OUT" grep Info
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
check_from "$OUT" fgrep -q Info
URL="inherit-paths.example.com/pagespeed_console"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_from "$OUT" grep console_div
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
check_from "$OUT" fgrep -q console_div
URL="inherit-paths.example.com/pagespeed_admin/"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_from "$OUT" grep Admin
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
check_from "$OUT" fgrep -q Admin
# Not served on normal paths when overriden.
URL="custom-paths.example.com/ngx_pagespeed_statistics"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_not_from "$OUT" grep cache_time_us
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET_DUMP $URL)
check_not_from "$OUT" fgrep -q cache_time_us
URL="custom-paths.example.com/ngx_pagespeed_message"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_not_from "$OUT" grep Info
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET_DUMP $URL)
check_not_from "$OUT" fgrep -q Info
URL="custom-paths.example.com/pagespeed_console"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_not_from "$OUT" grep console_div
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET_DUMP $URL)
check_not_from "$OUT" fgrep -q console_div
URL="custom-paths.example.com/pagespeed_admin/"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_not_from "$OUT" grep Admin
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET_DUMP $URL)
check_not_from "$OUT" fgrep -q Admin
# Served on custom paths when overriden
URL="custom-paths.example.com/custom_pagespeed_statistics"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_from "$OUT" grep cache_time_us
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
check_from "$OUT" fgrep -q cache_time_us
URL="custom-paths.example.com/custom_pagespeed_message"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_from "$OUT" grep Info
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
check_from "$OUT" fgrep -q Info
URL="custom-paths.example.com/custom_pagespeed_console"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_from "$OUT" grep console_div
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
check_from "$OUT" fgrep -q console_div
URL="custom-paths.example.com/custom_pagespeed_admin/"
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)
check_from "$OUT" grep Admin
OUT=$(http_proxy=$SECONDARY_HOSTNAME check $WGET_DUMP $URL)
check_from "$OUT" fgrep -q Admin
WGET_ARGS=""
function gunzip_grep_0ff() {
gunzip - | fgrep -q "color:#00f"
echo $?
@@ -603,21 +604,21 @@ start_test Accept bad query params and headers
# The examples page should have this EXPECTED_EXAMPLES_TEXT on it.
EXPECTED_EXAMPLES_TEXT="PageSpeed Examples Directory"
OUT=$(wget -O - $EXAMPLE_ROOT)
check_from "$OUT" grep "$EXPECTED_EXAMPLES_TEXT"
check_from "$OUT" fgrep -q "$EXPECTED_EXAMPLES_TEXT"
# It should still be there with bad query params.
OUT=$(wget -O - $EXAMPLE_ROOT?PageSpeedFilters=bogus)
check_from "$OUT" grep "$EXPECTED_EXAMPLES_TEXT"
check_from "$OUT" fgrep -q "$EXPECTED_EXAMPLES_TEXT"
# And also with bad request headers.
OUT=$(wget -O - --header=PageSpeedFilters:bogus $EXAMPLE_ROOT)
check_from "$OUT" grep "$EXPECTED_EXAMPLES_TEXT"
check_from "$OUT" fgrep -q "$EXPECTED_EXAMPLES_TEXT"
# Tests that an origin header with a Vary header other than Vary:Accept-Encoding
# loses that header when we are not respecting vary.
start_test Vary:User-Agent on resources is held by our cache.
URL="$TEST_ROOT/vary/no_respect/index.html"
fetch_until -save $URL 'grep -c \.pagespeed\.cf\.' 1
fetch_until -save $URL 'fgrep -c .pagespeed.cf.' 1
# Extract out the rewritten CSS file from the HTML saved by fetch_until
# above (see -save and definition of fetch_until). Fetch that CSS
@@ -678,14 +679,12 @@ echo "JS_URL=\$\(egrep -o http://.*[.]pagespeed.*[.]js $FETCHED\)=\"$JS_URL\""
JS_HEADERS=$($WGET -O /dev/null -q -S --header='Accept-Encoding: gzip' \
$JS_URL 2>&1)
echo JS_HEADERS=$JS_HEADERS
check_from "$JS_HEADERS" egrep -qi 'HTTP/1[.]. 200 OK'
check_200_http_response "$JS_HEADERS"
check_from "$JS_HEADERS" fgrep -qi 'Content-Encoding: gzip'
check_from "$JS_HEADERS" fgrep -qi 'Vary: Accept-Encoding'
check_from "$JS_HEADERS" egrep -qi '(Etag: W/"0")|(Etag: W/"0-gzip")'
check_from "$JS_HEADERS" fgrep -qi 'Last-Modified:'
WGET_ARGS="" # Done with test_filter, so clear WGET_ARGS.
start_test Respect X-Forwarded-Proto when told to
FETCHED=$OUTDIR/x_forwarded_proto
URL=$SECONDARY_HOSTNAME/mod_pagespeed_example/?PageSpeedFilters=add_base_tag
@@ -698,21 +697,20 @@ check fgrep -q '<base href="https://' $FETCHED
test_filter remove_comments retains appropriate comments.
URL="$SECONDARY_HOSTNAME/mod_pagespeed_example/$FILE"
check run_wget_with_args $URL --header=Host:retaincomment.example.com
check grep -q retained $FETCHED # RetainComment directive
check fgrep -q retained $FETCHED # RetainComment directive
# Make sure that when in PreserveURLs mode that we don't rewrite URLs. This is
# non-exhaustive, the unit tests should cover the rest.
# Note: We block with psatest here because this is a negative test. We wouldn't
# otherwise know how many wget attempts should be made.
start_test PreserveURLs on prevents URL rewriting
WGET_ARGS="--header=X-PSA-Blocking-Rewrite:psatest"
WGET_ARGS+=" --header=Host:preserveurls.example.com"
start_test PreserveURLs on prevents URL rewriting
FILE=preserveurls/on/preserveurls.html
URL=$SECONDARY_HOSTNAME/mod_pagespeed_test/$FILE
FETCHED=$OUTDIR/preserveurls.html
check run_wget_with_args $URL
WGET_ARGS=""
check_not fgrep -q .pagespeed. $FETCHED
# When PreserveURLs is off do a quick check to make sure that normal rewriting
@@ -746,10 +744,8 @@ URL="$SECONDARY_HOSTNAME/mod_pagespeed_test/no_transform/BikeCrashIcn.png"
wget -O - -S $URL $WGET_ARGS &> $FETCHED
# Make sure that the no-transfrom header is still there
check grep -q 'Cache-Control:.*no-transform' $FETCHED
WGET_ARGS=""
start_test respect vary user-agent
WGET_ARGS=""
URL="$SECONDARY_HOSTNAME/mod_pagespeed_test/vary/index.html"
URL+="?PageSpeedFilters=inline_css"
FETCH_CMD="$WGET_DUMP --header=Host:respectvary.example.com $URL"
@@ -778,9 +774,8 @@ start_test rewrite on Cache-control: no-transform
URL=$TEST_ROOT/disable_no_transform/index.html?PageSpeedFilters=inline_css
fetch_until -save -recursive $URL 'grep -c style' 2
WGET_ARGS=""
start_test ShardDomain directive in location block
fetch_until -save $TEST_ROOT/shard/shard.html 'grep -c \.pagespeed\.' 4
fetch_until -save $TEST_ROOT/shard/shard.html 'fgrep -c .pagespeed.ce' 4
check [ $(grep -ce href=\"http://shard1 $FETCH_FILE) = 2 ];
check [ $(grep -ce href=\"http://shard2 $FETCH_FILE) = 2 ];
@@ -858,7 +853,6 @@ start_test combine_javascript with long URL still works
URL=$TEST_ROOT/combine_js_very_many.html?PageSpeedFilters=combine_javascript
fetch_until $URL 'grep -c src=' 4
WGET_ARGS=""
start_test UseExperimentalJsMinifier
URL="$TEST_ROOT/experimental_js_minifier/index.html"
URL+="?PageSpeedFilters=rewrite_javascript"
@@ -925,10 +919,9 @@ PageSpeedFilters=inline_javascript,debug"
OUTFILE=$OUTDIR/blocking_rewrite.out.html
$WGET_DUMP --header 'X-PSA-Blocking-Rewrite: psatest' $URL > $OUTFILE
check egrep -q 'script[[:space:]]src=' $OUTFILE
EXPECTED_COMMENT_LINE="<!--InlineJs: Cannot create resource: either its \
domain is unauthorized and InlineUnauthorizedResources is not enabled, \
or it cannot be fetched (check the server logs)-->"
check grep -q "$EXPECTED_COMMENT_LINE" $OUTFILE
EXPECTED_COMMENT_LINE="<!--The preceding resource was not rewritten \
because its domain (www.gstatic.com) is not authorized-->"
check [ $(grep -o "$EXPECTED_COMMENT_LINE" $OUTFILE | wc -l) -eq 1 ]
start_test inline_unauthorized_resources allows inlining
HOST_NAME="http://unauthorizedresources.example.com"
@@ -952,10 +945,9 @@ PageSpeedFilters=inline_css,debug"
OUTFILE=$OUTDIR/blocking_rewrite.out.html
$WGET_DUMP --header 'X-PSA-Blocking-Rewrite: psatest' $URL > $OUTFILE
check egrep -q 'link[[:space:]]rel=' $OUTFILE
EXPECTED_COMMENT_LINE="<!--InlineCss: Cannot create resource: either its \
domain is unauthorized and InlineUnauthorizedResources is not enabled, \
or it cannot be fetched (check the server logs)-->"
check grep -q "$EXPECTED_COMMENT_LINE" $OUTFILE
EXPECTED_COMMENT_LINE="<!--The preceding resource was not rewritten \
because its domain (www.google.com) is not authorized-->"
check [ $(grep -o "$EXPECTED_COMMENT_LINE" $OUTFILE | wc -l) -eq 1 ]
start_test inline_unauthorized_resources allows inlining
HOST_NAME="http://unauthorizedresources.example.com"
@@ -1053,7 +1045,6 @@ wget -O - --header 'X-PSA-Blocking-Rewrite: psatest' $URL > $TEMPDIR/flush.$$
check [ `wget -O - $URL | grep -o 'link rel="subresource"' | wc -l` = 0 ]
rm -f $TEMPDIR/flush.$$
WGET_ARGS=""
start_test Respect custom options on resources.
IMG_NON_CUSTOM="$EXAMPLE_ROOT/images/xPuzzle.jpg.pagespeed.ic.fakehash.jpg"
IMG_CUSTOM="$TEST_ROOT/custom_options/xPuzzle.jpg.pagespeed.ic.fakehash.jpg"
@@ -1106,18 +1097,26 @@ WGET_ARGS="--save-headers"
# We should be able to fetch the original ...
echo http_proxy=$SECONDARY_HOSTNAME $WGET --save-headers -O - $ORIGINAL
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET --save-headers -O - $ORIGINAL 2>&1)
check_from "$OUT" fgrep " 200 OK"
check_200_http_response "$OUT"
# ... AND the rewritten version.
echo http_proxy=$SECONDARY_HOSTNAME $WGET --save-headers -O - $FILTERED
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET --save-headers -O - $FILTERED 2>&1)
check_from "$OUT" fgrep " 200 OK"
check_200_http_response "$OUT"
start_test MapProxyDomain
# depends on MapProxyDomain in pagespeed_test.conf.template
URL=$EXAMPLE_ROOT/proxy_external_resource.html
LEAF="proxy_external_resource.html?PageSpeedFilters=-inline_images"
URL="$EXAMPLE_ROOT/$LEAF"
echo Rewrite HTML with reference to a proxyable image.
fetch_until -save -recursive $URL?PageSpeedFilters=-inline_images \
'grep -c 1.gif.pagespeed' 1
fetch_until -save -recursive $URL 'grep -c 1.gif.pagespeed' 1 --save-headers
PAGESPEED_GIF=$(grep -o '/*1.gif.pagespeed[^"]*' $WGET_DIR/$LEAF)
check_from "$PAGESPEED_GIF" grep "gif$"
echo "If the next line fails, look in $WGET_DIR/wget_output.txt and you should"
echo "see a 404. This represents a failed attempt to download the proxied gif."
# TODO(jefftk): debug why this test sometimes fails with the native fetcher.
# https://github.com/pagespeed/ngx_pagespeed/issues/774
check test -f "$WGET_DIR$PAGESPEED_GIF"
start_test OptimizeForBandwidth
# We use blocking-rewrite tests because we want to make sure we don't
@@ -1157,12 +1156,11 @@ test_optimize_for_bandwidth core_filters/rewrite_css.html \
#
# With the proper hash, we'll get a long cache lifetime.
SECONDARY_HOST="http://mpd.example.com/gstatic_images"
PROXIED_IMAGE="$SECONDARY_HOST/$(basename $WGET_DIR/*1.gif.pagespeed*)"
WGET_ARGS="--save-headers"
PROXIED_IMAGE="$SECONDARY_HOST$PAGESPEED_GIF"
start_test $PROXIED_IMAGE expecting one year cache.
http_proxy=$SECONDARY_HOSTNAME fetch_until $PROXIED_IMAGE \
"grep -c max-age=31536000" 1
"grep -c max-age=31536000" 1 --save-headers
# With the wrong hash, we'll get a short cache lifetime (and also no output
# cache hit.
@@ -1170,14 +1168,12 @@ WRONG_HASH="0"
PROXIED_IMAGE="$SECONDARY_HOST/1.gif.pagespeed.ce.$WRONG_HASH.jpg"
start_test Fetching $PROXIED_IMAGE expecting short private cache.
http_proxy=$SECONDARY_HOSTNAME fetch_until $PROXIED_IMAGE \
"grep -c max-age=300,private" 1
WGET_ARGS=""
"grep -c max-age=300,private" 1 --save-headers
start_test ShowCache without URL gets a form, inputs, preloaded UA.
ADMIN_CACHE=$PRIMARY_SERVER/pagespeed_admin/cache
OUT=$($WGET_DUMP $ADMIN_CACHE)
check_from "$OUT" fgrep -q "<form "
check_from "$OUT" fgrep -q "<form>"
check_from "$OUT" fgrep -q "<input "
check_from "$OUT" fgrep -q "Cache-Control: max-age=0, no-cache"
# Preloaded user_agent value field leading with "Mozilla" set in
@@ -1185,8 +1181,8 @@ check_from "$OUT" fgrep -q "Cache-Control: max-age=0, no-cache"
check_from "$OUT" fgrep -q 'name=user_agent value="Mozilla'
start_test ShowCache with bogus URL gives a 404
wget $PRIMARY_SERVER/pagespeed_cache?url=bogus_format >& /dev/null
check [ $? = 8 ]
check_error_code 8 \
wget $PRIMARY_SERVER/pagespeed_cache?url=bogus_format >& /dev/null
start_test ShowCache with valid, present URL, with unique options.
options="PageSpeedImageInlineMaxBytes=6765"
@@ -1228,38 +1224,17 @@ check_from "$OUT" grep $'^Cache-Control: max-age=0, no-cache\r$'
start_test server-side includes
fetch_until -save $TEST_ROOT/ssi/ssi.shtml?PageSpeedFilters=combine_css \
'grep -c \.pagespeed\.' 1
'fgrep -c .pagespeed.' 1
check [ $(grep -ce $combine_css_filename $FETCH_FILE) = 1 ];
start_test Embed image configuration in rewritten image URL.
# The apache test names these virtual hosts as embed_config_*, which is
# unfortunate as underscores are not allowed in domain names. Apache doesn't
# care, and nginx doesn't either, except when you're proxying. So you can do:
#
# GET /embed_config.html HTTP/1.1
# Host: embed_config_html.example.com
#
# and it will work fine, but if you do:
#
# GET http://embed_config_html.example.com/embed_config.html HTTP/1.1
#
# then nginx will close the connection before you can even give it a Host
# header. I've modified this test code to replace embed_config_ with
# embed-config-, but the html file on disk has the underscore versions. Let's
# make a new html file that has the hyphen version:
cat "$SERVER_ROOT/mod_pagespeed_test/embed_config.html" | \
sed s/embed_config_/embed-config-/g > \
"$SERVER_ROOT/mod_pagespeed_test/embed-config.html"
# The embedded configuration is placed between the "pagespeed" and "ic", e.g.
# *xPuzzle.jpg.pagespeed.gp+jp+pj+js+rj+rp+rw+ri+cp+md+iq=73.ic.oFXPiLYMka.jpg
# We use a regex matching "gp+jp+pj+js+rj+rp+rw+ri+cp+md+iq=73" rather than
# spelling it out to avoid test regolds when we add image filter IDs.
WGET_ARGS="--save-headers"
http_proxy=$SECONDARY_HOSTNAME fetch_until -save -recursive \
http://embed-config-html.example.org/embed-config.html \
'grep -c \.pagespeed\.' 3
http://embed-config-html.example.org/embed_config.html \
'fgrep -c .pagespeed.' 3 --save-headers
# with the default rewriters in vhost embed-config-resources.example.com
# the image will be >200k. But by enabling resizing & compression 73
@@ -1328,7 +1303,6 @@ function embed_image_config_post_flush() {
# places where we flush cache, which requires sleeps since the
# cache-flush is poll driven.
start_test Embed image/css configuration decoding with clear cache.
WGET_ARGS=""
echo Looking for $EMBED_CONFIGURATION_IMAGE expecting \
$EMBED_CONFIGURATION_IMAGE_LENGTH bytes
http_proxy=$SECONDARY_HOSTNAME fetch_until "$EMBED_CONFIGURATION_IMAGE" \
@@ -1378,10 +1352,10 @@ check touch "$SECONDARY_CACHE/cache.flush"
check touch "$IPRO_CACHE/cache.flush"
sleep 1
CSS_FILE="$SERVER_ROOT/mod_pagespeed_test/update.css"
CSS_FILE="$SERVER_ROOT/mod_pagespeed_test/cache_flush/update.css"
echo ".class myclass { color: $COLOR0; }" > "$CSS_FILE"
URL_PATH="mod_pagespeed_test/cache_flush_test.html"
URL_PATH="mod_pagespeed_test/cache_flush/cache_flush_test.html"
URL="$SECONDARY_HOSTNAME/$URL_PATH"
CACHE_A="--header=Host:cache_a.example.com"
@@ -1519,7 +1493,7 @@ else
EXPECTED="Serf status 111"
fi
for i in {1..100}; do
ERRS=$(grep -c "$EXPECTED" $FETCHER_REFUSED_PATH)
ERRS=$(grep -c "$EXPECTED" $FETCHER_REFUSED_PATH || true)
if [ $ERRS -ge 1 ]; then
break;
fi;
@@ -1529,7 +1503,7 @@ done;
echo "."
# Kill the log monitor silently.
kill $TAIL_PID
wait $TAIL_PID 2> /dev/null
wait $TAIL_PID 2> /dev/null || true
check [ $ERRS -ge 1 ]
# TODO(jefftk): when we support ListOutstandingUrlsOnError uncomment the below
@@ -1548,7 +1522,6 @@ check [ $ERRS -ge 1 ]
#
# This rewrites the CSS, absolutifying the embedded relative image URL
# reference based on the the main server host.
WGET_ARGS=""
start_test Relative images embedded in a CSS file served from a mapped domain
DIR="mod_pagespeed_test/map_css_embedded"
URL="http://www.example.com/$DIR/issue494.html"
@@ -1605,7 +1578,8 @@ OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET -O /dev/null $ALLOWED 2>&1)
check_from "$OUT" fgrep -q "200 OK"
# .cf. is forbidden
FORBIDDEN=$FORBIDDEN_STYLES_ROOT/A.all_styles.css.pagespeed.cf.UH8L-zY4b4.css
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET -O /dev/null $FORBIDDEN 2>&1)
OUT=$(http_proxy=$SECONDARY_HOSTNAME check_not $WGET -O /dev/null $FORBIDDEN \
2>&1)
check_from "$OUT" fgrep -q "404 Not Found"
# The image will be optimized but NOT resized to the much smaller size,
# so it will be >200k (optimized) rather than <20k (resized).
@@ -1683,7 +1657,6 @@ function test_forbid_all_disabled() {
$WGET $WGET_ARGS -q -O $OUTFILE $HEADER $URL
check egrep -q '<style>.yellow' $OUTFILE
rm -f $OUTFILE
WGET_ARGS=""
}
start_test ForbidAllDisabledFilters baseline check.
test_forbid_all_disabled "" ""
@@ -1851,11 +1824,11 @@ check_not_from "$OUT" grep 'pagespeed_beacon.*exptid'
# order they're defined in the config file.
start_test Resource urls are rewritten to include experiment indexes.
http_proxy=$SECONDARY_HOSTNAME \
WGET_ARGS="--header Cookie:PageSpeedExperiment=7" fetch_until $EXP_EXTEND_CACHE \
"fgrep -c .pagespeed.a.ic." 1
fetch_until $EXP_EXTEND_CACHE \
"fgrep -c .pagespeed.a.ic." 1 --header=Cookie:PageSpeedExperiment=7
http_proxy=$SECONDARY_HOSTNAME \
WGET_ARGS="--header Cookie:PageSpeedExperiment=2" fetch_until $EXP_EXTEND_CACHE \
"fgrep -c .pagespeed.b.ic." 1
fetch_until $EXP_EXTEND_CACHE \
"fgrep -c .pagespeed.b.ic." 1 --header=Cookie:PageSpeedExperiment=2
OUT=$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP --header='Cookie: PageSpeedExperiment=7' \
$EXP_EXTEND_CACHE)
check_from "$OUT" fgrep ".pagespeed.a.ic."
@@ -1978,6 +1951,51 @@ check [ `grep -c '<style>[.]big{[^}]*}</style>' $FETCH_UNTIL_OUTFILE` = 1 ]
check [ `grep -c '<style>[.]blue{[^}]*}[.]bold{[^}]*}</style>' \
$FETCH_UNTIL_OUTFILE` = 1 ]
# Now repeat the critical_css_filter test on a host that processes post data via
# temp files to test that ngx_pagespeed specific code path.
test_filter prioritize_critical_css Able to read POST data from temp file.
URL="http://beacon-post-temp-file.example.com/mod_pagespeed_example/prioritize_critical_css.html"
http_proxy=$SECONDARY_HOSTNAME\
fetch_until -save $URL 'fgrep -c pagespeed.criticalCssBeaconInit' 1
check [ $(fgrep -o ".very_large_class_name_" $FETCH_FILE | wc -l) -eq 36 ]
CALL_PAT=".*criticalCssBeaconInit("
SKIP_ARG="[^,]*,"
CAPTURE_ARG="'\([^']*\)'.*"
BEACON_PATH=$(sed -n "s/${CALL_PAT}${CAPTURE_ARG}/\1/p" $FETCH_FILE)
ESCAPED_URL=$( \
sed -n "s/${CALL_PAT}${SKIP_ARG}${CAPTURE_ARG}/\1/p" $FETCH_FILE)
OPTIONS_HASH=$( \
sed -n "s/${CALL_PAT}${SKIP_ARG}${SKIP_ARG}${CAPTURE_ARG}/\1/p" $FETCH_FILE)
NONCE=$( \
sed -n "s/${CALL_PAT}${SKIP_ARG}${SKIP_ARG}${SKIP_ARG}${CAPTURE_ARG}/\1/p" \
$FETCH_FILE)
BEACON_URL="http://${SECONDARY_HOSTNAME}${BEACON_PATH}?url=${ESCAPED_URL}"
BEACON_DATA="oh=${OPTIONS_HASH}&n=${NONCE}&cs=.big,.blue,.bold,.foo"
OUT=$(wget -q --save-headers -O - --no-http-keep-alive \
--post-data "$BEACON_DATA" "$BEACON_URL" \
--header "Host:beacon-post-temp-file.example.com")
check_from "$OUT" grep '^HTTP/1.1 204'
# Now make sure we see the correct critical css rules.
http_proxy=$SECONDARY_HOSTNAME\
fetch_until $URL \
'grep -c <style>[.]blue{[^}]*}</style>' 1
http_proxy=$SECONDARY_HOSTNAME\
fetch_until $URL \
'grep -c <style>[.]big{[^}]*}</style>' 1
http_proxy=$SECONDARY_HOSTNAME\
fetch_until $URL \
'grep -c <style>[.]blue{[^}]*}[.]bold{[^}]*}</style>' 1
http_proxy=$SECONDARY_HOSTNAME\
fetch_until -save $URL \
'grep -c <style>[.]foo{[^}]*}</style>' 1
# The last one should also have the other 3, too.
check [ `grep -c '<style>[.]blue{[^}]*}</style>' $FETCH_UNTIL_OUTFILE` = 1 ]
check [ `grep -c '<style>[.]big{[^}]*}</style>' $FETCH_UNTIL_OUTFILE` = 1 ]
check [ `grep -c '<style>[.]blue{[^}]*}[.]bold{[^}]*}</style>' \
$FETCH_UNTIL_OUTFILE` = 1 ]
# This test checks that the ClientDomainRewrite directive can turn on.
start_test ClientDomainRewrite on directive
HOST_NAME="http://client-domain-rewrite.example.com"
@@ -1987,7 +2005,6 @@ MATCHES=$(echo "$RESPONSE_OUT" | grep -c pagespeed\.clientDomainRewriterInit)
check [ $MATCHES -eq 1 ]
# Verify rendered image dimensions test.
WGET_ARGS=""
start_test resize_rendered_image_dimensions with critical images beacon
HOST_NAME="http://renderedimagebeacon.example.com"
URL="$HOST_NAME/mod_pagespeed_test/image_rewriting/image_resize_using_rendered_dimensions.html"
@@ -2051,24 +2068,22 @@ OUT1=$(http_proxy=$SECONDARY_HOSTNAME \
$WGET_DUMP --header 'X-PSA-Blocking-Rewrite: psatest' $URL)
check_not_from "$OUT1" egrep -q 'pagespeed\.criticalCssBeaconInit'
check_from "$OUT1" grep -q "Cache-Control: private, max-age=3000"
# 2. We get an instrumented page if the correct key is present.
OUT2=$(http_proxy=$SECONDARY_HOSTNAME \
$WGET_DUMP $WGET_ARGS \
--header 'X-PSA-Blocking-Rewrite: psatest'\
--header="PS-ShouldBeacon: random_rebeaconing_key" $URL)
check_from "$OUT2" grep -q "Cache-Control: max-age=0, no-cache"
check_from "$OUT2" egrep -q "pagespeed\.criticalCssBeaconInit"
http_proxy=$SECONDARY_HOSTNAME \
fetch_until -save $URL 'grep -c criticalCssBeaconInit' 2 \
"--header=PS-ShouldBeacon:random_rebeaconing_key --save-headers"
check grep -q "Cache-Control: max-age=0, no-cache" $FETCH_UNTIL_OUTFILE
# 3. We do not get an instrumented page if the wrong key is present.
WGET_ARGS="--header=\"PS-ShouldBeacon: wrong_rebeaconing_key\""
OUT3=$(http_proxy=$SECONDARY_HOSTNAME \
OUT3=$(http_proxy=$SECONDARY_HOSTNAME check_not \
$WGET_DUMP $WGET_ARGS $URL)
check_not_from "$OUT3" egrep -q "pagespeed\.criticalCssBeaconInit"
check_from "$OUT3" grep -q "Cache-Control: private, max-age=3000"
# Verify that we can send a critical image beacon and that lazyload_images
# does not try to lazyload the critical images.
WGET_ARGS=""
start_test lazyload_images,rewrite_images with critical images beacon
HOST_NAME="http://imagebeacon.example.com"
URL="$HOST_NAME/mod_pagespeed_test/image_rewriting/rewrite_images.html"
@@ -2147,15 +2162,12 @@ check_not fgrep -q "interesting_color" $FETCH_FILE
# c) selectors that don't depend on flattening should appear in the selector
# list.
check [ $(fgrep -c "non_flattened_selector" $FETCH_FILE) -eq 1 ]
EXPECTED_IMPORT_FAILURE_LINE="<!--Flattening failed: Cannot import "
EXPECTED_IMPORT_FAILURE_LINE+="http://www.google.com/css/maia.css: is it on "
EXPECTED_IMPORT_FAILURE_LINE+="an unauthorized domain?-->"
check grep -q "$EXPECTED_IMPORT_FAILURE_LINE" $FETCH_FILE
EXPECTED_COMMENT_LINE="<!--CriticalCssBeacon: Cannot create resource: either "
EXPECTED_COMMENT_LINE+="its domain is unauthorized and "
EXPECTED_COMMENT_LINE+="InlineUnauthorizedResources is not enabled, or it "
EXPECTED_COMMENT_LINE+="cannot be fetched (check the server logs)-->"
check grep -q "$EXPECTED_COMMENT_LINE" $FETCH_FILE
EXPECTED_IMPORT_FAILURE_LINE="<!--Flattening failed: Cannot import \
http://www.google.com/css/maia.css as it is on an unauthorized domain-->"
check [ $(grep -o "$EXPECTED_IMPORT_FAILURE_LINE" $FETCH_FILE | wc -l) -eq 1 ]
EXPECTED_COMMENT_LINE="<!--The preceding resource was not rewritten \
because its domain (www.google.com) is not authorized-->"
check [ $(grep -o "$EXPECTED_COMMENT_LINE" $FETCH_FILE | wc -l) -eq 1 ]
start_test inline_unauthorized_resources allows unauthorized css selectors
HOST_NAME="http://unauthorizedresources.example.com"
@@ -2231,7 +2243,6 @@ check [ $(grep -c 'styles/big.css\"' $FETCH_UNTIL_OUTFILE) = 1 ]
# response-headers from the server. The reponse-headers from Serf never seem to
# include the Connection header. So we have to pick a JS file that is not
# otherwise used after cache is flushed in this block.
WGET_ARGS=""
start_test Sane Connection header
URL="$TEST_ROOT/normal.js"
fetch_until -save $URL 'grep -c W/\"PSA-aj-' 1 --save-headers
@@ -2284,11 +2295,8 @@ function test_ipro_for_browser_webp() {
IN_ACCEPT="$1"; shift
IMAGE_TYPE="$1"; shift
OUT_CONTENT_TYPE="$1"; shift
OUT_VARY="${1-}"; shift
OUT_CC="${1-}"; shift
WGET_ARGS="--save-headers \
${IN_UA:+--user-agent $IN_UA} \
${IN_ACCEPT:+--header=Accept:image/$IN_ACCEPT}"
OUT_VARY="${1-}"; shift || true
OUT_CC="${1-}"; shift || true
# Remaining args are the expected headers (Name:Value), photo, or synthetic.
if [ "$IMAGE_TYPE" = "photo" ]; then
URL="http://ipro-for-browser.example.com/images/Puzzle.jpg"
@@ -2314,6 +2322,9 @@ function test_ipro_for_browser_webp() {
TEST_ID+=" Cache-Control:${OUT_CC}."
fi
start_test $TEST_ID
WGET_ARGS="--save-headers \
${IN_UA:+--user-agent $IN_UA} \
${IN_ACCEPT:+--header=Accept:image/$IN_ACCEPT}"
http_proxy=$SECONDARY_HOSTNAME \
fetch_until -save $URL 'grep -c W/\"PSA-aj-' 1
check_from "$(extract_headers $FETCH_UNTIL_OUTFILE)" \
@@ -2394,14 +2405,53 @@ test_decent_browsers "New Opera" \
"Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14"
WGETRC=$OLD_WGETRC
WGET_ARGS=""
start_test Request Option Override : Correct values are passed
HOST_NAME="http://request-option-override.example.com"
OPTS="?ModPagespeed=on"
OPTS+="&ModPagespeedFilters=+collapse_whitespace,+remove_comments"
OPTS+="&PageSpeedRequestOptionOverride=abc"
URL="$HOST_NAME/mod_pagespeed_test/forbidden.html$OPTS"
OUT="$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)"
echo wget $URL
check_not_from "$OUT" grep -q '<!--'
start_test Request Option Override : Incorrect values are passed
HOST_NAME="http://request-option-override.example.com"
OPTS="?ModPagespeed=on"
OPTS+="&ModPagespeedFilters=+collapse_whitespace,+remove_comments"
OPTS+="&PageSpeedRequestOptionOverride=notabc"
URL="$HOST_NAME/mod_pagespeed_test/forbidden.html$OPTS"
OUT="$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $URL)"
echo wget $URL
check_from "$OUT" grep -q '<!--'
start_test Request Option Override : Correct values are passed as headers
HOST_NAME="http://request-option-override.example.com"
OPTS="--header=ModPagespeed:on"
OPTS+=" --header=ModPagespeedFilters:+collapse_whitespace,+remove_comments"
OPTS+=" --header=PageSpeedRequestOptionOverride:abc"
URL="$HOST_NAME/mod_pagespeed_test/forbidden.html"
echo wget $OPTS $URL
OUT="$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $OPTS $URL)"
check_not_from "$OUT" grep -q '<!--'
start_test Request Option Override : Incorrect values are passed as headers
HOST_NAME="http://request-option-override.example.com"
OPTS="--header=ModPagespeed:on"
OPTS+=" --header=ModPagespeedFilters:+collapse_whitespace,+remove_comments"
OPTS+=" --header=PageSpeedRequestOptionOverride:notabc"
URL="$HOST_NAME/mod_pagespeed_test/forbidden.html"
echo wget $OPTS $URL
OUT="$(http_proxy=$SECONDARY_HOSTNAME $WGET_DUMP $OPTS $URL)"
check_from "$OUT" grep -q '<!--'
start_test JS gzip headers
JS_URL="$HOSTNAME/pagespeed_custom_static/js_defer.$HASH.js"
JS_HEADERS=$($WGET -O /dev/null -q -S --header='Accept-Encoding: gzip' \
$JS_URL 2>&1)
check_from "$JS_HEADERS" egrep -qi 'HTTP/1[.]. 200 OK'
check_200_http_response "$JS_HEADERS"
check_from "$JS_HEADERS" fgrep -qi 'Content-Encoding: gzip'
check_from "$JS_HEADERS" fgrep -qi 'Vary: Accept-Encoding'
# Nginx's gzip module clears etags, which we don't want. Make sure we have it.
@@ -2589,18 +2639,19 @@ ETAG=$(extract_headers $FETCH_UNTIL_OUTFILE | awk '/ETag:/ {print $2}')
echo $WGET_DUMP --header "If-None-Match: $ETAG" $URL
OUTFILE=$OUTDIR/etags
# Note: -o gets debug info which is the only place that 304 message is sent.
$WGET -o $OUTFILE -O /dev/null --header "If-None-Match: $ETAG" $URL
check_not $WGET -o $OUTFILE -O /dev/null --header "If-None-Match: $ETAG" $URL
check fgrep -q "awaiting response... 304" $OUTFILE
start_test PageSpeed CSS loaded in fallback mode is always chunked
# This is because the domains in urls may be rewritten, changing content
# length from what's in the cache.
URL="$EXAMPLE_ROOT/styles/W.rewrite_css_images.css.pagespeed.cf.Hash.css"
fetch_until -save $URL "egrep -c Transfer-Encoding:" 1 "--save-headers"
OUT=$(cat $FETCH_UNTIL_OUTFILE)
check_from "$OUT" egrep -iq $'^Transfer-Encoding: chunked\r$'
check_not_from "$OUT" egrep -iq '^Content-Length:'
check_not_from "$OUT" egrep -iq '^Connection: close'
# Test if the warning messages are colored in message_history page.
# We color the messages in message_history page to make it clearer to read.
# Red for Error messages. Brown for Warning messages.
# Orange for Fatal messages. Black by default.
# Won't test Error messages and Fatal messages in this test.
start_test Messages are colored in message_history
INJECT=$($CURL --silent $HOSTNAME/?PageSpeed=Warning_trigger)
OUT=$($WGET -q -O - $HOSTNAME/pagespeed_admin/message_history | \
grep Warning_trigger)
check_from "$OUT" fgrep -q "color:brown;"
start_test Downstream cache integration caching headers.
URL="http://downstreamcacheresource.example.com/mod_pagespeed_example/images/"
@@ -2640,9 +2691,8 @@ check_from "$OUT" grep -q "/mod_pagespeed_example"
start_test Check keepalive after a 304 responses.
# '-m 2' specifies that the whole operation is allowed to take 2 seconds max.
curl -vv -m 2 http://$PRIMARY_HOSTNAME/foo.css.pagespeed.ce.0.css \
check curl -vv -m 2 http://$PRIMARY_HOSTNAME/foo.css.pagespeed.ce.0.css \
-H 'If-Modified-Since: Z' http://$PRIMARY_HOSTNAME/foo
check [ $? = "0" ]
start_test Date response header set
OUT=$($WGET_DUMP $EXAMPLE_ROOT/combine_css.html)
@@ -2653,12 +2703,51 @@ OUT=$($WGET_DUMP --header=Host:date.example.com \
check_from "$OUT" egrep -q '^Date: Fri, 16 Oct 2009 23:05:07 GMT'
WGET_ARGS=
#very basic tests to test gzip nesting configuration
start_test Nested gzip gzip off
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/"
HEADERS="--header=Accept-Encoding:gzip --header=Host:gzip-test1.example.com"
OUT=$($WGET_DUMP -O /dev/null -S $HEADERS $URL 2>&1)
check_not_from "$OUT" fgrep -qi 'Content-Encoding: gzip'
check_not_from "$OUT" fgrep -qi 'Vary: Accept-Encoding'
start_test Nested gzip gzip on
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/styles/big.css"
HEADERS="--header=Accept-Encoding:gzip --header=Host:gzip-test1.example.com"
OUT=$($WGET_DUMP -O /dev/null -S $HEADERS $URL 2>&1)
check_from "$OUT" fgrep -qi 'Content-Encoding: gzip'
check_from "$OUT" fgrep -qi 'Vary: Accept-Encoding'
start_test Nested gzip pagespeed off
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/"
HEADERS="--header=Accept-Encoding:gzip --header=Host:gzip-test2.example.com"
OUT=$($WGET_DUMP -O /dev/null -S $HEADERS $URL 2>&1)
check_not_from "$OUT" fgrep -qi 'Content-Encoding: gzip'
check_not_from "$OUT" fgrep -qi 'Vary: Accept-Encoding'
start_test Nested gzip pagespeed on
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/styles/big.css"
HEADERS="--header=Accept-Encoding:gzip --header=Host:gzip-test2.example.com"
OUT=$($WGET_DUMP -O /dev/null -S $HEADERS $URL 2>&1)
check_from "$OUT" fgrep -qi 'Content-Encoding: gzip'
check_from "$OUT" fgrep -qi 'Vary: Accept-Encoding'
start_test Test that POST requests are rewritten.
URL="http://$SECONDARY_HOSTNAME/mod_pagespeed_example/rewrite_images.html"
HEADERS="--header=Host:proxy-post.example.com --post-data=abcdefgh"
OUT=$($WGET_DUMP -S $HEADERS $URL 2>&1)
check_from "$OUT" fgrep -qi 'addInstrumentationInit'
if [ "$NATIVE_FETCHER" != "on" ]; then
start_test Test that we can rewrite an HTTPS resource.
fetch_until $TEST_ROOT/https_fetch/https_fetch.html \
'grep -c /https_gstatic_dot_com/1.gif.pagespeed.ce' 1
fi
start_test Base config has purging disabled. Check error message syntax.
OUT=$($WGET_DUMP "$HOSTNAME/pagespeed_admin/cache?purge=*")
check_from "$OUT" fgrep -q "pagespeed EnableCachePurge on;"
if $USE_VALGRIND; then
# It is possible that there are still ProxyFetches outstanding
# at this point in time. Give them a few extra seconds to allow
+261 -28
View File
@@ -27,6 +27,7 @@ http {
proxy_cache_path "@@PROXY_CACHE@@" levels=1:2 keys_zone=htmlcache:60m inactive=90m max_size=50m;
proxy_temp_path "@@TMP_PROXY_CACHE@@";
pagespeed ProcessScriptVariables on;
pagespeed StatisticsPath /ngx_pagespeed_statistics;
pagespeed GlobalStatisticsPath /ngx_pagespeed_global_statistics;
pagespeed ConsolePath /pagespeed_console;
@@ -36,6 +37,12 @@ http {
pagespeed StaticAssetPrefix /pagespeed_custom_static/;
pagespeed MessageBufferSize 200000;
# Increase the default fetcher timeout to resolve sporadic flakeyness when
# the native fetcher uses 8.8.8.8 to resolve.
pagespeed FetcherTimeoutMs 10000;
pagespeed NativeFetcherMaxKeepaliveRequests 50;
root "@@SERVER_ROOT@@";
# Block 5a: Decide on Cache-Control header value to use for outgoing
@@ -75,6 +82,7 @@ http {
# test ModPagespeedMaxCacheableContentLength, i.e.,
# max_cacheable_response_content_length.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name max-cacheable-content-length.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -94,6 +102,7 @@ http {
# running on the PRIMARY_PORT when the response is not available in
# the cache. It also services purge requests from the upstream server.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name proxy_cache.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -152,9 +161,9 @@ http {
set $bypass_cache "1";
}
# For testing purposes, we never generate values that will result in a beacon
# For testing purposes, we never generate values that will result in a beacon
# unless a test request it via "X-Allow-Beacon: yes" in its request header.
# This is for testing purposes, note that in a production environment,
# This is for testing purposes, note that in a production environment,
# you want 'set_random $rand 0 100;' unconditionally!
set $rand 5;
@@ -176,6 +185,7 @@ http {
# Block 4: Location block for purge requests.
location ~ /purge(/.*) {
allow 127.0.0.1;
allow ::1;
deny all;
proxy_cache_purge htmlcache $ps_capability_list$1$is_args$args;
}
@@ -214,6 +224,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name if-in-server.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
@@ -234,6 +245,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name if-in-location.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
@@ -253,6 +265,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name mpd.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
@@ -263,6 +276,7 @@ http {
# These two vhosts are for testing the experiment framework (Furious).
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name experiment.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
pagespeed InPlaceResourceOptimization off;
@@ -277,6 +291,7 @@ http {
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name experiment.noga.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -290,6 +305,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name preserveurls.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -319,6 +335,7 @@ http {
# Setup a vhost with the critical image beacon and lazyload filter enabled
# to make sure that critical images are not lazyloaded.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name imagebeacon.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -331,6 +348,7 @@ http {
# Setup a vhost with the critical image beacon enabled to make sure that
# downstream caches and rebeaconing interact correctly.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name downstreamcacherebeacon.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -346,6 +364,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name downstreamcacheresource.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
pagespeed RewriteLevel PassThrough;
@@ -355,6 +374,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name renderedimagebeacon.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -372,6 +392,7 @@ http {
# inheretence in Nginx we need to have location blocks inside a server block.
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name optimizeforbandwidth.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -403,6 +424,7 @@ http {
# to go back to this VirtualHost so we rely on the new third optional
# argument to MapOriginDomain.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name customhostheader.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@_test";
root "@@SERVER_ROOT@@/mod_pagespeed_test";
@@ -421,6 +443,7 @@ http {
# Sets up a virtual host where we can specify forbidden filters without
# affecting any other hosts.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name forbidden.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -436,6 +459,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name unauthorizedresources.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -446,6 +470,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name client-domain-rewrite.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -461,6 +486,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name url-attribute.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -494,6 +520,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name domain-hyperlinks-on.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -508,6 +535,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name domain-hyperlinks-off.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -522,6 +550,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name retaincomment.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -531,6 +560,7 @@ http {
server {
# Test host for shared memory cache.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name shmcache.example.com;
pagespeed FileCachePath "@@SHM_CACHE@@";
@@ -540,6 +570,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name xfp.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -548,6 +579,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name xheader.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -561,6 +593,7 @@ http {
# Note that we test with two distinct caches.
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name embed-config-html.example.org;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -580,6 +613,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name embed-config-resources.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -600,6 +634,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name ipro-for-browser.example.com;
root "@@SERVER_ROOT@@/mod_pagespeed_example";
pagespeed EnableFilters rewrite_images,rewrite_css;
@@ -611,6 +646,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name respectvary.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -620,16 +656,30 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name cache_a.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
pagespeed CacheFlushPollIntervalSec 1;
pagespeed RewriteLevel PassThrough;
pagespeed EnableFilters inline_css;
# Make a non-empty subdirectory config to make sure that
# cache.flush updates get transmitted to nested configurations.
#
# TODO(jmarantz): This test currently fails on ngx_pagespeed, meaning we
# don't handle cache flushing correctly here. Uncomment the config below to
# expose the error.
#location /mod_pagespeed_test/cache_flush/ {
# pagespeed RewriteLevel PassThrough;
# pagespeed EnableFilters inline_css;
# pagespeed DisableFilters add_instrumentation;
#}
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name cache_b.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
@@ -640,6 +690,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name cache_c.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -653,6 +704,7 @@ http {
server {
# Sets up a logical home-page server on www.example.com
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name www.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -666,6 +718,7 @@ http {
# Sets up a logical origin for CDNs to fetch content from, on
# origin.example.com.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name origin.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -679,6 +732,7 @@ http {
# Sets up a logical cdn, which is where we tell browsers to fetch resources
# from.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name cdn.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -690,6 +744,18 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name lff-ipro.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
pagespeed LoadFromFile
"http://lff-ipro.example.com/mod_pagespeed_example/lff_ipro"
"@@SERVER_ROOT@@/mod_pagespeed_example/lff_ipro";
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name tryfiles.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -703,6 +769,7 @@ http {
server {
# Proxy modpagespeed.com for testing Issue 582.
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name modpagespeed.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -715,6 +782,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name custom-paths.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -726,12 +794,14 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name inherit-paths.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name notransform.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
@@ -743,6 +813,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name blocking.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
@@ -752,6 +823,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name keepalive-html.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
pagespeed RewriteLevel CoreFilters;
@@ -760,6 +832,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name keepalive-resource.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
error_log "@@TEST_TMP@@/keepalive-resource.example.com.error.log" warn;
@@ -767,6 +840,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name keepalive-beacon-get.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
error_log "@@TEST_TMP@@/keepalive-beacon-get.example.com.error.log" warn;
@@ -774,6 +848,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name keepalive-beacon-post.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
error_log "@@TEST_TMP@@/keepalive-beacon-post.example.com.error.log" warn;
@@ -781,6 +856,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name keepalive-static.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
error_log "@@TEST_TMP@@/keepalive-static.example.com.error.log" warn;
@@ -788,6 +864,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name response-header-filters.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
pagespeed RewriteLevel PassThrough;
@@ -797,6 +874,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name response-header-disable.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
pagespeed EnableFilters add_instrumentation;
@@ -806,6 +884,7 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name ipro.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
@@ -829,6 +908,7 @@ http {
# 1. L2_d=LRU, L2_m=LRU
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name lrud-lrum.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@_lrud_lrum";
@@ -843,6 +923,7 @@ http {
"@@SECONDARY_CACHE@@_lrud_shmm" 8192;
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name lrud-shmm.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@_lrud_shmm";
@@ -857,6 +938,7 @@ http {
"@@SECONDARY_CACHE@@_noned_shmm" 8192;
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name noned-shmm.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@_noned_shmm";
@@ -867,6 +949,7 @@ http {
# 4. L2_d=none, L2_m=none
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name noned-nonem.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@_noned_nonem";
@@ -876,14 +959,95 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name date.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
add_header "Date" "Date: Fri, 16 Oct 2009 23:05:07 GMT";
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name options-by-cookies-enabled.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@_optionsbycookieson";
pagespeed AllowOptionsToBeSetByCookies true;
pagespeed StickyQueryParameters sticky_secret;
pagespeed RewriteLevel PassThrough;
pagespeed EnableFilters collapse_whitespace;
pagespeed DisableFilters remove_comments,add_instrumentation;
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name options-by-cookies-disabled.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@_optionsbycookiesoff";
pagespeed AllowOptionsToBeSetByCookies false;
pagespeed DisableFilters add_instrumentation;
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name redirect.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@_redirected";
pagespeed RewriteLevel PassThrough;
pagespeed EnableFilters add_instrumentation,collapse_whitespace;
location /redirect {
rewrite ^/redirect/(.*) http://$server_name/$1 permanent;
}
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name request-option-override.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
pagespeed RequestOptionOverride abc;
pagespeed RewriteLevel Passthrough;
pagespeed EnableFilters collapse_whitespace;
pagespeed DisableFilters remove_comments,add_instrumentation;
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name signed-urls.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
pagespeed UrlSigningKey helloworld;
pagespeed RewriteLevel Passthrough;
pagespeed EnableFilters collapse_whitespace,rewrite_images;
pagespeed DisableFilters remove_comments,add_instrumentation;
}
# For testing signed URLs, ignoring signature validity.
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name signed-urls-transition.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
pagespeed UrlSigningKey helloworld;
pagespeed AcceptInvalidSignatures true;
pagespeed RewriteLevel Passthrough;
pagespeed EnableFilters collapse_whitespace,rewrite_images;
pagespeed DisableFilters remove_comments,add_instrumentation;
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name unsigned-urls-transition.example.com;
pagespeed FileCachePath "@@SECONDARY_CACHE@@";
# This server will not sign URLs, but AcceptInvalidSignature is on.
pagespeed AcceptInvalidSignatures true;
pagespeed RewriteLevel Passthrough;
pagespeed EnableFilters collapse_whitespace,rewrite_images;
pagespeed DisableFilters remove_comments,add_instrumentation;
}
# Proxy + IPRO a gzip'd file for testing Issue 896.
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name ipro-proxy.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@_ipro_proxy";
@@ -899,18 +1063,104 @@ http {
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name compressed-css.example.com;
pagespeed on;
pagespeed FileCachePath "@@FILE_CACHE@@";
pagespeed InPlaceResourceOptimization on;
}
# nested gzip config: pagespeed gzip on/off
server {
listen @@PRIMARY_PORT@@;
pagespeed on;
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name gzip-test1.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
location /mod_pagespeed_example/ {
pagespeed gzip off;
}
location /mod_pagespeed_example/styles/ {
pagespeed gzip on;
}
}
# nested gzip config: pagespeed on/off
server {
pagespeed on;
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name gzip-test2.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
location /mod_pagespeed_example/ {
pagespeed off;
}
location /mod_pagespeed_example/styles/ {
pagespeed on;
}
}
server {
pagespeed on;
pagespeed EnableFilters add_instrumentation;
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name proxy-post.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
location / {
# Transform the POST to a GET request for the origin,
# as nginx's static handler doesn't allow POST requests.
proxy_method GET;
proxy_pass http://127.0.0.1:@@SECONDARY_PORT@@/;
proxy_set_header "Host" "proxy-post-origin.example.com";
}
}
server {
pagespeed off;
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name proxy-post-origin.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
root "@@SERVER_ROOT@@";
}
server {
# Write all post data to temp files
client_body_in_file_only clean;
pagespeed CriticalImagesBeaconEnabled true;
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name beacon-post-temp-file.example.com;
pagespeed FileCachePath "@@FILE_CACHE@@";
}
server {
listen @@SECONDARY_PORT@@;
listen [::]:@@SECONDARY_PORT@@;
server_name purge.example.com;
# Test purging individual URLs without flushing the entire metadata cache.
pagespeed EnableCachePurge on;
pagespeed PurgeMethod PURGE;
root "@@SERVER_ROOT@@";
pagespeed FileCachePath "@@FILE_CACHE@@_purge";
pagespeed DisableFilters add_instrumentation;
pagespeed RewriteLevel PassThrough;
pagespeed EnableFilters rewrite_css;
}
server {
listen @@PRIMARY_PORT@@;
listen [::]:@@PRIMARY_PORT@@;
server_name localhost;
pagespeed FileCachePath "@@FILE_CACHE@@";
location ~ ^/pagespeed_admin {
allow 127.0.0.1;
allow ::1;
deny all;
}
@@ -951,7 +1201,6 @@ http {
#pagespeed MemcachedThreads 1;
pagespeed on;
pagespeed MessageBufferSize 200000;
#pagespeed CacheFlushPollIntervalSec 1;
@@ -972,11 +1221,13 @@ http {
location /ngx_pagespeed_statistics {
allow 127.0.0.1;
allow ::1;
deny all;
}
location /ngx_pagespeed_message {
allow 127.0.0.1;
allow ::1;
deny all;
}
@@ -1149,8 +1400,11 @@ http {
https://www.gstatic.com/psa/static;
}
# $host implicitly tests script variable support. I'd love to test it more
# directly, but so far this is the best I've come up with and duplicating
# the test doesn't seem to make sense.
pagespeed LoadFromFile
"http://localhost:@@PRIMARY_PORT@@/mod_pagespeed_test/ipro/instant/"
"http://$host:@@PRIMARY_PORT@@/mod_pagespeed_test/ipro/instant/"
"@@SERVER_ROOT@@/mod_pagespeed_test/ipro/instant/";
pagespeed EnableFilters remove_comments;
@@ -1164,8 +1418,8 @@ http {
"@@SERVER_ROOT@@/mod_pagespeed_test/load_from_file/file_\1/";
pagespeed LoadFromFileRule Disallow
"@@SERVER_ROOT@@/mod_pagespeed_test/load_from_file/file_dir/httponly/";
pagespeed LoadFromFileRuleMatch Disallow \.ssp.css$;
pagespeed LoadFromFileRuleMatch Allow exception\.ssp\.css$;
pagespeed LoadFromFileRuleMatch Disallow \.ssp.css$ps_dollar;
pagespeed LoadFromFileRuleMatch Allow exception\.ssp\.css$ps_dollar;
#charset koi8-r;
@@ -1188,27 +1442,6 @@ http {
keepalive_timeout 65;
# set up gzip
gzip on;
gzip_vary on;
gzip_proxied any;
# Turn on gzip for all content types that should benefit from it.
gzip_types application/ecmascript;
gzip_types application/javascript;
gzip_types application/json;
gzip_types application/pdf;
gzip_types application/postscript;
gzip_types application/x-javascript;
gzip_types image/svg+xml;
gzip_types text/css;
gzip_types text/csv;
# "gzip_types text/html" is assumed.
gzip_types text/javascript;
gzip_types text/plain;
gzip_types text/xml;
gzip_http_version 1.0;
types {
text/html html htm shtml;
text/css css;
+3
View File
@@ -73,6 +73,9 @@ function run_test_checking_failure() {
3)
return # Only expected failures.
;;
4)
return # Return passing error code when running manually.
;;
*)
exit 1 # Real failure.
esac