diff options
Diffstat (limited to 'libmproxy/web')
-rw-r--r-- | libmproxy/web/__init__.py | 9 | ||||
-rw-r--r-- | libmproxy/web/static/css/app.css | 81 | ||||
-rw-r--r-- | libmproxy/web/static/flows.json (renamed from libmproxy/web/flows.json) | 0 | ||||
-rw-r--r-- | libmproxy/web/static/images/sprite.png | bin | 0 -> 10895 bytes | |||
-rw-r--r-- | libmproxy/web/static/js/app.js | 78 |
5 files changed, 148 insertions, 20 deletions
diff --git a/libmproxy/web/__init__.py b/libmproxy/web/__init__.py index c7e0d20d..69971436 100644 --- a/libmproxy/web/__init__.py +++ b/libmproxy/web/__init__.py @@ -1,8 +1,8 @@ +from __future__ import absolute_import, print_function import tornado.ioloop import tornado.httpserver -from .. import controller, utils, flow, script, proxy -import app -import pprint +from .. import controller, flow +from . import app class Stop(Exception): @@ -59,7 +59,7 @@ class WebMaster(flow.FlowMaster): def __init__(self, server, options): self.options = options self.app = app.Application(self.options.wdebug) - flow.FlowMaster.__init__(self, server, WebState()) + super(WebMaster, self).__init__(server, WebState()) self.last_log_id = 0 @@ -90,7 +90,6 @@ class WebMaster(flow.FlowMaster): return f def handle_response(self, f): - s = f.get_state(True) app.ClientConnection.broadcast("update_flow", f.get_state(True)) flow.FlowMaster.handle_response(self, f) if f: diff --git a/libmproxy/web/static/css/app.css b/libmproxy/web/static/css/app.css index ecc7426c..27acd68a 100644 --- a/libmproxy/web/static/css/app.css +++ b/libmproxy/web/static/css/app.css @@ -6,6 +6,60 @@ html { *:after { box-sizing: inherit; } +.resource-icon { + width: 32px; + height: 32px; +} +.resource-icon-css { + background-image: url("../images/sprite.png"); + background-position: 0px 0px; + background-size: 32px 320px!important; +} +.resource-icon-document { + background-image: url("../images/sprite.png"); + background-position: 0px -32px; + background-size: 32px 320px!important; +} +.resource-icon-js { + background-image: url("../images/sprite.png"); + background-position: 0px -64px; + background-size: 32px 320px!important; +} +.resource-icon-plain { + background-image: url("../images/sprite.png"); + background-position: 0px -96px; + background-size: 32px 320px!important; +} +.resource-icon-executable { + background-image: url("../images/sprite.png"); + background-position: 0px -128px; + background-size: 32px 320px!important; +} +.resource-icon-flash { + background-image: url("../images/sprite.png"); + background-position: 0px -160px; + background-size: 32px 320px!important; +} +.resource-icon-image { + background-image: url("../images/sprite.png"); + background-position: 0px -192px; + background-size: 32px 320px!important; +} +.resource-icon-java { + background-image: url("../images/sprite.png"); + background-position: 0px -224px; + background-size: 32px 320px!important; +} +.resource-icon-not-modified { + background-image: url("../images/sprite.png"); + background-position: 0px -256px; + background-size: 32px 320px!important; +} +.resource-icon-redirect { + background-image: url("../images/sprite.png"); + background-position: 0px -288px; + background-size: 32px 320px!important; +} html, body, #container { @@ -69,6 +123,33 @@ header .menu { } .flow-table { width: 100%; + table-layout: fixed; +} +.flow-table thead { + background-color: #dadada; +} +.flow-table td { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.flow-table .col-tls { + width: 10px; +} +.flow-table .col-tls-https { + background-color: rgba(0, 185, 0, 0.5); +} +.flow-table .col-icon { + width: 32px; +} +.flow-table .col-method { + width: 60px; +} +.flow-table .col-status { + width: 50px; +} +.flow-table .col-time { + width: 120px; } .eventlog { flex: 0 0 auto; diff --git a/libmproxy/web/flows.json b/libmproxy/web/static/flows.json index bdbfd5cc..bdbfd5cc 100644 --- a/libmproxy/web/flows.json +++ b/libmproxy/web/static/flows.json diff --git a/libmproxy/web/static/images/sprite.png b/libmproxy/web/static/images/sprite.png Binary files differnew file mode 100644 index 00000000..ff57a37d --- /dev/null +++ b/libmproxy/web/static/images/sprite.png diff --git a/libmproxy/web/static/js/app.js b/libmproxy/web/static/js/app.js index e967af89..ea49db4d 100644 --- a/libmproxy/web/static/js/app.js +++ b/libmproxy/web/static/js/app.js @@ -269,13 +269,14 @@ _.extend(FlowView.prototype, EventEmitter.prototype, { var updates = this.flows; this.flows = flows; updates.forEach(function(flow){ - this.update(flow); + this._update(flow); }.bind(this)); + this.emit("change"); }, - update: function(flow){ + _update: function(flow){ console.debug("FIXME: Use UUID"); var idx = _.findIndex(this.flows, function(f){ - return flow.request.timestamp_start == f.request.timestamp_start + return flow.request.timestamp_start == f.request.timestamp_start; }); if(idx < 0){ @@ -283,6 +284,9 @@ _.extend(FlowView.prototype, EventEmitter.prototype, { } else { this.flows[idx] = flow; } + }, + update: function(flow){ + this._update(flow); this.emit("change"); }, }); @@ -294,6 +298,11 @@ function _FlowStore() { _.extend(_FlowStore.prototype, EventEmitter.prototype, { getView: function (since) { var view = new FlowView(this, !since); + + $.getJSON("/static/flows.json", function(flows){ + view.add_bulk(flows); + }); + return view; }, handle: function (action) { @@ -442,7 +451,10 @@ var FlowRow = React.createClass({displayName: 'FlowRow', render: function(){ var flow = this.props.flow; var columns = this.props.columns.map(function(column){ - return column({flow: flow}); + return column({ + key: column.displayName, + flow: flow + }); }.bind(this)); return React.DOM.tr(null, columns); } @@ -460,55 +472,89 @@ var FlowTableHead = React.createClass({displayName: 'FlowTableHead', var FlowTableBody = React.createClass({displayName: 'FlowTableBody', render: function(){ var rows = this.props.flows.map(function(flow){ - return FlowRow({flow: flow, columns: this.props.columns}) + //TODO: Add UUID + return FlowRow({flow: flow, columns: this.props.columns}); }.bind(this)); return React.DOM.tbody(null, rows); } }); + +var TLSColumn = React.createClass({displayName: 'TLSColumn', + statics: { + renderTitle: function(){ + return React.DOM.th({key: "tls", className: "col-tls"}); + } + }, + render: function(){ + var flow = this.props.flow; + var ssl = (flow.request.scheme == "https"); + return React.DOM.td({className: ssl ? "col-tls-https" : "col-tls-http"}); + } +}); + + +var IconColumn = React.createClass({displayName: 'IconColumn', + statics: { + renderTitle: function(){ + return React.DOM.th({key: "icon", className: "col-icon"}); + } + }, + render: function(){ + var flow = this.props.flow; + return React.DOM.td({className: "resource-icon resource-icon-plain"}); + } +}); + var PathColumn = React.createClass({displayName: 'PathColumn', statics: { renderTitle: function(){ - return React.DOM.th({key: "PathColumn"}, "Path"); + return React.DOM.th({key: "path", className: "col-path"}, "Path"); } }, render: function(){ var flow = this.props.flow; - return React.DOM.td({key: "PathColumn"}, flow.request.scheme + "://" + flow.request.host + flow.request.path); + return React.DOM.td(null, flow.request.scheme + "://" + flow.request.host + flow.request.path); } }); + + var MethodColumn = React.createClass({displayName: 'MethodColumn', statics: { renderTitle: function(){ - return React.DOM.th({key: "MethodColumn"}, "Method"); + return React.DOM.th({key: "method", className: "col-method"}, "Method"); } }, render: function(){ var flow = this.props.flow; - return React.DOM.td({key: "MethodColumn"}, flow.request.method); + return React.DOM.td(null, flow.request.method); } }); + + var StatusColumn = React.createClass({displayName: 'StatusColumn', statics: { renderTitle: function(){ - return React.DOM.th({key: "StatusColumn"}, "Status"); + return React.DOM.th({key: "status", className: "col-status"}, "Status"); } }, render: function(){ var flow = this.props.flow; var status; if(flow.response){ - status = flow.response.code + " " + flow.response.msg; + status = flow.response.code; } else { status = null; } - return React.DOM.td({key: "StatusColumn"}, status); + return React.DOM.td(null, status); } }); + + var TimeColumn = React.createClass({displayName: 'TimeColumn', statics: { renderTitle: function(){ - return React.DOM.th({key: "TimeColumn"}, "Time"); + return React.DOM.th({key: "time", className: "col-time"}, "Time"); } }, render: function(){ @@ -519,11 +565,13 @@ var TimeColumn = React.createClass({displayName: 'TimeColumn', } else { time = "..."; } - return React.DOM.td({key: "TimeColumn"}, time); + return React.DOM.td(null, time); } }); -var all_columns = [PathColumn, MethodColumn, StatusColumn, TimeColumn]; + +var all_columns = [TLSColumn, IconColumn, PathColumn, MethodColumn, StatusColumn, TimeColumn]; + var FlowTable = React.createClass({displayName: 'FlowTable', getInitialState: function () { |