Chromium Code Reviews| Index: ios/web/web_state/ui/crw_wk_web_view_web_controller.mm |
| diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm |
| index c680bac819c6c8de6d660337a0b4c3c270862794..fa30d41dbc8a707166c845d36e62f7c20e17bb1a 100644 |
| --- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm |
| +++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm |
| @@ -10,7 +10,7 @@ |
| #include "base/ios/ios_util.h" |
| #include "base/ios/weak_nsobject.h" |
| #include "base/json/json_reader.h" |
| -#include "base/mac/objc_property_releaser.h" |
| +#import "base/mac/objc_property_releaser.h" |
| #import "base/mac/scoped_nsobject.h" |
| #include "base/macros.h" |
| #include "base/metrics/histogram_macros.h" |
| @@ -39,6 +39,7 @@ |
| #import "ios/web/web_state/crw_pass_kit_downloader.h" |
| #import "ios/web/web_state/error_translation_util.h" |
| #include "ios/web/web_state/frame_info.h" |
| +#import "ios/web/web_state/js/crw_js_post_request_loader.h" |
| #import "ios/web/web_state/js/crw_js_window_id_manager.h" |
| #import "ios/web/web_state/ui/crw_web_controller+protected.h" |
| #import "ios/web/web_state/ui/crw_wk_script_message_router.h" |
| @@ -187,6 +188,9 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| // Handles downloading PassKit data for WKWebView. Lazy initialized. |
| base::scoped_nsobject<CRWPassKitDownloader> _passKitDownloader; |
| + // Object for loading POST requests with body. |
| + base::scoped_nsobject<CRWJSPOSTRequestLoader> _POSTRequestLoader; |
| + |
| // Whether the web page is currently performing window.history.pushState or |
| // window.history.replaceState |
| // Set to YES on window.history.willChangeState message. To NO on |
| @@ -233,6 +237,15 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| // Downloader for PassKit files. Lazy initialized. |
| @property(nonatomic, readonly) CRWPassKitDownloader* passKitDownloader; |
| +// Loads POST request with body in |_wkWebView| by constructing an HTML page |
| +// that executes the request through JavaScript and replaces document with the |
| +// result. |
| +// Note that this approach includes multiple body encodings and decodings, plus |
| +// the data is passed to |_wkWebView| on main thread. |
| +// This is necessary because WKWebView ignores POST request body. |
| +// Workaround for https://bugs.webkit.org/show_bug.cgi?id=145410 |
| +- (void)loadPOSTRequest:(NSMutableURLRequest*)request; |
| + |
| // Returns the WKWebViewConfigurationProvider associated with the web |
| // controller's BrowserState. |
| - (web::WKWebViewConfigurationProvider&)webViewConfigurationProvider; |
| @@ -557,20 +570,42 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| - (void)loadRequestForCurrentNavigationItem { |
| DCHECK(self.webView && !self.nativeController); |
| + DCHECK([self currentSessionEntry]); |
| + |
| + web::WKBackForwardListItemHolder* holder = |
| + [self currentBackForwardListItemHolder]; |
| + BOOL isFormResubmission = |
| + (holder->navigation_type() == WKNavigationTypeFormResubmitted || |
| + holder->navigation_type() == WKNavigationTypeFormSubmitted); |
| + web::NavigationItemImpl* currentItem = |
| + [self currentSessionEntry].navigationItemImpl; |
| + NSData* POSTData = currentItem->GetPostData(); |
| + NSMutableURLRequest* request = [self requestForCurrentNavigationItem]; |
| + |
| + // If the request has POST data and is not a form resubmission, configure and |
| + // run the POST request. |
| + if (POSTData.length && !isFormResubmission) { |
| + [request setHTTPMethod:@"POST"]; |
| + [request setHTTPBody:POSTData]; |
| + [request setAllHTTPHeaderFields:[self currentHTTPHeaders]]; |
| + [self registerLoadRequest:[self currentNavigationURL] |
| + referrer:[self currentSessionEntryReferrer] |
| + transition:[self currentTransition]]; |
| + [self loadPOSTRequest:request]; |
| + return; |
| + } |
| ProceduralBlock defaultNavigationBlock = ^{ |
| [self registerLoadRequest:[self currentNavigationURL] |
| referrer:[self currentSessionEntryReferrer] |
| transition:[self currentTransition]]; |
| - [self loadRequest:[self requestForCurrentNavigationItem]]; |
| + [self loadRequest:request]; |
| }; |
| // If there is no corresponding WKBackForwardListItem, or the item is not in |
| // the current WKWebView's back-forward list, navigating using WKWebView API |
| // is not possible. In this case, fall back to the default navigation |
| // mechanism. |
| - web::WKBackForwardListItemHolder* holder = |
| - [self currentBackForwardListItemHolder]; |
| if (!holder->back_forward_list_item() || |
| ![self isBackForwardListItemValid:holder->back_forward_list_item()]) { |
| defaultNavigationBlock(); |
| @@ -594,10 +629,7 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| // If the request is not a form submission or resubmission, or the user |
| // doesn't need to confirm the load, then continue right away. |
| - web::NavigationItemImpl* currentItem = |
| - [self currentSessionEntry].navigationItemImpl; |
| - if ((holder->navigation_type() != WKNavigationTypeFormResubmitted && |
| - holder->navigation_type() != WKNavigationTypeFormSubmitted) || |
| + if (!isFormResubmission || |
| currentItem->ShouldSkipResubmitDataConfirmation()) { |
| webViewNavigationBlock(); |
| return; |
| @@ -605,6 +637,7 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| // If the request is form submission or resubmission, then prompt the |
| // user before proceeding. |
| + DCHECK(isFormResubmission); |
| [self.delegate webController:self |
| onFormResubmissionForRequest:nil |
| continueBlock:webViewNavigationBlock |
| @@ -715,6 +748,25 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| return self.webStateImpl->GetRequestTracker()->identifier(); |
| } |
| +- (void)loadPOSTRequest:(NSMutableURLRequest*)request { |
| + if (!_POSTRequestLoader) { |
| + _POSTRequestLoader.reset([[CRWJSPOSTRequestLoader alloc] init]); |
| + } |
| + |
| + CRWWKScriptMessageRouter* messageRouter = |
| + [self webViewConfigurationProvider].GetScriptMessageRouter(); |
| + |
| + [_POSTRequestLoader loadPOSTRequest:request |
| + inWebView:_wkWebView |
| + messageRouter:messageRouter |
| + completionBlock:^(NSError* loadError) { |
| + if (loadError) |
| + [self handleLoadError:loadError inMainFrame:YES]; |
| + else |
| + self.webStateImpl->SetContentsMimeType("text/html"); |
| + }]; |
| +} |
| + |
| - (web::WKWebViewConfigurationProvider&)webViewConfigurationProvider { |
| DCHECK(self.webStateImpl); |
| web::BrowserState* browserState = self.webStateImpl->GetBrowserState(); |
| @@ -850,19 +902,11 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| web::WKBackForwardListItemHolder* holder = |
| [self currentBackForwardListItemHolder]; |
| - |
| WKNavigationType navigationType = |
| _pendingNavigationInfo ? [_pendingNavigationInfo navigationType] |
| : WKNavigationTypeOther; |
| holder->set_back_forward_list_item([_wkWebView backForwardList].currentItem); |
| holder->set_navigation_type(navigationType); |
| - |
| - // Only update the MIME type in the holder if there was MIME type information |
| - // as part of this pending load. It will be nil when doing a fast |
| - // back/forward navigation, for instance, because the callback that would |
| - // populate it is not called in that flow. |
| - if ([_pendingNavigationInfo MIMEType]) |
| - holder->set_mime_type([_pendingNavigationInfo MIMEType]); |
| } |
| - (BOOL)isBackForwardListItemValid:(WKBackForwardListItem*)item { |
| @@ -1542,15 +1586,10 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| return; |
| } |
| GURL jsURL([result UTF8String]); |
| - // Make sure that the window location is as expected, |
| - // and re-check the origin and web view URL to prevent |
| - // race conditions. |
| - // TODO(crbug.com/563568): The third check may drop same |
| - // document URL changes if pending URL change occurs |
| - // immediately after. Revisit heuristics to prevent this. |
| + // Make sure that the URL is as expected, and re-check |
|
Eugene But (OOO till 7-30)
2015/12/03 16:51:43
Please revert
stkhapugin
2015/12/03 17:51:03
Done.
|
| + // the origin to prevent race conditions. |
| if (jsURL == url && |
| - _documentURL.GetOrigin() == url.GetOrigin() && |
| - net::GURLWithNSURL([_wkWebView URL]) == url) { |
| + _documentURL.GetOrigin() == url.GetOrigin()) { |
|
Eugene But (OOO till 7-30)
2015/12/03 16:51:42
ditto
stkhapugin
2015/12/03 17:51:03
Done.
|
| [self URLDidChangeWithoutDocumentChange:url]; |
| } |
| }]; |
| @@ -1714,17 +1753,6 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
| DCHECK(_documentURL == self.lastRegisteredRequestURL); |
| self.webStateImpl->OnNavigationCommitted(_documentURL); |
| [self commitPendingNavigationInfo]; |
| - if ([self currentBackForwardListItemHolder]->navigation_type() == |
|
Eugene But (OOO till 7-30)
2015/12/03 16:51:42
ditto
stkhapugin
2015/12/03 17:51:03
Done.
|
| - WKNavigationTypeBackForward) { |
| - // A fast back/forward won't call decidePolicyForNavigationResponse, so |
| - // the MIME type needs to be updated explicitly. |
| - NSString* storedMIMEType = |
| - [self currentBackForwardListItemHolder]->mime_type(); |
| - if (storedMIMEType) { |
| - self.webStateImpl->SetContentsMimeType( |
| - base::SysNSStringToUTF8(storedMIMEType)); |
| - } |
| - } |
| [self webPageChanged]; |
| [self updateSSLStatusForCurrentNavigationItem]; |