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 fb9433e76143ca0f7ba4772b73bb72f439098697..8da1e3777fb7e520b4d07386acb6cb89c5bf22c6 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 |
@@ -239,6 +243,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; |
@@ -573,20 +586,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(); |
@@ -610,10 +645,8 @@ 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; |
@@ -621,6 +654,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 |
@@ -744,6 +778,25 @@ WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
} |
#endif |
+- (void)loadPOSTRequest:(NSMutableURLRequest*)request { |
+ if (!_POSTRequestLoader) { |
+ _POSTRequestLoader.reset([[CRWJSPOSTRequestLoader alloc] init]); |
+ } |
+ |
+ CRWWKScriptMessageRouter* messageRouter = |
+ [self webViewConfigurationProvider].GetScriptMessageRouter(); |
+ |
+ [_POSTRequestLoader loadPOSTRequest:request |
+ inWebView:_wkWebView |
+ messageRouter:messageRouter |
+ completionHandler:^(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(); |