Skip to content
This repository was archived by the owner on Apr 10, 2025. It is now read-only.

Commit f56391f

Browse files
jmarantzcrowell
authored andcommitted
Propagate 'cache-control:public' from inputs to outputs.
Partially fixes apache/incubator-pagespeed-ngx#1149 General strategy: - adjust general mechanism for computing output response header from input response headers to incorporate 'public' on input. A challenge here is to make sure we test all the egress points, e.g. - pagespeed resources: cached and reconstructed on demand - fallbacks of various sorts - ipro resources: cached and reconstructed on demand - loaded from LoadFromFile Propagate 'cache-control:public' from inputs to outputs. Partially fixes apache/incubator-pagespeed-ngx#1149 General strategy: - adjust general mechanism for computing output response header from input response headers to incorporate 'public' on input. A challenge here is to make sure we test all the egress points, e.g. - pagespeed resources: cached and reconstructed on demand - fallbacks of various sorts - ipro resources: cached and reconstructed on demand - loaded from LoadFromFile fixup fixup for c++03 more c++03isms rm unused include rm override (no c++11 on branch 33) Also add 'public' to non-private cache-control if request has via:*google*. Completes the fix to apache/incubator-pagespeed-ngx#1149 A challenge here is to make sure we test all the egress points, e.g. - pagespeed resources: cached and reconstructed on demand - fallbacks of various sorts - ipro resources: cached and reconstructed on demand - loaded from LoadFromFile also we must make sure we don't cache the 'public' based on the request headers.
1 parent d4bcfe5 commit f56391f

20 files changed

+355
-105
lines changed

install/debug.conf.template

+7-2
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ ModPagespeedDefaultSharedMemoryCacheKB 0
105105
# in browser caches will stay relevant.
106106
<FilesMatch "\.(jpg|jpeg|gif|png|js|css)$">
107107
Header unset Etag
108-
Header set Cache-control "public, max-age=600"
108+
Header set Cache-control "max-age=600"
109109
</FilesMatch>
110110
</IfModule>
111111
</Directory>
@@ -940,7 +940,7 @@ NameVirtualHost 127.0.0.1:@@APACHE_TERTIARY_PORT@@
940940

941941
# Make the deadline long here for valgrind tests. We could
942942
# conditionalize this.
943-
ModPagespeedInPlaceRewriteDeadlineMs 10000
943+
ModPagespeedInPlaceRewriteDeadlineMs 20000
944944
</Directory>
945945

946946
<Directory "@@APACHE_DOC_ROOT@@/mod_pagespeed_test/ipro/wait/" >
@@ -1094,6 +1094,11 @@ ModPagespeedUsePerVHostStatistics on
10941094
ModPagespeedDownstreamCacheRebeaconingKey random_rebeaconing_key
10951095
</Directory>
10961096

1097+
<Directory "@@APACHE_DOC_ROOT@@/mod_pagespeed_test/public" >
1098+
Header set Cache-control "public,max-age=600"
1099+
ModPagespeedPreserveUrlRelativity off
1100+
</Directory>
1101+
10971102
<VirtualHost localhost:@@APACHE_SECONDARY_PORT@@>
10981103
ServerName downstreamcacheresource.example.com
10991104
DocumentRoot "@@APACHE_DOC_ROOT@@"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<link rel=stylesheet href="yellow.css" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.yellow {background-color: yellow;}

net/instaweb/rewriter/rewrite_context.cc

