blob: dd2ddd2cf4ffa97b919d80efb2efe1d94a16f653 [file] [log] [blame]
/*
* Copyright 2015 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: kspoelstra@we-amp.com (Kees Spoelstra)
#include "net/instaweb/rewriter/public/strip_subresource_hints_filter.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/html/html_element.h"
#include "pagespeed/kernel/html/html_name.h"
#include "pagespeed/kernel/http/google_url.h"
#include "net/instaweb/rewriter/public/domain_lawyer.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
namespace net_instaweb {
StripSubresourceHintsFilter::StripSubresourceHintsFilter(RewriteDriver* driver)
: driver_(driver),
delete_element_(NULL),
remove_script_(false),
remove_style_(false),
remove_image_(false),
remove_any_(false) {
}
StripSubresourceHintsFilter::~StripSubresourceHintsFilter() { }
void StripSubresourceHintsFilter::StartDocument() {
const RewriteOptions *options = driver_->options();
remove_script_ = driver_->can_modify_urls() && !options->js_preserve_urls();
remove_style_ = driver_->can_modify_urls() && !options->css_preserve_urls();
remove_image_ = driver_->can_modify_urls() && !options->image_preserve_urls();
remove_any_ = remove_script_ || remove_style_ || remove_image_;
delete_element_ = NULL;
}
void StripSubresourceHintsFilter::StartElement(HtmlElement* element) {
if (!remove_any_ || delete_element_) return;
if (element->keyword() == HtmlName::kLink) {
// Strip:
// <link rel=subresource href=...> regardless
// <link rel=preload as=script href=...> unless preserve scripts
// <link rel=preload as=style href=...> unless preserve styles
// <link rel=preload as=image href=...> unless preserve images
//
// Don't strip other kinds of rel=preload hints, because we don't change
// their urls, so existing ones are still valid.
const char* rel_value;
const char* as_value;
if ((rel_value = element->AttributeValue(HtmlName::kRel)) != NULL &&
(StringCaseEqual(rel_value, "subresource") ||
(StringCaseEqual(rel_value, "preload") &&
(as_value = element->AttributeValue(HtmlName::kAs)) != NULL &&
((remove_script_ && StringCaseEqual(as_value, "script")) ||
(remove_style_ && StringCaseEqual(as_value, "style")) ||
(remove_image_ && StringCaseEqual(as_value, "image")))))) {
const RewriteOptions *options = driver_->options();
const char *resource_url = element->AttributeValue(HtmlName::kHref);
if (!resource_url) {
// There's either no href attr, or one that we can't decode (utf8 etc).
// One way this could happen is if we have a url-encoded utf8 url in an
// img tag and a utf8 encoded url in the subresource tag. Delete the
// subresource link to be on the safe side.
delete_element_ = element;
return;
}
const GoogleUrl &base_url = driver_->decoded_base_url();
scoped_ptr<GoogleUrl> resolved_resource_url(
new GoogleUrl(base_url, resource_url));
if (options->IsAllowed(resolved_resource_url->Spec()) &&
options->domain_lawyer()->IsDomainAuthorized(
base_url, *resolved_resource_url)) {
delete_element_ = element;
}
}
}
}
void StripSubresourceHintsFilter::EndElement(HtmlElement* element) {
if (delete_element_ == element) {
driver_->DeleteNode(delete_element_);
delete_element_ = NULL;
}
}
void StripSubresourceHintsFilter::Flush() {
delete_element_ = NULL;
}
void StripSubresourceHintsFilter::EndDocument() {
}
} // namespace net_instaweb