mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 00:01:36 +00:00
web: various improvements
This commit is contained in:
parent
60cec1f9b6
commit
9cda2eb3a3
@ -148,9 +148,6 @@ header .menu {
|
||||
font-weight: normal;
|
||||
box-shadow: 0 1px 0 #a6a6a6;
|
||||
}
|
||||
.flow-table tbody {
|
||||
outline: 0;
|
||||
}
|
||||
.flow-table tr {
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -198,11 +195,16 @@ header .menu {
|
||||
background-color: #F2F2F2;
|
||||
}
|
||||
.flow-detail section {
|
||||
padding: 5px;
|
||||
padding: 5px 12px;
|
||||
}
|
||||
.flow-detail code {
|
||||
.flow-detail .first-line {
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
background-color: #428bca;
|
||||
color: white;
|
||||
margin: 0 -8px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 5px;
|
||||
word-break: break-all;
|
||||
padding-left: 0;
|
||||
}
|
||||
.flow-detail table {
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
|
@ -41,7 +41,7 @@ var Key = {
|
||||
var formatSize = function (bytes) {
|
||||
var size = bytes;
|
||||
var prefix = ["B", "KB", "MB", "GB", "TB"];
|
||||
while (size >= 1024 && prefix.length > 1) {
|
||||
while (Math.abs(size) >= 1024 && prefix.length > 1) {
|
||||
prefix.shift();
|
||||
size = size / 1024;
|
||||
}
|
||||
@ -50,9 +50,9 @@ var formatSize = function (bytes) {
|
||||
|
||||
var formatTimeDelta = function (milliseconds) {
|
||||
var time = milliseconds;
|
||||
var prefix = ["ms", "s", "m", "h"];
|
||||
var prefix = ["ms", "s", "min", "h"];
|
||||
var div = [1000, 60, 60];
|
||||
while (time >= div[0] && prefix.length > 1) {
|
||||
while (Math.abs(time) >= div[0] && prefix.length > 1) {
|
||||
prefix.shift();
|
||||
time = time / div.shift();
|
||||
}
|
||||
@ -617,12 +617,12 @@ var Header = React.createClass({displayName: 'Header',
|
||||
console.log("File click");
|
||||
},
|
||||
render: function () {
|
||||
var header = header_entries.map(function(entry){
|
||||
var header = header_entries.map(function(entry, i){
|
||||
var classes = React.addons.classSet({
|
||||
active: entry == this.state.active
|
||||
});
|
||||
return (
|
||||
React.DOM.a({key: entry.title,
|
||||
React.DOM.a({key: i,
|
||||
href: "#",
|
||||
className: classes,
|
||||
onClick: this.handleClick.bind(this, entry)
|
||||
@ -685,7 +685,6 @@ var IconColumn = React.createClass({displayName: 'IconColumn',
|
||||
var contentType = ResponseUtils.getContentType(flow.response);
|
||||
|
||||
//TODO: We should assign a type to the flow somewhere else.
|
||||
var icon;
|
||||
if(flow.response.code == 304) {
|
||||
icon = "resource-icon-not-modified";
|
||||
} else if(300 <= flow.response.code && flow.response.code < 400) {
|
||||
@ -763,9 +762,10 @@ var SizeColumn = React.createClass({displayName: 'SizeColumn',
|
||||
},
|
||||
render: function(){
|
||||
var flow = this.props.flow;
|
||||
|
||||
var total = flow.request.contentLength;
|
||||
if(flow.response){
|
||||
total += flow.response.contentLength;
|
||||
total += flow.response.contentLength || 0;
|
||||
}
|
||||
var size = formatSize(total);
|
||||
return React.DOM.td({className: "col-size"}, size);
|
||||
@ -917,9 +917,9 @@ var FlowDetailNav = React.createClass({displayName: 'FlowDetailNav',
|
||||
|
||||
var Headers = React.createClass({displayName: 'Headers',
|
||||
render: function(){
|
||||
var rows = this.props.message.headers.map(function(header){
|
||||
var rows = this.props.message.headers.map(function(header, i){
|
||||
return (
|
||||
React.DOM.tr(null,
|
||||
React.DOM.tr({key: i},
|
||||
React.DOM.td({className: "header-name"}, header[0]+":"),
|
||||
React.DOM.td({className: "header-value"}, header[1])
|
||||
)
|
||||
@ -954,7 +954,7 @@ var FlowDetailRequest = React.createClass({displayName: 'FlowDetailRequest',
|
||||
|
||||
return (
|
||||
React.DOM.section(null,
|
||||
React.DOM.code(null, first_line ),
|
||||
React.DOM.div({className: "first-line"}, first_line ),
|
||||
Headers({message: flow.request}),
|
||||
React.DOM.hr(null),
|
||||
content
|
||||
@ -982,7 +982,7 @@ var FlowDetailResponse = React.createClass({displayName: 'FlowDetailResponse',
|
||||
|
||||
return (
|
||||
React.DOM.section(null,
|
||||
React.DOM.code(null, first_line ),
|
||||
React.DOM.div({className: "first-line"}, first_line ),
|
||||
Headers({message: flow.response}),
|
||||
React.DOM.hr(null),
|
||||
content
|
||||
@ -993,24 +993,22 @@ var FlowDetailResponse = React.createClass({displayName: 'FlowDetailResponse',
|
||||
|
||||
var TimeStamp = React.createClass({displayName: 'TimeStamp',
|
||||
render: function() {
|
||||
var ts, delta;
|
||||
|
||||
if(!this.props.t && this.props.optional){
|
||||
if(!this.props.t){
|
||||
//should be return null, but that triggers a React bug.
|
||||
return React.DOM.tr(null);
|
||||
} else if (!this.props.t){
|
||||
ts = "active";
|
||||
} else {
|
||||
ts = (new Date(this.props.t * 1000)).toISOString();
|
||||
}
|
||||
|
||||
var ts = (new Date(this.props.t * 1000)).toISOString();
|
||||
ts = ts.replace("T", " ").replace("Z","");
|
||||
|
||||
var delta;
|
||||
if(this.props.deltaTo){
|
||||
delta = Math.round((this.props.t-this.props.deltaTo)*1000) + "ms";
|
||||
delta = formatTimeDelta(1000 * (this.props.t-this.props.deltaTo));
|
||||
delta = React.DOM.span({className: "text-muted"}, "(" + delta + ")");
|
||||
} else {
|
||||
delta = null;
|
||||
}
|
||||
}
|
||||
|
||||
return React.DOM.tr(null, React.DOM.td(null, this.props.title + ":"), React.DOM.td(null, ts, " ", delta));
|
||||
}
|
||||
@ -1030,24 +1028,7 @@ var ConnectionInfo = React.createClass({displayName: 'ConnectionInfo',
|
||||
React.DOM.table({className: "connection-table"},
|
||||
React.DOM.tbody(null,
|
||||
React.DOM.tr({key: "address"}, React.DOM.td(null, "Address:"), React.DOM.td(null, address)),
|
||||
sni,
|
||||
TimeStamp({title: "Start time",
|
||||
key: "start",
|
||||
t: conn.timestamp_start}),
|
||||
TimeStamp({title: "TCP Setup",
|
||||
key: "tcpsetup",
|
||||
t: conn.timestamp_tcp_setup,
|
||||
deltaTo: conn.timestamp_start,
|
||||
optional: true}),
|
||||
TimeStamp({title: "SSL handshake",
|
||||
key: "sslsetup",
|
||||
t: conn.timestamp_ssl_setup,
|
||||
deltaTo: conn.timestamp_start,
|
||||
optional: true}),
|
||||
TimeStamp({title: "End time",
|
||||
key: "end",
|
||||
t: conn.timestamp_end,
|
||||
deltaTo: conn.timestamp_start})
|
||||
sni
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -1061,13 +1042,92 @@ var CertificateInfo = React.createClass({displayName: 'CertificateInfo',
|
||||
var flow = this.props.flow;
|
||||
var client_conn = flow.client_conn;
|
||||
var server_conn = flow.server_conn;
|
||||
|
||||
var preStyle = {maxHeight: 100};
|
||||
return (
|
||||
React.DOM.div(null,
|
||||
client_conn.cert ? React.DOM.h4(null, "Client Certificate") : null,
|
||||
client_conn.cert ? React.DOM.pre(null, client_conn.cert) : null,
|
||||
client_conn.cert ? React.DOM.pre({style: preStyle}, client_conn.cert) : null,
|
||||
|
||||
server_conn.cert ? React.DOM.h4(null, "Server Certificate") : null,
|
||||
server_conn.cert ? React.DOM.pre(null, server_conn.cert) : null
|
||||
server_conn.cert ? React.DOM.pre({style: preStyle}, server_conn.cert) : null
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Timing = React.createClass({displayName: 'Timing',
|
||||
render: function(){
|
||||
var flow = this.props.flow;
|
||||
var sc = flow.server_conn;
|
||||
var cc = flow.client_conn;
|
||||
var req = flow.request;
|
||||
var resp = flow.response;
|
||||
|
||||
var timestamps = [
|
||||
{
|
||||
title: "Server conn. initiated",
|
||||
t: sc.timestamp_start,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Server conn. TCP handshake",
|
||||
t: sc.timestamp_tcp_setup,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Server conn. SSL handshake",
|
||||
t: sc.timestamp_ssl_setup,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Client conn. established",
|
||||
t: cc.timestamp_start,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Client conn. SSL handshake",
|
||||
t: cc.timestamp_ssl_setup,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "First request byte",
|
||||
t: req.timestamp_start,
|
||||
}, {
|
||||
title: "Request complete",
|
||||
t: req.timestamp_end,
|
||||
deltaTo: req.timestamp_start
|
||||
}
|
||||
];
|
||||
|
||||
if (flow.response) {
|
||||
timestamps.push(
|
||||
{
|
||||
title: "First response byte",
|
||||
t: resp.timestamp_start,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Response complete",
|
||||
t: resp.timestamp_end,
|
||||
deltaTo: req.timestamp_start
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
//Add unique key for each row.
|
||||
timestamps.forEach(function(e){
|
||||
e.key = e.title;
|
||||
});
|
||||
|
||||
timestamps = _.sortBy(timestamps, 't');
|
||||
|
||||
var rows = timestamps.map(function(e){
|
||||
return TimeStamp(e);
|
||||
});
|
||||
|
||||
return (
|
||||
React.DOM.div(null,
|
||||
React.DOM.h4(null, "Timing"),
|
||||
React.DOM.table(null,
|
||||
React.DOM.tbody(null,
|
||||
rows
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -1087,7 +1147,9 @@ var FlowDetailConnectionInfo = React.createClass({displayName: 'FlowDetailConnec
|
||||
React.DOM.h4(null, "Server Connection"),
|
||||
ConnectionInfo({conn: server_conn}),
|
||||
|
||||
CertificateInfo({flow: flow})
|
||||
CertificateInfo({flow: flow}),
|
||||
|
||||
Timing({flow: flow})
|
||||
|
||||
)
|
||||
);
|
||||
|
@ -1,3 +1,9 @@
|
||||
//TODO: Move into some utils
|
||||
.monospace(){
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
}
|
||||
|
||||
|
||||
.flow-detail {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
@ -7,20 +13,20 @@
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 5px;
|
||||
padding: 5px 12px;
|
||||
}
|
||||
|
||||
//FIXME: Style properly
|
||||
code {
|
||||
.first-line {
|
||||
.monospace();
|
||||
background-color: #428bca;
|
||||
color: white;
|
||||
margin: 0 -8px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 5px;
|
||||
word-break: break-all;
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Move into some utils
|
||||
.monospace(){
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
}
|
||||
|
||||
.flow-detail table {
|
||||
.monospace();
|
||||
|
@ -17,10 +17,6 @@
|
||||
box-shadow: 0 1px 0 #a6a6a6;
|
||||
}
|
||||
|
||||
tbody {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
tr {
|
||||
cursor: pointer;
|
||||
&.selected {
|
||||
|
@ -25,9 +25,9 @@ var FlowDetailNav = React.createClass({
|
||||
|
||||
var Headers = React.createClass({
|
||||
render: function(){
|
||||
var rows = this.props.message.headers.map(function(header){
|
||||
var rows = this.props.message.headers.map(function(header, i){
|
||||
return (
|
||||
<tr>
|
||||
<tr key={i}>
|
||||
<td className="header-name">{header[0]+":"}</td>
|
||||
<td className="header-value">{header[1]}</td>
|
||||
</tr>
|
||||
@ -62,7 +62,7 @@ var FlowDetailRequest = React.createClass({
|
||||
|
||||
return (
|
||||
<section>
|
||||
<code>{ first_line }</code>
|
||||
<div className="first-line">{ first_line }</div>
|
||||
<Headers message={flow.request}/>
|
||||
<hr/>
|
||||
{content}
|
||||
@ -90,7 +90,7 @@ var FlowDetailResponse = React.createClass({
|
||||
|
||||
return (
|
||||
<section>
|
||||
<code>{ first_line }</code>
|
||||
<div className="first-line">{ first_line }</div>
|
||||
<Headers message={flow.response}/>
|
||||
<hr/>
|
||||
{content}
|
||||
@ -101,24 +101,22 @@ var FlowDetailResponse = React.createClass({
|
||||
|
||||
var TimeStamp = React.createClass({
|
||||
render: function() {
|
||||
var ts, delta;
|
||||
|
||||
if(!this.props.t && this.props.optional){
|
||||
if(!this.props.t){
|
||||
//should be return null, but that triggers a React bug.
|
||||
return <tr></tr>;
|
||||
} else if (!this.props.t){
|
||||
ts = "active";
|
||||
} else {
|
||||
ts = (new Date(this.props.t * 1000)).toISOString();
|
||||
}
|
||||
|
||||
var ts = (new Date(this.props.t * 1000)).toISOString();
|
||||
ts = ts.replace("T", " ").replace("Z","");
|
||||
|
||||
var delta;
|
||||
if(this.props.deltaTo){
|
||||
delta = Math.round((this.props.t-this.props.deltaTo)*1000) + "ms";
|
||||
delta = formatTimeDelta(1000 * (this.props.t-this.props.deltaTo));
|
||||
delta = <span className="text-muted">{"(" + delta + ")"}</span>;
|
||||
} else {
|
||||
delta = null;
|
||||
}
|
||||
}
|
||||
|
||||
return <tr><td>{this.props.title + ":"}</td><td>{ts} {delta}</td></tr>;
|
||||
}
|
||||
@ -139,23 +137,6 @@ var ConnectionInfo = React.createClass({
|
||||
<tbody>
|
||||
<tr key="address"><td>Address:</td><td>{address}</td></tr>
|
||||
{sni}
|
||||
<TimeStamp title="Start time"
|
||||
key="start"
|
||||
t={conn.timestamp_start} />
|
||||
<TimeStamp title="TCP Setup"
|
||||
key="tcpsetup"
|
||||
t={conn.timestamp_tcp_setup}
|
||||
deltaTo={conn.timestamp_start}
|
||||
optional={true} />
|
||||
<TimeStamp title="SSL handshake"
|
||||
key="sslsetup"
|
||||
t={conn.timestamp_ssl_setup}
|
||||
deltaTo={conn.timestamp_start}
|
||||
optional={true} />
|
||||
<TimeStamp title="End time"
|
||||
key="end"
|
||||
t={conn.timestamp_end}
|
||||
deltaTo={conn.timestamp_start} />
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
@ -169,13 +150,92 @@ var CertificateInfo = React.createClass({
|
||||
var flow = this.props.flow;
|
||||
var client_conn = flow.client_conn;
|
||||
var server_conn = flow.server_conn;
|
||||
|
||||
var preStyle = {maxHeight: 100};
|
||||
return (
|
||||
<div>
|
||||
{client_conn.cert ? <h4>Client Certificate</h4> : null}
|
||||
{client_conn.cert ? <pre>{client_conn.cert}</pre> : null}
|
||||
{client_conn.cert ? <pre style={preStyle}>{client_conn.cert}</pre> : null}
|
||||
|
||||
{server_conn.cert ? <h4>Server Certificate</h4> : null}
|
||||
{server_conn.cert ? <pre>{server_conn.cert}</pre> : null}
|
||||
{server_conn.cert ? <pre style={preStyle}>{server_conn.cert}</pre> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Timing = React.createClass({
|
||||
render: function(){
|
||||
var flow = this.props.flow;
|
||||
var sc = flow.server_conn;
|
||||
var cc = flow.client_conn;
|
||||
var req = flow.request;
|
||||
var resp = flow.response;
|
||||
|
||||
var timestamps = [
|
||||
{
|
||||
title: "Server conn. initiated",
|
||||
t: sc.timestamp_start,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Server conn. TCP handshake",
|
||||
t: sc.timestamp_tcp_setup,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Server conn. SSL handshake",
|
||||
t: sc.timestamp_ssl_setup,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Client conn. established",
|
||||
t: cc.timestamp_start,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Client conn. SSL handshake",
|
||||
t: cc.timestamp_ssl_setup,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "First request byte",
|
||||
t: req.timestamp_start,
|
||||
}, {
|
||||
title: "Request complete",
|
||||
t: req.timestamp_end,
|
||||
deltaTo: req.timestamp_start
|
||||
}
|
||||
];
|
||||
|
||||
if (flow.response) {
|
||||
timestamps.push(
|
||||
{
|
||||
title: "First response byte",
|
||||
t: resp.timestamp_start,
|
||||
deltaTo: req.timestamp_start
|
||||
}, {
|
||||
title: "Response complete",
|
||||
t: resp.timestamp_end,
|
||||
deltaTo: req.timestamp_start
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
//Add unique key for each row.
|
||||
timestamps.forEach(function(e){
|
||||
e.key = e.title;
|
||||
});
|
||||
|
||||
timestamps = _.sortBy(timestamps, 't');
|
||||
|
||||
var rows = timestamps.map(function(e){
|
||||
return TimeStamp(e);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h4>Timing</h4>
|
||||
<table>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -197,6 +257,8 @@ var FlowDetailConnectionInfo = React.createClass({
|
||||
|
||||
<CertificateInfo flow={flow}/>
|
||||
|
||||
<Timing flow={flow}/>
|
||||
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ var IconColumn = React.createClass({
|
||||
var contentType = ResponseUtils.getContentType(flow.response);
|
||||
|
||||
//TODO: We should assign a type to the flow somewhere else.
|
||||
var icon;
|
||||
if(flow.response.code == 304) {
|
||||
icon = "resource-icon-not-modified";
|
||||
} else if(300 <= flow.response.code && flow.response.code < 400) {
|
||||
@ -112,9 +111,10 @@ var SizeColumn = React.createClass({
|
||||
},
|
||||
render: function(){
|
||||
var flow = this.props.flow;
|
||||
|
||||
var total = flow.request.contentLength;
|
||||
if(flow.response){
|
||||
total += flow.response.contentLength;
|
||||
total += flow.response.contentLength || 0;
|
||||
}
|
||||
var size = formatSize(total);
|
||||
return <td className="col-size">{size}</td>;
|
||||
|
@ -62,12 +62,12 @@ var Header = React.createClass({
|
||||
console.log("File click");
|
||||
},
|
||||
render: function () {
|
||||
var header = header_entries.map(function(entry){
|
||||
var header = header_entries.map(function(entry, i){
|
||||
var classes = React.addons.classSet({
|
||||
active: entry == this.state.active
|
||||
});
|
||||
return (
|
||||
<a key={entry.title}
|
||||
<a key={i}
|
||||
href="#"
|
||||
className={classes}
|
||||
onClick={this.handleClick.bind(this, entry)}
|
||||
|
@ -41,7 +41,7 @@ var Key = {
|
||||
var formatSize = function (bytes) {
|
||||
var size = bytes;
|
||||
var prefix = ["B", "KB", "MB", "GB", "TB"];
|
||||
while (size >= 1024 && prefix.length > 1) {
|
||||
while (Math.abs(size) >= 1024 && prefix.length > 1) {
|
||||
prefix.shift();
|
||||
size = size / 1024;
|
||||
}
|
||||
@ -50,9 +50,9 @@ var formatSize = function (bytes) {
|
||||
|
||||
var formatTimeDelta = function (milliseconds) {
|
||||
var time = milliseconds;
|
||||
var prefix = ["ms", "s", "m", "h"];
|
||||
var prefix = ["ms", "s", "min", "h"];
|
||||
var div = [1000, 60, 60];
|
||||
while (time >= div[0] && prefix.length > 1) {
|
||||
while (Math.abs(time) >= div[0] && prefix.length > 1) {
|
||||
prefix.shift();
|
||||
time = time / div.shift();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user