Skip to content
This repository has been archived by the owner on Apr 21, 2023. It is now read-only.

Commit

Permalink
url-valued-attributes: support css
Browse files Browse the repository at this point in the history
Fixes #1324

system-test: fix 'url-valued stylesheet attributes' flake

Fixes #1356

rm range based loops for c++98 compatibility in branch 33
  • Loading branch information
jeffkaufman authored and crowell committed Jul 21, 2016
1 parent 0654743 commit 59a1982
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 60 deletions.
5 changes: 5 additions & 0 deletions install/debug.conf.template
Expand Up @@ -647,6 +647,11 @@ NameVirtualHost localhost:@@APACHE_SECONDARY_PORT@@
ModPagespeedUrlValuedAttribute video alt-b Image ModPagespeedUrlValuedAttribute video alt-b Image
ModPagespeedUrlValuedAttribute video alt-b Image ModPagespeedUrlValuedAttribute video alt-b Image


ModPagespeedUrlValuedAttribute link data-stylesheet Stylesheet
ModPagespeedUrlValuedAttribute span data-stylesheet-a Stylesheet
ModPagespeedUrlValuedAttribute span data-stylesheet-b Stylesheet
ModPagespeedUrlValuedAttribute span data-stylesheet-c Stylesheet

# Also test that we can redefine spec-defined attributes. # Also test that we can redefine spec-defined attributes.
ModPagespeedUrlValuedAttribute blockquote cite Image ModPagespeedUrlValuedAttribute blockquote cite Image
</VirtualHost> </VirtualHost>
Expand Down
26 changes: 26 additions & 0 deletions install/mod_pagespeed_test/url_valued_attribute_css.html
@@ -0,0 +1,26 @@
<!-- this should get inlined -->
<link rel=stylesheet href="../mod_pagespeed_example/styles/bold.css">

<!-- these should get rewritten in-place -->
<link data-stylesheet="../mod_pagespeed_example/styles/bold.css">
<span data-stylesheet-a="../mod_pagespeed_example/styles/bold.css"
data-stylesheet-b="../mod_pagespeed_example/styles/bold.css"
data-stylesheet-c="../mod_pagespeed_example/styles/bold.css"></span>

<!-- this should still get rewritten in-place -->
<link rel=invalid data-stylesheet="../mod_pagespeed_example/styles/bold.css">

<!-- this should get inlined, and data-stylesheet rewritten in-place -->
<link rel=stylesheet
href="../mod_pagespeed_example/styles/bold.css"
data-stylesheet="../mod_pagespeed_example/styles/bold.css">

<!-- javascript to give a combining barrier -->
<script src="this-doesnt-exist.js"></script>

<!-- combining should treat span/data-stylesheet-a as a barrier -->
<link rel=stylesheet href="../mod_pagespeed_example/styles/blue.css">
<span data-stylesheet-a="../mod_pagespeed_example/styles/bold.css"></span>
<link rel=stylesheet href="../mod_pagespeed_example/styles/yellow.css">


15 changes: 15 additions & 0 deletions net/instaweb/rewriter/css_combine_filter.cc
Expand Up @@ -34,6 +34,7 @@
#include "net/instaweb/rewriter/public/resource.h" #include "net/instaweb/rewriter/public/resource.h"
#include "net/instaweb/rewriter/public/resource_combiner.h" #include "net/instaweb/rewriter/public/resource_combiner.h"
#include "net/instaweb/rewriter/public/resource_slot.h" #include "net/instaweb/rewriter/public/resource_slot.h"
#include "net/instaweb/rewriter/public/resource_tag_scanner.h"
#include "net/instaweb/rewriter/public/rewrite_context.h" #include "net/instaweb/rewriter/public/rewrite_context.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h" #include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_filter.h" #include "net/instaweb/rewriter/public/rewrite_filter.h"
Expand Down Expand Up @@ -460,6 +461,20 @@ void CssCombineFilter::StartElementImpl(HtmlElement* element) {
if (!context_->AddElement(element, href)) { if (!context_->AddElement(element, href)) {
NextCombination("resource not rewritable"); NextCombination("resource not rewritable");
} }
} else {
// Treat custom UrlValuedAttributes as combining barriers.
resource_tag_scanner::UrlCategoryVector attributes;
// This includes checking for spec-defined ones, but any elements that would
// match spec-defined ones would have hit the ParseCssElement case above.
resource_tag_scanner::ScanElement(
element, driver()->options(), &attributes);
resource_tag_scanner::UrlCategoryVector::iterator uc;
for (uc = attributes.begin(); uc != attributes.end(); uc++) {
if (uc->category == semantic_type::kStylesheet) {
NextCombination("custom or alternate stylesheet attribute");
return;
}
}
} }
} }


