OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #import "ios/web/web_state/js/crw_js_post_request_loader.h" | |
6 | |
7 #include "base/json/string_escape.h" | |
8 #import "base/mac/scoped_nsobject.h" | |
9 #import "base/strings/sys_string_conversions.h" | |
10 #import "ios/web/web_state/js/page_script_util.h" | |
11 #import "ios/web/web_state/ui/crw_wk_script_message_router.h" | |
12 | |
13 namespace { | |
14 | |
15 // Escapes characters and encloses given string in quotes for use in JavaScript. | |
16 NSString* EscapeAndQuoteStringForJavaScript(NSString* unescapedString) { | |
17 std::string string = base::SysNSStringToUTF8(unescapedString); | |
18 return base::SysUTF8ToNSString(base::GetQuotedJSONString(string)); | |
19 } | |
20 | |
21 // JavaScript message handler name installed in WKWebView for request errors. | |
22 NSString* const kErrorHandlerName = @"POSTErrorHandler"; | |
23 | |
24 // JavaScript message handler name installed in WKWebView for successful | |
25 // request completion. | |
26 NSString* const kSuccessHandlerName = @"POSTSuccessHandler"; | |
27 | |
28 } // namespace | |
29 | |
30 @interface CRWJSPOSTRequestLoader () { | |
31 base::scoped_nsobject<NSString> _requestScript; | |
32 } | |
33 | |
34 // JavaScript used to execute POST requests. Lazily instantiated. | |
35 @property(nonatomic, copy, readonly) NSString* requestScript; | |
36 | |
37 // Handler for UIApplicationDidReceiveMemoryWarningNotification. | |
38 - (void)handleMemoryWarning; | |
39 | |
40 // Forms a JavaScript method call to |requestScript| that executes given | |
41 // |request|. | |
42 - (NSString*)scriptToExecutePOSTRequest:(NSURLRequest*)request; | |
43 | |
44 // Converts a dictionary of HTTP request headers to a JavaScript object. | |
45 - (NSString*)JSONForJavaScriptFromRequestHeaders:(NSDictionary*)headers; | |
46 | |
47 @end | |
48 | |
49 @implementation CRWJSPOSTRequestLoader | |
50 | |
51 - (void)dealloc { | |
52 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
53 [super dealloc]; | |
54 } | |
55 | |
56 - (instancetype)init { | |
57 self = [super init]; | |
58 if (self) { | |
59 [[NSNotificationCenter defaultCenter] | |
60 addObserver:self | |
61 selector:@selector(handleMemoryWarning) | |
62 name:UIApplicationDidReceiveMemoryWarningNotification | |
63 object:nil]; | |
64 } | |
65 return self; | |
66 } | |
67 | |
68 - (NSString*)requestScript { | |
69 if (!_requestScript) { | |
70 _requestScript.reset([web::GetPageScript(@"post_request") copy]); | |
71 } | |
72 return _requestScript.get(); | |
73 } | |
74 | |
75 - (void)loadPOSTRequest:(NSURLRequest*)request | |
76 inWebView:(WKWebView*)webView | |
77 messageRouter:(CRWWKScriptMessageRouter*)messageRouter | |
78 completionHandler:(void (^)(NSError*))completionHandler { | |
79 DCHECK([request.HTTPMethod isEqualToString:@"POST"]); | |
80 DCHECK(webView); | |
81 DCHECK(messageRouter); | |
82 DCHECK(completionHandler); | |
83 | |
84 // Install error handling and success routers. | |
85 [messageRouter setScriptMessageHandler:^(WKScriptMessage* message) { | |
86 // Cleaning up script handlers. | |
87 [messageRouter removeScriptMessageHandlerForName:kErrorHandlerName | |
88 webView:webView]; | |
89 [messageRouter removeScriptMessageHandlerForName:kSuccessHandlerName | |
90 webView:webView]; | |
91 completionHandler(nil); | |
92 | |
Eugene But (OOO till 7-30)
2015/12/03 18:13:21
extra linebreak
stkhapugin
2015/12/04 16:28:10
Done.
| |
93 } | |
94 name:kSuccessHandlerName | |
95 webView:webView]; | |
96 | |
97 [messageRouter setScriptMessageHandler:^(WKScriptMessage* message) { | |
98 NSNumber* statusCode = message.body; | |
99 NSError* error = [NSError errorWithDomain:@"http" | |
100 code:statusCode.integerValue | |
101 userInfo:nil]; | |
102 // Cleaning up script handlers. | |
103 [messageRouter removeScriptMessageHandlerForName:kErrorHandlerName | |
104 webView:webView]; | |
105 [messageRouter removeScriptMessageHandlerForName:kSuccessHandlerName | |
106 webView:webView]; | |
107 completionHandler(error); | |
108 } | |
109 name:kErrorHandlerName | |
110 webView:webView]; | |
111 | |
112 NSString* HTML = | |
113 [NSString stringWithFormat:@"<html><script>%@%@</script></html>", | |
114 self.requestScript, | |
115 [self scriptToExecutePOSTRequest:request]]; | |
116 [webView loadHTMLString:HTML baseURL:request.URL]; | |
117 } | |
118 | |
119 #pragma mark - Private methods. | |
120 | |
121 - (void)handleMemoryWarning { | |
122 // Request script can be recreated from file at any moment. | |
123 [_requestScript release]; | |
Eugene But (OOO till 7-30)
2015/12/03 18:13:21
Please do not call release directly, this code wil
stkhapugin
2015/12/04 16:28:10
Done.
| |
124 _requestScript.reset(); | |
125 } | |
126 | |
127 - (NSString*)scriptToExecutePOSTRequest:(NSURLRequest*)request { | |
128 NSDictionary* headers = [request allHTTPHeaderFields]; | |
129 NSString* headerString = [self JSONForJavaScriptFromRequestHeaders:headers]; | |
130 NSString* URLString = [[request URL] absoluteString]; | |
131 NSString* contentType = headers[@"Content-Type"]; | |
132 NSString* base64Data = [[request HTTPBody] base64EncodedStringWithOptions:0]; | |
133 | |
134 // Here |headerString| is already properly escaped when returned from | |
135 // -JSONForJavaScriptFromRequestHeaders:. | |
136 return | |
137 [NSString stringWithFormat: | |
138 @"__crPostRequestWorkaround.runPostRequest(%@, %@, %@, %@)", | |
139 EscapeAndQuoteStringForJavaScript(URLString), headerString, | |
140 EscapeAndQuoteStringForJavaScript(base64Data), | |
141 EscapeAndQuoteStringForJavaScript(contentType)]; | |
142 } | |
143 | |
144 - (NSString*)JSONForJavaScriptFromRequestHeaders:(NSDictionary*)headers { | |
145 if (headers) { | |
146 NSData* headerData = | |
147 [NSJSONSerialization dataWithJSONObject:headers options:0 error:nil]; | |
148 if (headerData) { | |
149 // This string is properly escaped by NSJSONSerialization. It needs to | |
150 // have | |
151 // no quotes since JavaScripts takes this parameter as an | |
152 // Object<string, string>. | |
153 return [[[NSString alloc] initWithData:headerData | |
154 encoding:NSUTF8StringEncoding] autorelease]; | |
155 } | |
156 } | |
157 return @"{}"; | |
158 } | |
159 | |
160 @end | |
OLD | NEW |