From 1c830ada4645829513e1d213c4b9a3e9b521745e Mon Sep 17 00:00:00 2001 From: jcesarmobile Date: Mon, 5 Aug 2024 17:28:57 +0200 Subject: [PATCH] fix(http): pass original url as query param on the proxy url (#7527) (#7604) Co-authored-by: Michael Wolz --- .../src/main/assets/native-bridge.js | 12 ++++------ .../main/java/com/getcapacitor/Bridge.java | 5 ++++ .../com/getcapacitor/WebViewLocalServer.java | 20 ++-------------- core/native-bridge.ts | 16 ++++--------- ios/Capacitor/Capacitor/CapacitorBridge.swift | 2 ++ .../Capacitor/WebViewAssetHandler.swift | 23 ++++--------------- .../Capacitor/assets/native-bridge.js | 12 ++++------ 7 files changed, 27 insertions(+), 63 deletions(-) diff --git a/android/capacitor/src/main/assets/native-bridge.js b/android/capacitor/src/main/assets/native-bridge.js index 7cee6e1db2..44ca34056f 100644 --- a/android/capacitor/src/main/assets/native-bridge.js +++ b/android/capacitor/src/main/assets/native-bridge.js @@ -144,23 +144,19 @@ var nativeBridge = (function (exports) { return { data: body, type: 'json' }; }; const CAPACITOR_HTTP_INTERCEPTOR = '/_capacitor_http_interceptor_'; - const CAPACITOR_HTTPS_INTERCEPTOR = '/_capacitor_https_interceptor_'; + const CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM = 'u'; // TODO: export as Cap function const isRelativeOrProxyUrl = (url) => !url || !(url.startsWith('http:') || url.startsWith('https:')) || - url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1 || - url.indexOf(CAPACITOR_HTTPS_INTERCEPTOR) > -1; + url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1; // TODO: export as Cap function const createProxyUrl = (url, win) => { var _a, _b; if (isRelativeOrProxyUrl(url)) return url; - const proxyUrl = new URL(url); const bridgeUrl = new URL((_b = (_a = win.Capacitor) === null || _a === void 0 ? void 0 : _a.getServerUrl()) !== null && _b !== void 0 ? _b : ''); - const isHttps = proxyUrl.protocol === 'https:'; - bridgeUrl.search = proxyUrl.search; - bridgeUrl.hash = proxyUrl.hash; - bridgeUrl.pathname = `${isHttps ? CAPACITOR_HTTPS_INTERCEPTOR : CAPACITOR_HTTP_INTERCEPTOR}/${encodeURIComponent(proxyUrl.host)}${proxyUrl.pathname}`; + bridgeUrl.pathname = CAPACITOR_HTTP_INTERCEPTOR; + bridgeUrl.searchParams.append(CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM, url); return bridgeUrl.toString(); }; const initBridge = (w) => { diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index 1b01134c1e..13131949ca 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -89,8 +89,13 @@ public class Bridge { public static final String CAPACITOR_FILE_START = "/_capacitor_file_"; public static final String CAPACITOR_CONTENT_START = "/_capacitor_content_"; public static final String CAPACITOR_HTTP_INTERCEPTOR_START = "/_capacitor_http_interceptor_"; + + /** @deprecated CAPACITOR_HTTPS_INTERCEPTOR_START is no longer required. All proxied requests are handled via CAPACITOR_HTTP_INTERCEPTOR_START instead */ + @Deprecated public static final String CAPACITOR_HTTPS_INTERCEPTOR_START = "/_capacitor_https_interceptor_"; + public static final String CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM = "u"; + public static final int DEFAULT_ANDROID_WEBVIEW_VERSION = 60; public static final int MINIMUM_ANDROID_WEBVIEW_VERSION = 55; public static final int DEFAULT_HUAWEI_WEBVIEW_VERSION = 10; diff --git a/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java b/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java index b0e4c26a36..fd8cf8997e 100755 --- a/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java +++ b/android/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java @@ -30,7 +30,6 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; -import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; @@ -172,13 +171,7 @@ private static Uri parseAndVerifyUrl(String url) { public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) { Uri loadingUrl = request.getUrl(); - if ( - null != loadingUrl.getPath() && - ( - loadingUrl.getPath().startsWith(Bridge.CAPACITOR_HTTP_INTERCEPTOR_START) || - loadingUrl.getPath().startsWith(Bridge.CAPACITOR_HTTPS_INTERCEPTOR_START) - ) - ) { + if (null != loadingUrl.getPath() && loadingUrl.getPath().startsWith(Bridge.CAPACITOR_HTTP_INTERCEPTOR_START)) { Logger.debug("Handling CapacitorHttp request: " + loadingUrl); try { return handleCapacitorHttpRequest(request); @@ -259,16 +252,7 @@ private String getReasonPhraseFromResponseCode(int code) { } private WebResourceResponse handleCapacitorHttpRequest(WebResourceRequest request) throws IOException { - boolean isHttps = - request.getUrl().getPath() != null && request.getUrl().getPath().startsWith(Bridge.CAPACITOR_HTTPS_INTERCEPTOR_START); - - String urlString = request - .getUrl() - .toString() - .replace(bridge.getLocalUrl(), isHttps ? "https:/" : "http:/") - .replace(Bridge.CAPACITOR_HTTP_INTERCEPTOR_START, "") - .replace(Bridge.CAPACITOR_HTTPS_INTERCEPTOR_START, ""); - urlString = URLDecoder.decode(urlString, "UTF-8"); + String urlString = request.getUrl().getQueryParameter(Bridge.CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM); URL url = new URL(urlString); JSObject headers = new JSObject(); diff --git a/core/native-bridge.ts b/core/native-bridge.ts index cb415519e9..e298e14877 100644 --- a/core/native-bridge.ts +++ b/core/native-bridge.ts @@ -130,27 +130,21 @@ const convertBody = async ( }; const CAPACITOR_HTTP_INTERCEPTOR = '/_capacitor_http_interceptor_'; -const CAPACITOR_HTTPS_INTERCEPTOR = '/_capacitor_https_interceptor_'; +const CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM = 'u'; // TODO: export as Cap function const isRelativeOrProxyUrl = (url: string | undefined): boolean => !url || !(url.startsWith('http:') || url.startsWith('https:')) || - url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1 || - url.indexOf(CAPACITOR_HTTPS_INTERCEPTOR) > -1; + url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1; // TODO: export as Cap function const createProxyUrl = (url: string, win: WindowCapacitor): string => { if (isRelativeOrProxyUrl(url)) return url; - - const proxyUrl = new URL(url); const bridgeUrl = new URL(win.Capacitor?.getServerUrl() ?? ''); - const isHttps = proxyUrl.protocol === 'https:'; - bridgeUrl.search = proxyUrl.search; - bridgeUrl.hash = proxyUrl.hash; - bridgeUrl.pathname = `${ - isHttps ? CAPACITOR_HTTPS_INTERCEPTOR : CAPACITOR_HTTP_INTERCEPTOR - }/${encodeURIComponent(proxyUrl.host)}${proxyUrl.pathname}`; + bridgeUrl.pathname = CAPACITOR_HTTP_INTERCEPTOR; + bridgeUrl.searchParams.append(CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM, url); + return bridgeUrl.toString(); }; diff --git a/ios/Capacitor/Capacitor/CapacitorBridge.swift b/ios/Capacitor/Capacitor/CapacitorBridge.swift index 394c5afeba..a6ef6c7fd5 100644 --- a/ios/Capacitor/Capacitor/CapacitorBridge.swift +++ b/ios/Capacitor/Capacitor/CapacitorBridge.swift @@ -91,7 +91,9 @@ internal class CapacitorBridge: NSObject, CAPBridgeProtocol { public static let capacitorSite = "https://capacitorjs.com/" public static let fileStartIdentifier = "/_capacitor_file_" public static let httpInterceptorStartIdentifier = "/_capacitor_http_interceptor_" + @available(*, deprecated, message: "`httpsInterceptorStartIdentifier` is no longer required. All proxied requests are handled via `httpInterceptorStartIdentifier` instead") public static let httpsInterceptorStartIdentifier = "/_capacitor_https_interceptor_" + public static let httpInterceptorUrlParam = "u" public static let defaultScheme = "capacitor" var webViewAssetHandler: WebViewAssetHandler diff --git a/ios/Capacitor/Capacitor/WebViewAssetHandler.swift b/ios/Capacitor/Capacitor/WebViewAssetHandler.swift index 66121d3255..4dbaeb9dd8 100644 --- a/ios/Capacitor/Capacitor/WebViewAssetHandler.swift +++ b/ios/Capacitor/Capacitor/WebViewAssetHandler.swift @@ -35,11 +35,6 @@ internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler { return } - if url.path.starts(with: CapacitorBridge.httpsInterceptorStartIdentifier) { - handleCapacitorHttpRequest(urlSchemeTask, localUrl, true) - return - } - if stringToLoad.starts(with: CapacitorBridge.fileStartIdentifier) { startPath = stringToLoad.replacingOccurrences(of: CapacitorBridge.fileStartIdentifier, with: "") } else { @@ -138,21 +133,13 @@ internal class WebViewAssetHandler: NSObject, WKURLSchemeHandler { func handleCapacitorHttpRequest(_ urlSchemeTask: WKURLSchemeTask, _ localUrl: URL, _ isHttpsRequest: Bool) { var urlRequest = urlSchemeTask.request guard let url = urlRequest.url else { return } - var targetUrl = url.absoluteString - .replacingOccurrences(of: CapacitorBridge.httpInterceptorStartIdentifier, with: "") - .replacingOccurrences(of: CapacitorBridge.httpsInterceptorStartIdentifier, with: "") - // Only replace first occurrence of the scheme - if let range = targetUrl.range(of: localUrl.scheme ?? InstanceDescriptorDefaults.scheme) { - targetUrl = targetUrl.replacingCharacters(in: range, with: isHttpsRequest ? "https" : "http") + + let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) + if let targetUrl = urlComponents?.queryItems?.first(where: { $0.name == CapacitorBridge.httpInterceptorUrlParam })?.value, + !targetUrl.isEmpty { + urlRequest.url = URL(string: targetUrl) } - // Only replace first occurrence of the hostname - if let range = targetUrl.range(of: (localUrl.host ?? InstanceDescriptorDefaults.hostname) + "/") { - targetUrl = targetUrl.replacingCharacters(in: range, with: "") - } - - urlRequest.url = URL(string: targetUrl.removingPercentEncoding ?? targetUrl) - let urlSession = URLSession.shared let task = urlSession.dataTask(with: urlRequest) { (data, response, error) in DispatchQueue.main.async { diff --git a/ios/Capacitor/Capacitor/assets/native-bridge.js b/ios/Capacitor/Capacitor/assets/native-bridge.js index 7cee6e1db2..44ca34056f 100644 --- a/ios/Capacitor/Capacitor/assets/native-bridge.js +++ b/ios/Capacitor/Capacitor/assets/native-bridge.js @@ -144,23 +144,19 @@ var nativeBridge = (function (exports) { return { data: body, type: 'json' }; }; const CAPACITOR_HTTP_INTERCEPTOR = '/_capacitor_http_interceptor_'; - const CAPACITOR_HTTPS_INTERCEPTOR = '/_capacitor_https_interceptor_'; + const CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM = 'u'; // TODO: export as Cap function const isRelativeOrProxyUrl = (url) => !url || !(url.startsWith('http:') || url.startsWith('https:')) || - url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1 || - url.indexOf(CAPACITOR_HTTPS_INTERCEPTOR) > -1; + url.indexOf(CAPACITOR_HTTP_INTERCEPTOR) > -1; // TODO: export as Cap function const createProxyUrl = (url, win) => { var _a, _b; if (isRelativeOrProxyUrl(url)) return url; - const proxyUrl = new URL(url); const bridgeUrl = new URL((_b = (_a = win.Capacitor) === null || _a === void 0 ? void 0 : _a.getServerUrl()) !== null && _b !== void 0 ? _b : ''); - const isHttps = proxyUrl.protocol === 'https:'; - bridgeUrl.search = proxyUrl.search; - bridgeUrl.hash = proxyUrl.hash; - bridgeUrl.pathname = `${isHttps ? CAPACITOR_HTTPS_INTERCEPTOR : CAPACITOR_HTTP_INTERCEPTOR}/${encodeURIComponent(proxyUrl.host)}${proxyUrl.pathname}`; + bridgeUrl.pathname = CAPACITOR_HTTP_INTERCEPTOR; + bridgeUrl.searchParams.append(CAPACITOR_HTTP_INTERCEPTOR_URL_PARAM, url); return bridgeUrl.toString(); }; const initBridge = (w) => {