blob: 38c92e2f55b546ec8b18fb24cf8abb5559cef3f2 [file] [log] [blame]
/*
* 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