Expand Down
100 changes: 54 additions & 46 deletions net/instaweb/rewriter/css_combine_filter_test.cc
Expand Up @@ -451,15 +451,15 @@ class CssCombineFilterTest : public RewriteTestBase {
StringVector *css_urls) { StringVector *css_urls) {
// Put original CSS files into our fetcher. // Put original CSS files into our fetcher.
GoogleString html_url = StrCat(kDomain, "base_url.html"); GoogleString html_url = StrCat(kDomain, "base_url.html");
const char a_css_url[] = "http://other_domain.test/foo/a.css"; static const char kACssUrl[] = "http://other_domain.test/foo/a.css";
const char b_css_url[] = "http://other_domain.test/foo/b.css"; static const char kBCssUrl[] = "http://other_domain.test/foo/b.css";
const char c_css_url[] = "http://other_domain.test/foo/c.css"; static const char kCCssUrl[] = "http://other_domain.test/foo/c.css";


ResponseHeaders default_css_header; ResponseHeaders default_css_header;
SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header); SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header);
SetFetchResponse(a_css_url, default_css_header, kACssBody); SetFetchResponse(kACssUrl, default_css_header, kACssBody);
SetFetchResponse(b_css_url, default_css_header, kBCssBody); SetFetchResponse(kBCssUrl, default_css_header, kBCssBody);
SetFetchResponse(c_css_url, default_css_header, kCCssBody); SetFetchResponse(kCCssUrl, default_css_header, kCCssBody);


