aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmproxy/protocol/http.py6
-rw-r--r--libmproxy/web/static/css/app.css29
-rw-r--r--libmproxy/web/static/flows.json42
-rw-r--r--libmproxy/web/static/js/app.js133
-rw-r--r--web/gulpfile.js1
-rw-r--r--web/src/css/flowdetail.less44
-rw-r--r--web/src/css/flowtable.less5
-rw-r--r--web/src/js/components/flowdetail.jsx.js48
-rw-r--r--web/src/js/components/flowtable-columns.jsx.js25
-rw-r--r--web/src/js/flow/utils.js47
-rw-r--r--web/src/js/utils.js13
11 files changed, 375 insertions, 18 deletions
diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py
index 9db50cd7..644d4696 100644
--- a/libmproxy/protocol/http.py
+++ b/libmproxy/protocol/http.py
@@ -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
diff --git a/libmproxy/web/static/css/app.css b/libmproxy/web/static/css/app.css
index 26ed8c3d..ad2fe2e0 100644
--- a/libmproxy/web/static/css/app.css
+++ b/libmproxy/web/static/css/app.css
@@ -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;
diff --git a/libmproxy/web/static/flows.json b/libmproxy/web/static/flows.json
index ece178a7..a0358db0 100644
--- a/libmproxy/web/static/flows.json
+++ b/libmproxy/web/static/flows.json
@@ -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,
diff --git a/libmproxy/web/static/js/app.js b/libmproxy/web/static/js/app.js
index 8ee7133e..4c47e201 100644
--- a/libmproxy/web/static/js/app.js
+++ b/libmproxy/web/static/js/app.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)";
}
};
@@ -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})
)
);
}
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