diff options
author | Maximilian Hils <git@maximilianhils.com> | 2014-09-19 01:35:36 +0200 |
---|---|---|
committer | Maximilian Hils <git@maximilianhils.com> | 2014-09-19 01:35:36 +0200 |
commit | b0374710e4ef934c2ae9b416e5c981e04ed776ed (patch) | |
tree | 732772d4cbd11562f728c27370185abaad1f026e /web | |
parent | 390a435ac4b5ce78b1aa32b4b048318c5ef0ba03 (diff) | |
download | mitmproxy-b0374710e4ef934c2ae9b416e5c981e04ed776ed.tar.gz mitmproxy-b0374710e4ef934c2ae9b416e5c981e04ed776ed.tar.bz2 mitmproxy-b0374710e4ef934c2ae9b416e5c981e04ed776ed.zip |
start to fill detailpane
Diffstat (limited to 'web')
-rw-r--r-- | web/gulpfile.js | 1 | ||||
-rw-r--r-- | web/src/css/flowdetail.less | 44 | ||||
-rw-r--r-- | web/src/css/flowtable.less | 5 | ||||
-rw-r--r-- | web/src/js/components/flowdetail.jsx.js | 48 | ||||
-rw-r--r-- | web/src/js/components/flowtable-columns.jsx.js | 25 | ||||
-rw-r--r-- | web/src/js/flow/utils.js | 47 | ||||
-rw-r--r-- | web/src/js/utils.js | 13 |
7 files changed, 174 insertions, 9 deletions
diff --git a/web/gulpfile.js b/web/gulpfile.js index 584cc7d3..d106ecd1 100644 --- a/web/gulpfile.js +++ b/web/gulpfile.js @@ -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', diff --git a/web/src/css/flowdetail.less b/web/src/css/flowdetail.less index 88334391..8501ce6c 100644 --- a/web/src/css/flowdetail.less +++ b/web/src/css/flowdetail.less @@ -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 { + + } }
\ No newline at end of file diff --git a/web/src/css/flowtable.less b/web/src/css/flowtable.less index 2a9c318b..db4c6f12 100644 --- a/web/src/css/flowtable.less +++ b/web/src/css/flowtable.less @@ -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; } }
\ No newline at end of file diff --git a/web/src/js/components/flowdetail.jsx.js b/web/src/js/components/flowdetail.jsx.js index acf5e6f4..744901be 100644 --- a/web/src/js/components/flowdetail.jsx.js +++ b/web/src/js/components/flowdetail.jsx.js @@ -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> ); } diff --git a/web/src/js/components/flowtable-columns.jsx.js b/web/src/js/components/flowtable-columns.jsx.js index 0eb9966c..01130bc1 100644 --- a/web/src/js/components/flowtable-columns.jsx.js +++ b/web/src/js/components/flowtable-columns.jsx.js @@ -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]; diff --git a/web/src/js/flow/utils.js b/web/src/js/flow/utils.js new file mode 100644 index 00000000..b621f06d --- /dev/null +++ b/web/src/js/flow/utils.js @@ -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, {});
\ No newline at end of file diff --git a/web/src/js/utils.js b/web/src/js/utils.js index 947ad5c1..e53097f8 100644 --- a/web/src/js/utils.js +++ b/web/src/js/utils.js @@ -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(); };
\ No newline at end of file |