// Rewrite // Rewrite
ParseUrl(html_url, html_input); ParseUrl(html_url, html_input);
Expand Down Expand Up @@ -499,8 +499,8 @@ class CssCombineFilterTest : public RewriteTestBase {
AddDomain("a.com"); AddDomain("a.com");
AddDomain("b.com"); AddDomain("b.com");
bool supply_mock = false; bool supply_mock = false;
const char kUrl1[] = "http://a.com/1.css"; static const char kUrl1[] = "http://a.com/1.css";
const char kUrl2[] = "http://b.com/2.css"; static const char kUrl2[] = "http://b.com/2.css";
css_in.Add(kUrl1, kYellow, "", supply_mock); css_in.Add(kUrl1, kYellow, "", supply_mock);
css_in.Add(kUrl2, kBlue, "", supply_mock); css_in.Add(kUrl2, kBlue, "", supply_mock);
ResponseHeaders default_css_header; ResponseHeaders default_css_header;
Expand Down Expand Up @@ -769,62 +769,70 @@ TEST_F(CssCombineFilterWithDebugTest, IEDirectiveBarrier) {


TEST_F(CssCombineFilterTest, StyleBarrier) { TEST_F(CssCombineFilterTest, StyleBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char style_barrier[] = "<style>a { color: red }</style>\n"; static const char kStyleBarrier[] = "<style>a { color: red }</style>\n";
UseMd5Hasher(); UseMd5Hasher();
CombineCss("combine_css_style", style_barrier, "", true); CombineCss("combine_css_style", kStyleBarrier, "", true);
} }


TEST_F(CssCombineFilterWithDebugTest, StyleBarrier) { TEST_F(CssCombineFilterWithDebugTest, StyleBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char style_barrier[] = "<style>a { color: red }</style>\n"; static const char kStyleBarrier[] = "<style>a { color: red }</style>\n";
UseMd5Hasher(); UseMd5Hasher();
CombineCss("combine_css_style", style_barrier, CombineCss("combine_css_style", kStyleBarrier,
"<!--combine_css: Could not combine over barrier: inline style-->", "<!--combine_css: Could not combine over barrier: inline style-->",
true); true);
} }


TEST_F(CssCombineFilterTest, BogusLinkBarrier) { TEST_F(CssCombineFilterTest, BogusLinkBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char bogus_barrier[] = "<link rel='stylesheet' " static const char kBogusBarrier[] = "<link rel='stylesheet' "
"href='crazee://big/blue/fake' type='text/css'>\n"; "href='crazee://big/blue/fake' type='text/css'>\n";
UseMd5Hasher(); UseMd5Hasher();
CombineCss("combine_css_bogus_link", bogus_barrier, "", true); CombineCss("combine_css_bogus_link", kBogusBarrier, "", true);
} }


TEST_F(CssCombineFilterWithDebugTest, BogusLinkBarrier) { TEST_F(CssCombineFilterWithDebugTest, BogusLinkBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char bogus_barrier[] = "<link rel='stylesheet' " static const char kBogusBarrier[] = "<link rel='stylesheet' "
"href='crazee://big/blue/fake' type='text/css'>\n"; "href='crazee://big/blue/fake' type='text/css'>\n";
UseMd5Hasher(); UseMd5Hasher();
CombineCss("combine_css_bogus_link", bogus_barrier, CombineCss("combine_css_bogus_link", kBogusBarrier,
"<!--combine_css: Could not combine over barrier: " "<!--combine_css: Could not combine over barrier: "
"resource not rewritable-->", true); "resource not rewritable-->", true);
} }


TEST_F(CssCombineFilterTest, AlternateStylesheetBarrier) { TEST_F(CssCombineFilterTest, AlternateStylesheetBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char barrier[] = static const char kBarrier[] =
"<link rel='alternate stylesheet' type='text/css' href='a.css'>";
UseMd5Hasher();
CombineCss("alternate_stylesheet_barrier", kBarrier, "", true);
}

TEST_F(CssCombineFilterWithDebugTest, AlternateStylesheetBarrier) {
SetHtmlMimetype();
static const char kBarrier[] =
"<link rel='alternate stylesheet' type='text/css' href='a.css'>"; "<link rel='alternate stylesheet' type='text/css' href='a.css'>";
UseMd5Hasher(); UseMd5Hasher();
// TODO(sligocki): This should actually be a barrier: s/false/true/ CombineCss("alternate_stylesheet_barrier", kBarrier,
// Add CssCombineFilterWithDebugTest version as well when it is. "<!--combine_css: Could not combine over barrier: "
CombineCss("alternate_stylesheet_barrier", barrier, "", false); "custom or alternate stylesheet attribute-->", true);
} }


TEST_F(CssCombineFilterTest, NonStandardAttributesBarrier) { TEST_F(CssCombineFilterTest, NonStandardAttributesBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char barrier[] = static const char kBarrier[] =
"<link rel='stylesheet' type='text/css' href='a.css' foo='bar'>"; "<link rel='stylesheet' type='text/css' href='a.css' foo='bar'>";
UseMd5Hasher(); UseMd5Hasher();
CombineCss("non_standard_attributes_barrier", barrier, "", true); CombineCss("non_standard_attributes_barrier", kBarrier, "", true);
} }


TEST_F(CssCombineFilterWithDebugTest, NonStandardAttributesBarrier) { TEST_F(CssCombineFilterWithDebugTest, NonStandardAttributesBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char barrier[] = static const char kBarrier[] =
"<link rel='stylesheet' type='text/css' href='a.css' foo='bar'>"; "<link rel='stylesheet' type='text/css' href='a.css' foo='bar'>";
UseMd5Hasher(); UseMd5Hasher();
CombineCss("non_standard_attributes_barrier", barrier, CombineCss("non_standard_attributes_barrier", kBarrier,
"<!--combine_css: Could not combine over barrier: " "<!--combine_css: Could not combine over barrier: "
"potentially non-combinable attribute: &#39;foo&#39;-->", true); "potentially non-combinable attribute: &#39;foo&#39;-->", true);
} }
Expand Down Expand Up @@ -899,7 +907,7 @@ TEST_F(CssCombineFilterTest, StripBom) {


TEST_F(CssCombineFilterTest, StripBomReconstruct) { TEST_F(CssCombineFilterTest, StripBomReconstruct) {
// Make sure we strip the BOM properly when reconstructing, too. // Make sure we strip the BOM properly when reconstructing, too.
const char kCssText[] = "div {background-image:url(fancy.png);}"; static const char kCssText[] = "div {background-image:url(fancy.png);}";
SetResponseWithDefaultHeaders(kCssA, kContentTypeCss, SetResponseWithDefaultHeaders(kCssA, kContentTypeCss,
StrCat(kUtf8Bom, kCssText), StrCat(kUtf8Bom, kCssText),
300); 300);
Expand All @@ -916,45 +924,45 @@ TEST_F(CssCombineFilterTest, StripBomReconstruct) {


TEST_F(CssCombineFilterTest, CombineCssWithNoscriptBarrier) { TEST_F(CssCombineFilterTest, CombineCssWithNoscriptBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char noscript_barrier[] = static const char kNoscriptBarrier[] =
"<noscript>\n" "<noscript>\n"
" <link rel='stylesheet' href='d.css' type='text/css'>\n" " <link rel='stylesheet' href='d.css' type='text/css'>\n"
"</noscript>\n"; "</noscript>\n";


// Put this in the Test class to remove repetition here and below. // Put this in the Test class to remove repetition here and below.
GoogleString d_css_url = StrCat(kDomain, "d.css"); GoogleString d_css_url = StrCat(kDomain, "d.css");
const char d_css_body[] = ".c4 {\n color: green;\n}\n"; static const char kDCssBody[] = ".c4 {\n color: green;\n}\n";
ResponseHeaders default_css_header; ResponseHeaders default_css_header;
SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header); SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header);
SetFetchResponse(d_css_url, default_css_header, d_css_body); SetFetchResponse(d_css_url, default_css_header, kDCssBody);


UseMd5Hasher(); UseMd5Hasher();
CombineCss("combine_css_noscript", noscript_barrier, "", true); CombineCss("combine_css_noscript", kNoscriptBarrier, "", true);
} }


TEST_F(CssCombineFilterTest, CombineCssWithFakeNoscriptBarrier) { TEST_F(CssCombineFilterTest, CombineCssWithFakeNoscriptBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char non_barrier[] = static const char kNonBarrier[] =
"<noscript>\n" "<noscript>\n"
" <p>You have no scripts installed</p>\n" " <p>You have no scripts installed</p>\n"
"</noscript>\n"; "</noscript>\n";
UseMd5Hasher(); UseMd5Hasher();
CombineCss("combine_css_fake_noscript", non_barrier, "", false); CombineCss("combine_css_fake_noscript", kNonBarrier, "", false);
} }


TEST_F(CssCombineFilterTest, CombineCssWithMediaBarrier) { TEST_F(CssCombineFilterTest, CombineCssWithMediaBarrier) {
SetHtmlMimetype(); SetHtmlMimetype();
const char media_barrier[] = static const char kMediaBarrier[] =
"<link rel='stylesheet' href='d.css' type='text/css' media='print'>\n"; "<link rel='stylesheet' href='d.css' type='text/css' media='print'>\n";


GoogleString d_css_url = StrCat(kDomain, "d.css"); GoogleString d_css_url = StrCat(kDomain, "d.css");
const char d_css_body[] = ".c4 {\n color: green;\n}\n"; static const char kDCssBody[] = ".c4 {\n color: green;\n}\n";
ResponseHeaders default_css_header; ResponseHeaders default_css_header;
SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header); SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header);
SetFetchResponse(d_css_url, default_css_header, d_css_body); SetFetchResponse(d_css_url, default_css_header, kDCssBody);


UseMd5Hasher(); UseMd5Hasher();
CombineCss("combine_css_media", media_barrier, "", true); CombineCss("combine_css_media", kMediaBarrier, "", true);
} }


TEST_F(CssCombineFilterTest, CombineCssWithNonMediaBarrier) { TEST_F(CssCombineFilterTest, CombineCssWithNonMediaBarrier) {
Expand All @@ -967,14 +975,14 @@ TEST_F(CssCombineFilterTest, CombineCssWithNonMediaBarrier) {
GoogleString c_css_url = StrCat(kDomain, "c.css"); GoogleString c_css_url = StrCat(kDomain, "c.css");
GoogleString d_css_url = StrCat(kDomain, "d.css"); GoogleString d_css_url = StrCat(kDomain, "d.css");


const char d_css_body[] = ".c4 {\n color: green;\n}\n"; static const char kDCssBody[] = ".c4 {\n color: green;\n}\n";


ResponseHeaders default_css_header; ResponseHeaders default_css_header;
SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header); SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header);
SetFetchResponse(a_css_url, default_css_header, kACssBody); SetFetchResponse(a_css_url, default_css_header, kACssBody);
SetFetchResponse(b_css_url, default_css_header, kBCssBody); SetFetchResponse(b_css_url, default_css_header, kBCssBody);
SetFetchResponse(c_css_url, default_css_header, kCCssBody); SetFetchResponse(c_css_url, default_css_header, kCCssBody);
SetFetchResponse(d_css_url, default_css_header, d_css_body); SetFetchResponse(d_css_url, default_css_header, kDCssBody);


// Only the first two CSS files should be combined. // Only the first two CSS files should be combined.
GoogleString html_input(StrCat( GoogleString html_input(StrCat(
Expand Down Expand Up @@ -1127,14 +1135,14 @@ TEST_F(CssCombineFilterTest, CombineCssNoInput) {
SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header); SetDefaultLongCacheHeaders(&kContentTypeCss, &default_css_header);
SetFetchResponse(StrCat(kTestDomain, kCssB), SetFetchResponse(StrCat(kTestDomain, kCssB),
default_css_header, ".a {}"); default_css_header, ".a {}");
static const char html_input[] = static const char kHtmlInput[] =
"<head>\n" "<head>\n"
" <link rel='stylesheet' href='a_broken.css' type='text/css'>\n" " <link rel='stylesheet' href='a_broken.css' type='text/css'>\n"
" <link rel='stylesheet' href='b.css' type='text/css'>\n" " <link rel='stylesheet' href='b.css' type='text/css'>\n"
"</head>\n" "</head>\n"
"<body><div class='c1'><div class='c2'><p>\n" "<body><div class='c1'><div class='c2'><p>\n"
" Yellow on Blue</p></div></div></body>"; " Yellow on Blue</p></div></div></body>";
ValidateNoChanges("combine_css_missing_input", html_input); ValidateNoChanges("combine_css_missing_input", kHtmlInput);
} }


TEST_F(CssCombineFilterTest, CombineCssXhtml) { TEST_F(CssCombineFilterTest, CombineCssXhtml) {
Expand Down Expand Up @@ -1748,7 +1756,7 @@ class CssFilterWithCombineTest : public CssCombineFilterTest {
GoogleString OptimizedContent() { return "div{}div{}"; } GoogleString OptimizedContent() { return "div{}div{}"; }


void SetupResources() { void SetupResources() {
const char kCssText[] = " div { } "; static const char kCssText[] = " div { } ";
SetResponseWithDefaultHeaders(kCssA, kContentTypeCss, kCssText, 300); SetResponseWithDefaultHeaders(kCssA, kContentTypeCss, kCssText, 300);
SetResponseWithDefaultHeaders(kCssB, kContentTypeCss, kCssText, 300); SetResponseWithDefaultHeaders(kCssB, kContentTypeCss, kCssText, 300);
} }
Expand Down Expand Up @@ -1832,8 +1840,8 @@ TEST_F(CssFilterWithCombineTestUrlNamer, TestFollowCombine) {
// A verbatim copy of the test above but using TestUrlNamer. // A verbatim copy of the test above but using TestUrlNamer.
const GoogleString kCssOut = const GoogleString kCssOut =
EncodeCssCombineAndOptimize(kTestDomain, MultiUrl(kCssA, kCssB)); EncodeCssCombineAndOptimize(kTestDomain, MultiUrl(kCssA, kCssB));
const char kCssText[] = " div { } "; static const char kCssText[] = " div { } ";
const char kCssTextOptimized[] = "div{}"; static const char kCssTextOptimized[] = "div{}";


SetResponseWithDefaultHeaders(kCssA, kContentTypeCss, kCssText, 300); SetResponseWithDefaultHeaders(kCssA, kContentTypeCss, kCssText, 300);
SetResponseWithDefaultHeaders(kCssB, kContentTypeCss, kCssText, 300); SetResponseWithDefaultHeaders(kCssB, kContentTypeCss, kCssText, 300);
Expand Down Expand Up @@ -2031,24 +2039,24 @@ TEST_F(CollapseWhitespaceGeneralTest, CollapseAfterCombine) {
default_css_header, ".c { color: blue; }"); default_css_header, ".c { color: blue; }");


// Before and expected after text. // Before and expected after text.
const char before[] = static const char kBefore[] =
"<html>\n" "<html>\n"
" <head>\n" " <head>\n"
" <link rel=stylesheet type=text/css href=a.css>\n" " <link rel=stylesheet type=text/css href=a.css>\n"
" <link rel=stylesheet type=text/css href=b.css>\n" " <link rel=stylesheet type=text/css href=b.css>\n"
" <link rel=stylesheet type=text/css href=c.css>\n" " <link rel=stylesheet type=text/css href=c.css>\n"
" </head>\n" " </head>\n"
"</html>\n"; "</html>\n";
const char after_template[] = static const char kAfterTemplate[] =
"<html>\n" "<html>\n"
"<head>\n" "<head>\n"
"<link rel=stylesheet type=text/css href=%s />\n" "<link rel=stylesheet type=text/css href=%s />\n"
"</head>\n" "</head>\n"
"</html>\n"; "</html>\n";
GoogleString after = StringPrintf(after_template, Encode( GoogleString after = StringPrintf(kAfterTemplate, Encode(
"", "cc", "0", MultiUrl(kCssA, kCssB, "c.css"), "css").c_str()); "", "cc", "0", MultiUrl(kCssA, kCssB, "c.css"), "css").c_str());


ValidateExpected("collapse_after_combine", before, after); ValidateExpected("collapse_after_combine", kBefore, after);
} }


/* /*
Expand Down
27 changes: 13 additions & 14 deletions net/instaweb/rewriter/css_filter.cc
Expand Up @@ -46,6 +46,7 @@
#include "net/instaweb/rewriter/public/request_properties.h" #include "net/instaweb/rewriter/public/request_properties.h"
#include "net/instaweb/rewriter/public/resource.h" #include "net/instaweb/rewriter/public/resource.h"
#include "net/instaweb/rewriter/public/resource_slot.h" #include "net/instaweb/rewriter/public/resource_slot.h"
#include "net/instaweb/rewriter/public/resource_tag_scanner.h"
#include "net/instaweb/rewriter/public/rewrite_context.h" #include "net/instaweb/rewriter/public/rewrite_context.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h" #include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_options.h" #include "net/instaweb/rewriter/public/rewrite_options.h"
Expand Down Expand Up @@ -997,22 +998,20 @@ void CssFilter::EndElementImpl(HtmlElement* element) {
if (in_style_element_) { if (in_style_element_) {
CHECK(style_element_ == element); // HtmlParse should not pass unmatching. CHECK(style_element_ == element); // HtmlParse should not pass unmatching.
in_style_element_ = false; in_style_element_ = false;

}
// Rewrite an external style. if (driver()->IsRewritable(element)) {
} else if (element->keyword() == HtmlName::kLink && resource_tag_scanner::UrlCategoryVector attributes;
driver()->IsRewritable(element)) { resource_tag_scanner::ScanElement(
if (CssTagScanner::IsStylesheetOrAlternate( element, driver()->options(), &attributes);
element->AttributeValue(HtmlName::kRel))) { resource_tag_scanner::UrlCategoryVector::iterator uc;
HtmlElement::Attribute* element_href = element->FindAttribute( for (uc = attributes.begin(); uc != attributes.end(); uc++) {
HtmlName::kHref); if (uc->category == semantic_type::kStylesheet) {
if (element_href != NULL) { StartExternalRewrite(element, uc->url);
// If it has a href= attribute
StartExternalRewrite(element, element_href);
} }
} }
// Note any meta tag charset specifier. }
} else if (meta_tag_charset_.empty() && if (meta_tag_charset_.empty() && element->keyword() == HtmlName::kMeta) {
element->keyword() == HtmlName::kMeta) { // Note any meta tag charset specifier.
GoogleString content, mime_type, charset; GoogleString content, mime_type, charset;
if (ExtractMetaTagDetails(*element, NULL, &content, &mime_type, &charset)) { if (ExtractMetaTagDetails(*element, NULL, &content, &mime_type, &charset)) {
meta_tag_charset_ = charset; meta_tag_charset_ = charset;
Expand Down
9 changes: 9 additions & 0 deletions net/instaweb/rewriter/resource_tag_scanner.cc
Expand Up @@ -200,6 +200,15 @@ semantic_type::Category CategorizeAttribute(
StringCaseEqual(attribute->name_str(), attribute_i)) { StringCaseEqual(attribute->name_str(), attribute_i)) {
return category_i; return category_i;
} }
if (element->keyword() == HtmlName::kStyle) {
// When inlining we turn <link> into <style> while preserving attributes.
// This means that any custom attributes defined for <link> should also be
// interpreted on <style>.
if (StringCaseEqual("link", element_i) &&
StringCaseEqual(attribute->name_str(), attribute_i)) {
return category_i;
}
}
} }


// Handle spec-defined attributes. // Handle spec-defined attributes.
Expand Down

0 comments on commit 59a1982

Please sign in to comment.