mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 02:10:59 +00:00
Show http trailers in web-ui (#4142)
This commit is contained in:
parent
5ebc338fde
commit
5d0e1906e6
@ -7,6 +7,7 @@ Unreleased: mitmproxy next
|
|||||||
* Fix links to anticache docs in mitmweb and use HTTPS for links to documentation (@rugk)
|
* Fix links to anticache docs in mitmweb and use HTTPS for links to documentation (@rugk)
|
||||||
* Updated typing for WebsocketMessage.content (@prinzhorn)
|
* Updated typing for WebsocketMessage.content (@prinzhorn)
|
||||||
* Prevent transparent mode from connecting to itself in the basic cases (@prinzhorn)
|
* Prevent transparent mode from connecting to itself in the basic cases (@prinzhorn)
|
||||||
|
* Display HTTP trailers in mitmweb (@sanlengjingvv)
|
||||||
|
|
||||||
* --- TODO: add new PRs above this line ---
|
* --- TODO: add new PRs above this line ---
|
||||||
|
|
||||||
|
@ -305,6 +305,10 @@ class FlowHandler(RequestHandler):
|
|||||||
request.headers.clear()
|
request.headers.clear()
|
||||||
for header in v:
|
for header in v:
|
||||||
request.headers.add(*header)
|
request.headers.add(*header)
|
||||||
|
elif k == "trailers":
|
||||||
|
request.trailers.clear()
|
||||||
|
for trailer in v:
|
||||||
|
request.trailers.add(*trailer)
|
||||||
elif k == "content":
|
elif k == "content":
|
||||||
request.text = v
|
request.text = v
|
||||||
else:
|
else:
|
||||||
@ -321,6 +325,10 @@ class FlowHandler(RequestHandler):
|
|||||||
response.headers.clear()
|
response.headers.clear()
|
||||||
for header in v:
|
for header in v:
|
||||||
response.headers.add(*header)
|
response.headers.add(*header)
|
||||||
|
elif k == "trailers":
|
||||||
|
response.trailers.clear()
|
||||||
|
for trailer in v:
|
||||||
|
response.trailers.add(*trailer)
|
||||||
elif k == "content":
|
elif k == "content":
|
||||||
response.text = v
|
response.text = v
|
||||||
else:
|
else:
|
||||||
|
@ -58,7 +58,7 @@ describe('Request Component', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should handle change on flow request header', () => {
|
it('should handle change on flow request header', () => {
|
||||||
let headers = TestUtils.findRenderedComponentWithType(provider, Headers)
|
let headers = TestUtils.scryRenderedComponentsWithType(provider, Headers).filter(headers => headers.props.type === 'headers')[0]
|
||||||
headers.props.onChange('foo')
|
headers.props.onChange('foo')
|
||||||
expect(store.getActions()).toEqual([updateEdit({ request: { headers: 'foo' }})])
|
expect(store.getActions()).toEqual([updateEdit({ request: { headers: 'foo' }})])
|
||||||
})
|
})
|
||||||
@ -115,7 +115,7 @@ describe('Response Component', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should handle change on flow response headers', () => {
|
it('should handle change on flow response headers', () => {
|
||||||
let headers = TestUtils.findRenderedComponentWithType(provider, Headers)
|
let headers = TestUtils.scryRenderedComponentsWithType(provider, Headers).filter(headers => headers.props.type === 'headers')[0]
|
||||||
headers.props.onChange('foo')
|
headers.props.onChange('foo')
|
||||||
expect(store.getActions()).toEqual([updateEdit( { response: { headers: 'foo' }})])
|
expect(store.getActions()).toEqual([updateEdit( { response: { headers: 'foo' }})])
|
||||||
})
|
})
|
||||||
|
@ -199,6 +199,111 @@ exports[`Request Component should render correctly 1`] = `
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<hr />
|
<hr />
|
||||||
|
<hr />
|
||||||
|
<table
|
||||||
|
className="header-table"
|
||||||
|
>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
className="header-name"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="inline-input readonly"
|
||||||
|
contentEditable={undefined}
|
||||||
|
dangerouslySetInnerHTML={
|
||||||
|
Object {
|
||||||
|
"__html": "trailer",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onInput={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onPaste={[Function]}
|
||||||
|
tabIndex={undefined}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="header-colon"
|
||||||
|
>
|
||||||
|
:
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className="header-value"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="inline-input readonly"
|
||||||
|
contentEditable={undefined}
|
||||||
|
dangerouslySetInnerHTML={
|
||||||
|
Object {
|
||||||
|
"__html": "qvalue",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onInput={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onPaste={[Function]}
|
||||||
|
tabIndex={undefined}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
className="header-name"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="inline-input readonly"
|
||||||
|
contentEditable={undefined}
|
||||||
|
dangerouslySetInnerHTML={
|
||||||
|
Object {
|
||||||
|
"__html": "content-length",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onInput={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onPaste={[Function]}
|
||||||
|
tabIndex={undefined}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="header-colon"
|
||||||
|
>
|
||||||
|
:
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className="header-value"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="inline-input readonly"
|
||||||
|
contentEditable={undefined}
|
||||||
|
dangerouslySetInnerHTML={
|
||||||
|
Object {
|
||||||
|
"__html": "7",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onInput={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onPaste={[Function]}
|
||||||
|
tabIndex={undefined}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</article>
|
</article>
|
||||||
<footer>
|
<footer>
|
||||||
<div
|
<div
|
||||||
@ -462,6 +567,111 @@ exports[`Response Component should render correctly 1`] = `
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<hr />
|
<hr />
|
||||||
|
<hr />
|
||||||
|
<table
|
||||||
|
className="header-table"
|
||||||
|
>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
className="header-name"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="inline-input readonly"
|
||||||
|
contentEditable={undefined}
|
||||||
|
dangerouslySetInnerHTML={
|
||||||
|
Object {
|
||||||
|
"__html": "trailer",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onInput={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onPaste={[Function]}
|
||||||
|
tabIndex={undefined}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="header-colon"
|
||||||
|
>
|
||||||
|
:
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className="header-value"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="inline-input readonly"
|
||||||
|
contentEditable={undefined}
|
||||||
|
dangerouslySetInnerHTML={
|
||||||
|
Object {
|
||||||
|
"__html": "qvalue",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onInput={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onPaste={[Function]}
|
||||||
|
tabIndex={undefined}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
className="header-name"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="inline-input readonly"
|
||||||
|
contentEditable={undefined}
|
||||||
|
dangerouslySetInnerHTML={
|
||||||
|
Object {
|
||||||
|
"__html": "content-length",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onInput={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onPaste={[Function]}
|
||||||
|
tabIndex={undefined}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="header-colon"
|
||||||
|
>
|
||||||
|
:
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className="header-value"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="inline-input readonly"
|
||||||
|
contentEditable={undefined}
|
||||||
|
dangerouslySetInnerHTML={
|
||||||
|
Object {
|
||||||
|
"__html": "7",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBlur={[Function]}
|
||||||
|
onClick={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onInput={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onPaste={[Function]}
|
||||||
|
tabIndex={undefined}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</article>
|
</article>
|
||||||
<footer>
|
<footer>
|
||||||
<div
|
<div
|
||||||
|
@ -46,7 +46,17 @@ export default function(){
|
|||||||
"pretty_host": "address",
|
"pretty_host": "address",
|
||||||
"scheme": "http",
|
"scheme": "http",
|
||||||
"timestamp_end": null,
|
"timestamp_end": null,
|
||||||
"timestamp_start": null
|
"timestamp_start": null,
|
||||||
|
"trailers": [
|
||||||
|
[
|
||||||
|
"trailer",
|
||||||
|
"qvalue"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"content-length",
|
||||||
|
"7"
|
||||||
|
]
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"contentHash": "ab530a13e45914982b79f9b7e3fba994cfd1f3fb22f71cea1afbf02b460c6d1d",
|
"contentHash": "ab530a13e45914982b79f9b7e3fba994cfd1f3fb22f71cea1afbf02b460c6d1d",
|
||||||
@ -66,7 +76,17 @@ export default function(){
|
|||||||
"reason": "OK",
|
"reason": "OK",
|
||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
"timestamp_end": 1495370312.4814625,
|
"timestamp_end": 1495370312.4814625,
|
||||||
"timestamp_start": 1495370312.481462
|
"timestamp_start": 1495370312.481462,
|
||||||
|
"trailers": [
|
||||||
|
[
|
||||||
|
"trailer",
|
||||||
|
"qvalue"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"content-length",
|
||||||
|
"7"
|
||||||
|
]
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"server_conn": {
|
"server_conn": {
|
||||||
"address": [
|
"address": [
|
||||||
|
@ -46,10 +46,15 @@ export default class Headers extends Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
message: PropTypes.object.isRequired,
|
message: PropTypes.object.isRequired,
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
type: 'headers',
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(row, col, val) {
|
onChange(row, col, val) {
|
||||||
const nextHeaders = _.cloneDeep(this.props.message.headers)
|
const nextHeaders = _.cloneDeep(this.props.message[this.props.type])
|
||||||
|
|
||||||
nextHeaders[row][col] = val
|
nextHeaders[row][col] = val
|
||||||
|
|
||||||
@ -75,7 +80,7 @@ export default class Headers extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onTab(row, col, e) {
|
onTab(row, col, e) {
|
||||||
const headers = this.props.message.headers
|
const headers = this.props.message[this.props.type]
|
||||||
|
|
||||||
if (col === 0) {
|
if (col === 0) {
|
||||||
this._nextSel = `${row}-value`
|
this._nextSel = `${row}-value`
|
||||||
@ -88,7 +93,7 @@ export default class Headers extends Component {
|
|||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
const nextHeaders = _.cloneDeep(this.props.message.headers)
|
const nextHeaders = _.cloneDeep(this.props.message[this.props.type])
|
||||||
nextHeaders.push(['Name', 'Value'])
|
nextHeaders.push(['Name', 'Value'])
|
||||||
this.props.onChange(nextHeaders)
|
this.props.onChange(nextHeaders)
|
||||||
this._nextSel = `${row + 1}-key`
|
this._nextSel = `${row + 1}-key`
|
||||||
@ -113,37 +118,45 @@ export default class Headers extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { message, readonly } = this.props
|
const { message, readonly } = this.props
|
||||||
|
if (message[this.props.type]) {
|
||||||
return (
|
return (
|
||||||
<table className="header-table">
|
<table className="header-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
{message.headers.map((header, i) => (
|
{message[this.props.type].map((header, i) => (
|
||||||
<tr key={i}>
|
<tr key={i}>
|
||||||
<td className="header-name">
|
<td className="header-name">
|
||||||
<HeaderEditor
|
<HeaderEditor
|
||||||
ref={`${i}-key`}
|
ref={`${i}-key`}
|
||||||
content={header[0]}
|
content={header[0]}
|
||||||
readonly={readonly}
|
readonly={readonly}
|
||||||
onDone={val => this.onChange(i, 0, val)}
|
onDone={val => this.onChange(i, 0, val)}
|
||||||
onRemove={event => this.onRemove(i, 0, event)}
|
onRemove={event => this.onRemove(i, 0, event)}
|
||||||
onTab={event => this.onTab(i, 0, event)}
|
onTab={event => this.onTab(i, 0, event)}
|
||||||
/>
|
/>
|
||||||
<span className="header-colon">:</span>
|
<span className="header-colon">:</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="header-value">
|
<td className="header-value">
|
||||||
<HeaderEditor
|
<HeaderEditor
|
||||||
ref={`${i}-value`}
|
ref={`${i}-value`}
|
||||||
content={header[1]}
|
content={header[1]}
|
||||||
readonly={readonly}
|
readonly={readonly}
|
||||||
onDone={val => this.onChange(i, 1, val)}
|
onDone={val => this.onChange(i, 1, val)}
|
||||||
onRemove={event => this.onRemove(i, 1, event)}
|
onRemove={event => this.onRemove(i, 1, event)}
|
||||||
onTab={event => this.onTab(i, 1, event)}
|
onTab={event => this.onTab(i, 1, event)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<table className="header-table">
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,14 @@ export class Request extends Component {
|
|||||||
flow={flow}
|
flow={flow}
|
||||||
onContentChange={content => updateFlow({ request: {content}})}
|
onContentChange={content => updateFlow({ request: {content}})}
|
||||||
message={flow.request}/>
|
message={flow.request}/>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
<Headers
|
||||||
|
message={flow.request}
|
||||||
|
readonly={!isEdit}
|
||||||
|
onChange={trailers => updateFlow({ request: { trailers } })}
|
||||||
|
type='trailers'
|
||||||
|
/>
|
||||||
</article>
|
</article>
|
||||||
<HideInStatic>
|
<HideInStatic>
|
||||||
{!noContent &&
|
{!noContent &&
|
||||||
@ -150,6 +158,13 @@ export class Response extends Component {
|
|||||||
onContentChange={content => updateFlow({ response: {content}})}
|
onContentChange={content => updateFlow({ response: {content}})}
|
||||||
message={flow.response}
|
message={flow.response}
|
||||||
/>
|
/>
|
||||||
|
<hr/>
|
||||||
|
<Headers
|
||||||
|
message={flow.response}
|
||||||
|
readonly={!isEdit}
|
||||||
|
onChange={trailers => updateFlow({ response: { trailers } })}
|
||||||
|
type='trailers'
|
||||||
|
/>
|
||||||
</article>
|
</article>
|
||||||
<HideInStatic>
|
<HideInStatic>
|
||||||
{!noContent &&
|
{!noContent &&
|
||||||
|
Loading…
Reference in New Issue
Block a user