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 |