c6f01f2d42
we can usually detect via request-headers x-requested-with:xml-http-request. Preserve URLs for ajax requests as well. Re-establish 'disallow */wp-admin/*' in default set, as a back-stop against the wp-admin being visited from a browser that does not send that header. Did a couple of minor cleanups found in the vicinity of the changes reuqired in rewrite_options.cc: don't statically construct a std::vector (which we totally did not need in the first place). Use C++11 loops over static arrays. Fixes: https://github.com/pagespeed/mod_pagespeed/issues/1405 https://github.com/pagespeed/mod_pagespeed/issues/891 https://github.com/pagespeed/mod_pagespeed/issues/419 http://serverfault.com/questions/408057/mod-pagespeed-with-zend-framework-gives-404 Associated ngx_pagespeed pull: https://github.com/pagespeed/ngx_pagespeed/pull/1320
1199 lines
50 KiB
C++
1199 lines
50 KiB
C++
/*
|
|
* Copyright 2011 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: jmarantz@google.com (Joshua Marantz)
|
|
|
|
#include "net/instaweb/rewriter/public/rewrite_query.h"
|
|
|
|
#include "base/logging.h"
|
|
#include "net/instaweb/http/public/request_context.h"
|
|
#include "net/instaweb/rewriter/public/rewrite_options.h"
|
|
#include "net/instaweb/rewriter/public/rewrite_test_base.h"
|
|
#include "net/instaweb/rewriter/public/test_rewrite_driver_factory.h"
|
|
#include "pagespeed/kernel/base/google_message_handler.h"
|
|
#include "pagespeed/kernel/base/gtest.h"
|
|
#include "pagespeed/kernel/base/mock_message_handler.h"
|
|
#include "pagespeed/kernel/base/ref_counted_ptr.h"
|
|
#include "pagespeed/kernel/base/string_util.h"
|
|
#include "pagespeed/kernel/html/html_parse_test_base.h"
|
|
#include "pagespeed/kernel/http/google_url.h"
|
|
#include "pagespeed/kernel/http/http_names.h"
|
|
#include "pagespeed/kernel/http/response_headers.h"
|
|
|
|
namespace net_instaweb {
|
|
|
|
const char kHtmlUrl[] = "http://www.test.com/index.jsp";
|
|
|
|
class RewriteQueryTest : public RewriteTestBase {
|
|
protected:
|
|
virtual void SetUp() {
|
|
RewriteTestBase::SetUp();
|
|
allow_related_options_ = false;
|
|
allow_options_to_be_set_by_cookies_ = false;
|
|
request_option_override_ = "";
|
|
image_url_ = Encode(kTestDomain, "ic", "0", "image.jpg", "jpg");
|
|
}
|
|
|
|
const RewriteOptions* ParseAndScan(const StringPiece request_url,
|
|
const StringPiece& in_query,
|
|
const StringPiece& in_req_string) {
|
|
return ParseAndScan(request_url, in_query, in_req_string, NULL, NULL);
|
|
}
|
|
|
|
// Parses query-params &/or HTTP headers. The HTTP headers are specified
|
|
// as a string, with semi-colons separating attr:value pairs.
|
|
const RewriteOptions* ParseAndScan(const StringPiece request_url,
|
|
const StringPiece& in_query,
|
|
const StringPiece& in_req_string,
|
|
GoogleString* out_query,
|
|
GoogleString* out_req_string) {
|
|
GoogleString out_resp_string;
|
|
RequestHeaders request_headers;
|
|
StringPieceVector components;
|
|
SplitStringPieceToVector(in_req_string, ";", &components, true);
|
|
for (int i = 0, n = components.size(); i < n; ++i) {
|
|
StringPieceVector attr_value;
|
|
SplitStringPieceToVector(components[i], ":", &attr_value, false);
|
|
CHECK_EQ(2, attr_value.size());
|
|
request_headers.Add(attr_value[0], attr_value[1]);
|
|
}
|
|
return ParseAndScan(request_url, in_query, StringPiece(), &request_headers,
|
|
NULL, out_query, out_req_string, &out_resp_string);
|
|
}
|
|
|
|
const RewriteOptions* ParseAndScan(const StringPiece request_url,
|
|
const StringPiece& in_query,
|
|
const StringPiece& in_cookies,
|
|
RequestHeaders* request_headers,
|
|
ResponseHeaders* response_headers,
|
|
GoogleString* out_query,
|
|
GoogleString* out_req_string,
|
|
GoogleString* out_resp_string) {
|
|
Parse(request_url, in_query, in_cookies, request_headers,
|
|
response_headers, out_query, out_req_string, out_resp_string);
|
|
return rewrite_query_.options();
|
|
}
|
|
|
|
|
|
RewriteQuery::Status Parse(const StringPiece request_url,
|
|
const StringPiece& in_query,
|
|
const StringPiece& in_cookies,
|
|
RequestHeaders* request_headers,
|
|
ResponseHeaders* response_headers,
|
|
GoogleString* out_query,
|
|
GoogleString* out_req_string,
|
|
GoogleString* out_resp_string) {
|
|
GoogleUrl url(StrCat(request_url, "?", in_query));
|
|
if (!in_cookies.empty()) {
|
|
// For fidelity we can put multiple cookies per header line. We limit
|
|
// the line length to an arbitrary value to implement this.
|
|
const int kMaxLineLength = 128;
|
|
GoogleString header_value;
|
|
StringPieceVector cookie_vector;
|
|
SplitStringPieceToVector(in_cookies, ";", &cookie_vector, true);
|
|
for (int i = 0, nc = cookie_vector.size(); i < nc; ++i) {
|
|
if (header_value.empty() ||
|
|
(header_value.size() + cookie_vector[i].size()) < kMaxLineLength) {
|
|
if (!header_value.empty()) {
|
|
StrAppend(&header_value, ";");
|
|
}
|
|
StrAppend(&header_value, cookie_vector[i]);
|
|
} else {
|
|
request_headers->Add(HttpAttributes::kCookie, header_value);
|
|
cookie_vector[i].CopyToString(&header_value);
|
|
}
|
|
}
|
|
if (!header_value.empty()) {
|
|
request_headers->Add(HttpAttributes::kCookie, header_value);
|
|
}
|
|
}
|
|
RequestContextPtr null_request_context;
|
|
RewriteQuery::Status status = rewrite_query_.Scan(
|
|
allow_related_options_,
|
|
allow_options_to_be_set_by_cookies_,
|
|
request_option_override_, null_request_context,
|
|
factory(), server_context(), &url, request_headers,
|
|
response_headers, &handler_);
|
|
if (out_query != NULL) {
|
|
out_query->assign(url.Query().data(), url.Query().size());
|
|
}
|
|
if (out_req_string != NULL && request_headers != NULL) {
|
|
out_req_string->assign(request_headers->ToString());
|
|
}
|
|
if (out_resp_string != NULL && response_headers != NULL) {
|
|
out_resp_string->assign(response_headers->ToString());
|
|
}
|
|
return status;
|
|
}
|
|
|
|
// Starts with image_, applies the specified image-options, and any
|
|
// query-params and request-headers.
|
|
const RewriteOptions* ParseAndScanImageOptions(StringPiece image_options,
|
|
StringPiece query_params,
|
|
StringPiece request_headers) {
|
|
allow_related_options_ = true;
|
|
GoogleString query;
|
|
GoogleString req_string;
|
|
GoogleString image = AddOptionsToEncodedUrl(image_url_, image_options);
|
|
const RewriteOptions* options = ParseAndScan(image, query_params,
|
|
request_headers, &query,
|
|
&req_string);
|
|
EXPECT_STREQ("", query);
|
|
return options;
|
|
}
|
|
|
|
void CheckExtendCache(const RewriteOptions& options, bool x) {
|
|
EXPECT_EQ(x, options.Enabled(RewriteOptions::kExtendCacheCss));
|
|
EXPECT_EQ(x, options.Enabled(RewriteOptions::kExtendCacheImages));
|
|
EXPECT_EQ(x, options.Enabled(RewriteOptions::kExtendCacheScripts));
|
|
}
|
|
|
|
// In a fashion patterned after the usage in mod_instaweb.cc, establish
|
|
// a base configuration, and update it based on the passed-in query string.
|
|
void Incremental(const StringPiece& query, RewriteOptions* options) {
|
|
GoogleUrl gurl(StrCat("http://example.com/?ModPagespeedFilters=", query));
|
|
RequestContextPtr null_request_context;
|
|
ASSERT_EQ(RewriteQuery::kSuccess,
|
|
rewrite_query_.Scan(
|
|
allow_related_options_, allow_options_to_be_set_by_cookies_,
|
|
request_option_override_, null_request_context, factory(),
|
|
server_context(), &gurl, NULL, NULL, message_handler()));
|
|
options->Merge(*rewrite_query_.options());
|
|
}
|
|
|
|
void TestParseClientOptions(
|
|
RequestHeaders* request_headers,
|
|
bool expected_parsing_result,
|
|
RewriteQuery::ProxyMode expected_proxy_mode,
|
|
DeviceProperties::ImageQualityPreference expected_quality_preference) {
|
|
RewriteQuery::ProxyMode proxy_mode;
|
|
DeviceProperties::ImageQualityPreference quality_preference;
|
|
const StringPiece header_value(
|
|
request_headers->Lookup1(HttpAttributes::kXPsaClientOptions));
|
|
bool parsing_result = RewriteQuery::ParseClientOptions(
|
|
header_value, &proxy_mode, &quality_preference);
|
|
EXPECT_EQ(expected_parsing_result, parsing_result);
|
|
if (parsing_result) {
|
|
EXPECT_EQ(expected_proxy_mode, proxy_mode);
|
|
EXPECT_EQ(expected_quality_preference, quality_preference);
|
|
}
|
|
}
|
|
|
|
void TestClientOptions(
|
|
RequestHeaders* request_headers,
|
|
bool expected_parsing_result,
|
|
RewriteQuery::ProxyMode expected_proxy_mode,
|
|
DeviceProperties::ImageQualityPreference expected_quality_preference) {
|
|
ResponseHeaders response_headers;
|
|
GoogleString in_query, out_query, out_req_string, out_resp_string;
|
|
|
|
TestParseClientOptions(
|
|
request_headers, expected_parsing_result, expected_proxy_mode,
|
|
expected_quality_preference);
|
|
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, in_query, StringPiece(), request_headers, &response_headers,
|
|
&out_query, &out_req_string, &out_resp_string);
|
|
if (!expected_parsing_result) {
|
|
EXPECT_TRUE(options == NULL);
|
|
return;
|
|
}
|
|
if (expected_proxy_mode == RewriteQuery::kProxyModeNoTransform) {
|
|
EXPECT_EQ(RewriteOptions::kPassThrough, options->level());
|
|
// Not a complete list. Only checks the important ones.
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
EXPECT_FALSE(options->Enabled(
|
|
RewriteOptions::kRewriteJavascriptExternal));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteJavascriptInline));
|
|
}
|
|
if (expected_proxy_mode == RewriteQuery::kProxyModeNoTransform ||
|
|
expected_proxy_mode == RewriteQuery::kProxyModeNoImageTransform) {
|
|
// Not a complete list. Only checks the important ones.
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kConvertGifToPng));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kConvertPngToJpeg));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kConvertJpegToProgressive));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kConvertJpegToWebp));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kConvertToWebpLossless));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kResizeImages));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kResizeMobileImages));
|
|
} else {
|
|
EXPECT_EQ(RewriteQuery::kProxyModeDefault, expected_proxy_mode);
|
|
if (expected_quality_preference ==
|
|
DeviceProperties::kImageQualityDefault) {
|
|
EXPECT_TRUE(options == NULL);
|
|
}
|
|
}
|
|
EXPECT_TRUE(
|
|
request_headers->Lookup1(HttpAttributes::kXPsaClientOptions) == NULL);
|
|
}
|
|
|
|
GoogleMessageHandler handler_;
|
|
RewriteQuery rewrite_query_;
|
|
bool allow_related_options_;
|
|
bool allow_options_to_be_set_by_cookies_;
|
|
GoogleString request_option_override_;
|
|
GoogleString image_url_;
|
|
};
|
|
|
|
TEST_F(RewriteQueryTest, Empty) {
|
|
EXPECT_TRUE(ParseAndScan(kHtmlUrl, "", "") == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OffQuery) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "ModPagespeed=off", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_FALSE(options->enabled());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OffHeaders) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "", "ModPagespeed:off");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_FALSE(options->enabled());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OffResponseHeader) {
|
|
RequestHeaders request_headers;
|
|
ResponseHeaders response_headers;
|
|
GoogleString in_query, out_query, out_req_string, out_resp_string;
|
|
|
|
response_headers.Add("ModPagespeed", "off");
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, in_query, StringPiece(), &request_headers, &response_headers,
|
|
&out_query, &out_req_string, &out_resp_string);
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_FALSE(options->enabled());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OffQueryPageSpeed) {
|
|
const RewriteOptions* options = ParseAndScan(kHtmlUrl, "PageSpeed=off", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_FALSE(options->enabled());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OffHeadersPageSpeed) {
|
|
const RewriteOptions* options = ParseAndScan(kHtmlUrl, "", "PageSpeed:off");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_FALSE(options->enabled());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OffResponseHeaderPageSpeed) {
|
|
RequestHeaders request_headers;
|
|
ResponseHeaders response_headers;
|
|
GoogleString in_query, out_query, out_req_string, out_resp_string;
|
|
|
|
response_headers.Add("PageSpeed", "off");
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, in_query, StringPiece(), &request_headers, &response_headers,
|
|
&out_query, &out_req_string, &out_resp_string);
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_FALSE(options->enabled());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OnWithDefaultFiltersQuery) {
|
|
const RewriteOptions* options = ParseAndScan(kHtmlUrl, "ModPagespeed=on", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
CheckExtendCache(*options, true);
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kExtendCachePdfs));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kResizeImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptExternal));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptInline));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OnWithDefaultFiltersHeaders) {
|
|
const RewriteOptions* options = ParseAndScan(kHtmlUrl, "", "ModPagespeed:on");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
CheckExtendCache(*options, true);
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kExtendCachePdfs));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kResizeImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptExternal));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptInline));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OnWithDefaultFiltersQueryPageSpeed) {
|
|
const RewriteOptions* options = ParseAndScan(kHtmlUrl, "PageSpeed=on", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
CheckExtendCache(*options, true);
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kExtendCachePdfs));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kResizeImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptExternal));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptInline));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OnWithDefaultFiltersHeadersPageSpeed) {
|
|
const RewriteOptions* options = ParseAndScan(kHtmlUrl, "", "PageSpeed:on");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
CheckExtendCache(*options, true);
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kExtendCachePdfs));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kResizeImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptExternal));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptInline));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, SetFiltersQuery) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "ModPagespeedFilters=remove_quotes", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRemoveQuotes));
|
|
CheckExtendCache(*options, false);
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kExtendCachePdfs));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kResizeImages));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteJavascriptExternal));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteJavascriptInline));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, SetFiltersQueryCorePlusMinus) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl,
|
|
"ModPagespeedFilters=core,+div_structure,-inline_css,+extend_cache_css",
|
|
"");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
|
|
CheckExtendCache(*options, true);
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kExtendCacheCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kExtendCacheImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kDivStructure));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kInlineCss));
|
|
// Unlike above, these are true because 'core' is in the filter list.
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kResizeImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptExternal));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRewriteJavascriptInline));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, SetFiltersRequestHeaders) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "", "ModPagespeedFilters:remove_quotes");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRemoveQuotes));
|
|
CheckExtendCache(*options, false);
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kExtendCachePdfs));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kResizeImages));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteJavascriptExternal));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteJavascriptInline));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, SetFiltersResponseHeaders) {
|
|
// Check that response headers are properly parsed.
|
|
RequestHeaders request_headers;
|
|
ResponseHeaders response_headers;
|
|
GoogleString in_query, out_query, out_req_string, out_resp_string;
|
|
|
|
response_headers.Add("ModPagespeedFilters", "remove_quotes");
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, in_query, StringPiece(), &request_headers, &response_headers,
|
|
&out_query, &out_req_string, &out_resp_string);
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRemoveQuotes));
|
|
CheckExtendCache(*options, false);
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kExtendCachePdfs));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kResizeImages));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteJavascriptExternal));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteJavascriptInline));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, QueryAndRequestAndResponseAndCookies) {
|
|
RequestHeaders request_headers;
|
|
ResponseHeaders response_headers;
|
|
GoogleString in_query, in_cookies, out_query, out_req_string, out_resp_string;
|
|
|
|
in_query = ("ModPagespeedFilters=-div_structure,+extend_cache_css");
|
|
|
|
in_cookies = (" PageSpeedCssFlattenMaxBytes = 12345 "
|
|
";ModPagespeedFilters=%2binline_images" // Needed for:
|
|
";ModPagespeedImageInlineMaxBytes=67890"
|
|
";SessionId=1234567890" // Not ours.
|
|
";PageSpeedImageRecompressionQuality=77"
|
|
";PageSpeedNoSuchOption=123" // No such.
|
|
";ModPagespeedImageLimitOptimizedPercent=55" // Bad scope.
|
|
";PageSpeedWebpRecompressionQuality" // No value.
|
|
";ModPagespeedImageJpegRecompressQuality=33oops" // Bad value.
|
|
";ModPagespeedCssInlineMaxBytes=19" // Conflicts.
|
|
";PageSpeedEnrollExperiment=\n1\r"); // Bad chars.
|
|
|
|
request_headers.Add("ModPagespeedCssInlineMaxBytes", "10");
|
|
request_headers.Add("ModPagespeedJsInlineMaxBytes", "7");
|
|
request_headers.Add("ModPagespeedFilters",
|
|
"+div_structure,-inline_css,+remove_quotes");
|
|
|
|
response_headers.Add("ModPagespeedFilters", "+inline_css,-remove_quotes");
|
|
response_headers.Add("ModPagespeedJsInlineMaxBytes", "13");
|
|
response_headers.Add("ModPagespeedFilters", "");
|
|
|
|
allow_options_to_be_set_by_cookies_ = true;
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, in_query, in_cookies, &request_headers, &response_headers,
|
|
&out_query, &out_req_string, &out_resp_string);
|
|
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kInlineImages));
|
|
EXPECT_EQ(12345, options->css_flatten_max_bytes());
|
|
EXPECT_EQ(67890, options->ImageInlineMaxBytes());
|
|
EXPECT_EQ(77, options->image_recompress_quality());
|
|
EXPECT_EQ(RewriteOptions::kDefaultImageLimitOptimizedPercent,
|
|
options->image_limit_optimized_percent());
|
|
EXPECT_EQ(RewriteOptions::kDefaultImageWebpRecompressQuality,
|
|
options->ImageWebpQuality());
|
|
EXPECT_EQ(RewriteOptions::kDefaultImageLimitResizeAreaPercent,
|
|
options->image_limit_resize_area_percent());
|
|
|
|
// Request and cookies conflict, Request should win.
|
|
EXPECT_EQ(10, options->css_inline_max_bytes());
|
|
|
|
// Request and Response conflict, Response should win.
|
|
EXPECT_EQ(13, options->js_inline_max_bytes());
|
|
|
|
// Request/Response/Query conflicts, disabled should win over enabled
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kInlineCss));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRemoveQuotes));
|
|
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kDivStructure));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kExtendCacheCss));
|
|
|
|
// PageSpeed option cookies have been squirreled away.
|
|
EXPECT_STREQ("ModPagespeedCssInlineMaxBytes=19" // Conflicts but still saved.
|
|
"&ModPagespeedFilters=+inline_images"
|
|
"&ModPagespeedImageInlineMaxBytes=67890"
|
|
"&PageSpeedCssFlattenMaxBytes=12345"
|
|
"&PageSpeedEnrollExperiment=1" // The bad chars are removed.
|
|
"&PageSpeedImageRecompressionQuality=77",
|
|
rewrite_query_.pagespeed_option_cookies().ToEscapedString());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, CannotSetOptionsByCookiesWhenDisabled) {
|
|
RequestHeaders request_headers;
|
|
ResponseHeaders response_headers;
|
|
GoogleString in_query, in_cookies, out_query, out_req_string, out_resp_string;
|
|
|
|
// We only do this to ensure that ParseAndScan returns non-NULL options.
|
|
in_query = ("ModPagespeedFilters=-div_structure,+extend_cache_css");
|
|
|
|
in_cookies = (" PageSpeedCssFlattenMaxBytes = 12345 "
|
|
";ModPagespeedFilters=+inline_images" // Needed for:
|
|
";ModPagespeedImageInlineMaxBytes=67890"
|
|
";PageSpeedImageRecompressionQuality=77"
|
|
";ModPagespeedCssInlineMaxBytes=19");
|
|
|
|
allow_options_to_be_set_by_cookies_ = false; // Default, but let's be *sure*.
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, in_query, in_cookies, &request_headers, &response_headers,
|
|
&out_query, &out_req_string, &out_resp_string);
|
|
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
|
|
// Everything should be default value.
|
|
EXPECT_EQ(RewriteOptions::kDefaultCssFlattenMaxBytes,
|
|
options->css_flatten_max_bytes());
|
|
EXPECT_EQ(RewriteOptions::kDefaultImageInlineMaxBytes,
|
|
options->ImageInlineMaxBytes());
|
|
EXPECT_EQ(RewriteOptions::kDefaultImageRecompressQuality,
|
|
options->image_recompress_quality());
|
|
EXPECT_EQ(RewriteOptions::kDefaultCssInlineMaxBytes,
|
|
options->css_inline_max_bytes());
|
|
|
|
// The query parameter options should still have taken effect.
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kDivStructure));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kExtendCacheCss));
|
|
}
|
|
|
|
// Note: In the next four tests we intentionally mix ModPagespeed* and
|
|
// PageSpeed* query params to make sure all combinations work and are respected.
|
|
|
|
TEST_F(RewriteQueryTest, MultipleQuery) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "PageSpeedFilters=inline_css&ModPagespeedCssInlineMaxBytes=10",
|
|
"");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kInlineCss));
|
|
EXPECT_EQ(10, options->css_inline_max_bytes());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, MultipleHeaders) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "",
|
|
"ModPagespeedFilters:inline_css;PageSpeedCssInlineMaxBytes:10");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kInlineCss));
|
|
EXPECT_EQ(10, options->css_inline_max_bytes());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, MultipleQueryAndHeaders) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "ModPagespeedFilters=inline_css",
|
|
"ModPagespeedCssInlineMaxBytes:10");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kInlineCss));
|
|
EXPECT_EQ(10, options->css_inline_max_bytes());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, MultipleIgnoreUnrelated) {
|
|
const RewriteOptions* options = ParseAndScan(kHtmlUrl,
|
|
"PageSpeedFilters=inline_css"
|
|
"&PageSpeedCssInlineMaxBytes=10"
|
|
"&Unrelated1"
|
|
"&Unrelated2="
|
|
"&Unrelated3=value",
|
|
"");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kInlineCss));
|
|
EXPECT_EQ(10, options->css_inline_max_bytes());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, MultipleBroken) {
|
|
const RewriteOptions* options = ParseAndScan(kHtmlUrl,
|
|
"PageSpeedFilters=inline_css"
|
|
"&PageSpeedCssInlineMaxBytes=10"
|
|
"&PageSpeedFilters=bogus_filter",
|
|
"");
|
|
EXPECT_TRUE(options == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, MultipleInt64Params) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl,
|
|
"PageSpeedCssInlineMaxBytes=3"
|
|
"&PageSpeedImageInlineMaxBytes=5"
|
|
"&PageSpeedCssImageInlineMaxBytes=7"
|
|
"&PageSpeedJsInlineMaxBytes=11"
|
|
"&PageSpeedDomainShardCount=2",
|
|
"");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->enabled());
|
|
EXPECT_EQ(3, options->css_inline_max_bytes());
|
|
EXPECT_EQ(5, options->ImageInlineMaxBytes());
|
|
EXPECT_EQ(7, options->CssImageInlineMaxBytes());
|
|
EXPECT_EQ(11, options->js_inline_max_bytes());
|
|
EXPECT_EQ(2, options->domain_shard_count());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OptionsNotArbitrary) {
|
|
// Security sanity check: trying to set beacon URL
|
|
// externally should not succeed.
|
|
const RewriteOptions* options =
|
|
ParseAndScan(kHtmlUrl, StrCat("PageSpeed", RewriteOptions::kBeaconUrl,
|
|
"=", "evil.com"), "");
|
|
EXPECT_TRUE(options == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OutputQueryandHeaders) {
|
|
GoogleString output_query, output_headers;
|
|
ParseAndScan(kHtmlUrl, "ModPagespeedCssInlineMaxBytes=3"
|
|
"&ModPagespeedImageInlineMaxBytes=5"
|
|
"&ModPagespeedCssImageInlineMaxBytes=7"
|
|
"&ModPagespeedJsInlineMaxBytes=11"
|
|
"&ModPagespeedDomainShardCount=100"
|
|
"&ModPagespeedCssFlattenMaxBytes=13"
|
|
"&abc=1"
|
|
"&def",
|
|
"ModPagespeedFilters:inline_css;"
|
|
"xyz:6;"
|
|
"ModPagespeedFilters:remove_quotes",
|
|
&output_query, &output_headers);
|
|
EXPECT_EQ(output_query, "abc=1&def");
|
|
EXPECT_EQ(output_headers, "GET HTTP/1.0\r\nxyz: 6\r\n\r\n");
|
|
ParseAndScan(kHtmlUrl, "ModPagespeedCssInlineMaxBytes=3", "",
|
|
&output_query, &output_headers);
|
|
EXPECT_EQ(output_query, "");
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OutputQueryandHeadersPageSpeed) {
|
|
GoogleString output_query, output_headers;
|
|
ParseAndScan(kHtmlUrl, "PageSpeedCssInlineMaxBytes=3"
|
|
"&PageSpeedImageInlineMaxBytes=5"
|
|
"&PageSpeedCssImageInlineMaxBytes=7"
|
|
"&PageSpeedJsInlineMaxBytes=11"
|
|
"&PageSpeedDomainShardCount=100"
|
|
"&PageSpeedCssFlattenMaxBytes=13"
|
|
"&abc=1"
|
|
"&def",
|
|
"PageSpeedFilters:inline_css;"
|
|
"xyz:6;"
|
|
"PageSpeedFilters:remove_quotes",
|
|
&output_query, &output_headers);
|
|
EXPECT_EQ(output_query, "abc=1&def");
|
|
EXPECT_EQ(output_headers, "GET HTTP/1.0\r\nxyz: 6\r\n\r\n");
|
|
ParseAndScan(kHtmlUrl, "PageSpeedCssInlineMaxBytes=3", "",
|
|
&output_query, &output_headers);
|
|
EXPECT_EQ(output_query, "");
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OutputQueryandHeadersPostRequest) {
|
|
GoogleString output_query, output_req_headers, output_resp_headers;
|
|
RequestHeaders request_headers;
|
|
request_headers.set_method(RequestHeaders::kPost);
|
|
request_headers.Add("ModPagespeedFilters", "inline_css");
|
|
request_headers.Add("xyz", "6");
|
|
request_headers.set_message_body("pqr");
|
|
|
|
ParseAndScan(kHtmlUrl,
|
|
"ModPagespeedCssInlineMaxBytes=3"
|
|
"&abc=1"
|
|
"&def",
|
|
StringPiece(), &request_headers, NULL, &output_query,
|
|
&output_req_headers, &output_resp_headers);
|
|
EXPECT_EQ(output_query, "abc=1&def");
|
|
EXPECT_EQ(output_req_headers, "POST HTTP/1.0\r\nxyz: 6\r\n\r\n");
|
|
EXPECT_EQ(request_headers.message_body(), "pqr");
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OutputQueryandHeadersPostRequestPageSpeed) {
|
|
GoogleString output_query, output_req_headers, output_resp_headers;
|
|
RequestHeaders request_headers;
|
|
request_headers.set_method(RequestHeaders::kPost);
|
|
request_headers.Add("PageSpeedFilters", "inline_css");
|
|
request_headers.Add("xyz", "6");
|
|
request_headers.set_message_body("pqr");
|
|
|
|
ParseAndScan(kHtmlUrl,
|
|
"PageSpeedCssInlineMaxBytes=3"
|
|
"&abc=1"
|
|
"&def",
|
|
StringPiece(), &request_headers, NULL, &output_query,
|
|
&output_req_headers, &output_resp_headers);
|
|
EXPECT_EQ(output_query, "abc=1&def");
|
|
EXPECT_EQ(output_req_headers, "POST HTTP/1.0\r\nxyz: 6\r\n\r\n");
|
|
EXPECT_EQ(request_headers.message_body(), "pqr");
|
|
}
|
|
|
|
// Tests the ability to add an additional filter on the command-line based
|
|
// on whatever set is already installed in the configuration.
|
|
TEST_F(RewriteQueryTest, IncrementalAdd) {
|
|
RewriteOptions options(factory()->thread_system());
|
|
options.SetDefaultRewriteLevel(RewriteOptions::kCoreFilters);
|
|
options.EnableFilter(RewriteOptions::kStripScripts);
|
|
Incremental("+debug", &options);
|
|
EXPECT_TRUE(options.Enabled(RewriteOptions::kStripScripts));
|
|
EXPECT_TRUE(options.Enabled(RewriteOptions::kDebug));
|
|
EXPECT_TRUE(options.Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_FALSE(options.Enabled(RewriteOptions::kAddBaseTag));
|
|
EXPECT_TRUE(options.modified());
|
|
}
|
|
|
|
// Same exact test as above, except that we omit the "+". This wipes out
|
|
// the explicitly enabled filter in the configuration and also the core
|
|
// level.
|
|
TEST_F(RewriteQueryTest, NonIncrementalAdd) {
|
|
RewriteOptions options(factory()->thread_system());
|
|
options.SetDefaultRewriteLevel(RewriteOptions::kCoreFilters);
|
|
options.EnableFilter(RewriteOptions::kStripScripts);
|
|
Incremental("debug", &options);
|
|
EXPECT_FALSE(options.Enabled(RewriteOptions::kStripScripts));
|
|
EXPECT_TRUE(options.Enabled(RewriteOptions::kDebug));
|
|
EXPECT_FALSE(options.Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_TRUE(options.modified());
|
|
}
|
|
|
|
// In this version we specify nothing, and that should erase the filters.
|
|
TEST_F(RewriteQueryTest, IncrementalEmpty) {
|
|
RewriteOptions options(factory()->thread_system());
|
|
options.SetDefaultRewriteLevel(RewriteOptions::kCoreFilters);
|
|
options.EnableFilter(RewriteOptions::kStripScripts);
|
|
Incremental("", &options);
|
|
EXPECT_FALSE(options.Enabled(RewriteOptions::kStripScripts));
|
|
EXPECT_FALSE(options.Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_TRUE(options.modified());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, IncrementalRemoveExplicit) {
|
|
RewriteOptions options(factory()->thread_system());
|
|
options.SetDefaultRewriteLevel(RewriteOptions::kCoreFilters);
|
|
options.EnableFilter(RewriteOptions::kStripScripts);
|
|
Incremental("-strip_scripts", &options);
|
|
EXPECT_FALSE(options.Enabled(RewriteOptions::kStripScripts));
|
|
EXPECT_TRUE(options.Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_TRUE(options.modified());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, IncrementalRemoveFromCore) {
|
|
RewriteOptions options(factory()->thread_system());
|
|
options.SetDefaultRewriteLevel(RewriteOptions::kCoreFilters);
|
|
options.EnableFilter(RewriteOptions::kStripScripts);
|
|
Incremental("-combine_css", &options);
|
|
EXPECT_TRUE(options.Enabled(RewriteOptions::kStripScripts));
|
|
EXPECT_FALSE(options.Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_TRUE(options.modified());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, NoChangesShouldNotModify) {
|
|
RewriteOptions options(factory()->thread_system());
|
|
options.SetDefaultRewriteLevel(RewriteOptions::kCoreFilters);
|
|
Incremental("+combine_css", &options);
|
|
EXPECT_FALSE(options.Enabled(RewriteOptions::kStripScripts));
|
|
EXPECT_TRUE(options.Enabled(RewriteOptions::kCombineCss));
|
|
//
|
|
// TODO(jmarantz): We would like at this point to have options show up
|
|
// as unmodified. However our implementation of query-params parsing
|
|
// does not allow for this at this point, because it doesn't know
|
|
// that it is working with the core filters. Right now this is not
|
|
// that important as the only usage of RewriteOptions::modified() is
|
|
// in apache/mod_instaweb.cc which is just checking to see if there are
|
|
// any directory-specific options set.
|
|
//
|
|
// EXPECT_FALSE(options.modified());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, NoQueryValue) {
|
|
const RewriteOptions* options = ParseAndScan(kHtmlUrl, "ModPagespeed=", "");
|
|
EXPECT_TRUE(options == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, NoscriptQueryParamEmptyValue) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "PageSpeed=noscript", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
RewriteOptions::FilterVector filter_vector;
|
|
options->GetEnabledFiltersRequiringScriptExecution(&filter_vector);
|
|
EXPECT_TRUE(filter_vector.empty());
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kHandleNoscriptRedirect));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, NoscriptHeader) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "", "PageSpeed:noscript");
|
|
ASSERT_TRUE(options != NULL);
|
|
RewriteOptions::FilterVector filter_vector;
|
|
options->GetEnabledFiltersRequiringScriptExecution(&filter_vector);
|
|
EXPECT_TRUE(filter_vector.empty());
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kHandleNoscriptRedirect));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, NoscriptWithTrailingQuoteQueryParamEmptyValue) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl,
|
|
"PageSpeed=noscript'", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
RewriteOptions::FilterVector filter_vector;
|
|
options->GetEnabledFiltersRequiringScriptExecution(&filter_vector);
|
|
EXPECT_TRUE(filter_vector.empty());
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kLazyloadImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kHandleNoscriptRedirect));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, NoscriptWithTrailingEscapedQuoteQueryParamEmptyValue) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl,
|
|
"PageSpeed=noscript%5c%22", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
RewriteOptions::FilterVector filter_vector;
|
|
options->GetEnabledFiltersRequiringScriptExecution(&filter_vector);
|
|
EXPECT_TRUE(filter_vector.empty());
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kLazyloadImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kHandleNoscriptRedirect));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, NoscripWithTrailingQuotetHeader) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "",
|
|
"PageSpeed:noscript'");
|
|
ASSERT_TRUE(options != NULL);
|
|
RewriteOptions::FilterVector filter_vector;
|
|
options->GetEnabledFiltersRequiringScriptExecution(&filter_vector);
|
|
EXPECT_TRUE(filter_vector.empty());
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kLazyloadImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kHandleNoscriptRedirect));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, NoscripWithTrailingQuestionMarkHeader) {
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "",
|
|
"PageSpeed:noscript?");
|
|
ASSERT_TRUE(options != NULL);
|
|
RewriteOptions::FilterVector filter_vector;
|
|
options->GetEnabledFiltersRequiringScriptExecution(&filter_vector);
|
|
EXPECT_TRUE(filter_vector.empty());
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kLazyloadImages));
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kHandleNoscriptRedirect));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, JpegRecompressionQuality) {
|
|
const char kQuery[] = "PageSpeedJpegRecompressionQuality=73";
|
|
GoogleString query, req;
|
|
const RewriteOptions* options = ParseAndScan(
|
|
image_url_, kQuery, "", &query, &req);
|
|
EXPECT_TRUE(options != NULL);
|
|
EXPECT_STREQ("", query);
|
|
EXPECT_EQ(73, options->ImageJpegQuality());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, RequestOptionOverrideWithIncorrectToken) {
|
|
const char kQuery[] =
|
|
"PageSpeedJpegRecompressionQuality=88&PageSpeedRequestOptionOverride=def";
|
|
GoogleString query, req;
|
|
request_option_override_ = "abc";
|
|
const RewriteOptions* options =
|
|
ParseAndScan(image_url_, kQuery, "", &query, &req);
|
|
EXPECT_TRUE(options == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, RequestOptionOverride) {
|
|
const char kQuery[] =
|
|
"PageSpeedJpegRecompressionQuality=73&PageSpeedRequestOptionOverride=abc";
|
|
GoogleString query, req;
|
|
request_option_override_ = "abc";
|
|
const RewriteOptions* options =
|
|
ParseAndScan(image_url_, kQuery, "", &query, &req);
|
|
EXPECT_EQ(73, options->ImageJpegQuality());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, RequestOptionOverrideProvidedWhenNotRequired) {
|
|
const char kQuery[] =
|
|
"PageSpeedJpegRecompressionQuality=73&PageSpeedRequestOptionOverride=abc";
|
|
GoogleString query, req;
|
|
const RewriteOptions* options =
|
|
ParseAndScan(image_url_, kQuery, "", &query, &req);
|
|
EXPECT_EQ(73, options->ImageJpegQuality());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, RequestOptionOverrideNotProvidedWhenRequired) {
|
|
const char kQuery[] = "PageSpeedJpegRecompressionQuality=73";
|
|
GoogleString query, req;
|
|
request_option_override_ = "abc";
|
|
const RewriteOptions* options =
|
|
ParseAndScan(image_url_, kQuery, "", &query, &req);
|
|
EXPECT_TRUE(options == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, GenerateEmptyResourceOption) {
|
|
EXPECT_EQ("", RewriteQuery::GenerateResourceOption("ic", rewrite_driver()));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, GenerateResourceOptionRecompressImages) {
|
|
options()->EnableFilter(RewriteOptions::kRecompressJpeg); // relevant
|
|
options()->EnableFilter(RewriteOptions::kCombineCss); // not relevant
|
|
options()->set_image_jpeg_recompress_quality(70);
|
|
EXPECT_EQ("rj+iq=70",
|
|
RewriteQuery::GenerateResourceOption("ic", rewrite_driver()));
|
|
EXPECT_EQ("",
|
|
RewriteQuery::GenerateResourceOption("jm", rewrite_driver()));
|
|
|
|
// TODO(jmarantz): add support for CSS/JS options & test.
|
|
// TODO(jmarantz): test all relevant filter/option combinations.
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, DontAllowArbitraryOptionsForNonPagespeedResources) {
|
|
allow_related_options_ = true;
|
|
// The kHtmlUrl is a .jsp, which is not .pagespeed.
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, "PsolOpt=rj,iq:70", "");
|
|
EXPECT_TRUE(options == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, DontAllowArbitraryOptionsWhenDisabled) {
|
|
GoogleString image = AddOptionsToEncodedUrl(image_url_, "rj+iq=70");
|
|
const RewriteOptions* options = ParseAndScan(image, "", "");
|
|
EXPECT_TRUE(options == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, CanQueryRecompressImages) {
|
|
const RewriteOptions* options = ParseAndScanImageOptions("rj+iq=70", "", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRecompressJpeg));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_EQ(70, options->ImageJpegQuality());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, CanOverrideRecompressImagesWithQuery) {
|
|
const RewriteOptions* options = ParseAndScanImageOptions(
|
|
"rj+iq=70", "PageSpeedJpegRecompressionQuality=71", "");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRecompressJpeg));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_EQ(71, options->ImageJpegQuality());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, CanOverrideRecompressImagesWithReqHeaders) {
|
|
const RewriteOptions* options = ParseAndScanImageOptions(
|
|
"rj+iq=70", "", "PageSpeedJpegRecompressionQuality:72");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRecompressJpeg));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_EQ(72, options->ImageJpegQuality());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, CanOverrideRecompressImagesWithBoth) {
|
|
const RewriteOptions* options = ParseAndScanImageOptions(
|
|
"rj+iq=70",
|
|
"PageSpeedJpegRecompressionQuality=71",
|
|
"PageSpeedJpegRecompressionQuality:72");
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_TRUE(options->Enabled(RewriteOptions::kRecompressJpeg));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kCombineCss));
|
|
EXPECT_EQ(72, options->ImageJpegQuality()) << "req-headers win.";
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, OnlyAllowWhitelistedResources) {
|
|
allow_related_options_ = true;
|
|
|
|
// whitelisted by "ic"
|
|
GoogleString image = AddOptionsToEncodedUrl(image_url_, "rj");
|
|
EXPECT_TRUE(ParseAndScan(image, "", "") != NULL);
|
|
image = AddOptionsToEncodedUrl(image_url_, "iq=70");
|
|
EXPECT_TRUE(ParseAndScan(image, "", "") != NULL);
|
|
|
|
// not whitelisted by "ic"
|
|
image = AddOptionsToEncodedUrl(image_url_, "cc");
|
|
EXPECT_TRUE(ParseAndScan(image_url_, "", "") == NULL);
|
|
image = AddOptionsToEncodedUrl(image_url_, "rdm=10");
|
|
EXPECT_TRUE(ParseAndScan(image_url_, "", "") == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, ClientOptionsEmptyHeader) {
|
|
RequestHeaders request_headers;
|
|
|
|
TestClientOptions(&request_headers,
|
|
false, /* expected_parsing_result */
|
|
RewriteQuery::kProxyModeDefault,
|
|
DeviceProperties::kImageQualityDefault);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, ClientOptionsMultipleHeaders) {
|
|
RequestHeaders request_headers;
|
|
|
|
request_headers.Add(HttpAttributes::kXPsaClientOptions, "v=1,iqp=3,m=0");
|
|
request_headers.Add(HttpAttributes::kXPsaClientOptions, "v=1,iqp=3,m=0");
|
|
TestClientOptions(&request_headers,
|
|
false, /* expected_parsing_result */
|
|
RewriteQuery::kProxyModeDefault,
|
|
DeviceProperties::kImageQualityDefault);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, ClientOptionsOrder1) {
|
|
RequestHeaders request_headers;
|
|
|
|
request_headers.Replace(HttpAttributes::kXPsaClientOptions, "v=1,iqp=2,m=0");
|
|
// Image quality is set.
|
|
TestClientOptions(&request_headers,
|
|
true, /* expected_parsing_result */
|
|
RewriteQuery::kProxyModeDefault,
|
|
DeviceProperties::kImageQualityMedium);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, ClientOptionsOrder2) {
|
|
RequestHeaders request_headers;
|
|
|
|
// The order of name-value pairs does not matter.
|
|
// Not-supported parts are ignored.
|
|
request_headers.Replace(HttpAttributes::kXPsaClientOptions,
|
|
"m=0,iqp=3,v=1,xyz=100,zyx=,yzx");
|
|
TestClientOptions(&request_headers,
|
|
true, /* expected_parsing_result */
|
|
RewriteQuery::kProxyModeDefault,
|
|
DeviceProperties::kImageQualityHigh);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, ClientOptionsCaseInsensitive) {
|
|
RequestHeaders request_headers;
|
|
GoogleString lower(HttpAttributes::kXPsaClientOptions);
|
|
LowerString(&lower);
|
|
|
|
request_headers.Replace(lower, "v=1,iqp=3,m=1");
|
|
// Image quality is set.
|
|
TestClientOptions(&request_headers,
|
|
true, /* expected_parsing_result */
|
|
RewriteQuery::kProxyModeNoImageTransform,
|
|
DeviceProperties::kImageQualityDefault);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, ClientOptionsNonDefaultProxyMode) {
|
|
RequestHeaders request_headers;
|
|
|
|
// Image quality is ignored if mode is not Default.
|
|
request_headers.Replace(HttpAttributes::kXPsaClientOptions, "v=1,iqp=2,m=1");
|
|
TestClientOptions(&request_headers,
|
|
true, /* expected_parsing_result */
|
|
RewriteQuery::kProxyModeNoImageTransform,
|
|
DeviceProperties::kImageQualityDefault);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, ClientOptionsValidVersionBadOptions) {
|
|
RequestHeaders request_headers;
|
|
|
|
// A valid version with bad options.
|
|
request_headers.Replace(HttpAttributes::kXPsaClientOptions,
|
|
"v=1,iqp=2m=1,iqp=");
|
|
TestClientOptions(&request_headers,
|
|
true, /* expected_parsing_result */
|
|
RewriteQuery::kProxyModeDefault,
|
|
DeviceProperties::kImageQualityDefault);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, ClientOptionsInvalidVersion) {
|
|
RequestHeaders request_headers;
|
|
|
|
request_headers.Replace(HttpAttributes::kXPsaClientOptions, "iqp=2,m=1,v=2");
|
|
TestClientOptions(&request_headers,
|
|
false, /* expected_parsing_result */
|
|
RewriteQuery::kProxyModeDefault,
|
|
DeviceProperties::kImageQualityDefault);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, CacheControlNoTransform) {
|
|
RequestHeaders request_headers;
|
|
request_headers.Replace(HttpAttributes::kCacheControl, "no-transform");
|
|
|
|
ResponseHeaders response_headers;
|
|
GoogleString in_query, out_query, out_req_string, out_resp_string;
|
|
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, in_query, StringPiece(), &request_headers, &response_headers,
|
|
&out_query, &out_req_string, &out_resp_string);
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_FALSE(options->enabled());
|
|
EXPECT_TRUE(request_headers.Lookup1(HttpAttributes::kCacheControl) != NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, DisableFiltersWithXHR) {
|
|
RequestHeaders request_headers;
|
|
request_headers.Replace(HttpAttributes::kXRequestedWith,
|
|
HttpAttributes::kXmlHttpRequest);
|
|
|
|
ResponseHeaders response_headers;
|
|
GoogleString in_query, out_query, out_req_string, out_resp_string;
|
|
|
|
EXPECT_EQ(RewriteQuery::kSuccess, Parse(
|
|
kHtmlUrl, in_query, StringPiece(), &request_headers,
|
|
&response_headers, &out_query, &out_req_string, &out_resp_string));
|
|
scoped_ptr<RewriteOptions> options(rewrite_query_.options()->Clone());
|
|
|
|
// Convert disabled -> forbidden for easier testing.
|
|
options->set_forbid_all_disabled_filters(true);
|
|
|
|
// defer_js, mobilize generaly require JS.
|
|
EXPECT_TRUE(options->Forbidden(RewriteOptions::kDeferJavascript));
|
|
EXPECT_TRUE(options->Forbidden(RewriteOptions::kMobilize));
|
|
EXPECT_TRUE(options->Forbidden(RewriteOptions::kMoveCssToHead));
|
|
EXPECT_TRUE(options->Forbidden(RewriteOptions::kAddInstrumentation));
|
|
|
|
// rewrite_css doesn't, and shouldn't be defaulted on, either.
|
|
EXPECT_FALSE(options->Forbidden(RewriteOptions::kRewriteCss));
|
|
EXPECT_FALSE(options->Enabled(RewriteOptions::kRewriteCss));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, CacheControlPrivateNoTransformResponse) {
|
|
RequestHeaders request_headers;
|
|
|
|
ResponseHeaders response_headers;
|
|
response_headers.Replace(HttpAttributes::kCacheControl,
|
|
"private, no-transform");
|
|
GoogleString in_query, out_query, out_req_string, out_resp_string;
|
|
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, in_query, StringPiece(), &request_headers, &response_headers,
|
|
&out_query, &out_req_string, &out_resp_string);
|
|
ASSERT_TRUE(options != NULL);
|
|
EXPECT_FALSE(options->enabled());
|
|
|
|
// Check that we don't strip either of the cache-control values.
|
|
EXPECT_TRUE(response_headers.HasValue(HttpAttributes::kCacheControl,
|
|
"private"));
|
|
EXPECT_TRUE(response_headers.HasValue(HttpAttributes::kCacheControl,
|
|
"no-transform"));
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, NoCustomOptionsWithCacheControlPrivate) {
|
|
RequestHeaders request_headers;
|
|
|
|
ResponseHeaders response_headers;
|
|
response_headers.Replace(HttpAttributes::kCacheControl, "private");
|
|
GoogleString in_query, out_query, out_req_string, out_resp_string;
|
|
|
|
const RewriteOptions* options = ParseAndScan(
|
|
kHtmlUrl, in_query, StringPiece(), &request_headers, &response_headers,
|
|
&out_query, &out_req_string, &out_resp_string);
|
|
EXPECT_TRUE(options == NULL);
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, PageSpeedQueryParamsAreExtracted) {
|
|
GoogleUrl gurl("http://test.com/?a=b&"
|
|
"ModPagespeedFilters=debug&"
|
|
"x=y&"
|
|
"ModPagespeedCssFlattenMaxBytes=123");
|
|
RequestContextPtr null_request_context;
|
|
EXPECT_EQ(RewriteQuery::kSuccess,
|
|
rewrite_query_.Scan(
|
|
allow_related_options_, allow_options_to_be_set_by_cookies_,
|
|
request_option_override_, null_request_context, factory(),
|
|
server_context(), &gurl, NULL, NULL, message_handler()));
|
|
EXPECT_STREQ("http://test.com/?a=b&x=y", gurl.Spec());
|
|
EXPECT_EQ(2, rewrite_query_.pagespeed_query_params().size());
|
|
EXPECT_STREQ("ModPagespeedFilters=debug&"
|
|
"ModPagespeedCssFlattenMaxBytes=123",
|
|
rewrite_query_.pagespeed_query_params().ToEscapedString());
|
|
}
|
|
|
|
TEST_F(RewriteQueryTest, PageSpeedStickyQueryParametersTokenIsExtracted) {
|
|
// First test that no token is extracted if not specified.
|
|
RequestContextPtr request_context(CreateRequestContext());
|
|
GoogleUrl gurl("http://test.com/?PageSpeedFilters=debug");
|
|
EXPECT_EQ(RewriteQuery::kSuccess,
|
|
rewrite_query_.Scan(
|
|
allow_related_options_, allow_options_to_be_set_by_cookies_,
|
|
request_option_override_, request_context, factory(),
|
|
server_context(), &gurl, NULL, NULL, message_handler()));
|
|
EXPECT_STREQ("http://test.com/", gurl.Spec());
|
|
EXPECT_EQ(1, rewrite_query_.pagespeed_query_params().size());
|
|
EXPECT_STREQ("PageSpeedFilters=debug",
|
|
rewrite_query_.pagespeed_query_params().ToEscapedString());
|
|
EXPECT_STREQ("", request_context->sticky_query_parameters_token());
|
|
// Then test that the token is extracted when specified.
|
|
gurl.Reset("http://test.com/"
|
|
"?PageSpeedFilters=debug"
|
|
"&PageSpeedStickyQueryParameters=yadda");
|
|
EXPECT_EQ(RewriteQuery::kSuccess,
|
|
rewrite_query_.Scan(
|
|
allow_related_options_, allow_options_to_be_set_by_cookies_,
|
|
request_option_override_, request_context, factory(),
|
|
server_context(), &gurl, NULL, NULL, message_handler()));
|
|
EXPECT_STREQ("http://test.com/", gurl.Spec());
|
|
EXPECT_EQ(2, rewrite_query_.pagespeed_query_params().size());
|
|
EXPECT_STREQ("PageSpeedFilters=debug&PageSpeedStickyQueryParameters=yadda",
|
|
rewrite_query_.pagespeed_query_params().ToEscapedString());
|
|
EXPECT_STREQ("yadda", request_context->sticky_query_parameters_token());
|
|
}
|
|
|
|
} // namespace net_instaweb
|