google / tamperchrome

Tamper Dev is an extension that allows you to intercept and edit HTTP/HTTPS requests and responses as they happen without the need of a proxy. Works across all operating systems (including Chrome OS).
https://tamper.dev
Apache License 2.0
4.18k stars 214 forks source link

Changing HTTP Response code does not work #198

Open fossecode opened 3 years ago

fossecode commented 3 years ago

Hi! First of all, awesome extension :100: :+1:

I am however unable to modify the HTTP response code: image image

sirdarckcat commented 3 years ago

It's possible it's a DevTools issue, but I'll add a test to confirm :-)

sirdarckcat commented 3 years ago

yep, it's broken.

reproduced by going to: http://evilwebsite.com/shell.html and typing

(async x=>{print((await fetch("")).status)})()

changing from 200 to 201 returns 200

sirdarckcat commented 3 years ago

The value flows from here: https://github.com/google/tamperchrome/blob/1ad8700e85c719b32ece29931695b3f27b2d5b5a/v2/background/src/request.ts#L89 to here: https://github.com/google/tamperchrome/blob/1ad8700e85c719b32ece29931695b3f27b2d5b5a/v2/background/src/request.ts#L146 and ends in https://chromedevtools.github.io/devtools-protocol/tot/Fetch/#method-fulfillRequest

weird :)

sirdarckcat commented 3 years ago

traced it to the API call, and 201 is sent correctly, but the javascript code still sees value 200. image

sirdarckcat commented 3 years ago

Seems like Chrome recognizes the new status code, as it behaves differently when changing it from 200 to 302 (it only allows a Location redirect with 3XX and fails if the status is 200). It's probably a bug in Chrome.

sirdarckcat commented 3 years ago

And it seems like Chrome doesn't look at the status of intercepted requests https://source.chromium.org/chromium/chromium/src/+/master:content/browser/devtools/devtools_url_loader_interceptor.cc;l=1080;drc=63bc8056437ba6b1698c01e8f55e8fd187926640

There's an explicit check for head->headers->IsRedirect which explains why they make a difference.

Looking at how the url_fetcher gets the headers see why the status is different.

sirdarckcat commented 3 years ago

my current theory is that the headers come from the response_info_ object, while the response code comes from the request_job https://source.chromium.org/chromium/chromium/src/+/master:net/url_request/url_fetcher_core.cc;l=423;drc=63bc8056437ba6b1698c01e8f55e8fd187926640

sirdarckcat commented 3 years ago

this test seems to explain how the interception between devtools and the url req factory is done https://source.chromium.org/chromium/chromium/src/+/master:services/network/url_loader_unittest.cc;l=4781;drc=69d394f9899f1f39911df8e50a9e3d86d25dc1a4

sirdarckcat commented 3 years ago

so, networkserviceclient is the one that brokers the connection between the url_loader and devtools, it seems. https://source.chromium.org/chromium/chromium/src/+/master:content/browser/network_service_client.cc;l=229;drc=d6edf4bb211798b0aa0b656dfb06614cfea043e3

sirdarckcat commented 3 years ago

and here seems to be where things are overriden. https://source.chromium.org/chromium/chromium/src/+/master:services/network/url_loader.cc;l=1622;drc=63bc8056437ba6b1698c01e8f55e8fd187926640

or actually here to be more accurate: https://source.chromium.org/chromium/chromium/src/+/master:services/network/url_loader.cc;l=2010;drc=63bc8056437ba6b1698c01e8f55e8fd187926640

sirdarckcat commented 3 years ago

mojo's documentation https://source.chromium.org/chromium/chromium/src/+/master:services/network/public/mojom/network_context.mojom;l=185;drc=63bc8056437ba6b1698c01e8f55e8fd187926640

sirdarckcat commented 3 years ago

looking at the behavior of webRequestBlocking - it appears that it gets modified at a different layer, here: https://source.chromium.org/chromium/chromium/src/+/master:extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc;l=973;drc=63bc8056437ba6b1698c01e8f55e8fd187926640;bpv=1;bpt=1

sirdarckcat commented 3 years ago

So, the two mojo services are:

The difference is explained here:

// Callback interface for NetworkContext when routing identifiers aren't
// available. Otherwise generally callbacks from the network service go on
// NetworkServiceClient.
sirdarckcat commented 3 years ago

The request_info_ is reset here: https://source.chromium.org/chromium/chromium/src/+/master:net/url_request/url_request.cc;l=886;drc=63bc8056437ba6b1698c01e8f55e8fd187926640;bpv=1;bpt=1

and the job is set here: https://source.chromium.org/chromium/chromium/src/+/master:net/url_request/url_request.cc;l=611;drc=63bc8056437ba6b1698c01e8f55e8fd187926640;bpv=1;bpt=1

I'm not sure why this is done this way.

sirdarckcat commented 3 years ago

will file a bug with chrome, with a small reproducer, and see if they can investigate

michahell commented 3 years ago

Dang... this is the one thing that I needed to work to fake/mock backend errors and it doesnt work 😢 but really nice tool nonetheless

joaobibiano commented 3 years ago

Hi guys,

There's something that I can help you with?

This feature seems to be amazing testing.

sirdarckcat commented 3 years ago

it's complicated, it'll probably be easier to remove this feature from Tamper.dev (or restrict it to just the status code that have side effects - so, redirects)

sirdarckcat commented 2 years ago

https://bugs.chromium.org/p/chromium/issues/detail?id=1275920