THon
THon

Reputation: 31

iOS WKWebView - WKURLSchemeHandler crash on posting body (EXC_BAD_ACCESS)

I use my custom WKURLSchemeHandler to intercept resource requests from WKWebView.
It works for GET requests, but crashes on some POST requests.

Prerequisites:
set WKURLSchemeHandler to WKWebView like this

let config = WKWebViewConfiguration()
config.setURLSchemeHandler(WKURLSchemeHandlerImplementedClass(), forURLScheme: CUSTOM_SCHEME)
let webView = WKWebView(frame: CGRect.init(x: 0, y: 0, width: self.webViewContainer.frame.width, height: self.webViewContainer.frame.height), configuration: config)

Procedures:
1. Load URL where uploading files supported on WKWebView.
e.g. https://cgi-lib.berkeley.edu/ex/fup.html
(https should be changed to the CUSTOM_SCHEME)
2. Select any file from input file form.
3. Press a button to upload the file.
-> crash

Call stack:
WebViewProtocol is WKURLSchemeHandlerImplementedClass above.

#0  0x00007fff4b8d6a3e in WebCore::blobRegistry() ()
#1  0x00007fff4b9052ad in WebCore::createHTTPBodyCFReadStream(WebCore::FormData&) ()
#2  0x00007fff4b905d18 in WebCore::setHTTPBody(_CFURLRequest*, WebCore::FormData*) ()
#3  0x00007fff4a851e0c in WebCore::ResourceRequest::doUpdatePlatformHTTPBody() ()
#4  0x00007fff4b8fe47d in WebCore::ResourceRequestBase::updatePlatformRequest(WebCore::HTTPBodyUpdatePolicy) const ()
#5  0x00007fff4a8506de in WebCore::ResourceRequest::nsURLRequest(WebCore::HTTPBodyUpdatePolicy) const ()
#6  0x00007fff2d1950ea in WebKit::WebURLSchemeTask::nsRequest() const ()
#7  0x0000000105f082f4 in WebViewProtocol.webView(_:start:) at /Users/t_honda/iOSProjects/smartdb-mobile-ios/smartdb/DocumentDetail/webView/WebViewProtocol.swift:30
#8  0x0000000105f09989 in @objc WebViewProtocol.webView(_:start:) ()
#9  0x00007fff2d13b41f in WebKit::WebURLSchemeHandlerCocoa::platformStartTask(WebKit::WebPageProxy&, WebKit::WebURLSchemeTask&) ()
#10 0x00007fff2d1940ca in WebKit::WebURLSchemeHandler::startTask(WebKit::WebPageProxy&, WebKit::WebProcessProxy&, unsigned long long, WebCore::ResourceRequest&&, WTF::CompletionHandler<void (WebCore::ResourceResponse const&, WebCore::ResourceError const&, WTF::Vector<char, 0ul, WTF::CrashOnOverflow, 16ul> const&)>&&) ()
#11 0x00007fff2d165864 in WebKit::WebPageProxy::startURLSchemeTaskShared(WTF::Ref<WebKit::WebProcessProxy, WTF::DumbPtrTraits<WebKit::WebProcessProxy> >&&, WebKit::URLSchemeTaskParameters&&) ()
#12 0x00007fff2d1657db in WebKit::WebPageProxy::startURLSchemeTask(WebKit::URLSchemeTaskParameters&&) ()
#13 0x00007fff2d3cd225 in void IPC::handleMessage<Messages::WebPageProxy::StartURLSchemeTask, WebKit::WebPageProxy, void (WebKit::WebPageProxy::*)(WebKit::URLSchemeTaskParameters&&)>(IPC::Decoder&, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(WebKit::URLSchemeTaskParameters&&)) ()
#14 0x00007fff2cf4582e in IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&) ()
#15 0x00007fff2d190448 in WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) ()
#16 0x00007fff2cf31802 in IPC::Connection::dispatchMessage(std::__1::unique_ptr<IPC::Decoder, std::__1::default_delete<IPC::Decoder> >) ()
#17 0x00007fff2cf345a4 in IPC::Connection::dispatchIncomingMessages() ()

I confirmed the crash on iOS 13.3.

class WKURLSchemeHandlerImplementedClass:NSObject, WKURLSchemeHandler {
    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        guard let customUrl = urlSchemeTask.request.url else { return }
        var comps = URLComponents(url: customUrl, resolvingAgainstBaseURL: false)!
        comps.scheme = "https"
        let httpsUrl = comps.url!
        // Send HTTP Request with service-specific headers via service-specfic proxy
        // Crash occurrs on referring to urlSchemeTask.request
    }
    func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask)     {
    }
}

Upvotes: 1

Views: 4523

Answers (3)

luca
luca

Reputation: 1

Try this before your request.

   SEL selector = sel_registerName("_setLoadResourcesSerially:");
id webViewClass = NSClassFromString(@"WebView");
if ([webViewClass respondsToSelector:selector]) {
    [webViewClass performSelector:selector withObject:@NO];
}

Thanks for Rick Huang.I was tortured miserably by this problem.First I try to call this method by webview instance.The crash also.Then I consult this method in wkwebview source code, I saw this method is a class method. Then I try to call this with webview class instance. It works good. I am very glad. Thanks for one more time.

By the way, who knows how the method effect? Why I need call this on iOS13?

Upvotes: 0

Rick Huang
Rick Huang

Reputation: 11

Inspired by Eugene Pavlyuk's reply, method "_setLoadResourcesSerially:" works for me.

Written in swift:

let selector = sel_registerName("_setLoadResourcesSerially:")
if let wv = NSClassFromString("WebView") as? NSObject.Type,
    wv.responds(to: selector) {
    wv.perform(selector, with: false as Any)
}

Upvotes: 1

Eugene Pavlyuk
Eugene Pavlyuk

Reputation: 11

Try this before getting the request in SchemeHandler:

id webView = NSClassFromString(@"WebView");
[webView _setLoadResourcesSerially:NO];

Upvotes: 1

Related Questions