269 lines
12 KiB
Swift
269 lines
12 KiB
Swift
//
|
|
// InterceptAjaxRequestsJS.swift
|
|
// flutter_inappwebview
|
|
//
|
|
// Created by Lorenzo Pichilli on 16/02/21.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT"
|
|
let FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._useShouldInterceptAjaxRequest"
|
|
|
|
|
|
let FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._interceptOnlyAsyncAjaxRequests";
|
|
|
|
let INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT = PluginScript(
|
|
groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
|
source: INTERCEPT_AJAX_REQUEST_JS_SOURCE,
|
|
injectionTime: .atDocumentStart,
|
|
forMainFrameOnly: false,
|
|
requiredInAllContentWorlds: true,
|
|
messageHandlerNames: [])
|
|
|
|
func createInterceptOnlyAsyncAjaxRequestsPluginScript(onlyAsync: Bool) -> PluginScript {
|
|
return PluginScript(groupName: INTERCEPT_AJAX_REQUEST_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
|
source: "\(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE) = \(onlyAsync);",
|
|
injectionTime: .atDocumentStart,
|
|
forMainFrameOnly: false,
|
|
requiredInAllContentWorlds: true,
|
|
messageHandlerNames: []
|
|
);
|
|
}
|
|
|
|
let INTERCEPT_AJAX_REQUEST_JS_SOURCE = """
|
|
\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) = true;
|
|
(function(ajax) {
|
|
var send = ajax.prototype.send;
|
|
var open = ajax.prototype.open;
|
|
var setRequestHeader = ajax.prototype.setRequestHeader;
|
|
ajax.prototype._flutter_inappwebview_url = null;
|
|
ajax.prototype._flutter_inappwebview_method = null;
|
|
ajax.prototype._flutter_inappwebview_isAsync = null;
|
|
ajax.prototype._flutter_inappwebview_user = null;
|
|
ajax.prototype._flutter_inappwebview_password = null;
|
|
ajax.prototype._flutter_inappwebview_password = null;
|
|
ajax.prototype._flutter_inappwebview_already_onreadystatechange_wrapped = false;
|
|
ajax.prototype._flutter_inappwebview_request_headers = {};
|
|
function convertRequestResponse(request, callback) {
|
|
if (request.response != null && request.responseType != null) {
|
|
switch (request.responseType) {
|
|
case 'arraybuffer':
|
|
callback(new Uint8Array(request.response));
|
|
return;
|
|
case 'blob':
|
|
const reader = new FileReader();
|
|
reader.addEventListener('loadend', function() {
|
|
callback(new Uint8Array(reader.result));
|
|
});
|
|
reader.readAsArrayBuffer(blob);
|
|
return;
|
|
case 'document':
|
|
callback(request.response.documentElement.outerHTML);
|
|
return;
|
|
case 'json':
|
|
callback(request.response);
|
|
return;
|
|
};
|
|
}
|
|
callback(null);
|
|
};
|
|
ajax.prototype.open = function(method, url, isAsync, user, password) {
|
|
isAsync = (isAsync != null) ? isAsync : true;
|
|
this._flutter_inappwebview_url = url;
|
|
this._flutter_inappwebview_method = method;
|
|
this._flutter_inappwebview_isAsync = isAsync;
|
|
this._flutter_inappwebview_user = user;
|
|
this._flutter_inappwebview_password = password;
|
|
this._flutter_inappwebview_request_headers = {};
|
|
open.call(this, method, url, isAsync, user, password);
|
|
};
|
|
ajax.prototype.setRequestHeader = function(header, value) {
|
|
this._flutter_inappwebview_request_headers[header] = value;
|
|
setRequestHeader.call(this, header, value);
|
|
};
|
|
function handleEvent(e) {
|
|
var self = this;
|
|
if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == true) {
|
|
var headers = this.getAllResponseHeaders();
|
|
var responseHeaders = {};
|
|
if (headers != null) {
|
|
var arr = headers.trim().split(/[\\r\\n]+/);
|
|
arr.forEach(function (line) {
|
|
var parts = line.split(': ');
|
|
var header = parts.shift();
|
|
var value = parts.join(': ');
|
|
responseHeaders[header] = value;
|
|
});
|
|
}
|
|
convertRequestResponse(this, function(response) {
|
|
var ajaxRequest = {
|
|
method: self._flutter_inappwebview_method,
|
|
url: self._flutter_inappwebview_url,
|
|
isAsync: self._flutter_inappwebview_isAsync,
|
|
user: self._flutter_inappwebview_user,
|
|
password: self._flutter_inappwebview_password,
|
|
withCredentials: self.withCredentials,
|
|
headers: self._flutter_inappwebview_request_headers,
|
|
readyState: self.readyState,
|
|
status: self.status,
|
|
responseURL: self.responseURL,
|
|
responseType: self.responseType,
|
|
response: response,
|
|
responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null,
|
|
responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null,
|
|
statusText: self.statusText,
|
|
responseHeaders, responseHeaders,
|
|
event: {
|
|
type: e.type,
|
|
loaded: e.loaded,
|
|
lengthComputable: e.lengthComputable,
|
|
total: e.total
|
|
}
|
|
};
|
|
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler('onAjaxProgress', ajaxRequest).then(function(result) {
|
|
if (result != null) {
|
|
switch (result) {
|
|
case 0:
|
|
self.abort();
|
|
return;
|
|
};
|
|
}
|
|
});
|
|
});
|
|
}
|
|
};
|
|
ajax.prototype.send = function(data) {
|
|
var self = this;
|
|
var canBeIntercepted = self._flutter_inappwebview_isAsync || \(FLAG_VARIABLE_FOR_INTERCEPT_ONLY_ASYNC_AJAX_REQUESTS_JS_SOURCE) === false;
|
|
if (canBeIntercepted && (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == true)) {
|
|
if (!this._flutter_inappwebview_already_onreadystatechange_wrapped) {
|
|
this._flutter_inappwebview_already_onreadystatechange_wrapped = true;
|
|
var onreadystatechange = this.onreadystatechange;
|
|
this.onreadystatechange = function() {
|
|
if (\(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == null || \(FLAG_VARIABLE_FOR_SHOULD_INTERCEPT_AJAX_REQUEST_JS_SOURCE) == true) {
|
|
var headers = this.getAllResponseHeaders();
|
|
var responseHeaders = {};
|
|
if (headers != null) {
|
|
var arr = headers.trim().split(/[\\r\\n]+/);
|
|
arr.forEach(function (line) {
|
|
var parts = line.split(': ');
|
|
var header = parts.shift();
|
|
var value = parts.join(': ');
|
|
responseHeaders[header] = value;
|
|
});
|
|
}
|
|
convertRequestResponse(this, function(response) {
|
|
var ajaxRequest = {
|
|
method: self._flutter_inappwebview_method,
|
|
url: self._flutter_inappwebview_url,
|
|
isAsync: self._flutter_inappwebview_isAsync,
|
|
user: self._flutter_inappwebview_user,
|
|
password: self._flutter_inappwebview_password,
|
|
withCredentials: self.withCredentials,
|
|
headers: self._flutter_inappwebview_request_headers,
|
|
readyState: self.readyState,
|
|
status: self.status,
|
|
responseURL: self.responseURL,
|
|
responseType: self.responseType,
|
|
response: response,
|
|
responseText: (self.responseType == 'text' || self.responseType == '') ? self.responseText : null,
|
|
responseXML: (self.responseType == 'document' && self.responseXML != null) ? self.responseXML.documentElement.outerHTML : null,
|
|
statusText: self.statusText,
|
|
responseHeaders: responseHeaders
|
|
};
|
|
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler('onAjaxReadyStateChange', ajaxRequest).then(function(result) {
|
|
if (result != null) {
|
|
switch (result) {
|
|
case 0:
|
|
self.abort();
|
|
return;
|
|
};
|
|
}
|
|
if (onreadystatechange != null) {
|
|
onreadystatechange();
|
|
}
|
|
});
|
|
});
|
|
} else if (onreadystatechange != null) {
|
|
onreadystatechange();
|
|
}
|
|
};
|
|
}
|
|
this.addEventListener('loadstart', handleEvent);
|
|
this.addEventListener('load', handleEvent);
|
|
this.addEventListener('loadend', handleEvent);
|
|
this.addEventListener('progress', handleEvent);
|
|
this.addEventListener('error', handleEvent);
|
|
this.addEventListener('abort', handleEvent);
|
|
this.addEventListener('timeout', handleEvent);
|
|
\(JAVASCRIPT_UTIL_VAR_NAME).convertBodyRequest(data).then(function(data) {
|
|
var ajaxRequest = {
|
|
data: data,
|
|
method: self._flutter_inappwebview_method,
|
|
url: self._flutter_inappwebview_url,
|
|
isAsync: self._flutter_inappwebview_isAsync,
|
|
user: self._flutter_inappwebview_user,
|
|
password: self._flutter_inappwebview_password,
|
|
withCredentials: self.withCredentials,
|
|
headers: self._flutter_inappwebview_request_headers,
|
|
responseType: self.responseType
|
|
};
|
|
window.\(JAVASCRIPT_BRIDGE_NAME).callHandler('shouldInterceptAjaxRequest', ajaxRequest).then(function(result) {
|
|
if (result != null) {
|
|
switch (result) {
|
|
case 0:
|
|
self.abort();
|
|
return;
|
|
};
|
|
if (result.data != null && !\(JAVASCRIPT_UTIL_VAR_NAME).isString(result.data) && result.data.length > 0) {
|
|
var bodyString = \(JAVASCRIPT_UTIL_VAR_NAME).arrayBufferToString(result.data);
|
|
if (\(JAVASCRIPT_UTIL_VAR_NAME).isBodyFormData(bodyString)) {
|
|
var formDataContentType = \(JAVASCRIPT_UTIL_VAR_NAME).getFormDataContentType(bodyString);
|
|
if (result.headers != null) {
|
|
result.headers['Content-Type'] = result.headers['Content-Type'] == null ? formDataContentType : result.headers['Content-Type'];
|
|
} else {
|
|
result.headers = { 'Content-Type': formDataContentType };
|
|
}
|
|
}
|
|
}
|
|
if (\(JAVASCRIPT_UTIL_VAR_NAME).isString(result.data) || result.data == null) {
|
|
data = result.data;
|
|
} else if (result.data.length > 0) {
|
|
data = new Uint8Array(result.data);
|
|
}
|
|
self.withCredentials = result.withCredentials;
|
|
if (result.responseType != null && self._flutter_inappwebview_isAsync) {
|
|
self.responseType = result.responseType;
|
|
};
|
|
if (result.headers != null) {
|
|
for (var header in result.headers) {
|
|
var value = result.headers[header];
|
|
var flutter_inappwebview_value = self._flutter_inappwebview_request_headers[header];
|
|
if (flutter_inappwebview_value == null) {
|
|
self._flutter_inappwebview_request_headers[header] = value;
|
|
} else {
|
|
self._flutter_inappwebview_request_headers[header] += ', ' + value;
|
|
}
|
|
setRequestHeader.call(self, header, value);
|
|
};
|
|
}
|
|
if ((self._flutter_inappwebview_method != result.method && result.method != null) ||
|
|
(self._flutter_inappwebview_url != result.url && result.url != null) ||
|
|
(self._flutter_inappwebview_isAsync != result.isAsync && result.isAsync != null) ||
|
|
(self._flutter_inappwebview_user != result.user && result.user != null) ||
|
|
(self._flutter_inappwebview_password != result.password && result.password != null)) {
|
|
self.abort();
|
|
self.open(result.method, result.url, result.isAsync, result.user, result.password);
|
|
}
|
|
}
|
|
send.call(self, data);
|
|
});
|
|
});
|
|
} else {
|
|
send.call(this, data);
|
|
}
|
|
};
|
|
})(window.XMLHttpRequest);
|
|
"""
|