Skip to content

Commit 3bee8ab

Browse files
committed
fixup! implement uuid in query param matcher
1 parent 32875fc commit 3bee8ab

7 files changed

Lines changed: 46 additions & 22 deletions

File tree

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,28 @@ To manually process requests:
5252
}
5353
```
5454

55+
For both cases you can choose between different strategies for how the recorded requests (including
56+
the body) and the intercepted requests are matched together. By default, only the url is used. If
57+
you want to use a different strategy, for example if you have parallel requests to the same url with
58+
different bodies (e.g. GraphQL queries), you can pass a custom `RequestMatcher` to the constructor
59+
of `RequestInspectorWebViewClient`:
60+
61+
```kotlin
62+
val webView = WebView(this)
63+
webView.webViewClient = RequestInspectorWebViewClient(
64+
webView,
65+
matcher = RequestUuidInHeaderMatcher()
66+
)
67+
```
68+
69+
Currently available matchers are `RequestUuidInHeaderMatcher` and `RequestUuidInUrlMatcher`, which
70+
both create an UUID and add it to the request before it's recorded and sent. They only differ by how
71+
the attach the UUID to the request, as an additional header or as an additional query param. But
72+
both clean up the request before it's been sent.
73+
74+
If you want to implement your own matching strategy, you can implement the `RequestMatcher`
75+
interface and pass an instance of it to the constructor of `RequestInspectorWebViewClient`.
76+
5577
Known limitations
5678
===
5779

app/src/main/java/com/acsbendi/requestinspectorwebview/RequestInspectorJavaScriptInterface.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,12 @@ class RequestInspectorJavaScriptInterface(webView: WebView, val matcher: Request
122122

123123
@JavascriptInterface
124124
fun getAdditionalHeaders(url: String): String {
125-
return matcher.additionalHeaders(url).toString()
125+
return matcher.getAdditionalHeaders(url).toString()
126126
}
127127

128128
@JavascriptInterface
129129
fun getAdditionalQueryParam(): String {
130-
return matcher.getAdditionalQueryParam()
130+
return matcher.getAdditionalQueryParams()
131131
}
132132

133133
private fun addRecordedRequest(recordedRequest: RecordedRequest) {
@@ -256,7 +256,7 @@ function getFullUrl(url) {
256256
}
257257
}
258258
259-
function appendAdditionalQueryParam(url) {
259+
function appendAdditionalQueryParams(url) {
260260
try {
261261
var extraQueryParam = $INTERFACE_NAME.getAdditionalQueryParam();
262262
if (extraQueryParam) {
@@ -266,7 +266,9 @@ function appendAdditionalQueryParam(url) {
266266
url += '&' + extraQueryParam;
267267
}
268268
}
269-
} catch (e) { console.warn('Failed to inject query param from Kotlin:', e); }
269+
} catch (e) {
270+
console.warn('Failed to inject query param from Kotlin:', e);
271+
}
270272
return url;
271273
}
272274
@@ -290,7 +292,7 @@ function recordFormSubmission(form) {
290292
291293
const path = form.attributes['action'] === undefined ? "/" : form.attributes['action'].nodeValue;
292294
const method = form.attributes['method'] === undefined ? "GET" : form.attributes['method'].nodeValue;
293-
const url = appendAdditionalQueryParam(getFullUrl(path));
295+
const url = appendAdditionalQueryParams(getFullUrl(path));
294296
const encType = form.attributes['enctype'] === undefined ? "application/x-www-form-urlencoded" : form.attributes['enctype'].nodeValue;
295297
const err = new Error();
296298
$INTERFACE_NAME.recordFormSubmission(
@@ -322,7 +324,7 @@ let xmlhttpRequestUrl = null;
322324
XMLHttpRequest.prototype._open = XMLHttpRequest.prototype.open;
323325
XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
324326
lastXmlhttpRequestPrototypeMethod = method;
325-
xmlhttpRequestUrl = appendAdditionalQueryParam(url);
327+
xmlhttpRequestUrl = appendAdditionalQueryParams(url);
326328
const asyncWithDefault = async === undefined ? true : async;
327329
this._open(method, xmlhttpRequestUrl, asyncWithDefault, user, password);
328330
};
@@ -364,7 +366,7 @@ window.fetch = function () {
364366
const firstArgument = arguments[0];
365367
let url, method, body, headers;
366368
if (typeof firstArgument === 'string') {
367-
url = appendAdditionalQueryParam(firstArgument);
369+
url = appendAdditionalQueryParams(firstArgument);
368370
if (!arguments[1]) arguments[1] = {};
369371
method = arguments[1] && 'method' in arguments[1] ? arguments[1]['method'] : "GET";
370372
body = arguments[1] && 'body' in arguments[1] ? arguments[1]['body'] : "";
@@ -379,7 +381,7 @@ window.fetch = function () {
379381
arguments[0] = url;
380382
} else {
381383
// Request object
382-
url = appendAdditionalQueryParam(firstArgument.url);
384+
url = appendAdditionalQueryParams(firstArgument.url);
383385
method = firstArgument.method;
384386
body = firstArgument.body;
385387
headers = Object.fromEntries(firstArgument.headers.entries());

app/src/main/java/com/acsbendi/requestinspectorwebview/RequestInspectorWebViewClient.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import android.webkit.WebResourceRequest
77
import android.webkit.WebResourceResponse
88
import android.webkit.WebView
99
import android.webkit.WebViewClient
10-
import androidx.core.net.toUri
1110
import com.acsbendi.requestinspectorwebview.matcher.RequestMatcher
1211
import com.acsbendi.requestinspectorwebview.matcher.RequestUrlMatcher
1312

1413
@SuppressLint("SetJavaScriptEnabled")
1514
open class RequestInspectorWebViewClient @JvmOverloads constructor(
16-
webView: WebView, val matcher: RequestMatcher = RequestUrlMatcher(),
15+
webView: WebView,
16+
val matcher: RequestMatcher = RequestUrlMatcher(),
1717
private val options: RequestInspectorOptions = RequestInspectorOptions()
1818
) : WebViewClient() {
1919

@@ -48,7 +48,7 @@ open class RequestInspectorWebViewClient @JvmOverloads constructor(
4848

4949
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
5050
Log.i(LOG_TAG, "Page started loading, enabling request inspection. URL: $url")
51-
matcher.setOrigin(url)
51+
matcher.onPageStarted(url)
5252
RequestInspectorJavaScriptInterface.enabledRequestInspection(
5353
view,
5454
options.extraJavaScriptToInject

app/src/main/java/com/acsbendi/requestinspectorwebview/matcher/RequestMatcher.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import org.json.JSONObject
88
interface RequestMatcher {
99
fun addRecordedRequest(recordedRequest: RecordedRequest)
1010
fun createWebViewRequest(request: WebResourceRequest): WebViewRequest
11-
fun additionalHeaders(url: String): JSONObject = JSONObject()
12-
fun getAdditionalQueryParam(): String = ""
13-
fun setOrigin(url: String) {}
11+
fun getAdditionalHeaders(url: String): JSONObject = JSONObject()
12+
fun getAdditionalQueryParams(): String = ""
13+
fun onPageStarted(url: String) {}
1414
}
1515

app/src/main/java/com/acsbendi/requestinspectorwebview/matcher/RequestUuidInHeaderMatcher.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class RequestUuidInHeaderMatcher() : RequestUuidMatcher() {
2626
override fun getUuidFromRequest(webResourceRequest: WebResourceRequest): String? =
2727
webResourceRequest.requestHeaders[REQUEST_INSPECTOR_ID]
2828

29-
override fun cleanupRequests(request: WebResourceRequest, recordedRequest: RecordedRequest?): Pair<WebResourceRequest, RecordedRequest?> {
29+
override fun removeUuidFromRequests(request: WebResourceRequest, recordedRequest: RecordedRequest?): Pair<WebResourceRequest, RecordedRequest?> {
3030
// Clean up headers by removing REQUEST_ID_HEADER from both requests
3131
val cleanedRequest = object : WebResourceRequest by request {
3232
override fun getRequestHeaders(): Map<String, String> =
@@ -38,7 +38,7 @@ class RequestUuidInHeaderMatcher() : RequestUuidMatcher() {
3838
return cleanedRequest to cleanedRecordedRequest
3939
}
4040

41-
override fun additionalHeaders(url: String): JSONObject {
41+
override fun getAdditionalHeaders(url: String): JSONObject {
4242
val headersJson = JSONObject()
4343
if (getOrigin(url) == origin) {
4444
val uuid = UUID.randomUUID().toString()
@@ -49,7 +49,7 @@ class RequestUuidInHeaderMatcher() : RequestUuidMatcher() {
4949
return headersJson
5050
}
5151

52-
override fun setOrigin(url: String) {
52+
override fun onPageStarted(url: String) {
5353
origin = getOrigin(url)
5454
}
5555

app/src/main/java/com/acsbendi/requestinspectorwebview/matcher/RequestUuidInQueryParamMatcher.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class RequestUuidInQueryParamMatcher : RequestUuidMatcher() {
1212
override fun getUuidFromRequest(webResourceRequest: WebResourceRequest): String? =
1313
webResourceRequest.url.getQueryParameter(REQUEST_INSPECTOR_ID)
1414

15-
override fun cleanupRequests(
15+
override fun removeUuidFromRequests(
1616
request: WebResourceRequest,
1717
recordedRequest: RequestInspectorJavaScriptInterface.RecordedRequest?
1818
): Pair<WebResourceRequest, RequestInspectorJavaScriptInterface.RecordedRequest?> {
@@ -32,7 +32,7 @@ class RequestUuidInQueryParamMatcher : RequestUuidMatcher() {
3232
return cleanedWebResourceRequest to cleanedRecordedRequest
3333
}
3434

35-
override fun getAdditionalQueryParam(): String {
35+
override fun getAdditionalQueryParams(): String {
3636
val uuid = UUID.randomUUID().toString()
3737
return "$REQUEST_INSPECTOR_ID=$uuid"
3838
}

app/src/main/java/com/acsbendi/requestinspectorwebview/matcher/RequestUuidMatcher.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ abstract class RequestUuidMatcher : RequestMatcher {
1010

1111
abstract fun getUuidFromRequest(recordedRequest: RecordedRequest): String?
1212
abstract fun getUuidFromRequest(webResourceRequest: WebResourceRequest): String?
13-
abstract fun cleanupRequests(
13+
abstract fun removeUuidFromRequests(
1414
request: WebResourceRequest,
1515
recordedRequest: RecordedRequest?
1616
): Pair<WebResourceRequest, RecordedRequest?>
@@ -25,7 +25,7 @@ abstract class RequestUuidMatcher : RequestMatcher {
2525

2626
override fun createWebViewRequest(request: WebResourceRequest): WebViewRequest {
2727
val recordedRequest = findRecordedRequest(request)
28-
val (cleanedRequest, cleanedRecordedRequest) = cleanupRequests(request, recordedRequest)
28+
val (cleanedRequest, cleanedRecordedRequest) = removeUuidFromRequests(request, recordedRequest)
2929
return WebViewRequest.create(cleanedRequest, cleanedRecordedRequest)
3030
}
3131

@@ -38,7 +38,7 @@ abstract class RequestUuidMatcher : RequestMatcher {
3838
return recordedRequest
3939
}
4040

41-
override fun setOrigin(url: String) {}
41+
override fun onPageStarted(url: String) {}
4242

4343
companion object {
4444
const val REQUEST_INSPECTOR_ID = "x-request-inspector-id"

0 commit comments

Comments
 (0)