| /* |
| * Copyright 2012 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: matterbury@google.com (Matt Atterbury) |
| |
| #include "net/instaweb/public/global_constants.h" |
| #include "net/instaweb/rewriter/public/local_storage_cache_filter.h" |
| #include "net/instaweb/rewriter/public/rewrite_driver.h" |
| #include "net/instaweb/rewriter/public/rewrite_options.h" |
| #include "net/instaweb/rewriter/public/rewrite_test_base.h" |
| #include "net/instaweb/rewriter/public/server_context.h" |
| #include "net/instaweb/rewriter/public/static_asset_manager.h" |
| #include "pagespeed/kernel/base/gtest.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| #include "pagespeed/kernel/html/html_parse_test_base.h" |
| #include "pagespeed/kernel/http/content_type.h" |
| #include "pagespeed/kernel/http/http_names.h" |
| #include "pagespeed/kernel/http/request_headers.h" |
| |
| namespace net_instaweb { |
| |
| namespace { |
| |
| // Filenames of resource files. |
| const char kJunkCssFilename[] = "http://example.com/junk.css"; // NOT test.com |
| const char kStylesCssFilename[] = "styles.css"; |
| const char kCuppaPngFilename[] = "Cuppa.png"; |
| const char kPuzzleJpgFilename[] = "Puzzle.jpg"; |
| |
| // Contents of resource files. |
| const char kJunkCssContents[] = |
| "@import url(junk://junk.com);"; |
| const char kStylesCssContents[] = |
| ".background_cyan{background-color:#0ff}" |
| ".foreground_pink{color:#ffc0cb}"; |
| const char kCuppaPngInlineData[] = |
| "data:image/png;base64,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"; |
| const char kCuppaPng30sqInlineData[] = |
| "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAAAAAAeW/F+AAABLU" |
| "lEQVQoz2P4jxcwUEv6z4H//99u+/7/1U2s0pv0//+tMP74vzUbm/Qvm6D/TyRj/v3XzsIm/U" |
| "iy+P8Zxtz/f1nzsUl/VdH/91xe681/G9U32OyOYbz0N4tx+f/FzIuxSc9m7Pm/nSHx3wOGYm" |
| "zScxnn/N/M0PR/O+sqbNIJUh/+psjf/x/o8R2L9De19f9faK//f0fmHjaX/5vy4//z5t//7y" |
| "3ECNTXxyDg6CEQAcTHPyBLr2FAB72rTv2ES+/DkFZ3NCz4DZO+hCF94fd1jRsw6W8saLIyH/" |
| "+/MbsEd7kmmrTfr38bTN7DpQvRpCf+WyYzG+HvSxyo0k56egv/IaT/1DAiSXKlrjv1HSXUPq" |
| "Uxw2XZp/zGCNR/m+WhsvpbsCbFi7Mg4BUtsgEZ0gD3t6kusa+ehQAAAABJRU5ErkJggg=="; |
| const char kCuppaPng150sqInlineData[] = |
| "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAABGCAAAAAC2maYhAAACyU" |
| "lEQVRYw+3XXWjVdRzH8ffZXE5wK4T0SnFCzJYXSlghofiADwQmEyy6G01KSBEKDNMlgXMYyI" |
| "aRj3SRESlOnIweoDJR1FLQkEQsrTnFqQg+rrkdz7uLc86F+j/n/H4EQbjvze/m/3vx//8ePl" |
| "/++G+LQeFxED7vyI4dH3Wq2tWSjhOOMVvVsxW8r2oTh6OEzIvUq7oAvlDNjGN9lLAP3lM9nY" |
| "KTqj/BO1HCy/CZ6mKoSqu+BR/GCL8DZ9RMNcxU9XlojxH2QLXqH0CDaroSDsUIrVB+V+0Cpq" |
| "r2lcMnMUIn8L3qaBh6VbUOpsQI3cBi1TeAZtVV5DYldC9GwIh+9RtgzH21qwzejhEWAd9mDx" |
| "J0qs6FqtsRQgfQqLoSeFX1K+DLCOEiMFr1F+DJ/NKsiLkXwyD1t3oL4JJ6G1gWczfHAldVn4" |
| "Bh93IvszPmHSqhRvU8MEN1G5RfjhD+ApbnF3BD7q4tjdnNjTD0ouo8qLunnoBRN2KEabBS9c" |
| "8UqYOqDbAj5lRfKaO2T/XT3EnsqmB+VNKegt2q1lN7J/tVT/dECTeZlFF1PD+rup6tkWn/Qi" |
| "5O5r2SHXc92x8pDORDvzs79nb/Vz1r+wcBtfpYEWE6IbWuiDA/SGje39qy5Vqy0EBwVTf3Jg" |
| "nvBgPlMD1JWBs0e8mPZ65nGuFogrApSDiiOlDDwgRhdwhQdlfV1UxMEH4LEWqzz37M5AShvy" |
| "JAeD37bFu+Cz54qp8LEFryGfRmkvBa6EJ6EA4kCetKA0+lVS/XUZNJEs6WFupVLzwDm5Nv9+" |
| "SSwibtaxsJSwrkQ2tJ4bv2pjHAnIECQs+QoGM5YUe6YEY1lZxdNbFhf7GUG3ip6PSpe3tK5u" |
| "S5qiJXoi0oafdWFhQ2BGb10bGFgiE47W81Jn7CmvsR/aJ9+CPArF/jOs7XqYeA5dE96/gPD1" |
| "bv4P/moPC/Ef4BwgJ0BoZbWwQAAAAASUVORK5CYII="; |
| |
| class LocalStorageCacheTest : public RewriteTestBase, |
| public ::testing::WithParamInterface<bool> { |
| protected: |
| virtual void SetUp() { |
| RewriteTestBase::SetUp(); |
| MySetUp(); |
| } |
| |
| void MySetUp() { |
| options()->EnableFilter(RewriteOptions::kInlineCss); |
| options()->EnableFilter(RewriteOptions::kInlineImages); |
| options()->EnableFilter(RewriteOptions::kLocalStorageCache); |
| options()->set_image_inline_max_bytes(2000); |
| rewrite_driver()->AddFilters(); |
| |
| SetResponseWithDefaultHeaders(kJunkCssFilename, kContentTypeCss, |
| kJunkCssContents, 100); |
| SetResponseWithDefaultHeaders(kStylesCssFilename, kContentTypeCss, |
| kStylesCssContents, 100); |
| AddFileToMockFetcher(StrCat(kTestDomain, kCuppaPngFilename), |
| kCuppaPngFilename, kContentTypePng, 100); |
| AddFileToMockFetcher(StrCat(kTestDomain, kPuzzleJpgFilename), |
| kPuzzleJpgFilename, kContentTypeJpeg, 100); |
| StaticAssetManager* static_asset_manager = |
| server_context()->static_asset_manager(); |
| local_storage_cache_js_ = |
| StrCat("<script type=\"text/javascript\" data-pagespeed-no-defer>" |
| "//<![CDATA[\n", |
| static_asset_manager->GetAsset( |
| StaticAssetEnum::LOCAL_STORAGE_CACHE_JS, options()), |
| LocalStorageCacheFilter::kLscInitializer, |
| "\n//]]></script>"); |
| } |
| |
| void TestLocalStorage(const StringPiece& case_id, |
| const GoogleString& head_html_in, |
| const GoogleString& head_html_out, |
| const GoogleString& body_html_in, |
| const GoogleString& body_html_out) { |
| const char kInWrapperFormat[] = |
| "<head>\n" |
| " <title>Local Storage Cache Test</title>\n" |
| "%s" |
| "</head>\n" |
| "<body>\n" |
| "%s" |
| "</body>\n"; |
| const GoogleString out_wrapper_format = StrCat( |
| "<head>\n" |
| " <title>Local Storage Cache Test</title>\n" |
| "%s" |
| "</head>\n" |
| "<body>", |
| kNoScriptRedirectFormatter, "\n" |
| "%s" |
| "</body>\n"); |
| |
| GoogleString url = StrCat( |
| "http://test.com/", case_id, ".html?PageSpeed=noscript"); |
| |
| GoogleString html_in(StringPrintf( |
| kInWrapperFormat, head_html_in.c_str(), body_html_in.c_str())); |
| GoogleString html_out(StringPrintf( |
| out_wrapper_format.c_str(), head_html_out.c_str(), url.c_str(), |
| url.c_str(), body_html_out.c_str())); |
| |
| // Clear request_headers and set them afresh for every test. |
| ClearRewriteDriver(); |
| rewrite_driver()->SetRequestHeaders(request_headers_); |
| |
| Parse(case_id, html_in); |
| GoogleString expected_out = doctype_string_ + AddHtmlBody(html_out); |
| |
| EXPECT_EQ(expected_out, output_buffer_) << "Test id:" << case_id; |
| output_buffer_.clear(); |
| } |
| |
| GoogleString InsertScriptBefore(const StringPiece& snippet) const { |
| return StrCat(local_storage_cache_js_, snippet); |
| } |
| |
| RequestHeaders request_headers_; |
| GoogleString local_storage_cache_js_; |
| }; |
| |
| TEST_F(LocalStorageCacheTest, Simple) { |
| TestLocalStorage("simple", "", "", "<div/>", "<div/>"); |
| } |
| |
| TEST_F(LocalStorageCacheTest, Link) { |
| TestLocalStorage( |
| "link", |
| "<link rel='stylesheet' href='styles.css'>", |
| InsertScriptBefore( |
| "<style " |
| "data-pagespeed-lsc-url=\"http://test.com/styles.css\" " |
| "data-pagespeed-lsc-hash=\"0\" " |
| "data-pagespeed-lsc-expiry=\"Tue, 02 Feb 2010 18:53:06 GMT\">" |
| ".background_cyan{background-color:#0ff}" |
| ".foreground_pink{color:#ffc0cb}" |
| "</style>"), |
| "<div/>", "<div/>"); |
| } |
| |
| TEST_F(LocalStorageCacheTest, LinkRewriteContextNotExecuted) { |
| // The domains are different so the RewriteContext is never kicked off, |
| // which should result in no local storage cache changes at all. |
| TestLocalStorage("link_rewrite_context_not_executed", |
| "<link rel='stylesheet' href='http://example.com/junk.css'>", |
| "<link rel='stylesheet' href='http://example.com/junk.css'>", |
| "<div/>", "<div/>"); |
| } |
| |
| TEST_F(LocalStorageCacheTest, LinkUrlTransormationFails) { |
| // The CSS rewriting fails so the local storage cache attributes are omitted |
| // but because the CSS rewriting is asynchronous we still insert the JS even |
| // though it ends up not being used. C'est la vie! |
| AddDomain("example.com"); |
| TestLocalStorage("link_url_transormation_fails", |
| "<link rel='stylesheet' href='http://example.com/junk.css'>", |
| InsertScriptBefore( |
| "<link rel='stylesheet' " |
| "href='http://example.com/junk.css'>"), |
| "<div/>", "<div/>"); |
| } |
| |
| class LocalStorageCacheTinyTest : public LocalStorageCacheTest { |
| protected: |
| virtual void SetUp() { |
| RewriteTestBase::SetUp(); |
| options()->set_css_inline_max_bytes(10); // An arbitrary tiny value. |
| MySetUp(); |
| } |
| }; |
| |
| TEST_F(LocalStorageCacheTinyTest, LinkDontInline) { |
| // The CSS inlining fails because we've turned the limit down low. We expect |
| // no LSC attributes in the result but because the CSS rewriting is |
| // asynchronous we still insert the JS even though it ends up not being used. |
| TestLocalStorage("link_dont_inline", |
| "<link rel='stylesheet' href='styles.css'>", |
| InsertScriptBefore( |
| "<link rel='stylesheet' href='styles.css'>"), |
| "<div/>", "<div/>"); |
| } |
| |
| TEST_F(LocalStorageCacheTest, Img) { |
| TestLocalStorage("img", "", "", |
| StrCat("<img src='", kCuppaPngFilename, "'>"), |
| InsertScriptBefore( |
| StrCat("<img src='", kCuppaPngInlineData, |
| "' data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kCuppaPngFilename, "\"" |
| " data-pagespeed-lsc-hash=\"0\"" |
| " data-pagespeed-lsc-expiry=" |
| "\"Tue, 02 Feb 2010 18:53:06 GMT\"" |
| ">"))); |
| } |
| |
| TEST_F(LocalStorageCacheTest, ImgTooBig) { |
| TestLocalStorage("img_too_big", "", "", |
| StrCat("<img src='", kPuzzleJpgFilename, "'>"), |
| InsertScriptBefore( |
| StrCat("<img src='", kPuzzleJpgFilename, "'>"))); |
| } |
| |
| TEST_F(LocalStorageCacheTest, ImgLocalStorageDisabled) { |
| options()->ClearSignatureForTesting(); |
| // Enabling another filter that triggers the NOSCRIPT tag-insertion in HTML. |
| options()->EnableFilter(RewriteOptions::kDeferIframe); |
| options()->DisableFilter(RewriteOptions::kLocalStorageCache); |
| options()->set_in_place_rewriting_enabled(true); |
| server_context()->ComputeSignature(options()); |
| |
| TestLocalStorage("img_local_storage_disabled", "", "", |
| StrCat("<img src='", kPuzzleJpgFilename, "'>"), |
| StrCat("<img src='", kPuzzleJpgFilename, "'>")); |
| } |
| |
| TEST_F(LocalStorageCacheTest, CookieSet) { |
| // The 2 hash values are Fe1SLPZ14c and du_OhARrJl. Only suppress the first. |
| UseMd5Hasher(); |
| GoogleString cookie = StrCat(LocalStorageCacheFilter::kLscCookieName, |
| "=Fe1SLPZ14c"); |
| request_headers_.Add(HttpAttributes::kCookie, cookie); |
| TestLocalStorage("cookie_set", |
| StrCat("<link rel='stylesheet' href='", |
| kStylesCssFilename, |
| "'>"), |
| InsertScriptBefore( |
| StrCat("<script data-pagespeed-no-defer>" |
| "pagespeed.localStorageCache.inlineCss(" |
| "\"", kTestDomain, kStylesCssFilename, "\"" |
| ");</script>")), |
| StrCat("<img src='", kCuppaPngFilename, "'>"), |
| StrCat("<img src='", kCuppaPngInlineData, |
| "' data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kCuppaPngFilename, "\"" |
| " data-pagespeed-lsc-hash=\"du_OhARrJl\"" |
| " data-pagespeed-lsc-expiry=" |
| "\"Tue, 02 Feb 2010 18:53:06 GMT\"" |
| ">")); |
| } |
| |
| TEST_F(LocalStorageCacheTest, RepeatViews) { |
| // The 2 hash values are Fe1SLPZ14c (CSS) and du_OhARrJl (image). |
| UseMd5Hasher(); |
| |
| GoogleString css = StrCat("<link rel='stylesheet' href='", |
| kStylesCssFilename, |
| "'>"); |
| GoogleString img = StrCat("<img src='", kCuppaPngFilename, "'>"); |
| |
| // First view shouldn't rewrite anything though lsc_url attributes are added. |
| // Don't rewrite because in the real world the fetch and processing of the |
| // resource could take longer than the rewriting timeout, and we want to |
| // simulate that here. We redo it below with the rewriting completing in time. |
| GoogleString external_css = StrCat("<link rel='stylesheet' href=" |
| "'", kStylesCssFilename, "'" |
| " data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kStylesCssFilename, "\"" |
| ">"); |
| GoogleString external_img = StrCat("<img src=" |
| "'", kCuppaPngFilename, "'" |
| " data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kCuppaPngFilename, "\"" |
| ">"); |
| SetupWaitFetcher(); |
| TestLocalStorage("first_view", |
| css, InsertScriptBefore(external_css), |
| img, external_img); |
| CallFetcherCallbacks(); |
| |
| // Second view will inline them both and add an expiry to both. |
| GoogleString inlined_css = StrCat("<style data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kStylesCssFilename, "\"" |
| " data-pagespeed-lsc-hash=\"Fe1SLPZ14c\"" |
| " data-pagespeed-lsc-expiry=" |
| "\"Tue, 02 Feb 2010 18:53:06 GMT\"" |
| ">", |
| kStylesCssContents, |
| "</style>"); |
| GoogleString inlined_img = StrCat("<img src='", kCuppaPngInlineData, |
| "' data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kCuppaPngFilename, "\"" |
| " data-pagespeed-lsc-hash=\"du_OhARrJl\"" |
| " data-pagespeed-lsc-expiry=" |
| "\"Tue, 02 Feb 2010 18:53:06 GMT\"" |
| ">"); |
| TestLocalStorage("second_view", |
| css, InsertScriptBefore(inlined_css), |
| img, inlined_img); |
| |
| // The JavaScript would set these cookies for the next request. |
| GoogleString cookie = StrCat(LocalStorageCacheFilter::kLscCookieName, |
| "=", "Fe1SLPZ14c", "!", "du_OhARrJl"); |
| request_headers_.Add(HttpAttributes::kCookie, cookie); |
| |
| // Third view will not send the inlined data and will send scripts in place |
| // of the link and img elements. |
| GoogleString scripted_css = StrCat("<script data-pagespeed-no-defer>" |
| "pagespeed.localStorageCache.inlineCss(" |
| "\"", kTestDomain, kStylesCssFilename, "\"" |
| ");</script>"); |
| GoogleString scripted_img = StrCat("<script data-pagespeed-no-defer>" |
| "pagespeed.localStorageCache.inlineImg(" |
| "\"", kTestDomain, kCuppaPngFilename, "\"" |
| ", \"du_OhARrJl\");</script>"); |
| TestLocalStorage("third_view", |
| css, InsertScriptBefore(scripted_css), |
| img, scripted_img); |
| } |
| |
| TEST_F(LocalStorageCacheTest, RepeatViewsWithOtherAttributes) { |
| // The 2 hash values are Fe1SLPZ14c (CSS) and du_OhARrJl (image). |
| UseMd5Hasher(); |
| |
| GoogleString css = StrCat("<link rel='stylesheet' href='", |
| kStylesCssFilename, |
| "'>"); |
| GoogleString img = StrCat("<img src='", kCuppaPngFilename, "'" |
| " alt='A cup of joe'" |
| " alt=\"A cup of joe\"" |
| " alt='A cup of joe's \"joe\"'" |
| " alt=\"A cup of joe's "joe"\">"); |
| |
| // First view shouldn't rewrite anything though lsc_url attributes are added. |
| // Don't rewrite because in the real world the fetch and processing of the |
| // resource could take longer than the rewriting timeout, and we want to |
| // simulate that here. We redo it below with the rewriting completing in time. |
| GoogleString external_css = StrCat("<link rel='stylesheet' href=" |
| "'", kStylesCssFilename, "'" |
| " data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kStylesCssFilename, "\"" |
| ">"); |
| GoogleString external_img = StrCat("<img src=" |
| "'", kCuppaPngFilename, "'" |
| " alt='A cup of joe'" |
| " alt=\"A cup of joe\"" |
| " alt='A cup of joe's \"joe\"'" |
| " alt=\"A cup of joe's "joe"\"" |
| " data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kCuppaPngFilename, "\"" |
| ">"); |
| SetupWaitFetcher(); |
| TestLocalStorage("first_view", |
| css, InsertScriptBefore(external_css), |
| img, external_img); |
| CallFetcherCallbacks(); |
| |
| // Second view will inline them both and add an expiry to both. |
| GoogleString inlined_css = StrCat("<style" |
| " data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kStylesCssFilename, "\"" |
| " data-pagespeed-lsc-hash=\"Fe1SLPZ14c\"" |
| " data-pagespeed-lsc-expiry=" |
| "\"Tue, 02 Feb 2010 18:53:06 GMT\"" |
| ">", |
| kStylesCssContents, |
| "</style>"); |
| GoogleString inlined_img = StrCat("<img src='", kCuppaPngInlineData, "'" |
| " alt='A cup of joe'" |
| " alt=\"A cup of joe\"" |
| " alt='A cup of joe's \"joe\"'" |
| " alt=\"A cup of joe's "joe"\"" |
| " data-pagespeed-lsc-url=" |
| "\"", kTestDomain, kCuppaPngFilename, "\"" |
| " data-pagespeed-lsc-hash=\"du_OhARrJl\"" |
| " data-pagespeed-lsc-expiry=" |
| "\"Tue, 02 Feb 2010 18:53:06 GMT\"" |
| ">"); |
| TestLocalStorage("second_view", |
| css, InsertScriptBefore(inlined_css), |
| img, inlined_img); |
| |
| // The JavaScript would set these cookies for the next request. |
| GoogleString cookie = StrCat(LocalStorageCacheFilter::kLscCookieName, |
| "=", "Fe1SLPZ14c", "!", "du_OhARrJl"); |
| request_headers_.Add(HttpAttributes::kCookie, cookie); |
| |
| // Third view will not send the inlined data and will send scripts in place |
| // of the link and img elements. |
| GoogleString scripted_css = StrCat("<script data-pagespeed-no-defer>" |
| "pagespeed.localStorageCache.inlineCss(" |
| "\"", kTestDomain, kStylesCssFilename, "\"" |
| ");</script>"); |
| GoogleString scripted_img = StrCat("<script data-pagespeed-no-defer>" |
| "pagespeed.localStorageCache.inlineImg(" |
| "\"", kTestDomain, kCuppaPngFilename, "\"" |
| ", \"du_OhARrJl\"" |
| ", \"alt=A cup of joe\"" |
| ", \"alt=A cup of joe\"" |
| ", \"alt=A cup of joe\\'s \\\"joe\\\"\"" |
| ", \"alt=A cup of joe\\'s \\\"joe\\\"\"" |
| ");</script>"); |
| TestLocalStorage("third_view", |
| css, InsertScriptBefore(scripted_css), |
| img, scripted_img); |
| } |
| |
| TEST_F(LocalStorageCacheTest, RepeatViewsOfSameImageAtDifferentSizes) { |
| // Enable "rewrite_images" so that the first instance of the image is |
| // rescaled. |
| options()->ClearSignatureForTesting(); |
| options()->EnableFilter(RewriteOptions::kConvertGifToPng); |
| options()->EnableFilter(RewriteOptions::kConvertJpegToProgressive); |
| options()->EnableFilter(RewriteOptions::kInlineImages); |
| options()->EnableFilter(RewriteOptions::kJpegSubsampling); |
| options()->EnableFilter(RewriteOptions::kRecompressJpeg); |
| options()->EnableFilter(RewriteOptions::kRecompressPng); |
| options()->EnableFilter(RewriteOptions::kRecompressWebp); |
| options()->EnableFilter(RewriteOptions::kResizeImages); |
| options()->EnableFilter(RewriteOptions::kStripImageColorProfile); |
| options()->EnableFilter(RewriteOptions::kStripImageMetaData); |
| server_context()->ComputeSignature(options()); |
| |
| UseMd5Hasher(); |
| const char kHash30x30[] = "07FPv8sBor"; |
| const char kHash150x150[] = "jSr1gEyima"; |
| |
| GoogleString imgs = StrCat("<img src='", kCuppaPngFilename, "'" |
| "width=\"30\" height=\"30\">" |
| "<img src='", kCuppaPngFilename, "'" |
| "width=\"150\" height=\"150\">"); |
| |
| // First view shouldn't rewrite anything though lsc_url attributes are added. |
| // Don't rewrite because in the real world the fetch and processing of the |
| // resource could take longer than the rewriting timeout, and we want to |
| // simulate that here. We redo it below with the rewriting completing in time. |
| GoogleString external_imgs = |
| StrCat("<img src='", kCuppaPngFilename, "'" |
| " width=\"30\" height=\"30\"" |
| " data-pagespeed-lsc-url=""\"", |
| kTestDomain, kCuppaPngFilename, "\">", |
| "<img src='", kCuppaPngFilename, "'" |
| " width=\"150\" height=\"150\"" |
| " data-pagespeed-lsc-url=\"", |
| kTestDomain, kCuppaPngFilename, "\">"); |
| |
| SetupWaitFetcher(); |
| TestLocalStorage("first_view", "", "", |
| imgs, InsertScriptBefore(external_imgs)); |
| CallFetcherCallbacks(); |
| |
| // Second view will inline them and add an expiry. |
| GoogleString inlined_imgs = |
| StrCat("<img src='", kCuppaPng30sqInlineData, "'" |
| // This is dropped; see below for why. |
| // " width=\"30\" height=\"30\"" |
| " data-pagespeed-lsc-url=\"", |
| kTestDomain, kCuppaPngFilename, "\"" |
| " data-pagespeed-lsc-hash=\"", kHash30x30, "\"" |
| " data-pagespeed-lsc-expiry=" |
| "\"Tue, 02 Feb 2010 18:53:06 GMT\">", |
| "<img src='", kCuppaPng150sqInlineData, "'" |
| " width=\"150\" height=\"150\"" |
| " data-pagespeed-lsc-url=\"", |
| kTestDomain, kCuppaPngFilename, "\"" |
| " data-pagespeed-lsc-hash=\"", kHash150x150, "\"" |
| " data-pagespeed-lsc-expiry=" |
| "\"Tue, 02 Feb 2010 18:53:06 GMT\">"); |
| // NOTE: Why are width=30 and height=30 dropped from the first img tag? |
| // Because the image rewriter calls DeleteMatchingImageDimsAfterInline for |
| // each inlined image, and at this point the cached version of Cuppa.png is |
| // the 30x30 version, so the attributes are stripped, but the 150x150 version |
| // is different so its attributes are kept. |
| // TODO(matterbury): Work out if the image rewriter needs to be smarter about |
| // cached versions on inline images in this situation: same image, inlined |
| // at different resolutions. |
| TestLocalStorage("second_view", "", "", |
| imgs, InsertScriptBefore(inlined_imgs)); |
| |
| // The JavaScript would set this cookie for the next request. |
| GoogleString cookie = StrCat(LocalStorageCacheFilter::kLscCookieName, |
| "=", kHash30x30, "!", kHash150x150); |
| request_headers_.Add(HttpAttributes::kCookie, cookie); |
| |
| // Third view will not send the inlined data and will send scripts in place |
| // of the link and img elements. |
| GoogleString scripted_imgs = |
| StrCat("<script data-pagespeed-no-defer>" |
| "pagespeed.localStorageCache.inlineImg(" |
| "\"", kTestDomain, kCuppaPngFilename, |
| "\", \"", kHash30x30, "\"" |
| ", \"width=30\", \"height=30\"" |
| ");</script>", |
| "<script data-pagespeed-no-defer>" |
| "pagespeed.localStorageCache.inlineImg(" |
| "\"", kTestDomain, kCuppaPngFilename, |
| "\", \"", kHash150x150, "\"" |
| ", \"width=150\", \"height=150\"" |
| ");</script>"); |
| TestLocalStorage("third_view", "", "", |
| imgs, InsertScriptBefore(scripted_imgs)); |
| } |
| |
| } // namespace |
| |
| } // namespace net_instaweb |