aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy')
-rw-r--r--libmproxy/controller.py2
-rw-r--r--libmproxy/web/__init__.py9
-rw-r--r--libmproxy/web/static/css/app.css81
-rw-r--r--libmproxy/web/static/flows.json (renamed from libmproxy/web/flows.json)0
-rw-r--r--libmproxy/web/static/images/sprite.pngbin0 -> 10895 bytes
-rw-r--r--libmproxy/web/static/js/app.js78
6 files changed, 149 insertions, 21 deletions
diff --git a/libmproxy/controller.py b/libmproxy/controller.py
index b754ac36..39e7695f 100644
--- a/libmproxy/controller.py
+++ b/libmproxy/controller.py
@@ -77,7 +77,7 @@ class Slave(threading.Thread):
self.server.serve_forever()
-class Master:
+class Master(object):
"""
Masters get and respond to messages from slaves.
"""
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
new file mode 100644
index 00000000..ff57a37d
--- /dev/null
+++ b/libmproxy/web/static/images/sprite.png
Binary files differ
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 () {