mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 10:16:27 +00:00
change way to edit
This commit is contained in:
parent
45349b3597
commit
5f3782dd5f
@ -201,7 +201,7 @@ class DumpFlows(RequestHandler):
|
||||
def post(self):
|
||||
self.state.clear()
|
||||
|
||||
content = self.request.files.values()[0][0]["body"]
|
||||
content = self.request.files.values()[0][0].body
|
||||
bio = BytesIO(content)
|
||||
self.state.load_flows(FlowReader(bio).stream())
|
||||
bio.close()
|
||||
@ -297,14 +297,15 @@ class FlowContent(RequestHandler):
|
||||
|
||||
flow = self.flow
|
||||
flow.backup()
|
||||
content = 'Can not read file!'
|
||||
if (len(self.request.files.values()) > 0):
|
||||
content = self.request.files.values()[0][0]["body"]
|
||||
flow.response.content = str(content)
|
||||
content = self.request.files.values()[0][0].body
|
||||
if (message == "response"):
|
||||
with models.decoded(flow.response):
|
||||
flow.response.content = content
|
||||
elif(message == "request"):
|
||||
with models.decoded(flow.request):
|
||||
flow.request.content = content
|
||||
self.state.update_flow(flow)
|
||||
|
||||
|
||||
|
||||
def get(self, flow_id, message):
|
||||
message = getattr(self.flow, message)
|
||||
|
||||
|
@ -109,4 +109,4 @@
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import { ViewAuto, ViewImage } from './ContentView/ContentViews'
|
||||
import * as MetaViews from './ContentView/MetaViews'
|
||||
import ContentLoader from './ContentView/ContentLoader'
|
||||
import ViewSelector from './ContentView/ViewSelector'
|
||||
import * as flowsActions from '../ducks/flows'
|
||||
import ContentEditor from './ContentView/ContentEditor'
|
||||
|
||||
export default class ContentView extends Component {
|
||||
|
||||
@ -14,12 +14,13 @@ export default class ContentView extends Component {
|
||||
// <Auto flow={flow} message={flow.request}/>
|
||||
flow: React.PropTypes.object.isRequired,
|
||||
message: React.PropTypes.object.isRequired,
|
||||
onContentChange: React.PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
|
||||
this.state = { displayLarge: false, View: ViewAuto }
|
||||
this.state = { displayLarge: false, View: ViewAuto, contentEditorClosed: true }
|
||||
this.selectView = this.selectView.bind(this)
|
||||
}
|
||||
|
||||
@ -43,9 +44,7 @@ export default class ContentView extends Component {
|
||||
|
||||
onOpenFile(e) {
|
||||
if (e.target.files.length > 0) {
|
||||
//alert(e.target.files[0])
|
||||
flowsActions.update_content(this.props.flow, e.target.files[0])
|
||||
//this.fileInput.value = ''
|
||||
this.props.onContentChange(e.target.files[0])
|
||||
}
|
||||
e.preventDefault()
|
||||
}
|
||||
@ -68,30 +67,56 @@ export default class ContentView extends Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{View.textView ? (
|
||||
<ContentLoader flow={flow} message={message}>
|
||||
<this.state.View update_content={content => flowsActions.update_content(this.props.flow, content)} content="" />
|
||||
</ContentLoader>
|
||||
) : (
|
||||
<View flow={flow} update_content={content => flowsActions.update_content(this.props.flow, content)} message={message} />
|
||||
)}
|
||||
<div className="view-options text-center">
|
||||
<ViewSelector onSelectView={this.selectView} active={View} message={message}/>
|
||||
|
||||
<a className="btn btn-default btn-xs" href={MessageUtils.getContentURL(flow, message)}>
|
||||
<i className="fa fa-download"/>
|
||||
</a>
|
||||
|
||||
<a className="btn btn-default btn-xs" href="#" onClick={e => {this.fileInput.click(); e.preventDefault();}}>
|
||||
<i className="fa fa-upload"/>
|
||||
</a>
|
||||
<input
|
||||
ref={ref => this.fileInput = ref}
|
||||
className="hidden"
|
||||
type="file"
|
||||
onChange={e => this.onOpenFile(e)}
|
||||
/>
|
||||
<div className="row">
|
||||
<div className="col-sm-12">
|
||||
<ContentLoader flow={flow} message={message}>
|
||||
<ContentEditor
|
||||
onSave={this.props.onContentChange}
|
||||
onClose={() => this.setState({contentEditorClosed : true})}
|
||||
onOpen={() => this.setState({contentEditorClosed : false})}
|
||||
isClosed={this.state.contentEditorClosed}
|
||||
content=""
|
||||
/>
|
||||
</ContentLoader>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.contentEditorClosed && (<div>
|
||||
{View.textView ? (
|
||||
<ContentLoader flow={flow} message={message}>
|
||||
<this.state.View content="" />
|
||||
</ContentLoader>
|
||||
) : (
|
||||
<View flow={flow} message={message} />
|
||||
)}
|
||||
|
||||
|
||||
|
||||
<div className="view-options text-center">
|
||||
<ViewSelector onSelectView={this.selectView} active={View} message={message}/>
|
||||
|
||||
<a className="btn btn-default btn-xs"
|
||||
href={MessageUtils.getContentURL(flow, message)}
|
||||
title="Download the content of the flow."
|
||||
>
|
||||
<i className="fa fa-download"/>
|
||||
</a>
|
||||
|
||||
<a className="btn btn-default btn-xs"
|
||||
href="#"
|
||||
onClick={e => {this.fileInput.click(); e.preventDefault();}}
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i className="fa fa-upload"/>
|
||||
</a>
|
||||
<input
|
||||
ref={ref => this.fileInput = ref}
|
||||
className="hidden"
|
||||
type="file"
|
||||
onChange={e => this.onOpenFile(e)}
|
||||
/>
|
||||
</div>
|
||||
</div>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
42
web/src/js/components/ContentView/ContentEditor.jsx
Normal file
42
web/src/js/components/ContentView/ContentEditor.jsx
Normal file
@ -0,0 +1,42 @@
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import CodeEditor from '../common/CodeEditor'
|
||||
|
||||
export default class ContentEditor extends Component {
|
||||
|
||||
static propTypes = {
|
||||
content: PropTypes.string.isRequired,
|
||||
onSave: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onOpen: PropTypes.func.isRequired,
|
||||
isClosed: PropTypes.bool.isRequired
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {content: this.props.content}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.props.isClosed ?
|
||||
<a className="btn btn-default btn-xs pull-right" onClick={this.props.onOpen}>
|
||||
<i className="fa fa-pencil-square-o"/>
|
||||
</a> :
|
||||
<span>
|
||||
<a className="btn btn-default btn-xs pull-right" onClick={this.props.onClose}>
|
||||
<i className="fa fa-times"/>
|
||||
</a>
|
||||
<a className="btn btn-default btn-xs pull-right" onClick={() => this.props.onSave(this.state.content)}>
|
||||
<i className="fa fa-floppy-o"/>
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
{!this.props.isClosed &&
|
||||
<CodeEditor value={this.state.content} onChange={content => this.setState({content: content})}/>
|
||||
}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
@ -1,12 +1,9 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import ContentLoader from './ContentLoader'
|
||||
import { MessageUtils } from '../../flow/utils.js'
|
||||
import CodeEditor from '../common/CodeEditor'
|
||||
import {formatSize} from '../../utils.js'
|
||||
|
||||
|
||||
|
||||
const views = [ViewAuto, ViewImage, ViewJSON, ViewRaw, ViewFile]
|
||||
const views = [ViewAuto, ViewImage, ViewJSON, ViewRaw]
|
||||
|
||||
ViewImage.regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i
|
||||
ViewImage.matches = msg => ViewImage.regex.test(MessageUtils.getContentType(msg))
|
||||
@ -26,16 +23,13 @@ export function ViewImage({ flow, message }) {
|
||||
|
||||
ViewRaw.textView = true
|
||||
ViewRaw.matches = () => true
|
||||
ViewRaw.input = {}
|
||||
|
||||
ViewRaw.propTypes = {
|
||||
content: React.PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
export function ViewRaw({ content, update_content }) {
|
||||
return (
|
||||
<CodeEditor value={content} onSave={update_content}/>
|
||||
)
|
||||
export function ViewRaw({ content }) {
|
||||
return <pre>{content}</pre>
|
||||
}
|
||||
|
||||
ViewJSON.textView = true
|
||||
@ -65,26 +59,13 @@ ViewAuto.propTypes = {
|
||||
flow: React.PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
export function ViewAuto({ message, flow, update_content }) {
|
||||
export function ViewAuto({ message, flow }) {
|
||||
const View = ViewAuto.findView(message)
|
||||
if (View.textView) {
|
||||
return <ContentLoader message={message} flow={flow}><View update_content={update_content} content="" /></ContentLoader>
|
||||
return <ContentLoader message={message} flow={flow}><View content="" /></ContentLoader>
|
||||
} else {
|
||||
return <View message={message} flow={flow} />
|
||||
}
|
||||
}
|
||||
|
||||
ViewFile.matches = () => false
|
||||
|
||||
ViewFile.propTypes = {
|
||||
message: React.PropTypes.object.isRequired,
|
||||
flow: React.PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
export function ViewFile({ message, flow }) {
|
||||
return <div className="alert alert-info">
|
||||
{formatSize(message.contentLength)} content size.
|
||||
</div>
|
||||
}
|
||||
|
||||
export default views
|
||||
|
@ -6,6 +6,7 @@ import { Key, formatTimeStamp } from '../../utils.js'
|
||||
import ContentView from '../ContentView'
|
||||
import ValueEditor from '../ValueEditor'
|
||||
import Headers from './Headers'
|
||||
import * as flowActions from '../../ducks/flows'
|
||||
|
||||
class RequestLine extends Component {
|
||||
|
||||
@ -89,7 +90,10 @@ export class Request extends Component {
|
||||
onChange={headers => updateFlow({ request: { headers } })}
|
||||
/>
|
||||
<hr/>
|
||||
<ContentView flow={flow} message={flow.request} onChange={content => updateFlow({request: {content} })}/>
|
||||
<ContentView flow={flow}
|
||||
onContentChange={content => flowActions.updateContent(this.props.flow, content, "request") }
|
||||
message={flow.request}
|
||||
/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@ -128,7 +132,10 @@ export class Response extends Component {
|
||||
onChange={headers => updateFlow({ response: { headers } })}
|
||||
/>
|
||||
<hr/>
|
||||
<ContentView flow={flow} message={flow.response} onChange={content => updateFlow({response: {content} }) }/>
|
||||
<ContentView flow={flow}
|
||||
onContentChange={content => flowActions.updateContent(this.props.flow, content, "response") }
|
||||
message={flow.response}
|
||||
/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ import React, { PropTypes } from 'react'
|
||||
|
||||
Button.propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
text: PropTypes.string.isRequired
|
||||
text: PropTypes.string,
|
||||
icon: PropTypes.string
|
||||
}
|
||||
|
||||
export default function Button({ onClick, text, icon, disabled }) {
|
||||
@ -10,11 +11,8 @@ export default function Button({ onClick, text, icon, disabled }) {
|
||||
<div className={"btn btn-default"}
|
||||
onClick={onClick}
|
||||
disabled={disabled}>
|
||||
<span hidden={!icon}>
|
||||
<i className={"fa fa-fw " + icon}/>
|
||||
|
||||
</span>
|
||||
{text}
|
||||
{icon && (<i className={"fa fa-fw " + icon}/> )}
|
||||
{text && text}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,40 +1,28 @@
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { render } from 'react-dom';
|
||||
import brace from 'brace';
|
||||
import AceEditor from 'react-ace';
|
||||
import Button from './Button'
|
||||
|
||||
|
||||
import 'brace/mode/javascript';
|
||||
import 'brace/mode/json';
|
||||
import 'brace/theme/kuroir';
|
||||
|
||||
|
||||
|
||||
|
||||
export default class CodeEditor extends Component{
|
||||
constructor( props ) {
|
||||
super(props)
|
||||
this.state = {value: this.props.value}
|
||||
}
|
||||
|
||||
onChange(newValue) {
|
||||
this.setState({value: newValue})
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div onKeyDown={e => e.stopPropagation()}>
|
||||
<AceEditor
|
||||
onChange={e => this.onChange(e)}
|
||||
mode="javascript"
|
||||
theme="kuroir"
|
||||
value={this.state.value}
|
||||
onChange={this.props.onChange}
|
||||
name="rea"
|
||||
value={this.props.value}
|
||||
width="100%"
|
||||
name="codeEditor"
|
||||
editorProps={{$blockScrolling: Infinity}}
|
||||
/>
|
||||
<Button onClick={(e) => this.props.onSave(this.state.value)} text="Update"/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -117,13 +117,12 @@ export function update(flow, data) {
|
||||
return { type: REQUEST_ACTION }
|
||||
}
|
||||
|
||||
export function update_content(flow, file) {
|
||||
export function updateContent(flow, file, type) {
|
||||
const body = new FormData()
|
||||
if (typeof file !== File)
|
||||
file = new Blob([file], {type: 'plain/text'})
|
||||
body.append('file', file)
|
||||
fetchApi(`/flows/${flow.id}/response/content`, {method: 'post', body} )
|
||||
update(flow, {response: {headers: [['Content-Encoding', '']]} } )
|
||||
fetchApi(`/flows/${flow.id}/${type}/content`, {method: 'post', body} )
|
||||
return { type: REQUEST_ACTION }
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user