mirror of
https://github.com/mitmproxy/mitmproxy.git
synced 2024-11-26 06:40:23 +00:00
start to fill detailpane
This commit is contained in:
parent
390a435ac4
commit
b0374710e4
@ -108,6 +108,12 @@ class HTTPMessage(stateobject.StateObject):
|
||||
)
|
||||
_stateobject_long_attributes = {"content"}
|
||||
|
||||
def get_state(self, short=False):
|
||||
ret = super(HTTPMessage, self).get_state(short)
|
||||
if short:
|
||||
ret["contentLength"] = len(self.content)
|
||||
return ret
|
||||
|
||||
def get_decoded_content(self):
|
||||
"""
|
||||
Returns the decoded content based on the current Content-Encoding
|
||||
|
@ -180,10 +180,14 @@ header .menu {
|
||||
.flow-table .col-status {
|
||||
width: 50px;
|
||||
}
|
||||
.flow-table .col-size {
|
||||
width: 70px;
|
||||
}
|
||||
.flow-table .col-time {
|
||||
width: 50px;
|
||||
}
|
||||
.flow-table td.col-time {
|
||||
.flow-table td.col-time,
|
||||
.flow-table td.col-size {
|
||||
text-align: right;
|
||||
}
|
||||
.flow-detail {
|
||||
@ -193,6 +197,29 @@ header .menu {
|
||||
.flow-detail nav {
|
||||
background-color: #F2F2F2;
|
||||
}
|
||||
.flow-detail section {
|
||||
padding: 5px;
|
||||
}
|
||||
.flow-detail code {
|
||||
word-break: break-all;
|
||||
padding-left: 0;
|
||||
}
|
||||
.header-table {
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
word-break: break-all;
|
||||
}
|
||||
.header-table tr {
|
||||
border-top: 1px solid #f7f7f7;
|
||||
}
|
||||
.header-table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
.header-table .header-name {
|
||||
width: 33%;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.eventlog {
|
||||
flex: 0 0 auto;
|
||||
margin: 0;
|
||||
|
@ -1,6 +1,7 @@
|
||||
[{
|
||||
"id": "b5e5483c-e124-45bb-aa2e-360706e03ef4",
|
||||
"request": {
|
||||
"contentLength": 0,
|
||||
"timestamp_end": 1410651311.107,
|
||||
"timestamp_start": 1410651311.106,
|
||||
"form_in": "relative",
|
||||
@ -54,6 +55,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651311.055,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": 1410651311.096,
|
||||
@ -77,6 +79,7 @@
|
||||
"ssl_established": true
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651310.36,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -160,6 +163,7 @@
|
||||
{
|
||||
"id": "85e9781f-d81d-43ca-a694-2cd86c76d991",
|
||||
"request": {
|
||||
"contentLength": 42000,
|
||||
"timestamp_end": 1410651311.657,
|
||||
"timestamp_start": 1410651311.653,
|
||||
"form_in": "relative",
|
||||
@ -217,6 +221,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651311.055,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": 1410651311.096,
|
||||
@ -240,6 +245,7 @@
|
||||
"ssl_established": true
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651310.36,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -323,6 +329,7 @@
|
||||
{
|
||||
"id": "1bf281fd-e02a-423c-a69c-aa65657bc3dd",
|
||||
"request": {
|
||||
"contentLength": 132121,
|
||||
"timestamp_end": 1410651312.362,
|
||||
"timestamp_start": 1410651312.359,
|
||||
"form_in": "relative",
|
||||
@ -380,6 +387,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651312.303,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": 1410651312.349,
|
||||
@ -403,6 +411,7 @@
|
||||
"ssl_established": true
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651312.193,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -490,6 +499,7 @@
|
||||
{
|
||||
"id": "833253a0-f7dd-48c7-893c-1f13a38a71ce",
|
||||
"request": {
|
||||
"contentLength": 13233121,
|
||||
"timestamp_end": 1410651312.389,
|
||||
"timestamp_start": 1410651312.368,
|
||||
"form_in": "relative",
|
||||
@ -547,6 +557,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651312.307,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": 1410651312.355,
|
||||
@ -570,6 +581,7 @@
|
||||
"ssl_established": true
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651312.2,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -657,6 +669,7 @@
|
||||
{
|
||||
"id": "152d8e71-2469-4034-8d6d-11099bbb4248",
|
||||
"request": {
|
||||
"contentLength": 132121231231,
|
||||
"timestamp_end": 1410651312.386,
|
||||
"timestamp_start": 1410651312.368,
|
||||
"form_in": "relative",
|
||||
@ -714,6 +727,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651312.303,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": 1410651312.355,
|
||||
@ -737,6 +751,7 @@
|
||||
"ssl_established": true
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651312.192,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -824,6 +839,7 @@
|
||||
{
|
||||
"id": "b3758e4d-7bae-4771-b154-e100c0722d00",
|
||||
"request": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_end": 1410651373.965,
|
||||
"timestamp_start": 1410651373.963,
|
||||
"form_in": "absolute",
|
||||
@ -865,6 +881,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651374.189,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": null,
|
||||
@ -888,6 +905,7 @@
|
||||
"ssl_established": false
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651373.958,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -955,6 +973,7 @@
|
||||
{
|
||||
"id": "ea9e47ab-fd7b-4463-bfea-cfd64cc5f78d",
|
||||
"request": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_end": 1410651374.391,
|
||||
"timestamp_start": 1410651374.387,
|
||||
"form_in": "absolute",
|
||||
@ -1000,6 +1019,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651374.189,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": null,
|
||||
@ -1023,6 +1043,7 @@
|
||||
"ssl_established": false
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651373.958,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -1090,6 +1111,7 @@
|
||||
{
|
||||
"id": "13ee4cd1-08e0-43ef-9bee-56fc0d9cbf3f",
|
||||
"request": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_end": 1410651374.396,
|
||||
"timestamp_start": 1410651374.394,
|
||||
"form_in": "absolute",
|
||||
@ -1135,6 +1157,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651374.567,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": null,
|
||||
@ -1158,6 +1181,7 @@
|
||||
"ssl_established": false
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651374.389,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -1221,6 +1245,7 @@
|
||||
{
|
||||
"id": "5c50e1fc-5ac4-4748-aed1-c969ede63e4e",
|
||||
"request": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_end": 1410651374.795,
|
||||
"timestamp_start": 1410651374.793,
|
||||
"form_in": "absolute",
|
||||
@ -1266,6 +1291,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651374.99,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": null,
|
||||
@ -1289,6 +1315,7 @@
|
||||
"ssl_established": false
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651374.389,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -1372,6 +1399,7 @@
|
||||
{
|
||||
"id": "0285a0b2-380e-43eb-a7a9-a18893950216",
|
||||
"request": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_end": 1410651375.084,
|
||||
"timestamp_start": 1410651375.078,
|
||||
"form_in": "absolute",
|
||||
@ -1417,6 +1445,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651374.99,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": null,
|
||||
@ -1440,6 +1469,7 @@
|
||||
"ssl_established": false
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651374.389,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -1519,6 +1549,7 @@
|
||||
{
|
||||
"id": "c9af9c71-dc68-462e-8446-f3a4b2782400",
|
||||
"request": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_end": 1410651374.778,
|
||||
"timestamp_start": 1410651374.766,
|
||||
"form_in": "absolute",
|
||||
@ -1564,6 +1595,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651374.952,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": null,
|
||||
@ -1587,6 +1619,7 @@
|
||||
"ssl_established": false
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651374.39,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -1650,6 +1683,7 @@
|
||||
{
|
||||
"id": "310386ab-3ae1-4129-9a2e-8dd2ce60ecdb",
|
||||
"request": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_end": 1410651374.778,
|
||||
"timestamp_start": 1410651374.766,
|
||||
"form_in": "absolute",
|
||||
@ -1695,6 +1729,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651374.189,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": null,
|
||||
@ -1718,6 +1753,7 @@
|
||||
"ssl_established": false
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651373.958,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -1781,6 +1817,7 @@
|
||||
{
|
||||
"id": "b92e5f6e-bb0f-4e47-a50c-ef4072ea40b3",
|
||||
"request": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_end": 1410651376.078,
|
||||
"timestamp_start": 1410651376.075,
|
||||
"form_in": "absolute",
|
||||
@ -1826,6 +1863,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651374.189,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": null,
|
||||
@ -1849,6 +1887,7 @@
|
||||
"ssl_established": false
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651373.958,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
@ -1904,6 +1943,7 @@
|
||||
{
|
||||
"id": "597d086f-d836-49e3-85bb-77a983bed87f",
|
||||
"request": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_end": 1410651376.282,
|
||||
"timestamp_start": 1410651376.279,
|
||||
"form_in": "absolute",
|
||||
@ -1949,6 +1989,7 @@
|
||||
]
|
||||
},
|
||||
"server_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_tcp_setup": 1410651374.189,
|
||||
"state": [],
|
||||
"timestamp_ssl_setup": null,
|
||||
@ -1972,6 +2013,7 @@
|
||||
"ssl_established": false
|
||||
},
|
||||
"client_conn": {
|
||||
"contentLength" : 54321,
|
||||
"timestamp_start": 1410651373.958,
|
||||
"address": {
|
||||
"use_ipv6": false,
|
||||
|
@ -13,11 +13,11 @@ var AutoScrollMixin = {
|
||||
};
|
||||
|
||||
var StickyHeadMixin = {
|
||||
adjustHead: function(){
|
||||
adjustHead: function () {
|
||||
// Abusing CSS transforms to set the element
|
||||
// referenced as head into some kind of position:sticky.
|
||||
var head = this.refs.head.getDOMNode();
|
||||
head.style.transform = "translate(0,"+this.getDOMNode().scrollTop+"px)";
|
||||
head.style.transform = "translate(0," + this.getDOMNode().scrollTop + "px)";
|
||||
}
|
||||
};
|
||||
|
||||
@ -31,6 +31,15 @@ var Key = {
|
||||
ENTER: 13,
|
||||
ESC: 27
|
||||
};
|
||||
|
||||
var formatSize = function (size) {
|
||||
var prefix = ["B", "KB", "MB", "GB", "TB"];
|
||||
while (size >= 1024 && prefix.length > 1) {
|
||||
prefix.shift();
|
||||
size = size / 1024;
|
||||
}
|
||||
return (Math.floor(size * 100) / 100.0) + prefix.shift();
|
||||
};
|
||||
const PayloadSources = {
|
||||
VIEW: "view",
|
||||
SERVER: "server"
|
||||
@ -104,6 +113,53 @@ var EventLogActions = {
|
||||
});
|
||||
}
|
||||
};
|
||||
var _MessageUtils = {
|
||||
getContentType: function (message) {
|
||||
return MessageUtils.getHeader(message, /Content-Type/i);
|
||||
},
|
||||
get_first_header: function (message, regex) {
|
||||
//FIXME: Cache Invalidation.
|
||||
if (!message._headerLookups)
|
||||
Object.defineProperty(message, "_headerLookups", {
|
||||
value: {},
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false
|
||||
});
|
||||
if (!(regex in message._headerLookups)) {
|
||||
var header;
|
||||
for (var i = 0; i < message.headers.length; i++) {
|
||||
if (!!message.headers[i][0].match(regex)) {
|
||||
header = message.headers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
message._headerLookups[regex] = header ? header[1] : undefined;
|
||||
}
|
||||
return message._headerLookups[regex];
|
||||
}
|
||||
};
|
||||
|
||||
var defaultPorts = {
|
||||
"http": 80,
|
||||
"https": 443
|
||||
};
|
||||
|
||||
var RequestUtils = _.extend(_MessageUtils, {
|
||||
pretty_host: function (request) {
|
||||
//FIXME: Add hostheader
|
||||
return request.host;
|
||||
},
|
||||
pretty_url: function (request) {
|
||||
var port = "";
|
||||
if (defaultPorts[request.scheme] !== request.port) {
|
||||
port = ":" + request.port;
|
||||
}
|
||||
return request.scheme + "://" + this.pretty_host(request) + port + request.path;
|
||||
}
|
||||
});
|
||||
|
||||
var ResponseUtils = _.extend(_MessageUtils, {});
|
||||
function EventEmitter() {
|
||||
this.listeners = {};
|
||||
}
|
||||
@ -654,6 +710,22 @@ var StatusColumn = React.createClass({displayName: 'StatusColumn',
|
||||
});
|
||||
|
||||
|
||||
var SizeColumn = React.createClass({displayName: 'SizeColumn',
|
||||
statics: {
|
||||
renderTitle: function(){
|
||||
return React.DOM.th({key: "size", className: "col-size"}, "Size");
|
||||
}
|
||||
},
|
||||
render: function(){
|
||||
var flow = this.props.flow;
|
||||
var size = formatSize(
|
||||
flow.request.contentLength +
|
||||
(flow.response.contentLength || 0));
|
||||
return React.DOM.td({className: "col-size"}, size);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var TimeColumn = React.createClass({displayName: 'TimeColumn',
|
||||
statics: {
|
||||
renderTitle: function(){
|
||||
@ -673,7 +745,14 @@ var TimeColumn = React.createClass({displayName: 'TimeColumn',
|
||||
});
|
||||
|
||||
|
||||
var all_columns = [TLSColumn, IconColumn, PathColumn, MethodColumn, StatusColumn, TimeColumn];
|
||||
var all_columns = [
|
||||
TLSColumn,
|
||||
IconColumn,
|
||||
PathColumn,
|
||||
MethodColumn,
|
||||
StatusColumn,
|
||||
SizeColumn,
|
||||
TimeColumn];
|
||||
|
||||
|
||||
/** @jsx React.DOM */
|
||||
@ -829,21 +908,59 @@ var FlowDetailNav = React.createClass({displayName: 'FlowDetailNav',
|
||||
}
|
||||
});
|
||||
|
||||
var Headers = React.createClass({displayName: 'Headers',
|
||||
render: function(){
|
||||
var rows = this.props.message.headers.map(function(header){
|
||||
return (
|
||||
React.DOM.tr(null,
|
||||
React.DOM.td({className: "header-name"}, header[0]),
|
||||
React.DOM.td({className: "header-value"}, header[1])
|
||||
)
|
||||
);
|
||||
})
|
||||
return (
|
||||
React.DOM.table({className: "header-table"},
|
||||
React.DOM.tbody(null,
|
||||
rows
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
})
|
||||
|
||||
var FlowDetailRequest = React.createClass({displayName: 'FlowDetailRequest',
|
||||
render: function(){
|
||||
return React.DOM.div(null, "request");
|
||||
var flow = this.props.flow;
|
||||
var url = React.DOM.code(null, RequestUtils.pretty_url(flow.request) );
|
||||
var content = null;
|
||||
if(flow.request.contentLength > 0){
|
||||
content = "Request Content Size: "+ formatSize(flow.request.contentLength);
|
||||
} else {
|
||||
content = React.DOM.div({className: "alert alert-info"}, "No Content");
|
||||
}
|
||||
|
||||
//TODO: Styling
|
||||
|
||||
return (
|
||||
React.DOM.section(null,
|
||||
url,
|
||||
Headers({message: flow.request}),
|
||||
React.DOM.hr(null),
|
||||
content
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var FlowDetailResponse = React.createClass({displayName: 'FlowDetailResponse',
|
||||
render: function(){
|
||||
return React.DOM.div(null, "response");
|
||||
return React.DOM.section(null, "response");
|
||||
}
|
||||
});
|
||||
|
||||
var FlowDetailConnectionInfo = React.createClass({displayName: 'FlowDetailConnectionInfo',
|
||||
render: function(){
|
||||
return React.DOM.div(null, "details");
|
||||
return React.DOM.section(null, "details");
|
||||
}
|
||||
});
|
||||
|
||||
@ -860,8 +977,8 @@ var FlowDetail = React.createClass({displayName: 'FlowDetail',
|
||||
var Tab = tabs[this.props.active];
|
||||
return (
|
||||
React.DOM.div({className: "flow-detail", onScroll: this.adjustHead},
|
||||
FlowDetailNav({active: this.props.active, selectTab: this.props.selectTab}),
|
||||
Tab(null)
|
||||
FlowDetailNav({ref: "head", active: this.props.active, selectTab: this.props.selectTab}),
|
||||
Tab({flow: this.props.flow})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ var path = {
|
||||
'js/utils.js',
|
||||
'js/dispatcher.js',
|
||||
'js/actions.js',
|
||||
'js/flow/utils.js',
|
||||
'js/stores/base.js',
|
||||
'js/stores/settingstore.js',
|
||||
'js/stores/eventlogstore.js',
|
||||
|
@ -5,4 +5,48 @@
|
||||
nav {
|
||||
background-color: #F2F2F2;
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
//FIXME: Style properly
|
||||
code {
|
||||
word-break: break-all;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Move into some utils
|
||||
.monospace(){
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
}
|
||||
|
||||
.header-table {
|
||||
.monospace();
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
word-break: break-all;
|
||||
|
||||
tr {
|
||||
//&:not(:first-child){
|
||||
border-top: 1px solid #f7f7f7;
|
||||
//}
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
//alt:
|
||||
//white-space: nowrap;
|
||||
//overflow: hidden;
|
||||
//text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.header-name {
|
||||
width: 33%;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.header-value {
|
||||
|
||||
}
|
||||
}
|
@ -51,10 +51,13 @@
|
||||
.col-status {
|
||||
width: 50px;
|
||||
}
|
||||
.col-size {
|
||||
width: 70px;
|
||||
}
|
||||
.col-time {
|
||||
width: 50px;
|
||||
}
|
||||
td.col-time {
|
||||
td.col-time, td.col-size {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
@ -23,21 +23,59 @@ var FlowDetailNav = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
var Headers = React.createClass({
|
||||
render: function(){
|
||||
var rows = this.props.message.headers.map(function(header){
|
||||
return (
|
||||
<tr>
|
||||
<td className="header-name">{header[0]}</td>
|
||||
<td className="header-value">{header[1]}</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
return (
|
||||
<table className="header-table">
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
})
|
||||
|
||||
var FlowDetailRequest = React.createClass({
|
||||
render: function(){
|
||||
return <div>request</div>;
|
||||
var flow = this.props.flow;
|
||||
var url = <code>{ RequestUtils.pretty_url(flow.request) }</code>;
|
||||
var content = null;
|
||||
if(flow.request.contentLength > 0){
|
||||
content = "Request Content Size: "+ formatSize(flow.request.contentLength);
|
||||
} else {
|
||||
content = <div className="alert alert-info">No Content</div>;
|
||||
}
|
||||
|
||||
//TODO: Styling
|
||||
|
||||
return (
|
||||
<section>
|
||||
{url}
|
||||
<Headers message={flow.request}/>
|
||||
<hr/>
|
||||
{content}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var FlowDetailResponse = React.createClass({
|
||||
render: function(){
|
||||
return <div>response</div>;
|
||||
return <section>response</section>;
|
||||
}
|
||||
});
|
||||
|
||||
var FlowDetailConnectionInfo = React.createClass({
|
||||
render: function(){
|
||||
return <div>details</div>;
|
||||
return <section>details</section>;
|
||||
}
|
||||
});
|
||||
|
||||
@ -54,8 +92,8 @@ var FlowDetail = React.createClass({
|
||||
var Tab = tabs[this.props.active];
|
||||
return (
|
||||
<div className="flow-detail" onScroll={this.adjustHead}>
|
||||
<FlowDetailNav active={this.props.active} selectTab={this.props.selectTab}/>
|
||||
<Tab/>
|
||||
<FlowDetailNav ref="head" active={this.props.active} selectTab={this.props.selectTab}/>
|
||||
<Tab flow={this.props.flow}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -77,6 +77,22 @@ var StatusColumn = React.createClass({
|
||||
});
|
||||
|
||||
|
||||
var SizeColumn = React.createClass({
|
||||
statics: {
|
||||
renderTitle: function(){
|
||||
return <th key="size" className="col-size">Size</th>;
|
||||
}
|
||||
},
|
||||
render: function(){
|
||||
var flow = this.props.flow;
|
||||
var size = formatSize(
|
||||
flow.request.contentLength +
|
||||
(flow.response.contentLength || 0));
|
||||
return <td className="col-size">{size}</td>;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var TimeColumn = React.createClass({
|
||||
statics: {
|
||||
renderTitle: function(){
|
||||
@ -96,5 +112,12 @@ var TimeColumn = React.createClass({
|
||||
});
|
||||
|
||||
|
||||
var all_columns = [TLSColumn, IconColumn, PathColumn, MethodColumn, StatusColumn, TimeColumn];
|
||||
var all_columns = [
|
||||
TLSColumn,
|
||||
IconColumn,
|
||||
PathColumn,
|
||||
MethodColumn,
|
||||
StatusColumn,
|
||||
SizeColumn,
|
||||
TimeColumn];
|
||||
|
||||
|
47
web/src/js/flow/utils.js
Normal file
47
web/src/js/flow/utils.js
Normal file
@ -0,0 +1,47 @@
|
||||
var _MessageUtils = {
|
||||
getContentType: function (message) {
|
||||
return MessageUtils.getHeader(message, /Content-Type/i);
|
||||
},
|
||||
get_first_header: function (message, regex) {
|
||||
//FIXME: Cache Invalidation.
|
||||
if (!message._headerLookups)
|
||||
Object.defineProperty(message, "_headerLookups", {
|
||||
value: {},
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false
|
||||
});
|
||||
if (!(regex in message._headerLookups)) {
|
||||
var header;
|
||||
for (var i = 0; i < message.headers.length; i++) {
|
||||
if (!!message.headers[i][0].match(regex)) {
|
||||
header = message.headers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
message._headerLookups[regex] = header ? header[1] : undefined;
|
||||
}
|
||||
return message._headerLookups[regex];
|
||||
}
|
||||
};
|
||||
|
||||
var defaultPorts = {
|
||||
"http": 80,
|
||||
"https": 443
|
||||
};
|
||||
|
||||
var RequestUtils = _.extend(_MessageUtils, {
|
||||
pretty_host: function (request) {
|
||||
//FIXME: Add hostheader
|
||||
return request.host;
|
||||
},
|
||||
pretty_url: function (request) {
|
||||
var port = "";
|
||||
if (defaultPorts[request.scheme] !== request.port) {
|
||||
port = ":" + request.port;
|
||||
}
|
||||
return request.scheme + "://" + this.pretty_host(request) + port + request.path;
|
||||
}
|
||||
});
|
||||
|
||||
var ResponseUtils = _.extend(_MessageUtils, {});
|
@ -13,11 +13,11 @@ var AutoScrollMixin = {
|
||||
};
|
||||
|
||||
var StickyHeadMixin = {
|
||||
adjustHead: function(){
|
||||
adjustHead: function () {
|
||||
// Abusing CSS transforms to set the element
|
||||
// referenced as head into some kind of position:sticky.
|
||||
var head = this.refs.head.getDOMNode();
|
||||
head.style.transform = "translate(0,"+this.getDOMNode().scrollTop+"px)";
|
||||
head.style.transform = "translate(0," + this.getDOMNode().scrollTop + "px)";
|
||||
}
|
||||
};
|
||||
|
||||
@ -30,4 +30,13 @@ var Key = {
|
||||
RIGHT: 39,
|
||||
ENTER: 13,
|
||||
ESC: 27
|
||||
};
|
||||
|
||||
var formatSize = function (size) {
|
||||
var prefix = ["B", "KB", "MB", "GB", "TB"];
|
||||
while (size >= 1024 && prefix.length > 1) {
|
||||
prefix.shift();
|
||||
size = size / 1024;
|
||||
}
|
||||
return (Math.floor(size * 100) / 100.0) + prefix.shift();
|
||||
};
|
Loading…
Reference in New Issue
Block a user