Skip to content

Commit

Permalink
[web] fix query editing
Browse files Browse the repository at this point in the history
  • Loading branch information
yesmeck committed Oct 26, 2022
1 parent 201651c commit 485ea2f
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
([#5658](https://github.com/mitmproxy/mitmproxy/issues/5658), [#5661](https://github.com/mitmproxy/mitmproxy/issues/5661), @LIU-shuyi, @mhils)
* Added Docs for Transparent Mode on Windows.
([#5402](https://github.com/mitmproxy/mitmproxy/issues/5402), @stephenspol)
* Fix query editing on mitmweb.
([#5574](https://github.com/mitmproxy/mitmproxy/pull/5574), @yesmeck)


## 28 June 2022: mitmproxy 8.1.1
Expand Down
22 changes: 22 additions & 0 deletions mitmproxy/tools/web/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from mitmproxy import version
from mitmproxy.dns import DNSFlow
from mitmproxy.http import HTTPFlow
from mitmproxy.net.http import url
from mitmproxy.tcp import TCPFlow, TCPMessage
from mitmproxy.udp import UDPFlow, UDPMessage
from mitmproxy.utils.emoji import emoji
Expand Down Expand Up @@ -403,6 +404,8 @@ def put(self, flow_id):
request.trailers.add(*trailer)
elif k == "content":
request.text = v
elif k == "query":
request.query = [tuple(i) for i in v]
else:
raise APIError(400, f"Unknown update request.{k}: {v}")

Expand Down Expand Up @@ -485,6 +488,21 @@ def get(self, flow_id, message):
self.write(message.get_content(strict=False))


class FlowQuery(RequestHandler):
def post(self, flow_id):
self.flow.backup()
message = getattr(self.flow, 'request')
message.query = url.decode(b"&".join(self.filecontents.strip().splitlines()))
self.view.update([self.flow])

def get(self, flow_id):
message = getattr(self.flow, 'request')
self.set_header("Content-Type", "application/text")
self.set_header("X-Content-Type-Options", "nosniff")
self.set_header("X-Frame-Options", "DENY")
self.write("\n".join("=".join(field) for field in message.query.fields))


class FlowContentView(RequestHandler):
def message_to_json(
self,
Expand Down Expand Up @@ -674,6 +692,10 @@ def __init__(
r"/flows/(?P<flow_id>[0-9a-f\-]+)/(?P<message>request|response|messages)/content.data",
FlowContent,
),
(
r"/flows/(?P<flow_id>[0-9a-f\-]+)/request/query.data",
FlowQuery,
),
(
r"/flows/(?P<flow_id>[0-9a-f\-]+)/(?P<message>request|response|messages)/"
r"content/(?P<content_view>[0-9a-zA-Z\-\_%]+)(?:\.json)?",
Expand Down
37 changes: 37 additions & 0 deletions test/mitmproxy/tools/web/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,13 +306,15 @@ def test_flow_update(self):
upd = {
"request": {
"trailers": [("foo", "baz")],
"query": [("foo", "2")]
},
"response": {
"trailers": [("foo", "baz")],
},
}
assert self.put_json("/flows/42", upd).code == 200
assert f.request.trailers["foo"] == "baz"
assert f.request.query["foo"] == "2"

f.revert()

Expand Down Expand Up @@ -424,6 +426,41 @@ def test_update_flow_content_multipart(self):
assert f.modified()
f.revert()

def test_flow_query(self):
f = self.view.get_by_id("42")
f.backup()

f.request.query = (("foo", "1"), ("bar", "2"))

r = self.fetch("/flows/42/request/query.data")

assert r.code == 200
assert r.body == b"foo=1\nbar=2"

f.revert()

def test_flow_update_query(self):
assert (
self.fetch("/flows/42/request/query.data", method="POST", body="foo=1&bar=2").code
== 200
)
f = self.view.get_by_id("42")
assert f.request.query["foo"] == "1"
assert f.request.query["bar"] == "2"
assert f.modified()
f.revert()

def test_flow_update_query_with_multiple_lines(self):
assert (
self.fetch("/flows/42/request/query.data", method="POST", body="foo=1\nbar=2").code
== 200
)
f = self.view.get_by_id("42")
assert f.request.query["foo"] == "1"
assert f.request.query["bar"] == "2"
assert f.modified()
f.revert()

def test_flow_contentview(self):
assert get_json(self.fetch("/flows/42/request/content/raw")) == {
"lines": [[["text", "foo"]], [["text", "bar"]]],
Expand Down
65 changes: 64 additions & 1 deletion web/src/js/__tests__/components/contentviews/HttpMessageSpec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@ import HttpMessage, {ViewImage} from '../../../components/contentviews/HttpMessa
import {fireEvent, render, screen, waitFor} from "../../test-utils"
import fetchMock, {enableFetchMocks} from "jest-fetch-mock";

jest.mock("../../../contrib/CodeMirror")
jest.mock("../../../contrib/CodeMirror", () => {
const React = require("react");
return {
__esModule: true,
default: React.forwardRef((props, ref) => {
React.useImperativeHandle(ref, () => ({
codeMirror: {
getValue: () => props.value
}
}));
return <div>{props.value}</div>
})
}
})

enableFetchMocks();

Expand All @@ -25,13 +38,19 @@ test("HttpMessage", async () => {
description: "Raw",
}),
"raw content",
JSON.stringify({
lines: Array(5).fill([["text", "rawdata"]]),
description: "Raw",
}),
"",
JSON.stringify({
lines: Array(5).fill([["text", "rawdata"]]),
description: "Raw",
})
);

const tflow = TFlow();
tflow.request.method = "POST";
const {asFragment} = render(<HttpMessage flow={tflow} message={tflow.request}/>);
await waitFor(() => screen.getAllByText("data"));
expect(screen.queryByText('additional')).toBeNull();
Expand All @@ -50,6 +69,50 @@ test("HttpMessage", async () => {

await waitFor(() => screen.getAllByText("rawdata"));
expect(asFragment()).toMatchSnapshot();

fireEvent.click(screen.getByText("Edit"));
fireEvent.click(screen.getByText("Done"));
await waitFor(() => screen.getAllByText("rawdata"));
expect(asFragment()).toMatchSnapshot();
});

test("HttpMessage edit query string", async () => {
const lines = [
[
["header", "foo"],
["text", "1"],
],
[
["header", "bar"],
["text", "2"],
],
];

fetchMock.mockResponses(
JSON.stringify({
lines: lines,
description: "Query",
}),
"foo=1\nbar=2",
'',
JSON.stringify({
lines,
description: "Query",
})
);

const tflow = TFlow();
tflow.request.path = "/path?foo=1&bar=2";
const { asFragment, debug } = render(
<HttpMessage flow={tflow} message={tflow.request} />
);
fireEvent.click(screen.getByText("Edit"));
await waitFor(() => screen.getAllByText(/foo/));
expect(asFragment()).toMatchSnapshot();
fireEvent.click(screen.getByText("Done"));

await waitFor(() => screen.getAllByText("foo"));
expect(asFragment()).toMatchSnapshot();
});

test("ViewImage", async () => {
Expand Down

0 comments on commit 485ea2f

Please sign in to comment.