| 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 "base/json/string_escape.h" |
| 7 #include "base/mac/bind_objc_block.h" | 8 #include "base/mac/bind_objc_block.h" |
| 8 #include "base/mac/scoped_nsobject.h" | 9 #include "base/mac/scoped_nsobject.h" |
| 9 #include "base/memory/scoped_vector.h" | 10 #include "base/memory/scoped_vector.h" |
| 11 #include "base/strings/stringprintf.h" |
| 10 #import "base/strings/sys_string_conversions.h" | 12 #import "base/strings/sys_string_conversions.h" |
| 13 #include "base/strings/utf_string_conversions.h" |
| 11 #include "base/values.h" | 14 #include "base/values.h" |
| 12 #import "ios/web/net/request_group_util.h" | 15 #import "ios/web/net/request_group_util.h" |
| 13 #include "ios/web/public/browser_state.h" | 16 #include "ios/web/public/browser_state.h" |
| 14 #include "ios/web/public/web_client.h" | 17 #include "ios/web/public/web_client.h" |
| 15 #import "ios/web/public/web_state/web_state_observer_bridge.h" | 18 #import "ios/web/public/web_state/web_state_observer_bridge.h" |
| 16 #include "ios/web/web_state/web_state_impl.h" | 19 #include "ios/web/web_state/web_state_impl.h" |
| 17 #import "ios/web/webui/crw_web_ui_page_builder.h" | 20 #import "ios/web/webui/crw_web_ui_page_builder.h" |
| 18 #include "ios/web/webui/url_fetcher_block_adapter.h" | 21 #include "ios/web/webui/url_fetcher_block_adapter.h" |
| 19 #import "net/base/mac/url_conversions.h" | 22 #import "net/base/mac/url_conversions.h" |
| 20 | 23 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 33 - (void)loadWebUIPageForURL:(const GURL&)webUIURL | 36 - (void)loadWebUIPageForURL:(const GURL&)webUIURL |
| 34 completionHandler:(void (^)(NSString*))completionHandler; | 37 completionHandler:(void (^)(NSString*))completionHandler; |
| 35 | 38 |
| 36 // Retrieves resource for URL and invokes completionHandler with the result. | 39 // Retrieves resource for URL and invokes completionHandler with the result. |
| 37 - (void)fetchResourceWithURL:(const GURL&)URL | 40 - (void)fetchResourceWithURL:(const GURL&)URL |
| 38 completionHandler:(void (^)(NSData*))completionHandler; | 41 completionHandler:(void (^)(NSData*))completionHandler; |
| 39 | 42 |
| 40 // Handles JavaScript message from the WebUI page. | 43 // Handles JavaScript message from the WebUI page. |
| 41 - (BOOL)handleWebUIJSMessage:(const base::DictionaryValue&)message; | 44 - (BOOL)handleWebUIJSMessage:(const base::DictionaryValue&)message; |
| 42 | 45 |
| 46 // Handles webui.requestFavicon JavaScript message from the WebUI page. |
| 47 - (BOOL)handleRequestFavicon:(const base::ListValue*)arguments; |
| 48 |
| 49 // Handles webui.loadMojo JavaScript message from the WebUI page. |
| 50 - (BOOL)handleLoadMojo:(const base::ListValue*)arguments; |
| 51 |
| 43 // Removes favicon callback from web state. | 52 // Removes favicon callback from web state. |
| 44 - (void)resetWebState; | 53 - (void)resetWebState; |
| 45 | 54 |
| 46 // Removes fetcher from vector of active fetchers. | 55 // Removes fetcher from vector of active fetchers. |
| 47 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher; | 56 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher; |
| 48 | 57 |
| 49 @end | 58 @end |
| 50 | 59 |
| 51 @implementation CRWWebUIManager { | 60 @implementation CRWWebUIManager { |
| 52 // Set of live WebUI fetchers for retrieving data. | 61 // Set of live WebUI fetchers for retrieving data. |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 [weakSelf removeFetcher:fetcher]; | 163 [weakSelf removeFetcher:fetcher]; |
| 155 }; | 164 }; |
| 156 | 165 |
| 157 _fetchers.push_back( | 166 _fetchers.push_back( |
| 158 [self fetcherForURL:URL completionHandler:fetcherCompletion]); | 167 [self fetcherForURL:URL completionHandler:fetcherCompletion]); |
| 159 _fetchers.back()->Start(); | 168 _fetchers.back()->Start(); |
| 160 } | 169 } |
| 161 | 170 |
| 162 - (BOOL)handleWebUIJSMessage:(const base::DictionaryValue&)message { | 171 - (BOOL)handleWebUIJSMessage:(const base::DictionaryValue&)message { |
| 163 std::string command; | 172 std::string command; |
| 164 if (!message.GetString("message", &command) || | 173 if (!message.GetString("message", &command)) { |
| 165 command != "webui.requestFavicon") { | 174 DLOG(WARNING) << "Malformed message received"; |
| 166 DLOG(WARNING) << "Unexpected message received" << command; | |
| 167 return NO; | 175 return NO; |
| 168 } | 176 } |
| 169 const base::ListValue* arguments = nullptr; | 177 const base::ListValue* arguments = nullptr; |
| 170 if (!message.GetList("arguments", &arguments)) { | 178 if (!message.GetList("arguments", &arguments)) { |
| 171 DLOG(WARNING) << "JS message parameter not found: arguments"; | 179 DLOG(WARNING) << "JS message parameter not found: arguments"; |
| 172 return NO; | 180 return NO; |
| 173 } | 181 } |
| 182 |
| 183 if (!arguments) { |
| 184 DLOG(WARNING) << "No arguments provided to " << command; |
| 185 return NO; |
| 186 } |
| 187 |
| 188 if (command == "webui.requestFavicon") |
| 189 return [self handleRequestFavicon:arguments]; |
| 190 if (command == "webui.loadMojo") |
| 191 return [self handleLoadMojo:arguments]; |
| 192 |
| 193 DLOG(WARNING) << "Unknown webui command received: " << command; |
| 194 return NO; |
| 195 } |
| 196 |
| 197 - (BOOL)handleRequestFavicon:(const base::ListValue*)arguments { |
| 174 std::string favicon; | 198 std::string favicon; |
| 175 if (!arguments->GetString(0, &favicon)) { | 199 if (!arguments->GetString(0, &favicon)) { |
| 176 DLOG(WARNING) << "JS message parameter not found: Favicon URL"; | 200 DLOG(WARNING) << "JS message parameter not found: Favicon URL"; |
| 177 return NO; | 201 return NO; |
| 178 } | 202 } |
| 179 GURL faviconURL(favicon); | 203 GURL faviconURL(favicon); |
| 180 DCHECK(faviconURL.is_valid()); | 204 DCHECK(faviconURL.is_valid()); |
| 181 // Retrieve favicon resource and set favicon background image via JavaScript. | 205 // Retrieve favicon resource and set favicon background image via JavaScript. |
| 182 base::WeakNSObject<CRWWebUIManager> weakSelf(self); | 206 base::WeakNSObject<CRWWebUIManager> weakSelf(self); |
| 183 void (^faviconHandler)(NSData*) = ^void(NSData* data) { | 207 void (^faviconHandler)(NSData*) = ^void(NSData* data) { |
| 184 base::scoped_nsobject<CRWWebUIManager> strongSelf([weakSelf retain]); | 208 base::scoped_nsobject<CRWWebUIManager> strongSelf([weakSelf retain]); |
| 185 if (!strongSelf) | 209 if (!strongSelf) |
| 186 return; | 210 return; |
| 187 NSString* base64EncodedResource = [data base64EncodedStringWithOptions:0]; | 211 NSString* base64EncodedResource = [data base64EncodedStringWithOptions:0]; |
| 188 NSString* dataURLString = [NSString | 212 NSString* dataURLString = [NSString |
| 189 stringWithFormat:@"data:image/png;base64,%@", base64EncodedResource]; | 213 stringWithFormat:@"data:image/png;base64,%@", base64EncodedResource]; |
| 190 NSString* faviconURLString = base::SysUTF8ToNSString(faviconURL.spec()); | 214 NSString* faviconURLString = base::SysUTF8ToNSString(faviconURL.spec()); |
| 191 NSString* script = | 215 NSString* script = |
| 192 [NSString stringWithFormat:@"chrome.setFaviconBackground('%@', '%@');", | 216 [NSString stringWithFormat:@"chrome.setFaviconBackground('%@', '%@');", |
| 193 faviconURLString, dataURLString]; | 217 faviconURLString, dataURLString]; |
| 194 [strongSelf webState]->ExecuteJavaScriptAsync( | 218 [strongSelf webState]->ExecuteJavaScript(base::SysNSStringToUTF16(script)); |
| 195 base::SysNSStringToUTF16(script)); | |
| 196 }; | 219 }; |
| 197 [self fetchResourceWithURL:faviconURL completionHandler:faviconHandler]; | 220 [self fetchResourceWithURL:faviconURL completionHandler:faviconHandler]; |
| 198 return YES; | 221 return YES; |
| 199 } | 222 } |
| 200 | 223 |
| 224 - (BOOL)handleLoadMojo:(const base::ListValue*)arguments { |
| 225 std::string moduleName; |
| 226 if (!arguments->GetString(0, &moduleName)) { |
| 227 DLOG(WARNING) << "JS message parameter not found: Module name"; |
| 228 return NO; |
| 229 } |
| 230 std::string loadID; |
| 231 if (!arguments->GetString(1, &loadID)) { |
| 232 DLOG(WARNING) << "JS message parameter not found: Load ID"; |
| 233 return NO; |
| 234 } |
| 235 |
| 236 // Load and inject the script. |
| 237 GURL resourceURL(self.webState->GetLastCommittedURL().Resolve(moduleName)); |
| 238 base::WeakNSObject<CRWWebUIManager> weakSelf(self); |
| 239 [self fetchResourceWithURL:resourceURL completionHandler:^(NSData* data) { |
| 240 std::string script; |
| 241 if (data) { |
| 242 script = base::SysNSStringToUTF8( |
| 243 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); |
| 244 // WebUIIOSDataSourceImpl returns the default resource (which is the HTML |
| 245 // page itself) if the resource URL isn't found. Fail with error instead |
| 246 // of silently injecting garbage (leading to a not-very-useful syntax |
| 247 // error from the JS side). |
| 248 if (script.find("<!doctype") != std::string::npos) { |
| 249 NOTREACHED() << "cannot load " << moduleName; |
| 250 script.clear(); |
| 251 } |
| 252 } |
| 253 |
| 254 // Append with completion function call. |
| 255 if (script.empty()) { |
| 256 DLOG(ERROR) << "Unable to find a module named " << moduleName; |
| 257 script = "__crWeb.webUIModuleLoadNotifier.moduleLoadFailed"; |
| 258 } else { |
| 259 script += "__crWeb.webUIModuleLoadNotifier.moduleLoadCompleted"; |
| 260 } |
| 261 base::StringAppendF(&script, "(%s, %s);", |
| 262 base::GetQuotedJSONString(moduleName).c_str(), |
| 263 base::GetQuotedJSONString(loadID).c_str()); |
| 264 |
| 265 [weakSelf webState]->ExecuteJavaScript(base::UTF8ToUTF16(script)); |
| 266 }]; |
| 267 |
| 268 return YES; |
| 269 } |
| 270 |
| 201 - (void)resetWebState { | 271 - (void)resetWebState { |
| 202 if (_webState) { | 272 if (_webState) { |
| 203 _webState->RemoveScriptCommandCallback(kScriptCommandPrefix); | 273 _webState->RemoveScriptCommandCallback(kScriptCommandPrefix); |
| 204 } | 274 } |
| 205 _webState = nullptr; | 275 _webState = nullptr; |
| 206 } | 276 } |
| 207 | 277 |
| 208 - (web::WebStateImpl*)webState { | 278 - (web::WebStateImpl*)webState { |
| 209 return _webState; | 279 return _webState; |
| 210 } | 280 } |
| 211 | 281 |
| 212 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher { | 282 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher { |
| 213 _fetchers.erase(std::find(_fetchers.begin(), _fetchers.end(), fetcher)); | 283 _fetchers.erase(std::find(_fetchers.begin(), _fetchers.end(), fetcher)); |
| 214 } | 284 } |
| 215 | 285 |
| 216 #pragma mark - Testing-Only Methods | 286 #pragma mark - Testing-Only Methods |
| 217 | 287 |
| 218 - (std::unique_ptr<web::URLFetcherBlockAdapter>) | 288 - (std::unique_ptr<web::URLFetcherBlockAdapter>) |
| 219 fetcherForURL:(const GURL&)URL | 289 fetcherForURL:(const GURL&)URL |
| 220 completionHandler:(web::URLFetcherBlockAdapterCompletion)handler { | 290 completionHandler:(web::URLFetcherBlockAdapterCompletion)handler { |
| 221 return std::unique_ptr<web::URLFetcherBlockAdapter>( | 291 return std::unique_ptr<web::URLFetcherBlockAdapter>( |
| 222 new web::URLFetcherBlockAdapter( | 292 new web::URLFetcherBlockAdapter( |
| 223 URL, _webState->GetBrowserState()->GetRequestContext(), handler)); | 293 URL, _webState->GetBrowserState()->GetRequestContext(), handler)); |
| 224 } | 294 } |
| 225 | 295 |
| 226 @end | 296 @end |
| OLD | NEW |