From fed2da63ba4d733ce1f5bd35acd38751fbd53b4b Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Mon, 18 Nov 2019 02:50:56 +0100 Subject: [PATCH] fixed issue with headers in javascript code for intercepting ajax requests --- .idea/workspace.xml | 117 ++++++++++-------- .../InAppWebView/InAppWebView.java | 12 +- .../JavaScriptBridgeInterface.java | 6 +- example/ios/Runner/Info.plist | 2 +- example/lib/inline_example.screen.dart | 2 +- ios/Classes/InAppWebView.swift | 14 ++- lib/src/in_app_webview.dart | 6 +- lib/src/types.dart | 29 ++++- 8 files changed, 117 insertions(+), 71 deletions(-) diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 26e70306..800cea43 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -15,23 +15,12 @@ - - - - - - - - - - + - - - + @@ -69,7 +58,7 @@ - + @@ -78,8 +67,8 @@ - - + + @@ -88,10 +77,19 @@ + + + + + + + + + - - + + @@ -99,11 +97,20 @@ + + + + + + + + + - - + + @@ -120,11 +127,6 @@ - IosSafariOptionsDismissButtonStyle - method - AjaxRequestEvent - withCredentials - current FetchRequest my-special-custom-scheme should @@ -150,6 +152,11 @@ getHtml loadUrl evaluateJavascript + isAsync + "headers": headers + shouldIn + onZaboHandlerCallback + AndroidView activity.getPreferences(0) @@ -175,7 +182,6 @@ @@ -494,7 +501,7 @@ - + @@ -506,7 +513,7 @@ - + @@ -533,7 +540,6 @@ - @@ -742,13 +748,6 @@ - - - - - - - @@ -791,13 +790,6 @@ - - - - - - - @@ -808,33 +800,54 @@ - + - - + + + + + + + + + - - + + + + + + + + + - - + + + + + + + + + diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java index b9844d5a..a33c0b5f 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/InAppWebView/InAppWebView.java @@ -146,10 +146,12 @@ final public class InAppWebView extends InputAwareWebView { " this._flutter_inappbrowser_isAsync = isAsync;" + " this._flutter_inappbrowser_user = user;" + " this._flutter_inappbrowser_password = password;" + + " this._flutter_inappbrowser_request_headers = {};" + " open.call(this, method, url, isAsync, user, password);" + " };" + " ajax.prototype.setRequestHeader = function(header, value) {" + " this._flutter_inappbrowser_request_headers[header] = value;" + + " setRequestHeader.call(this, header, value);" + " };" + " function handleEvent(e) {" + " var self = this;" + @@ -290,10 +292,12 @@ final public class InAppWebView extends InputAwareWebView { " };" + " for (var header in result.headers) {" + " var value = result.headers[header];" + - " self._flutter_inappbrowser_request_headers[header] = value;" + - " };" + - " for (var header in self._flutter_inappbrowser_request_headers) {" + - " var value = self._flutter_inappbrowser_request_headers[header];" + + " var flutter_inappbrowser_value = self._flutter_inappbrowser_request_headers[header];" + + " if (flutter_inappbrowser_value == null) {" + + " self._flutter_inappbrowser_request_headers[header] = value;" + + " } else {" + + " self._flutter_inappbrowser_request_headers[header] += ', ' + value;" + + " }" + " setRequestHeader.call(self, header, value);" + " };" + " if ((self._flutter_inappbrowser_method != result.method && result.method != null) || (self._flutter_inappbrowser_url != result.url && result.url != null)) {" + diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java index f59dba56..10f965e8 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappbrowser/JavaScriptBridgeInterface.java @@ -39,7 +39,7 @@ public class JavaScriptBridgeInterface { } @JavascriptInterface - public void _callHandler(String handlerName, final String _callHandlerID, String args) { + public void _callHandler(final String handlerName, final String _callHandlerID, String args) { final Map obj = new HashMap<>(); if (inAppBrowserActivity != null) obj.put("uuid", inAppBrowserActivity.uuid); @@ -62,10 +62,10 @@ public class JavaScriptBridgeInterface { return; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - webView.evaluateJavascript("window." + name + "[" + _callHandlerID + "](" + json + "); delete window." + name + "[" + _callHandlerID + "];", (ValueCallback) null); + webView.evaluateJavascript("if(window." + name + "[" + _callHandlerID + "] != null) {window." + name + "[" + _callHandlerID + "](" + json + "); delete window." + name + "[" + _callHandlerID + "];}", (ValueCallback) null); } else { - webView.loadUrl("javascript:window." + name + "[" + _callHandlerID + "](" + json + "); delete window." + name + "[" + _callHandlerID + "];"); + webView.loadUrl("javascript:if(window." + name + "[" + _callHandlerID + "] != null) {window." + name + "[" + _callHandlerID + "](" + json + "); delete window." + name + "[" + _callHandlerID + "];}"); } } diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index fc362f4e..20ca57dc 100755 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -2,7 +2,7 @@ - NSLocationAlwaysUsageDescription + NSLocationAlwaysUsageDescription Need location NSLocationWhenInUseUsageDescription Need location diff --git a/example/lib/inline_example.screen.dart b/example/lib/inline_example.screen.dart index 9ade8a3e..0035030d 100755 --- a/example/lib/inline_example.screen.dart +++ b/example/lib/inline_example.screen.dart @@ -450,4 +450,4 @@ class _InlineExampleScreenState extends State { : await getApplicationDocumentsDirectory(); return directory.path; } -} +} \ No newline at end of file diff --git a/ios/Classes/InAppWebView.swift b/ios/Classes/InAppWebView.swift index d8bdeea5..97ba8059 100755 --- a/ios/Classes/InAppWebView.swift +++ b/ios/Classes/InAppWebView.swift @@ -296,10 +296,12 @@ let interceptAjaxRequestsJS = """ this._flutter_inappbrowser_isAsync = isAsync; this._flutter_inappbrowser_user = user; this._flutter_inappbrowser_password = password; + this._flutter_inappbrowser_request_headers = {}; open.call(this, method, url, isAsync, user, password); }; ajax.prototype.setRequestHeader = function(header, value) { this._flutter_inappbrowser_request_headers[header] = value; + setRequestHeader.call(this, header, value); }; function handleEvent(e) { var self = this; @@ -440,10 +442,12 @@ let interceptAjaxRequestsJS = """ }; for (var header in result.headers) { var value = result.headers[header]; - self._flutter_inappbrowser_request_headers[header] = value; - }; - for (var header in self._flutter_inappbrowser_request_headers) { - var value = self._flutter_inappbrowser_request_headers[header]; + var flutter_inappbrowser_value = self._flutter_inappbrowser_request_headers[header]; + if (flutter_inappbrowser_value == null) { + self._flutter_inappbrowser_request_headers[header] = value; + } else { + self._flutter_inappbrowser_request_headers[header] += ', ' + value; + } setRequestHeader.call(self, header, value); }; if ((self._flutter_inappbrowser_method != result.method && result.method != null) || (self._flutter_inappbrowser_url != result.url && result.url != null)) { @@ -2021,7 +2025,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi if let r = result { json = r as! String } - self.evaluateJavaScript("window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)](\(json)); delete window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)];", completionHandler: nil) + self.evaluateJavaScript("if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)](\(json)); delete window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)];}", completionHandler: nil) } }) } diff --git a/lib/src/in_app_webview.dart b/lib/src/in_app_webview.dart index 83a0df3f..09df3a7a 100755 --- a/lib/src/in_app_webview.dart +++ b/lib/src/in_app_webview.dart @@ -591,7 +591,7 @@ class InAppWebViewController { String user = argMap["user"]; String password = argMap["password"]; bool withCredentials = argMap["withCredentials"]; - Map headers = argMap["headers"]; + AjaxRequestHeaders headers = AjaxRequestHeaders(argMap["headers"]); String responseType = argMap["responseType"]; var request = new AjaxRequest(data: data, method: method, url: url, isAsync: isAsync, user: user, password: password, withCredentials: withCredentials, headers: headers, responseType: responseType); @@ -610,7 +610,7 @@ class InAppWebViewController { String user = argMap["user"]; String password = argMap["password"]; bool withCredentials = argMap["withCredentials"]; - Map headers = argMap["headers"]; + AjaxRequestHeaders headers = AjaxRequestHeaders(argMap["headers"]); int readyState = argMap["readyState"]; int status = argMap["status"]; String responseURL = argMap["responseURL"]; @@ -639,7 +639,7 @@ class InAppWebViewController { String user = argMap["user"]; String password = argMap["password"]; bool withCredentials = argMap["withCredentials"]; - Map headers = argMap["headers"]; + AjaxRequestHeaders headers = AjaxRequestHeaders(argMap["headers"]); int readyState = argMap["readyState"]; int status = argMap["status"]; String responseURL = argMap["responseURL"]; diff --git a/lib/src/types.dart b/lib/src/types.dart index 6a1d1de1..375a3f8b 100644 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -1064,6 +1064,31 @@ class AjaxRequestReadyState { int get hashCode => _value.hashCode; } +///AjaxRequestHeaders class represents the HTTP headers of an [AjaxRequest]. +class AjaxRequestHeaders { + Map _headers; + Map _newHeaders = {}; + + AjaxRequestHeaders(this._headers); + + ///Gets the HTTP headers of the [AjaxRequest]. + Map getHeaders() { + return this._headers; + } + + ///Sets/updates an HTTP header of the [AjaxRequest]. If there is already an existing [header] with the same name, the values are merged into one single request header. + ///For security reasons, some headers can only be controlled by the user agent. + ///These headers include the [forbidden header names](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name) + ///and [forbidden response header names](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_response_header_name). + void setRequestHeader(String header, String value) { + _newHeaders[header] = value; + } + + Map toMap() { + return _newHeaders; + } +} + ///AjaxRequest class represents a JavaScript [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) object. class AjaxRequest { ///Data passed as a parameter to the `XMLHttpRequest.send()` method. @@ -1084,7 +1109,7 @@ class AjaxRequest { ///In addition, this flag is also used to indicate when cookies are to be ignored in the response. The default is false. bool withCredentials; ///The HTTP request headers. - Map headers; + AjaxRequestHeaders headers; ///The state of the `XMLHttpRequest` request. AjaxRequestReadyState readyState; ///The numerical HTTP [status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) of the `XMLHttpRequest`'s response. @@ -1128,7 +1153,7 @@ class AjaxRequest { "user": user, "password": password, "withCredentials": withCredentials, - "headers": headers, + "headers": headers?.toMap(), "readyState": readyState?.toValue(), "status": status, "responseURL": responseURL,