| // 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 |