| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/web/webui/crw_web_ui_manager.h" | 5 #import "ios/web/webui/crw_web_ui_manager.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/json/string_escape.h" | 10 #include "base/json/string_escape.h" |
| 11 #import "base/mac/bind_objc_block.h" | 11 #import "base/mac/bind_objc_block.h" |
| 12 #import "base/mac/scoped_nsobject.h" | 12 #import "base/mac/scoped_nsobject.h" |
| 13 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 14 #include "base/memory/ref_counted_memory.h" | 14 #include "base/memory/ref_counted_memory.h" |
| 15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 16 #import "base/strings/sys_string_conversions.h" | 16 #import "base/strings/sys_string_conversions.h" |
| 17 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 18 #include "base/values.h" | 18 #include "base/values.h" |
| 19 #include "ios/web/grit/ios_web_resources.h" | 19 #include "ios/web/grit/ios_web_resources.h" |
| 20 #include "ios/web/public/browser_state.h" | 20 #include "ios/web/public/browser_state.h" |
| 21 #import "ios/web/public/web_client.h" | 21 #import "ios/web/public/web_client.h" |
| 22 #import "ios/web/public/web_state/navigation_context.h" | 22 #import "ios/web/public/web_state/navigation_context.h" |
| 23 #import "ios/web/public/web_state/web_state_observer_bridge.h" | 23 #import "ios/web/public/web_state/web_state_observer_bridge.h" |
| 24 #import "ios/web/web_state/web_state_impl.h" | 24 #import "ios/web/web_state/web_state_impl.h" |
| 25 #import "ios/web/webui/crw_web_ui_page_builder.h" | 25 #import "ios/web/webui/crw_web_ui_page_builder.h" |
| 26 #include "ios/web/webui/mojo_js_constants.h" | |
| 27 #import "ios/web/webui/url_fetcher_block_adapter.h" | 26 #import "ios/web/webui/url_fetcher_block_adapter.h" |
| 28 #include "mojo/public/js/constants.h" | |
| 29 #import "net/base/mac/url_conversions.h" | 27 #import "net/base/mac/url_conversions.h" |
| 30 | 28 |
| 31 #if !defined(__has_feature) || !__has_feature(objc_arc) | 29 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 32 #error "This file requires ARC support." | 30 #error "This file requires ARC support." |
| 33 #endif | 31 #endif |
| 34 | 32 |
| 35 namespace { | 33 namespace { |
| 36 // Prefix for JavaScript messages. | 34 // Prefix for JavaScript messages. |
| 37 const char kScriptCommandPrefix[] = "webui"; | 35 const char kScriptCommandPrefix[] = "webui"; |
| 38 } | 36 } |
| 39 | 37 |
| 40 @interface CRWWebUIManager () <CRWWebUIPageBuilderDelegate> | 38 @interface CRWWebUIManager () <CRWWebUIPageBuilderDelegate> |
| 41 | 39 |
| 42 // Current web state. | 40 // Current web state. |
| 43 @property(nonatomic, readonly) web::WebStateImpl* webState; | 41 @property(nonatomic, readonly) web::WebStateImpl* webState; |
| 44 | 42 |
| 45 // Composes WebUI page for webUIURL and invokes completionHandler with the | 43 // Composes WebUI page for webUIURL and invokes completionHandler with the |
| 46 // result. | 44 // result. |
| 47 - (void)loadWebUIPageForURL:(const GURL&)webUIURL | 45 - (void)loadWebUIPageForURL:(const GURL&)webUIURL |
| 48 completionHandler:(void (^)(NSString*))completionHandler; | 46 completionHandler:(void (^)(NSString*))completionHandler; |
| 49 | 47 |
| 50 // Retrieves resource for URL and invokes completionHandler with the result. | 48 // Retrieves resource for URL and invokes completionHandler with the result. |
| 51 - (void)fetchResourceWithURL:(const GURL&)URL | 49 - (void)fetchResourceWithURL:(const GURL&)URL |
| 52 completionHandler:(void (^)(NSData*))completionHandler; | 50 completionHandler:(void (^)(NSData*))completionHandler; |
| 53 | 51 |
| 54 // Handles JavaScript message from the WebUI page. | 52 // Handles JavaScript message from the WebUI page. |
| 55 - (BOOL)handleWebUIJSMessage:(const base::DictionaryValue&)message; | 53 - (BOOL)handleWebUIJSMessage:(const base::DictionaryValue&)message; |
| 56 | 54 |
| 57 // Handles webui.loadMojo JavaScript message from the WebUI page. | |
| 58 - (BOOL)handleLoadMojo:(const base::ListValue*)arguments; | |
| 59 | |
| 60 // Executes mojo script and signals |webui.loadMojo| finish. | |
| 61 - (void)executeMojoScript:(const std::string&)mojoScript | |
| 62 forModuleName:(const std::string&)moduleName | |
| 63 loadID:(const std::string&)loadID; | |
| 64 | |
| 65 // Removes favicon callback from web state. | 55 // Removes favicon callback from web state. |
| 66 - (void)resetWebState; | 56 - (void)resetWebState; |
| 67 | 57 |
| 68 // Removes fetcher from vector of active fetchers. | 58 // Removes fetcher from vector of active fetchers. |
| 69 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher; | 59 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher; |
| 70 | 60 |
| 71 @end | 61 @end |
| 72 | 62 |
| 73 @implementation CRWWebUIManager { | 63 @implementation CRWWebUIManager { |
| 74 // Set of live WebUI fetchers for retrieving data. | 64 // Set of live WebUI fetchers for retrieving data. |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 if (!message.GetList("arguments", &arguments)) { | 171 if (!message.GetList("arguments", &arguments)) { |
| 182 DLOG(WARNING) << "JS message parameter not found: arguments"; | 172 DLOG(WARNING) << "JS message parameter not found: arguments"; |
| 183 return NO; | 173 return NO; |
| 184 } | 174 } |
| 185 | 175 |
| 186 if (!arguments) { | 176 if (!arguments) { |
| 187 DLOG(WARNING) << "No arguments provided to " << command; | 177 DLOG(WARNING) << "No arguments provided to " << command; |
| 188 return NO; | 178 return NO; |
| 189 } | 179 } |
| 190 | 180 |
| 191 if (command == "webui.loadMojo") | |
| 192 return [self handleLoadMojo:arguments]; | |
| 193 | |
| 194 DLOG(WARNING) << "Unknown webui command received: " << command; | 181 DLOG(WARNING) << "Unknown webui command received: " << command; |
| 195 return NO; | 182 return NO; |
| 196 } | 183 } |
| 197 | 184 |
| 198 - (BOOL)handleLoadMojo:(const base::ListValue*)arguments { | |
| 199 std::string moduleName; | |
| 200 if (!arguments->GetString(0, &moduleName)) { | |
| 201 DLOG(WARNING) << "JS message parameter not found: Module name"; | |
| 202 return NO; | |
| 203 } | |
| 204 std::string loadID; | |
| 205 if (!arguments->GetString(1, &loadID)) { | |
| 206 DLOG(WARNING) << "JS message parameter not found: Load ID"; | |
| 207 return NO; | |
| 208 } | |
| 209 | |
| 210 // Look for built-in scripts first. | |
| 211 std::map<std::string, int> resource_map{ | |
| 212 {mojo::kAssociatedBindingsModuleName, IDR_MOJO_ASSOCIATED_BINDINGS_JS}, | |
| 213 {mojo::kBindingsModuleName, IDR_MOJO_BINDINGS_JS}, | |
| 214 {mojo::kBufferModuleName, IDR_MOJO_BUFFER_JS}, | |
| 215 {mojo::kCodecModuleName, IDR_MOJO_CODEC_JS}, | |
| 216 {mojo::kConnectorModuleName, IDR_MOJO_CONNECTOR_JS}, | |
| 217 {mojo::kControlMessageHandlerModuleName, | |
| 218 IDR_MOJO_CONTROL_MESSAGE_HANDLER_JS}, | |
| 219 {mojo::kControlMessageProxyModuleName, IDR_MOJO_CONTROL_MESSAGE_PROXY_JS}, | |
| 220 {mojo::kInterfaceControlMessagesMojom, | |
| 221 IDR_MOJO_INTERFACE_CONTROL_MESSAGES_MOJOM_JS}, | |
| 222 {mojo::kInterfaceTypesModuleName, IDR_MOJO_INTERFACE_TYPES_JS}, | |
| 223 {mojo::kRouterModuleName, IDR_MOJO_ROUTER_JS}, | |
| 224 {mojo::kUnicodeModuleName, IDR_MOJO_UNICODE_JS}, | |
| 225 {mojo::kValidatorModuleName, IDR_MOJO_VALIDATOR_JS}, | |
| 226 {web::kConsoleModuleName, IDR_IOS_CONSOLE_JS}, | |
| 227 {web::kTimerModuleName, IDR_IOS_TIMER_JS}, | |
| 228 {web::kCoreModuleName, IDR_IOS_MOJO_CORE_JS}, | |
| 229 {web::kHandleUtilModuleName, IDR_IOS_MOJO_HANDLE_UTIL_JS}, | |
| 230 {web::kInterfaceProviderModuleName, IDR_IOS_SHELL_INTERFACE_PROVIDER_JS}, | |
| 231 {web::kSupportModuleName, IDR_IOS_MOJO_SUPPORT_JS}, | |
| 232 {web::kSyncMessageChannelModuleName, | |
| 233 IDR_IOS_MOJO_SYNC_MESSAGE_CHANNEL_JS}, | |
| 234 {mojo::kPipeControlMessagesMojom, | |
| 235 IDR_MOJO_PIPE_CONTROL_MESSAGES_MOJOM_JS}, | |
| 236 {mojo::kInterfaceEndpointClientModuleName, | |
| 237 IDR_MOJO_INTERFACE_ENDPOINT_CLIENT_JS}, | |
| 238 {mojo::kInterfaceEndpointHandleModuleName, | |
| 239 IDR_MOJO_INTERFACE_ENDPOINT_HANDLE_JS}, | |
| 240 {mojo::kPipeControlMessageHandlerModuleName, | |
| 241 IDR_MOJO_PIPE_CONTROL_MESSAGE_HANDLER_JS}, | |
| 242 {mojo::kPipeControlMessageProxyModuleName, | |
| 243 IDR_MOJO_PIPE_CONTROL_MESSAGE_PROXY_JS}, | |
| 244 }; | |
| 245 scoped_refptr<base::RefCountedMemory> scriptData( | |
| 246 web::GetWebClient()->GetDataResourceBytes(resource_map[moduleName])); | |
| 247 if (scriptData) { | |
| 248 std::string script(reinterpret_cast<const char*>(scriptData->front()), | |
| 249 scriptData->size()); | |
| 250 [self executeMojoScript:script forModuleName:moduleName loadID:loadID]; | |
| 251 return YES; | |
| 252 } | |
| 253 | |
| 254 // Not a built-in script, try retrieving from network. | |
| 255 GURL resourceURL(self.webState->GetLastCommittedURL().Resolve(moduleName)); | |
| 256 base::WeakNSObject<CRWWebUIManager> weakSelf(self); | |
| 257 [self fetchResourceWithURL:resourceURL completionHandler:^(NSData* data) { | |
| 258 std::string script; | |
| 259 if (data) { | |
| 260 script = base::SysNSStringToUTF8( | |
| 261 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); | |
| 262 // WebUIIOSDataSourceImpl returns the default resource (which is the HTML | |
| 263 // page itself) if the resource URL isn't found. Fail with error instead | |
| 264 // of silently injecting garbage (leading to a not-very-useful syntax | |
| 265 // error from the JS side). | |
| 266 if (script.find("<!doctype") != std::string::npos) { | |
| 267 NOTREACHED() << "cannot load " << moduleName; | |
| 268 script.clear(); | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 [weakSelf executeMojoScript:script forModuleName:moduleName loadID:loadID]; | |
| 273 }]; | |
| 274 | |
| 275 return YES; | |
| 276 } | |
| 277 | |
| 278 - (void)executeMojoScript:(const std::string&)mojoScript | |
| 279 forModuleName:(const std::string&)moduleName | |
| 280 loadID:(const std::string&)loadID { | |
| 281 std::string script = mojoScript; | |
| 282 // Append with completion function call. | |
| 283 if (script.empty()) { | |
| 284 DLOG(ERROR) << "Unable to find a module named " << moduleName; | |
| 285 script = "__crWeb.webUIModuleLoadNotifier.moduleLoadFailed"; | |
| 286 } else { | |
| 287 script += "__crWeb.webUIModuleLoadNotifier.moduleLoadCompleted"; | |
| 288 } | |
| 289 base::StringAppendF(&script, "(%s, %s);", | |
| 290 base::GetQuotedJSONString(moduleName).c_str(), | |
| 291 base::GetQuotedJSONString(loadID).c_str()); | |
| 292 | |
| 293 _webState->ExecuteJavaScript(base::UTF8ToUTF16(script)); | |
| 294 } | |
| 295 | |
| 296 - (void)resetWebState { | 185 - (void)resetWebState { |
| 297 if (_webState) { | 186 if (_webState) { |
| 298 _webState->RemoveScriptCommandCallback(kScriptCommandPrefix); | 187 _webState->RemoveScriptCommandCallback(kScriptCommandPrefix); |
| 299 } | 188 } |
| 300 _webState = nullptr; | 189 _webState = nullptr; |
| 301 } | 190 } |
| 302 | 191 |
| 303 - (web::WebStateImpl*)webState { | 192 - (web::WebStateImpl*)webState { |
| 304 return _webState; | 193 return _webState; |
| 305 } | 194 } |
| 306 | 195 |
| 307 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher { | 196 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher { |
| 308 _fetchers.erase(std::find_if( | 197 _fetchers.erase(std::find_if( |
| 309 _fetchers.begin(), _fetchers.end(), | 198 _fetchers.begin(), _fetchers.end(), |
| 310 [fetcher](const std::unique_ptr<web::URLFetcherBlockAdapter>& ptr) { | 199 [fetcher](const std::unique_ptr<web::URLFetcherBlockAdapter>& ptr) { |
| 311 return ptr.get() == fetcher; | 200 return ptr.get() == fetcher; |
| 312 })); | 201 })); |
| 313 } | 202 } |
| 314 | 203 |
| 315 #pragma mark - Testing-Only Methods | 204 #pragma mark - Testing-Only Methods |
| 316 | 205 |
| 317 - (std::unique_ptr<web::URLFetcherBlockAdapter>) | 206 - (std::unique_ptr<web::URLFetcherBlockAdapter>) |
| 318 fetcherForURL:(const GURL&)URL | 207 fetcherForURL:(const GURL&)URL |
| 319 completionHandler:(web::URLFetcherBlockAdapterCompletion)handler { | 208 completionHandler:(web::URLFetcherBlockAdapterCompletion)handler { |
| 320 return base::MakeUnique<web::URLFetcherBlockAdapter>( | 209 return base::MakeUnique<web::URLFetcherBlockAdapter>( |
| 321 URL, _webState->GetBrowserState()->GetRequestContext(), handler); | 210 URL, _webState->GetBrowserState()->GetRequestContext(), handler); |
| 322 } | 211 } |
| 323 | 212 |
| 324 @end | 213 @end |
| OLD | NEW |