+18-6
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ class RewriteContext::FetchContext {
10661066
response_headers->CopyFrom(*(
10671067
output_resource_->response_headers()));
10681068
// Use the most conservative Cache-Control considering all inputs.
1069-
ApplyInputCacheControl(response_headers);
1069+
AdjustCacheControl();
10701070
AddMetadataHeaderIfNecessary(response_headers);
10711071
StringPiece contents = output_resource_->ExtractUncompressedContents();
10721072
async_fetch_->set_content_length(contents.size());
@@ -1108,7 +1108,7 @@ class RewriteContext::FetchContext {
11081108
// Use the most conservative Cache-Control considering all inputs.
11091109
// Note that this is needed because FixFetchFallbackHeaders might
11101110
// actually relax things a bit if the input was no-cache.
1111-
ApplyInputCacheControl(response_headers);
1111+
AdjustCacheControl();
11121112
StringPiece contents = input_resource->ExtractUncompressedContents();
11131113
ok = rewrite_context_->SendFallbackResponse(
11141114
original_output_url_, contents, async_fetch_, handler_);
@@ -1165,7 +1165,18 @@ class RewriteContext::FetchContext {
11651165
rewrite_context_->FixFetchFallbackHeaders(*cached_result,
11661166
async_fetch_->response_headers());
11671167
// Use the most conservative Cache-Control considering all inputs.
1168-
ApplyInputCacheControl(async_fetch_->response_headers());
1168+
AdjustCacheControl();
1169+
1170+
// Add 'public' header if rewritten resource had explicit 'public', which
1171+
// happens if the source URLs had 'public'. This is needed for
1172+
// ipro-optimized resources, where the actual inputs are used to
1173+
// compute the cache-control for a hidden .pagespeed. resource in a
1174+
// nested RewriteContext, and we need to propogate that to the ipro
1175+
// resource response headers.
1176+
if (headers->HasValue(HttpAttributes::kCacheControl, "public")) {
1177+
async_fetch_->response_headers()->SetCacheControlPublic();
1178+
}
1179+
11691180
if (!detached_) {
11701181
// If we're detached then we don't know what the state of the metadata is
11711182
// here as the Rewrite() could still be ongoing in the low-priority
@@ -1199,14 +1210,15 @@ class RewriteContext::FetchContext {
11991210
bool skip_fetch_rewrite() { return skip_fetch_rewrite_; }
12001211

12011212
private:
1202-
void ApplyInputCacheControl(ResponseHeaders* headers) {
1213+
void AdjustCacheControl() {
12031214
ResourceVector inputs;
12041215
for (int i = 0; i < rewrite_context_->num_slots(); i++) {
12051216
inputs.push_back(rewrite_context_->slot(i)->resource());
12061217
}
12071218

1208-
rewrite_context_->FindServerContext()->ApplyInputCacheControl(inputs,
1209-
headers);
1219+
rewrite_context_->FindServerContext()->ApplyInputCacheControl(
1220+
inputs, async_fetch_->response_headers());
1221+
async_fetch_->FixCacheControlForGoogleCache();
12101222
}
12111223

12121224
RewriteContext* rewrite_context_;

net/instaweb/rewriter/rewrite_driver.cc

+14-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,19 @@ RewriteDriver* RewriteDriver::Clone() {
403403
result = server_context_->NewRewriteDriverFromPool(pool, request_context_);
404404
}
405405
result->is_nested_ = true;
406-
result->SetRequestHeaders(*request_headers_);
406+
407+
// Remove any Via headers for the nested driver. This is intended for
408+
// removing "Via:1.1 google", so that nested drivers don't wind up
409+
// adding cc:public into intermediate cached results.
410+
//
411+
// Note that we *do* want to propagate http/2 detection to nested drivers.
412+
// This is OK because it gets captured in the RequestContext, which is
413+
// shared, and is not reconstructed from request-headers.
414+
RequestHeaders headers;
415+
headers.CopyFrom(*request_headers_);
416+
headers.RemoveAll(HttpAttributes::kVia);
417+
result->SetRequestHeaders(headers);
418+
407419
return result;
408420
}
409421

@@ -1831,6 +1843,7 @@ class CacheCallback : public OptionsAwareHTTPCacheCallback {
18311843
output_resource_->Link(value, handler_);
18321844
output_resource_->SetWritten(true);
18331845
async_fetch_->set_content_length(content.size());
1846+
async_fetch_->FixCacheControlForGoogleCache();
18341847
async_fetch_->HeadersComplete();
18351848
success = async_fetch_->Write(content, handler_);
18361849
}

net/instaweb/rewriter/rewrite_driver_test.cc

+34
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,19 @@ TEST_F(RewriteDriverTest, NoChanges) {
193193

194194
TEST_F(RewriteDriverTest, CloneMarksNested) {
195195
RequestHeaders request_headers;
196+
request_headers.Add(HttpAttributes::kAccept, "image/webp");
196197
request_headers.Add("a", "b");
198+
request_headers.Add(HttpAttributes::kVia, "1.1 google");
197199
rewrite_driver()->SetRequestHeaders(request_headers);
198200
RewriteDriver* clone1 = rewrite_driver()->Clone();
199201
EXPECT_TRUE(clone1->is_nested());
202+
EXPECT_TRUE(clone1->request_properties()->SupportsWebpRewrittenUrls());
203+
EXPECT_TRUE(rewrite_driver()->request_headers()->HasValue("a", "b"));
200204
EXPECT_TRUE(clone1->request_headers()->HasValue("a", "b"));
205+
EXPECT_TRUE(rewrite_driver()->request_headers()->HasValue(
206+
HttpAttributes::kVia, "1.1 google"));
207+
EXPECT_FALSE(clone1->request_headers()->HasValue(
208+
HttpAttributes::kVia, "1.1 google"));
201209
clone1->Cleanup();
202210

203211
RewriteDriver* parent2 =
@@ -439,6 +447,32 @@ TEST_F(RewriteDriverTest, TestCacheUse) {
439447
EXPECT_EQ(0, lru_cache()->num_identical_reinserts());
440448
}
441449

450+
// Test to make sure when we fetch a with a Via header, "public"
451+
// is added to the Cache-Control.
452+
TEST_F(RewriteDriverTest, ViaPublicPageSpeedResource) {
453+
RequestHeaders request_headers;
454+
request_headers.Add(HttpAttributes::kVia, "1.1 google");
455+
AddFilter(RewriteOptions::kRewriteCss);
456+
457+
const char kCss[] = "* { display: none; }";
458+
const char kMinCss[] = "*{display:none}";
459+
SetResponseWithDefaultHeaders("a.css", kContentTypeCss, kCss, 100);
460+
461+
GoogleString url = Encode(kTestDomain, RewriteOptions::kCssFilterId,
462+
hasher()->Hash(kMinCss), "a.css", "css");
463+
464+
// Cold load.
465+
ResponseHeaders response;
466+
GoogleString contents;
467+
ASSERT_TRUE(FetchResourceUrl(url, &request_headers, &contents, &response));
468+
EXPECT_TRUE(response.HasValue(HttpAttributes::kCacheControl, "public"));
469+
470+
// Warm load.
471+
response.Clear();
472+
ASSERT_TRUE(FetchResourceUrl(url, &request_headers, &contents, &response));
473+
EXPECT_TRUE(response.HasValue(HttpAttributes::kCacheControl, "public"));
474+
}
475+
442476
// Extension of above with cache invalidation.
443477
TEST_F(RewriteDriverTest, TestCacheUseWithInvalidation) {
444478
AddFilter(RewriteOptions::kRewriteCss);

net/instaweb/rewriter/rewrite_test_base.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ void RewriteTestBase::DefaultResponseHeaders(
475475
ResponseHeaders* response_headers) {
476476
SetDefaultLongCacheHeaders(&content_type, response_headers);
477477
response_headers->SetDateAndCaching(
478-
timer()->NowMs(), ttl_sec * Timer::kSecondMs, ", public");
478+
timer()->NowMs(), ttl_sec * Timer::kSecondMs);
479479
response_headers->ComputeCaching();
480480
}
481481

net/instaweb/rewriter/server_context.cc

+11-3
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,9 @@ void ServerContext::ApplyInputCacheControl(const ResourceVector& inputs,
445445
ResponseHeaders::kHasValidator);
446446

447447
bool browser_cacheable = headers->IsBrowserCacheable();
448-
bool no_store = headers->HasValue(HttpAttributes::kCacheControl,
449-
"no-store");
448+
bool no_store = headers->HasValue(HttpAttributes::kCacheControl, "no-store");
449+
bool is_public = true; // Only used if we see a non-empty resource.
450+
bool saw_nonempty_resource = false;
450451
int64 max_age = headers->cache_ttl_ms();
451452
for (int i = 0, n = inputs.size(); i < n; ++i) {
452453
const ResourcePtr& input_resource(inputs[i]);
@@ -464,11 +465,18 @@ void ServerContext::ApplyInputCacheControl(const ResourceVector& inputs,
464465
browser_cacheable &= input_headers->IsBrowserCacheable();
465466
no_store |= input_headers->HasValue(HttpAttributes::kCacheControl,
466467
"no-store");
468+
is_public &= input_headers->HasValue(HttpAttributes::kCacheControl,
469+
"public");
470+
saw_nonempty_resource = true;
467471
}
468472
}
469473
DCHECK(!(proxy_cacheable && !browser_cacheable)) <<
470474
"You can't have a proxy-cacheable result that is not browser-cacheable";
471-
if (!proxy_cacheable) {
475+
if (proxy_cacheable) {
476+
if (is_public && saw_nonempty_resource) {
477+
headers->SetCacheControlPublic();
478+
}
479+
} else {
472480
const char* directives = NULL;
473481
if (browser_cacheable) {
474482
directives = ",private";

0 commit comments

Comments
 (0)