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 f051b49
Show file tree
Hide file tree
Showing 9 changed files with 330 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 @@ -14,6 +14,7 @@
import tornado.websocket

import mitmproxy.flow
from mitmproxy.net.http import url
import mitmproxy.tools.web.master
from mitmproxy import certs, command, contentviews
from mitmproxy import flowfilter
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, message):
self.flow.backup()
message = getattr(self.flow, message)
message.query = url.decode(b"&".join(self.filecontents.strip().splitlines()))
self.view.update([self.flow])

def get(self, flow_id, message):
message = getattr(self.flow, message)
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\-]+)/(?P<message>request|response|messages)/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
15 changes: 15 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 @@ -390,6 +392,19 @@ def test_flow_content_returns_raw_content_when_decoding_fails(self):

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_update_flow_content(self):
assert (
self.fetch("/flows/42/request/content.data", method="POST", body="new").code
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
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,11 @@ exports[`HttpMessage 2`] = `
</div>
<div
class="codeeditor"
/>
>
<div>
{"lines":[[["text","rawdata"]],[["text","rawdata"]],[["text","rawdata"]],[["text","rawdata"]],[["text","rawdata"]]],"description":"Raw"}
</div>
</div>
</div>
</DocumentFragment>
`;
Expand Down Expand Up @@ -226,6 +230,189 @@ exports[`HttpMessage 3`] = `
</DocumentFragment>
`;

exports[`HttpMessage 4`] = `
<DocumentFragment>
<div
class="contentview"
>
<div
class="controls"
>
<h5>
Loading...
</h5>
<button
class="btn-xs btn btn-default"
>
<i
class="fa fa-edit"
/>
 Edit
</button>
 
<a
class="btn btn-default btn-xs"
href="#"
title="Upload a file to replace the content."
>
<i
class="fa fa-fw fa-upload"
/>
Replace
<input
class="hidden"
type="file"
/>
</a>
 
<a
class="btn btn-default btn-xs"
href="#"
>
<span>
<i
class="fa fa-fw fa-files-o"
/>
 
<b>
View:
</b>
raw
<span
class="caret"
/>
</span>
</a>
</div>
</div>
</DocumentFragment>
`;

exports[`HttpMessage edit query string 1`] = `
<DocumentFragment>
<div
class="contentview"
>
<div
class="controls"
>
<h5>
[Editing]
</h5>
<button
class="btn-xs btn btn-default"
>
<i
class="fa fa-check text-success"
/>
 Done
</button>
 
<button
class="btn-xs btn btn-default"
>
<i
class="fa fa-times text-danger"
/>
 Cancel
</button>
</div>
<div
class="codeeditor"
>
<div>
foo=1
bar=2
</div>
</div>
</div>
</DocumentFragment>
`;

exports[`HttpMessage edit query string 2`] = `
<DocumentFragment>
<div
class="contentview"
>
<div
class="controls"
>
<h5>
Query
</h5>
<button
class="btn-xs btn btn-default"
>
<i
class="fa fa-edit"
/>
 Edit
</button>
 
<a
class="btn btn-default btn-xs"
href="#"
title="Upload a file to replace the content."
>
<i
class="fa fa-fw fa-upload"
/>
Replace
<input
class="hidden"
type="file"
/>
</a>
 
<a
class="btn btn-default btn-xs"
href="#"
>
<span>
<i
class="fa fa-fw fa-files-o"
/>
 
<b>
View:
</b>
auto
<span
class="caret"
/>
</span>
</a>
</div>
<pre>
<div>
<span
class="header"
>
foo
</span>
<span
class="text"
>
1
</span>
</div>
<div>
<span
class="header"
>
bar
</span>
<span
class="text"
>
2
</span>
</div>
</pre>
</div>
</DocumentFragment>
`;

exports[`ViewImage 1`] = `
<DocumentFragment>
<div
Expand Down

0 comments on commit f051b49

Please sign in to comment.