Skip to content

Commit

Permalink
[web] fix query editing
Browse files Browse the repository at this point in the history
fix #4565
  • Loading branch information
yesmeck committed Sep 9, 2022
1 parent 57c71ea commit d0863fc
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -29,6 +29,8 @@
([#5548](https://github.com/mitmproxy/mitmproxy/pull/5548), @sanlengjingvv)
* Fix a mitmweb crash when scrolling down the flow list.
([#5507](https://github.com/mitmproxy/mitmproxy/pull/5507), @LIU-shuyi)
* Fix query editing on mitmweb.
([#5574](https://github.com/mitmproxy/mitmproxy/pull/5574), @yesmeck)

## 28 June 2022: mitmproxy 8.1.1

Expand Down
2 changes: 2 additions & 0 deletions mitmproxy/tools/web/app.py
Expand Up @@ -392,6 +392,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
3 changes: 3 additions & 0 deletions test/mitmproxy/tools/web/test_app.py
Expand Up @@ -162,6 +162,7 @@ async def make_master() -> webmaster.WebMaster:
f = tflow.tflow(resp=True)
f.id = "42"
f.request.content = b"foo\nbar"
f.request.query = [("foo", "1")]
f2 = tflow.tflow(ws=True, resp=True)
f2.request.content = None
f2.response.content = None
Expand Down Expand Up @@ -296,13 +297,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
67 changes: 66 additions & 1 deletion web/src/js/__tests__/components/contentviews/HttpMessageSpec.tsx
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,52 @@ 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",
}),
JSON.stringify({
lines,
description: "Query",
}),
"",
JSON.stringify({
lines,
description: "Query",
})
);

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

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

test("ViewImage", async () => {
Expand Down
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
18 changes: 15 additions & 3 deletions web/src/js/components/contentviews/HttpMessage.tsx
Expand Up @@ -32,7 +32,13 @@ export default function HttpMessage({flow, message}: HttpMessageProps) {
} else {
url = MessageUtils.getContentURL(flow, message, contentView, maxLines + 1);
}
const content = useContent(url, message.contentHash);
let content = useContent(url, message.contentHash);
if (flow.request.method === "GET" && edit) {
const params = new URLSearchParams(new URL(`${flow.request.scheme}://${flow.request.host}/${flow.request.path}`).search);
content = Array.from(params.entries())
.reduce((acc, [key, value]) => [...acc, `${key}=${value}`], [])
.join("\n");
}
const contentViewData = useMemo<ContentViewData | undefined>(() => {
if (content && !edit) {
try {
Expand All @@ -48,8 +54,14 @@ export default function HttpMessage({flow, message}: HttpMessageProps) {

if (edit) {
const save = async () => {
const content = editorRef.current?.getContent();
await dispatch(flowActions.update(flow, {[part]: {content}}));
let content = editorRef.current?.getContent();
await dispatch(flowActions.update(flow, {
[part]: flow.request.method === 'GET' ? {
query: content?.split("\n").map(item => item.split('='))
}: {
content
}
}));
setEdit(false);
}
return (
Expand Down

0 comments on commit d0863fc

Please sign in to comment.