blob: 48eb6eac82a10307462620774116cd1cb165d2ba [file] [log] [blame]
// Copyright 2013 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: jmarantz@google.com (Joshua Marantz)
#include "pagespeed/kernel/http/caching_headers.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/http/http_names.h"
namespace net_instaweb {
class TestCachingHeaders : public CachingHeaders {
public:
explicit TestCachingHeaders(const char* cache_control)
: CachingHeaders(HttpStatus::kOK),
cache_control_(cache_control),
likely_static_resource_type_(true),
cacheable_resource_status_code_(true) {
}
virtual bool Lookup(const StringPiece& key, StringPieceVector* values) {
if (key == HttpAttributes::kCacheControl) {
SplitStringPieceToVector(cache_control_, ",", values, true);
for (int i = 0, n = values->size(); i < n; ++i) {
TrimWhitespace(&((*values)[i]));
}
return true;
} else {
return false;
}
}
virtual bool IsLikelyStaticResourceType() const {
return likely_static_resource_type_;
}
virtual bool IsCacheableResourceStatusCode() const {
return cacheable_resource_status_code_;
}
void set_likely_static_resource_type(bool x) {
likely_static_resource_type_ = x;
}
void set_cacheable_resource_status_code(bool x) {
cacheable_resource_status_code_ = x;
}
private:
GoogleString cache_control_;
bool likely_static_resource_type_;
bool cacheable_resource_status_code_;
DISALLOW_COPY_AND_ASSIGN(TestCachingHeaders);
};
class CachingHeadersTest : public testing::Test {
protected:
void SetCacheControl(const char* cache_control) {
headers_.reset(new TestCachingHeaders(cache_control));
}
GoogleString DisableCacheControl() {
return headers_->GenerateDisabledCacheControl();
}
scoped_ptr<TestCachingHeaders> headers_;
};
TEST_F(CachingHeadersTest, DisableEmpty) {
SetCacheControl("");
EXPECT_STREQ(HttpAttributes::kNoCacheMaxAge0, DisableCacheControl());
}
TEST_F(CachingHeadersTest, DisableCaching) {
SetCacheControl("max-age=60");
EXPECT_STREQ(HttpAttributes::kNoCacheMaxAge0, DisableCacheControl());
}
TEST_F(CachingHeadersTest, DisablePrivateCaching) {
SetCacheControl("private, max-age=60");
EXPECT_STREQ(HttpAttributes::kNoCacheMaxAge0, DisableCacheControl());
}
TEST_F(CachingHeadersTest, DisablePublicCaching) {
SetCacheControl("public, max-age=60");
EXPECT_STREQ(HttpAttributes::kNoCacheMaxAge0, DisableCacheControl());
}
TEST_F(CachingHeadersTest, DisableNostore) {
SetCacheControl("must-revalidate, private, no-store");
EXPECT_STREQ(StrCat(HttpAttributes::kNoCacheMaxAge0,
", must-revalidate, ",
HttpAttributes::kNoStore),
DisableCacheControl());
}
TEST_F(CachingHeadersTest, DisableNostoreRetainNoCache) {
SetCacheControl("no-cache, must-revalidate, private, no-store");
EXPECT_STREQ(StrCat(HttpAttributes::kNoCacheMaxAge0,
", must-revalidate, ",
HttpAttributes::kNoStore),
DisableCacheControl());
}
TEST_F(CachingHeadersTest, IsCacheable) {
// Default of no headers, likely static resource type and cacheable status
// code is cacheable.
SetCacheControl("");
EXPECT_TRUE(headers_->IsCacheable());
// It's false if type isn't likely static or status isn't cacheable, though.
SetCacheControl("");
headers_->set_cacheable_resource_status_code(false);
EXPECT_FALSE(headers_->IsCacheable());
SetCacheControl("");
headers_->set_likely_static_resource_type(false);
EXPECT_FALSE(headers_->IsCacheable());
// Private is OK, for browser cacheability.
SetCacheControl("private");
EXPECT_TRUE(headers_->IsCacheable());
EXPECT_FALSE(headers_->IsProxyCacheable());
// Various flags that make it non-cacheable.
SetCacheControl("no-cache");
EXPECT_FALSE(headers_->IsCacheable());
SetCacheControl("no-store");
EXPECT_FALSE(headers_->IsCacheable());
SetCacheControl("must-revalidate");
EXPECT_FALSE(headers_->IsCacheable());
EXPECT_FALSE(headers_->ProxyRevalidate());
EXPECT_TRUE(headers_->MustRevalidate());
EXPECT_FALSE(headers_->IsProxyCacheable());
SetCacheControl("proxy-revalidate");
EXPECT_TRUE(headers_->IsCacheable());
EXPECT_TRUE(headers_->ProxyRevalidate());
EXPECT_FALSE(headers_->MustRevalidate());
// must-revalidate does not imply uncacheability: it just means
// that stale content should not be trusted.
SetCacheControl("must-revalidate,max-age=600");
EXPECT_FALSE(headers_->ProxyRevalidate());
EXPECT_TRUE(headers_->MustRevalidate());
EXPECT_TRUE(headers_->IsProxyCacheable());
// proxy-revalidate is similar, but does not affect browser heuristics
SetCacheControl("proxy-revalidate,max-age=600");
EXPECT_TRUE(headers_->ProxyRevalidate());
EXPECT_FALSE(headers_->MustRevalidate());
EXPECT_TRUE(headers_->IsProxyCacheable());
}
} // namespace net_instaweb