/** @jsx React.DOM */
var FlowDetailNav = React.createClass({
render: function(){
var items = this.props.tabs.map(function(e){
var str = e.charAt(0).toUpperCase() + e.slice(1);
var className = this.props.active === e ? "active" : "";
var onClick = function(){
this.props.selectTab(e);
return false;
}.bind(this);
return {str} ;
}.bind(this));
return (
{items}
);
}
});
var Headers = React.createClass({
render: function(){
var rows = this.props.message.headers.map(function(header, i){
return (
{header[0]+":"}
{header[1]}
);
});
return (
);
}
});
var FlowDetailRequest = React.createClass({
render: function(){
var flow = this.props.flow;
var first_line = [
flow.request.method,
RequestUtils.pretty_url(flow.request),
"HTTP/"+ flow.response.httpversion.join(".")
].join(" ");
var content = null;
if(flow.request.contentLength > 0){
content = "Request Content Size: "+ formatSize(flow.request.contentLength);
} else {
content = No Content
;
}
//TODO: Styling
return (
);
}
});
var FlowDetailResponse = React.createClass({
render: function(){
var flow = this.props.flow;
var first_line = [
"HTTP/"+ flow.response.httpversion.join("."),
flow.response.code,
flow.response.msg
].join(" ");
var content = null;
if(flow.response.contentLength > 0){
content = "Response Content Size: "+ formatSize(flow.response.contentLength);
} else {
content = No Content
;
}
//TODO: Styling
return (
);
}
});
var TimeStamp = React.createClass({
render: function() {
if(!this.props.t){
//should be return null, but that triggers a React bug.
return ;
}
var ts = (new Date(this.props.t * 1000)).toISOString();
ts = ts.replace("T", " ").replace("Z","");
var delta;
if(this.props.deltaTo){
delta = formatTimeDelta(1000 * (this.props.t-this.props.deltaTo));
delta = {"(" + delta + ")"} ;
} else {
delta = null;
}
return {this.props.title + ":"} {ts} {delta} ;
}
});
var ConnectionInfo = React.createClass({
render: function() {
var conn = this.props.conn;
var address = conn.address.address.join(":");
var sni = ; //should be null, but that triggers a React bug.
if(conn.sni){
sni = TLS SNI: {conn.sni} ;
}
return (
);
}
});
var CertificateInfo = React.createClass({
render: function(){
//TODO: We should fetch human-readable certificate representation
// from the server
var flow = this.props.flow;
var client_conn = flow.client_conn;
var server_conn = flow.server_conn;
var preStyle = {maxHeight: 100};
return (
{client_conn.cert ?
Client Certificate : null}
{client_conn.cert ?
{client_conn.cert} : null}
{server_conn.cert ?
Server Certificate : null}
{server_conn.cert ?
{server_conn.cert} : null}
);
}
});
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 (
);
}
});
var FlowDetailConnectionInfo = React.createClass({
render: function(){
var flow = this.props.flow;
var client_conn = flow.client_conn;
var server_conn = flow.server_conn;
return (
Client Connection
Server Connection
);
}
});
var tabs = {
request: FlowDetailRequest,
response: FlowDetailResponse,
details: FlowDetailConnectionInfo
};
var FlowDetail = React.createClass({
getDefaultProps: function(){
return {
tabs: ["request","response", "details"]
};
},
mixins: [StickyHeadMixin],
nextTab: function(i) {
var currentIndex = this.props.tabs.indexOf(this.props.active);
// JS modulo operator doesn't correct negative numbers, make sure that we are positive.
var nextIndex = (currentIndex + i + this.props.tabs.length) % this.props.tabs.length;
this.props.selectTab(this.props.tabs[nextIndex]);
},
render: function(){
var flow = JSON.stringify(this.props.flow, null, 2);
var Tab = tabs[this.props.active];
return (
);
}
});