blob: aff2456bad3eb7baacd00447886992e33a8e2a46 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/web/js_messaging/java_script_feature_util_impl.h"
#import <Foundation/Foundation.h>
#include "base/logging.h"
#include "base/no_destructor.h"
#import "base/strings/sys_string_conversions.h"
#import "ios/web/favicon/favicon_java_script_feature.h"
#import "ios/web/find_in_page/find_in_page_java_script_feature.h"
#include "ios/web/js_features/context_menu/context_menu_java_script_feature.h"
#include "ios/web/js_features/scroll_helper/scroll_helper_java_script_feature.h"
#import "ios/web/js_features/window_error/window_error_java_script_feature.h"
#include "ios/web/public/js_messaging/java_script_feature.h"
#import "ios/web/public/web_client.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace web {
namespace {
const char kBaseScriptName[] = "base_js";
const char kCommonScriptName[] = "common_js";
const char kMessageScriptName[] = "message_js";
const char kPluginPlaceholderScriptName[] = "plugin_placeholder_js";
const char kMainFrameDescription[] = "Main frame";
const char kIframeDescription[] = "Iframe";
// Returns the dictionary for placeholder replacements.
NSDictionary<NSString*, NSString*>* PlaceholderReplacements() {
// The replacement value is computed dynamically each time this function is
// evaluated as the WebClient may change (in case of tests) or the returned
// value may change over time (nothing prevent a WebClient from doing that).
NSString* replacement =
base::SysUTF16ToNSString(GetWebClient()->GetPluginNotSupportedText());
// Escape the \ and ' characters in replacement. This is not done using the
// GetQuotedJSONString() function as it converts UTF-16 to UTF-8 which can
// cause problems when injecting script depending on the page enconding.
// See https://crbug.com/302741/.
replacement = [replacement stringByReplacingOccurrencesOfString:@"\\"
withString:@"\\\\"];
replacement = [replacement stringByReplacingOccurrencesOfString:@"'"
withString:@"\'"];
return @{@"$(PLUGIN_NOT_SUPPORTED_TEXT)" : replacement};
}
FaviconJavaScriptFeature* GetFaviconJavaScriptFeature() {
// Static storage is ok for |favicon_feature| as it holds no state.
static base::NoDestructor<FaviconJavaScriptFeature> favicon_feature;
return favicon_feature.get();
}
WindowErrorJavaScriptFeature* GetWindowErrorJavaScriptFeature() {
// Static storage is ok for |window_error_feature| as it holds no state.
static base::NoDestructor<WindowErrorJavaScriptFeature> window_error_feature(
base::BindRepeating(^(
WindowErrorJavaScriptFeature::ErrorDetails error_details) {
// Displays the JavaScript error details in the following format:
// _________ JavaScript error: _________
// {error_message}
// {url} | {filename}:{line_number}
// {kMainFrameDescription|kIframeDescription}
const char* frame_description = error_details.is_main_frame
? kMainFrameDescription
: kIframeDescription;
DLOG(ERROR) << "\n_________ JavaScript error: _________"
<< "\n " << base::SysNSStringToUTF8(error_details.message)
<< "\n " << error_details.url.spec() << " | "
<< base::SysNSStringToUTF8(error_details.filename) << ":"
<< error_details.line_number << "\n " << frame_description;
}));
return window_error_feature.get();
}
JavaScriptFeature* GetPluginPlaceholderJavaScriptFeature() {
// Static storage is ok for |plugin_placeholder_feature| as it holds no state.
static base::NoDestructor<JavaScriptFeature> plugin_placeholder_feature(
JavaScriptFeature::ContentWorld::kAnyContentWorld,
std::vector<const JavaScriptFeature::FeatureScript>(
{JavaScriptFeature::FeatureScript::CreateWithFilename(
kPluginPlaceholderScriptName,
JavaScriptFeature::FeatureScript::InjectionTime::kDocumentEnd,
JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames,
JavaScriptFeature::FeatureScript::ReinjectionBehavior::
kReinjectOnDocumentRecreation,
base::BindRepeating(&PlaceholderReplacements))}));
return plugin_placeholder_feature.get();
}
} // namespace
namespace java_script_features {
std::vector<JavaScriptFeature*> GetBuiltInJavaScriptFeatures(
BrowserState* browser_state) {
return {ContextMenuJavaScriptFeature::FromBrowserState(browser_state),
FindInPageJavaScriptFeature::GetInstance(),
GetFaviconJavaScriptFeature(),
GetPluginPlaceholderJavaScriptFeature(),
GetScrollHelperJavaScriptFeature(),
GetWindowErrorJavaScriptFeature()};
}
ScrollHelperJavaScriptFeature* GetScrollHelperJavaScriptFeature() {
// Static storage is ok for |scroll_helper_feature| as it holds no state.
static base::NoDestructor<ScrollHelperJavaScriptFeature>
scroll_helper_feature;
return scroll_helper_feature.get();
}
JavaScriptFeature* GetBaseJavaScriptFeature() {
// Static storage is ok for |base_feature| as it holds no state.
static base::NoDestructor<JavaScriptFeature> base_feature(
JavaScriptFeature::ContentWorld::kAnyContentWorld,
std::vector<const JavaScriptFeature::FeatureScript>(
{JavaScriptFeature::FeatureScript::CreateWithFilename(
kBaseScriptName,
JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames)}));
return base_feature.get();
}
JavaScriptFeature* GetCommonJavaScriptFeature() {
// Static storage is ok for |common_feature| as it holds no state.
static base::NoDestructor<JavaScriptFeature> common_feature(
JavaScriptFeature::ContentWorld::kAnyContentWorld,
std::vector<const JavaScriptFeature::FeatureScript>(
{JavaScriptFeature::FeatureScript::CreateWithFilename(
kCommonScriptName,
JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames)}),
std::vector<const JavaScriptFeature*>({GetBaseJavaScriptFeature()}));
return common_feature.get();
}
JavaScriptFeature* GetMessageJavaScriptFeature() {
// Static storage is ok for |message_feature| as it holds no state.
static base::NoDestructor<JavaScriptFeature> message_feature(
JavaScriptFeature::ContentWorld::kAnyContentWorld,
std::vector<const JavaScriptFeature::FeatureScript>(
{JavaScriptFeature::FeatureScript::CreateWithFilename(
kMessageScriptName,
JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart,
JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames)}),
std::vector<const JavaScriptFeature*>({GetCommonJavaScriptFeature()}));
return message_feature.get();
}
} // namespace java_script_features
} // namespace web