[webkit-reviews] review denied: [Bug 207446] Web Inspector: request interception : [Attachment 399243] Patch
bugzilla-daemon at webkit.org
bugzilla-daemon at webkit.org
Thu May 14 15:57:21 PDT 2020
Devin Rousso <drousso at apple.com> has denied review:
Bug 207446: Web Inspector: request interception
https://bugs.webkit.org/show_bug.cgi?id=207446
Attachment 399243: Patch
https://bugs.webkit.org/attachment.cgi?id=399243&action=review
--- Comment #15 from Devin Rousso <drousso at apple.com> ---
Comment on attachment 399243
--> https://bugs.webkit.org/attachment.cgi?id=399243
Patch
View in context: https://bugs.webkit.org/attachment.cgi?id=399243&action=review
r-, this needs a _lot_ more tests
- intercept/override URL defined in HTML
- intercept/override URL defined in CSS
- test `method` parameter of `interceptWithRequest`
- test `headers` parameter of `interceptWithRequest`
- test `postData` parameter of `interceptWithRequest`
there are a _lot_ of different situations/configurations for request
interception, and we should have at least one test per.
> Source/JavaScriptCore/inspector/protocol/Network.json:247
> + { "name": "url", "type": "string", "description": "URL
pattern to intercept, intercept everything if not specified or empty" },
I am still not comfortable with this "intercept everything" concept. I don't
think that there's a good way to make a UI for this. Network interception
should be a whitelist not a let-me-decide catch-all.
> Source/JavaScriptCore/inspector/protocol/Network.json:276
> + { "name": "url", "type": "string", "optional":
true,"description": "HTTP request url." },
I'm not sure I like this idea. This is really more of a redirect rather than
an override.
> Source/JavaScriptCore/inspector/protocol/Network.json:278
> + { "name": "postData", "type": "string", "optional": true,
"description": "HTTP POST request data, base64-encoded." }
Why is this _always_ base64-encoded? That should probably be another
parameter, assuming it even needs to exist at all.
> Source/JavaScriptCore/inspector/protocol/Network.json:292
> + { "name": "errorType", "$ref": "ResourceErrorType",
"optional": true, "description": "Deliver error reason for the request
failure." }
Where did this come from? How is it related to _request_ interception? It
seems like you're trying to expose a way to modify internal state/concepts via
the inspector protocol, which is not really something I think Web Inspector
wants to do.
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1054
> +void InspectorNetworkAgent::addInterception(ErrorString& errorString, const
String& url, const bool* optionalCaseSensitive, const bool* optionalIsRegex,
const String* optionalNetworkStageString)
The `NetworkStage` actually probably shouldn't be optional. What would not
specifying a `NetworkStage` even mean? The only thing that makes sense to me
would be for not specifying a `NetworkStage` to mean "intercept at every
point", but for reasons i've mentioned i don't see why that's needed/wanted.
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1125
> + String requestId = IdentifiersFactory::requestId(loader.identifier());
We should double-check that the `requestId` isn't already in
`m_pendingInterceptRequests`, and if so invoke the `handler` and return.
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1126
> + auto pendingRequest = makeUnique<PendingInterceptRequest>(&loader,
WTFMove(handler));
You could just inline this and avoid the `WTFMove(pendingRequest)`.
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1148
> void InspectorNetworkAgent::interceptContinue(ErrorString& errorString,
const String& requestId)
This should also probably take a `NetworkStage` so that we know whether we're
trying to continue the request or the response (also see :1054).
Alternatively, we could add an `InterceptId` that makes this even more clear,
but I think the combo of `RequestId` + `NetworkStage` is probably unique
enough.
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1167
> + auto pendingRequest = m_pendingInterceptRequests.take(requestId);
I think this should really be a completely separate command so as to not
conflate things, like `interceptRequestWithImmediateResponse`.
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1169
> + ResourceLoader* loader = pendingRequest->m_loader.get();
`auto`?
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1175
> + ResourceRequest request = loader->request();
Ditto (:1169)
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1182
> + for (auto& header : *headers) {
NIT: you could use structured binding
```
for (auto& [key, value] : *headers)
```
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1194
> + }
Style: missing newline after block containing `return`
(rest of file too)
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1195
> + }
> + Ref<FormData> data = FormData::create(buffer);
Ditto (:1169), or could even just inline it to avoid the `WTFMove(data)`.
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1208
> + if (pendingRequest && errorTypeString) {
all of these `if`s could be nested under a shared `if (pendingRequest)`
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1252
> + if (base64Encoded && *base64Encoded && content) {
NIT: you could next these two `if`s under a shared `if (content &&
!content->isEmpty())`
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1263
> + ResourceResponse response(pendingRequest->m_loader->url(),
*mimeType, data->size(), String());
`data` is not guaranteed to exist
> Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp:1275
> + loader->didReceiveResponse(response, [loader, data =
data.releaseNonNull()]() mutable {
Replacing something with its own name is not the easiest to read. Also, `data`
is not guaranteed to exist, which `RefPtr::releaseNonNull` expects. It should
probably either just be a regular `&data` capture or a `buffer =
WTFMove(data)`.
Why does this need to be `mutable`?
> Source/WebCore/inspector/agents/InspectorNetworkAgent.h:226
> + NetworkStage networkStage { NetworkStage::Response };
Ditto (InspectorNetworkAgent.cpp:1054)
> Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp:240
> + RefPtr<ResourceLoader> protectedResourceLoader = &resourceLoader;
This is normally done as part of the lambda capture.
```
[protectedResourceLoader = makeRef(resourceLoader)]
```
> LayoutTests/inspector/network/intercept-request.html:10
> + const response = await fetch('resources/data.json');
Style: we only use `const` for values that never change between executions
(i.e. an actual constant), which is not the case here, so please use `let`
(rest of file too)
> LayoutTests/inspector/network/intercept-request.html:16
> + header: response.headers.get('my-header')
Style: missing trailing comma
(rest of file too)
> LayoutTests/inspector/network/intercept-request.html:23
> +async function test()
Please don't make the `test` function `async`. The test harness doesn't really
support `async` functions. Our usual pattern is to set up the entire test
suite and then put the `runTestCasesAndFinish` call in the callback.
> LayoutTests/inspector/network/intercept-request.html:25
> + let suite =
ProtocolTest.createAsyncSuite("Network.setInterceptionEnabled");
Oops?
> LayoutTests/inspector/network/intercept-request.html:27
> + const [, , {result}] = await Promise.all([
Even if it's not used, I'd rather give a name to each item so that I don't have
to read the code to figure out what is being "skipped"
(rest of file too)
> LayoutTests/inspector/network/intercept-request.html:43
> + name: "requestIntercepted.interceptContinue",
NIT: I like to prefix each test case name with the test suite's name so that
the relationship is clear
> LayoutTests/inspector/network/intercept-request.html:48
> + InspectorProtocol.awaitCommand({method: "Runtime.evaluate",
params: {
This is definitely not our style. Usually we only inline objects if there are
only a few simple values (e.g. numbers, strings, etc.). For something this
complex, please put things onto separate lines.
(rest of file too)
> LayoutTests/inspector/network/intercept-request.html:55
> + const [ fetchResult ] = await Promise.all([
Style: no space after `[` and before `]`
> LayoutTests/inspector/network/intercept-request.html:64
> + ProtocolTest.pass("Response data: '" +
fetchResult.result.value.text.trim() + "'");
We shouldn't be using `ProtocolTest.pass` for unknown values, since if this
code breaks somehow, we'd now be printing `PASS: ` with some _other_ value,
which could seriously confuse bot watchers or future developers as to what the
right value is supposed to be.
I'd either use `ProtocolText.expectEqual` and compare against some
known/expected value or just use `ProtocolTest.log`.
(rest of file too)
> LayoutTests/inspector/network/intercept-request.html:155
> + name: "tearDown",
This shouldn't be necessary, as when the `InspectorNetworkAgent` is destroyed
(when Web Inspector closes/disconnects) we should automatically continue any
pending intercepted activity.
> LayoutTests/inspector/network/intercept-request.html:163
> + function printFetchResult(result)
Please put this function above it's usage. I realize that this is perfectly
valid JavaScript, but we prefer to declare things before they're used for
readability.
More information about the webkit-reviews
mailing list