blob: b1647e1ab2a678f08fd9f3cdf26e7d94ac4d4a28 [file] [log] [blame]
/*
* 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: sriharis@google.com (Srihari Sukumaran)
#include "net/instaweb/rewriter/public/support_noscript_filter.h"
#include "net/instaweb/public/global_constants.h"
#include "net/instaweb/rewriter/public/mobilize_rewrite_filter.h"
#include "net/instaweb/rewriter/public/request_properties.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/rewriter/public/rewrite_query.h"
#include "net/instaweb/rewriter/public/split_html_beacon_filter.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/html/html_element.h"
#include "pagespeed/kernel/html/html_keywords.h"
#include "pagespeed/kernel/html/html_name.h"
#include "pagespeed/kernel/html/html_node.h"
#include "pagespeed/kernel/http/google_url.h"
namespace net_instaweb {
SupportNoscriptFilter::SupportNoscriptFilter(RewriteDriver* rewrite_driver)
: rewrite_driver_(rewrite_driver),
should_insert_noscript_(true) {
}
SupportNoscriptFilter::~SupportNoscriptFilter() {
}
void SupportNoscriptFilter::DetermineEnabled(GoogleString* disabled_reason) {
// Insert a NOSCRIPT tag only if at least one of the filters requiring
// JavaScript for execution is enabled.
should_insert_noscript_ = IsAnyFilterRequiringScriptExecutionEnabled();
set_is_enabled(should_insert_noscript_);
}
void SupportNoscriptFilter::StartElement(HtmlElement* element) {
if (should_insert_noscript_ && element->keyword() == HtmlName::kBody) {
scoped_ptr<GoogleUrl> url_with_psa_off(
rewrite_driver_->google_url().CopyAndAddQueryParam(
RewriteQuery::kPageSpeed, RewriteQuery::kNoscriptValue));
GoogleString escaped_url;
HtmlKeywords::Escape(url_with_psa_off->Spec(), &escaped_url);
// TODO(sriharis): Replace the usage of HtmlCharactersNode with HtmlElement
// and Attribute.
HtmlCharactersNode* noscript_node = rewrite_driver_->NewCharactersNode(
element, StringPrintf(kNoScriptRedirectFormatter,
escaped_url.c_str(), escaped_url.c_str()));
rewrite_driver_->PrependChild(element, noscript_node);
should_insert_noscript_ = false;
}
// TODO(sriharis): Handle the case where there is no body -- insert a body in
// EndElement of kHtml?
}
bool SupportNoscriptFilter::IsAnyFilterRequiringScriptExecutionEnabled() const {
const RewriteOptions* options = rewrite_driver_->options();
const RequestProperties* request_properties =
rewrite_driver_->request_properties();
RewriteOptions::FilterVector js_filters;
options->GetEnabledFiltersRequiringScriptExecution(&js_filters);
for (int i = 0, n = js_filters.size(); i < n; ++i) {
RewriteOptions::Filter filter = js_filters[i];
bool filter_enabled = true;
switch (filter) {
case RewriteOptions::kDeferIframe:
case RewriteOptions::kDeferJavascript:
case RewriteOptions::kSplitHtml:
// We don't need to insert a noscript redirect if we are just
// instrumenting the page, instead of actually running split HTML.
filter_enabled =
(request_properties->SupportsJsDefer(
options->enable_aggressive_rewriters_for_mobile()) &&
!SplitHtmlBeaconFilter::ShouldApply(rewrite_driver_));
break;
case RewriteOptions::kDedupInlinedImages:
case RewriteOptions::kDelayImages:
case RewriteOptions::kLazyloadImages:
case RewriteOptions::kLocalStorageCache:
filter_enabled = request_properties->SupportsImageInlining();
break;
case RewriteOptions::kFlushSubresources:
filter_enabled = rewrite_driver_->flushed_early();;
break;
case RewriteOptions::kCachePartialHtml:
filter_enabled = rewrite_driver_->flushing_cached_html();
break;
case RewriteOptions::kMobilize:
filter_enabled =
MobilizeRewriteFilter::IsApplicableFor(rewrite_driver_);
break;
default:
break;
}
if (filter_enabled) {
return true;
}
}
return false;
}
} // namespace net_instaweb