iosWebViewFix/flutter_inappwebview_macos/macos/Classes/PluginScriptsJS/InterceptAjaxRequestJS.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);
"""