diff options
author | Maximilian Hils <git@maximilianhils.com> | 2014-12-23 20:33:42 +0100 |
---|---|---|
committer | Maximilian Hils <git@maximilianhils.com> | 2014-12-23 20:33:42 +0100 |
commit | 2861d99de4d329bcba0a3c2193523398a22673c0 (patch) | |
tree | 0aa1a2aae666c2909285a6fd5049f2ef7d6d8ebc /web | |
parent | 459772a8ef79ac0adeaeba56577972e86074265e (diff) | |
download | mitmproxy-2861d99de4d329bcba0a3c2193523398a22673c0.tar.gz mitmproxy-2861d99de4d329bcba0a3c2193523398a22673c0.tar.bz2 mitmproxy-2861d99de4d329bcba0a3c2193523398a22673c0.zip |
web: intercept feature
Diffstat (limited to 'web')
-rw-r--r-- | web/gulpfile.js | 1 | ||||
-rw-r--r-- | web/src/css/flowtable.less | 11 | ||||
-rw-r--r-- | web/src/js/actions.js | 6 | ||||
-rw-r--r-- | web/src/js/components/flowtable.jsx.js | 9 | ||||
-rw-r--r-- | web/src/js/components/footer.jsx.js | 3 | ||||
-rw-r--r-- | web/src/js/components/header.jsx.js | 91 | ||||
-rw-r--r-- | web/src/js/components/mainview.jsx.js | 11 | ||||
-rw-r--r-- | web/src/js/components/utils.jsx.js | 2 | ||||
-rw-r--r-- | web/src/js/store/settingstore.js | 0 | ||||
-rw-r--r-- | web/src/js/utils.js | 8 |
10 files changed, 91 insertions, 51 deletions
diff --git a/web/gulpfile.js b/web/gulpfile.js index 8dc888e7..5a0b93af 100644 --- a/web/gulpfile.js +++ b/web/gulpfile.js @@ -40,7 +40,6 @@ var path = { 'js/flow/utils.js', 'js/store/store.js', 'js/store/view.js', - 'js/store/settingstore.js', 'js/connection.js', 'js/components/utils.jsx.js', 'js/components/virtualscroll.jsx.js', diff --git a/web/src/css/flowtable.less b/web/src/css/flowtable.less index 2b0e8df3..b18a71fa 100644 --- a/web/src/css/flowtable.less +++ b/web/src/css/flowtable.less @@ -40,7 +40,16 @@ text-overflow: ellipsis; } - tr + tr.intercepted:not(.has-response) { + .col-path, .col-method { + color: hsl(30, 100%, 50%); + } + } + tr.intercepted.has-response { + .col-status, .col-size, .col-time { + color: hsl(30, 100%, 50%); + } + } .col-tls { width: 10px; diff --git a/web/src/js/actions.js b/web/src/js/actions.js index 863663f3..e7799118 100644 --- a/web/src/js/actions.js +++ b/web/src/js/actions.js @@ -38,7 +38,11 @@ var ConnectionActions = { var SettingsActions = { update: function (settings) { - //TODO: Update server. + jQuery.ajax({ + type: "PUT", + url: "/settings", + data: settings + }); //Facebook Flux: We do an optimistic update on the client already. AppDispatcher.dispatchViewAction({ diff --git a/web/src/js/components/flowtable.jsx.js b/web/src/js/components/flowtable.jsx.js index efc975a6..a3a37c40 100644 --- a/web/src/js/components/flowtable.jsx.js +++ b/web/src/js/components/flowtable.jsx.js @@ -11,6 +11,15 @@ var FlowRow = React.createClass({ if (this.props.highlighted) { className += " highlighted"; } + if (flow.intercepted) { + className += " intercepted"; + } + if (flow.request) { + className += " has-request"; + } + if (flow.response) { + className += " has-response"; + } return ( <tr className={className} onClick={this.props.selectFlow.bind(null, flow)}> diff --git a/web/src/js/components/footer.jsx.js b/web/src/js/components/footer.jsx.js index 73fadef2..52d52e0f 100644 --- a/web/src/js/components/footer.jsx.js +++ b/web/src/js/components/footer.jsx.js @@ -1,9 +1,12 @@ var Footer = React.createClass({ render: function () { var mode = this.props.settings.mode; + var intercept = this.props.settings.intercept; return ( <footer> {mode != "regular" ? <span className="label label-success">{mode} mode</span> : null} + + {intercept ? <span className="label label-success">Intercept: {intercept}</span> : null} </footer> ); } diff --git a/web/src/js/components/header.jsx.js b/web/src/js/components/header.jsx.js index 9e090770..cb9cd149 100644 --- a/web/src/js/components/header.jsx.js +++ b/web/src/js/components/header.jsx.js @@ -1,9 +1,8 @@ var FilterInput = React.createClass({ getInitialState: function () { - // Focus: Show popover - // Mousefocus: Mouse over Tooltip - // onBlur is triggered before click on tooltip, - // hiding the tooltip before link is clicked. + // Consider both focus and mouseover for showing/hiding the tooltip, + // because onBlur of the input is triggered before the click on the tooltip + // finalized, hiding the tooltip just as the user clicks on it. return { value: this.props.value, focus: false, @@ -18,16 +17,14 @@ var FilterInput = React.createClass({ this.setState({ value: nextValue }); - try { - Filt.parse(nextValue); - } catch (err) { - return; + // Only propagate valid filters upwards. + if (this.isValid(nextValue)) { + this.props.onChange(nextValue); } - this.props.onChange(nextValue); }, - isValid: function () { + isValid: function (filt) { try { - Filt.parse(this.state.value); + Filt.parse(filt || this.state.value); return true; } catch (e) { return false; @@ -64,16 +61,14 @@ var FilterInput = React.createClass({ this.setState({mousefocus: false}); }, onKeyDown: function (e) { - if (e.target.value === "" && - e.keyCode === Key.BACKSPACE) { - e.preventDefault(); - this.remove(); + if (e.keyCode === Key.ESC || e.keyCode === Key.ENTER) { + this.blur(); + // If closed using ESC/ENTER, hide the tooltip. + this.setState({mousefocus: false}); } }, - remove: function () { - if (this.props.onRemove) { - this.props.onRemove(); - } + blur: function () { + this.refs.input.getDOMNode().blur(); }, focus: function () { this.refs.input.getDOMNode().select(); @@ -100,7 +95,7 @@ var FilterInput = React.createClass({ <span className="input-group-addon"> <i className={icon} style={{color: this.props.color}}></i> </span> - <input type="text" placeholder="filter expression" className="form-control" + <input type="text" placeholder={this.props.placeholder} className="form-control" ref="input" onChange={this.onChange} onFocus={this.onFocus} @@ -115,12 +110,6 @@ var FilterInput = React.createClass({ var MainMenu = React.createClass({ mixins: [Navigation, State], - getInitialState: function () { - return { - filter: this.getQuery()[Query.FILTER] || "", - highlight: this.getQuery()[Query.HIGHLIGHT] || "" - }; - }, statics: { title: "Traffic", route: "flows" @@ -131,39 +120,59 @@ var MainMenu = React.createClass({ }); }, clearFlows: function () { - $.post("/clear"); + jQuery.post("/clear"); }, - applyFilter: function (filter, highlight) { + onFilterChange: function (val) { var d = {}; - d[Query.FILTER] = filter; - d[Query.HIGHLIGHT] = highlight; + d[Query.FILTER] = val; this.setQuery(d); }, - onFilterChange: function (val) { - this.setState({filter: val}); - this.applyFilter(val, this.state.highlight); - }, onHighlightChange: function (val) { - this.setState({highlight: val}); - this.applyFilter(this.state.filter, val); + var d = {}; + d[Query.HIGHLIGHT] = val; + this.setQuery(d); + }, + onInterceptChange: function (val) { + SettingsActions.update({intercept: val}); }, render: function () { + var filter = this.getQuery()[Query.FILTER] || ""; + var highlight = this.getQuery()[Query.HIGHLIGHT] || ""; + var intercept = this.props.settings.intercept || ""; + return ( <div> <button className={"btn " + (this.props.settings.showEventLog ? "btn-primary" : "btn-default")} onClick={this.toggleEventLog}> <i className="fa fa-database"></i> Display Event Log </button> - + <span> </span> <button className="btn btn-default" onClick={this.clearFlows}> <i className="fa fa-eraser"></i> Clear Flows </button> - + <span> </span> <form className="form-inline" style={{display: "inline"}}> - <FilterInput type="filter" color="black" value={this.state.filter} onChange={this.onFilterChange} /> - - <FilterInput type="tag" color="hsl(48, 100%, 50%)" value={this.state.highlight} onChange={this.onHighlightChange}/> + <FilterInput + placeholder="Filter" + type="filter" + color="black" + value={filter} + onChange={this.onFilterChange} /> + <span> </span> + <FilterInput + placeholder="Highlight" + type="tag" + color="hsl(48, 100%, 50%)" + value={highlight} + onChange={this.onHighlightChange}/> + <span> </span> + <FilterInput + placeholder="Intercept" + type="pause" + color="hsl(208, 56%, 53%)" + value={intercept} + onChange={this.onInterceptChange}/> </form> </div> ); diff --git a/web/src/js/components/mainview.jsx.js b/web/src/js/components/mainview.jsx.js index 113b0896..046d6af0 100644 --- a/web/src/js/components/mainview.jsx.js +++ b/web/src/js/components/mainview.jsx.js @@ -16,12 +16,12 @@ var MainView = React.createClass({ var filt = Filt.parse(this.getQuery()[Query.FILTER] || ""); var highlightStr = this.getQuery()[Query.HIGHLIGHT]; var highlight = highlightStr ? Filt.parse(highlightStr) : false; - } catch(e){ + } catch (e) { console.error("Error when processing filter: " + e); } return function filter_and_highlight(flow) { - if(!this._highlight){ + if (!this._highlight) { this._highlight = {}; } this._highlight[flow.id] = highlight && highlight(flow); @@ -143,6 +143,13 @@ var MainView = React.createClass({ this.refs.flowDetails.nextTab(+1); } break; + case Key.A: + if (e.shiftKey) { + $.post("/flows/accept"); + } else if(this.getSelected()) { + $.post("/flows/" + this.getSelected().id + "/accept"); + } + break; default: console.debug("keydown", e.keyCode); return; diff --git a/web/src/js/components/utils.jsx.js b/web/src/js/components/utils.jsx.js index 81ba6b4d..20dbda94 100644 --- a/web/src/js/components/utils.jsx.js +++ b/web/src/js/components/utils.jsx.js @@ -113,7 +113,7 @@ var xsrf = $.param({_xsrf: getCookie("_xsrf")}); //Tornado XSRF Protection. $.ajaxPrefilter(function (options) { - if (options.type === "post" && options.url[0] === "/") { + if (["post","put","delete"].indexOf(options.type.toLowerCase()) >= 0 && options.url[0] === "/") { if (options.data) { options.data += ("&" + xsrf); } else { diff --git a/web/src/js/store/settingstore.js b/web/src/js/store/settingstore.js deleted file mode 100644 index e69de29b..00000000 --- a/web/src/js/store/settingstore.js +++ /dev/null diff --git a/web/src/js/utils.js b/web/src/js/utils.js index b96aed0b..082f7272 100644 --- a/web/src/js/utils.js +++ b/web/src/js/utils.js @@ -90,11 +90,11 @@ var Key = { TAB: 9, SPACE: 32, BACKSPACE: 8, - J: 74, - K: 75, - H: 72, - L: 76 }; +// Add A-Z +for(var i=65; i <= 90; i++){ + Key[String.fromCharCode(i)] = i; +} var formatSize = function (bytes) { |