mitmproxy/libmproxy/web/static/app.js
2015-10-08 12:43:55 +02:00

6272 lines
185 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
}
throw TypeError('Uncaught, unspecified "error" event.');
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
handler.apply(this, args);
}
} else if (isObject(handler)) {
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
var m;
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.listenerCount = function(emitter, type) {
var ret;
if (!emitter._events || !emitter._events[type])
ret = 0;
else if (isFunction(emitter._events[type]))
ret = 1;
else
ret = emitter._events[type].length;
return ret;
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
},{}],2:[function(require,module,exports){
"use strict";
var $ = require("jquery");
var _ = require("lodash");
var AppDispatcher = require("./dispatcher.js").AppDispatcher;
var ActionTypes = {
// Connection
CONNECTION_OPEN: "connection_open",
CONNECTION_CLOSE: "connection_close",
CONNECTION_ERROR: "connection_error",
// Stores
SETTINGS_STORE: "settings",
EVENT_STORE: "events",
FLOW_STORE: "flows"
};
var StoreCmds = {
ADD: "add",
UPDATE: "update",
REMOVE: "remove",
RESET: "reset"
};
var ConnectionActions = {
open: function open() {
AppDispatcher.dispatchViewAction({
type: ActionTypes.CONNECTION_OPEN
});
},
close: function close() {
AppDispatcher.dispatchViewAction({
type: ActionTypes.CONNECTION_CLOSE
});
},
error: function error() {
AppDispatcher.dispatchViewAction({
type: ActionTypes.CONNECTION_ERROR
});
}
};
var SettingsActions = {
update: function update(settings) {
$.ajax({
type: "PUT",
url: "/settings",
contentType: 'application/json',
data: JSON.stringify(settings)
});
/*
//Facebook Flux: We do an optimistic update on the client already.
AppDispatcher.dispatchViewAction({
type: ActionTypes.SETTINGS_STORE,
cmd: StoreCmds.UPDATE,
data: settings
});
*/
}
};
var EventLogActions_event_id = 0;
var EventLogActions = {
add_event: function add_event(message) {
AppDispatcher.dispatchViewAction({
type: ActionTypes.EVENT_STORE,
cmd: StoreCmds.ADD,
data: {
message: message,
level: "web",
id: "viewAction-" + EventLogActions_event_id++
}
});
}
};
var FlowActions = {
accept: function accept(flow) {
$.post("/flows/" + flow.id + "/accept");
},
accept_all: function accept_all() {
$.post("/flows/accept");
},
"delete": function _delete(flow) {
$.ajax({
type: "DELETE",
url: "/flows/" + flow.id
});
},
duplicate: function duplicate(flow) {
$.post("/flows/" + flow.id + "/duplicate");
},
replay: function replay(flow) {
$.post("/flows/" + flow.id + "/replay");
},
revert: function revert(flow) {
$.post("/flows/" + flow.id + "/revert");
},
update: function update(flow, nextProps) {
/*
//Facebook Flux: We do an optimistic update on the client already.
var nextFlow = _.cloneDeep(flow);
_.merge(nextFlow, nextProps);
AppDispatcher.dispatchViewAction({
type: ActionTypes.FLOW_STORE,
cmd: StoreCmds.UPDATE,
data: nextFlow
});
*/
$.ajax({
type: "PUT",
url: "/flows/" + flow.id,
contentType: 'application/json',
data: JSON.stringify(nextProps)
});
},
clear: function clear() {
$.post("/clear");
}
};
var Query = {
SEARCH: "s",
HIGHLIGHT: "h",
SHOW_EVENTLOG: "e"
};
module.exports = {
ActionTypes: ActionTypes,
ConnectionActions: ConnectionActions,
FlowActions: FlowActions,
StoreCmds: StoreCmds,
SettingsActions: SettingsActions,
EventLogActions: EventLogActions,
Query: Query
};
},{"./dispatcher.js":21,"jquery":"jquery","lodash":"lodash"}],3:[function(require,module,exports){
"use strict";
var React = require("react");
var ReactRouter = require("react-router");
var $ = require("jquery");
var Connection = require("./connection");
var proxyapp = require("./components/proxyapp.js");
var EventLogActions = require("./actions.js").EventLogActions;
$(function () {
window.ws = new Connection("/updates");
window.onerror = function (msg) {
EventLogActions.add_event(msg);
};
ReactRouter.run(proxyapp.routes, function (Handler, state) {
React.render(React.createElement(Handler, null), document.body);
});
});
},{"./actions.js":2,"./components/proxyapp.js":18,"./connection":20,"jquery":"jquery","react":"react","react-router":"react-router"}],4:[function(require,module,exports){
"use strict";
var React = require("react");
var ReactRouter = require("react-router");
var _ = require("lodash");
// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example)
var AutoScrollMixin = {
componentWillUpdate: function componentWillUpdate() {
var node = this.getDOMNode();
this._shouldScrollBottom = node.scrollTop !== 0 && node.scrollTop + node.clientHeight === node.scrollHeight;
},
componentDidUpdate: function componentDidUpdate() {
if (this._shouldScrollBottom) {
var node = this.getDOMNode();
node.scrollTop = node.scrollHeight;
}
}
};
var StickyHeadMixin = {
adjustHead: function adjustHead() {
// 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)";
}
};
var SettingsState = {
contextTypes: {
settingsStore: React.PropTypes.object.isRequired
},
getInitialState: function getInitialState() {
return {
settings: this.context.settingsStore.dict
};
},
componentDidMount: function componentDidMount() {
this.context.settingsStore.addListener("recalculate", this.onSettingsChange);
},
componentWillUnmount: function componentWillUnmount() {
this.context.settingsStore.removeListener("recalculate", this.onSettingsChange);
},
onSettingsChange: function onSettingsChange() {
this.setState({
settings: this.context.settingsStore.dict
});
}
};
var ChildFocus = {
contextTypes: {
returnFocus: React.PropTypes.func
},
returnFocus: function returnFocus() {
React.findDOMNode(this).blur();
window.getSelection().removeAllRanges();
this.context.returnFocus();
}
};
var Navigation = _.extend({}, ReactRouter.Navigation, {
setQuery: function setQuery(dict) {
var q = this.context.router.getCurrentQuery();
for (var i in dict) {
if (dict.hasOwnProperty(i)) {
q[i] = dict[i] || undefined; //falsey values shall be removed.
}
}
this.replaceWith(this.context.router.getCurrentPath(), this.context.router.getCurrentParams(), q);
},
replaceWith: function replaceWith(routeNameOrPath, params, query) {
if (routeNameOrPath === undefined) {
routeNameOrPath = this.context.router.getCurrentPath();
}
if (params === undefined) {
params = this.context.router.getCurrentParams();
}
if (query === undefined) {
query = this.context.router.getCurrentQuery();
}
this.context.router.replaceWith(routeNameOrPath, params, query);
}
});
// react-router is fairly good at changing its API regularly.
// We keep the old method for now - if it should turn out that their changes are permanent,
// we may remove this mixin and access react-router directly again.
var RouterState = _.extend({}, ReactRouter.State, {
getQuery: function getQuery() {
// For whatever reason, react-router always returns the same object, which makes comparing
// the current props with nextProps impossible. As a workaround, we just clone the query object.
return _.clone(this.context.router.getCurrentQuery());
},
getParams: function getParams() {
return _.clone(this.context.router.getCurrentParams());
}
});
var Splitter = React.createClass({
displayName: "Splitter",
getDefaultProps: function getDefaultProps() {
return {
axis: "x"
};
},
getInitialState: function getInitialState() {
return {
applied: false,
startX: false,
startY: false
};
},
onMouseDown: function onMouseDown(e) {
this.setState({
startX: e.pageX,
startY: e.pageY
});
window.addEventListener("mousemove", this.onMouseMove);
window.addEventListener("mouseup", this.onMouseUp);
// Occasionally, only a dragEnd event is triggered, but no mouseUp.
window.addEventListener("dragend", this.onDragEnd);
},
onDragEnd: function onDragEnd() {
this.getDOMNode().style.transform = "";
window.removeEventListener("dragend", this.onDragEnd);
window.removeEventListener("mouseup", this.onMouseUp);
window.removeEventListener("mousemove", this.onMouseMove);
},
onMouseUp: function onMouseUp(e) {
this.onDragEnd();
var node = this.getDOMNode();
var prev = node.previousElementSibling;
var next = node.nextElementSibling;
var dX = e.pageX - this.state.startX;
var dY = e.pageY - this.state.startY;
var flexBasis;
if (this.props.axis === "x") {
flexBasis = prev.offsetWidth + dX;
} else {
flexBasis = prev.offsetHeight + dY;
}
prev.style.flex = "0 0 " + Math.max(0, flexBasis) + "px";
next.style.flex = "1 1 auto";
this.setState({
applied: true
});
this.onResize();
},
onMouseMove: function onMouseMove(e) {
var dX = 0,
dY = 0;
if (this.props.axis === "x") {
dX = e.pageX - this.state.startX;
} else {
dY = e.pageY - this.state.startY;
}
this.getDOMNode().style.transform = "translate(" + dX + "px," + dY + "px)";
},
onResize: function onResize() {
// Trigger a global resize event. This notifies components that employ virtual scrolling
// that their viewport may have changed.
window.setTimeout(function () {
window.dispatchEvent(new CustomEvent("resize"));
}, 1);
},
reset: function reset(willUnmount) {
if (!this.state.applied) {
return;
}
var node = this.getDOMNode();
var prev = node.previousElementSibling;
var next = node.nextElementSibling;
prev.style.flex = "";
next.style.flex = "";
if (!willUnmount) {
this.setState({
applied: false
});
}
this.onResize();
},
componentWillUnmount: function componentWillUnmount() {
this.reset(true);
},
render: function render() {
var className = "splitter";
if (this.props.axis === "x") {
className += " splitter-x";
} else {
className += " splitter-y";
}
return React.createElement(
"div",
{ className: className },
React.createElement("div", { onMouseDown: this.onMouseDown, draggable: "true" })
);
}
});
module.exports = {
ChildFocus: ChildFocus,
RouterState: RouterState,
Navigation: Navigation,
StickyHeadMixin: StickyHeadMixin,
AutoScrollMixin: AutoScrollMixin,
Splitter: Splitter,
SettingsState: SettingsState
};
},{"lodash":"lodash","react":"react","react-router":"react-router"}],5:[function(require,module,exports){
"use strict";
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var React = require("react");
var common = require("./common.js");
var utils = require("../utils.js");
var contentToHtml = function contentToHtml(content) {
return _.escape(content);
};
var nodeToContent = function nodeToContent(node) {
return node.textContent;
};
/*
Basic Editor Functionality
*/
var EditorBase = React.createClass({
displayName: "EditorBase",
propTypes: {
content: React.PropTypes.string.isRequired,
onDone: React.PropTypes.func.isRequired,
contentToHtml: React.PropTypes.func,
nodeToContent: React.PropTypes.func, // content === nodeToContent( Node<innerHTML=contentToHtml(content)> )
onStop: React.PropTypes.func,
submitOnEnter: React.PropTypes.bool,
className: React.PropTypes.string,
tag: React.PropTypes.string
},
getDefaultProps: function getDefaultProps() {
return {
contentToHtml: contentToHtml,
nodeToContent: nodeToContent,
submitOnEnter: true,
className: "",
tag: "div"
};
},
getInitialState: function getInitialState() {
return {
editable: false
};
},
render: function render() {
var className = "inline-input " + this.props.className;
var html = { __html: this.props.contentToHtml(this.props.content) };
var Tag = this.props.tag;
return React.createElement(Tag, _extends({}, this.props, {
tabIndex: "0",
className: className,
contentEditable: this.state.editable || undefined, // workaround: use undef instead of false to remove attr
onFocus: this.onFocus,
onMouseDown: this.onMouseDown,
onClick: this.onClick,
onBlur: this._stop,
onKeyDown: this.onKeyDown,
onInput: this.onInput,
onPaste: this.onPaste,
dangerouslySetInnerHTML: html
}));
},
onPaste: function onPaste(e) {
e.preventDefault();
var content = e.clipboardData.getData("text/plain");
document.execCommand("insertHTML", false, content);
},
onMouseDown: function onMouseDown(e) {
this._mouseDown = true;
window.addEventListener("mouseup", this.onMouseUp);
this.props.onMouseDown && this.props.onMouseDown(e);
},
onMouseUp: function onMouseUp() {
if (this._mouseDown) {
this._mouseDown = false;
window.removeEventListener("mouseup", this.onMouseUp);
}
},
onClick: function onClick(e) {
this.onMouseUp();
this.onFocus(e);
},
onFocus: function onFocus(e) {
console.log("onFocus", this._mouseDown, this._ignore_events, this.state.editable);
if (this._mouseDown || this._ignore_events || this.state.editable) {
return;
}
//contenteditable in FireFox is more or less broken.
// - we need to blur() and then focus(), otherwise the caret is not shown.
// - blur() + focus() == we need to save the caret position before
// Firefox sometimes just doesn't set a caret position => use caretPositionFromPoint
var sel = window.getSelection();
var range;
if (sel.rangeCount > 0) {
range = sel.getRangeAt(0);
} else if (document.caretPositionFromPoint && e.clientX && e.clientY) {
var pos = document.caretPositionFromPoint(e.clientX, e.clientY);
range = document.createRange();
range.setStart(pos.offsetNode, pos.offset);
} else if (document.caretRangeFromPoint && e.clientX && e.clientY) {
range = document.caretRangeFromPoint(e.clientX, e.clientY);
} else {
range = document.createRange();
range.selectNodeContents(React.findDOMNode(this));
}
this._ignore_events = true;
this.setState({ editable: true }, function () {
var node = React.findDOMNode(this);
node.blur();
node.focus();
this._ignore_events = false;
//sel.removeAllRanges();
//sel.addRange(range);
});
},
stop: function stop() {
// a stop would cause a blur as a side-effect.
// but a blur event must trigger a stop as well.
// to fix this, make stop = blur and do the actual stop in the onBlur handler.
React.findDOMNode(this).blur();
this.props.onStop && this.props.onStop();
},
_stop: function _stop(e) {
if (this._ignore_events) {
return;
}
console.log("_stop", _.extend({}, e));
window.getSelection().removeAllRanges(); //make sure that selection is cleared on blur
var node = React.findDOMNode(this);
var content = this.props.nodeToContent(node);
this.setState({ editable: false });
this.props.onDone(content);
this.props.onBlur && this.props.onBlur(e);
},
reset: function reset() {
React.findDOMNode(this).innerHTML = this.props.contentToHtml(this.props.content);
},
onKeyDown: function onKeyDown(e) {
e.stopPropagation();
switch (e.keyCode) {
case utils.Key.ESC:
e.preventDefault();
this.reset();
this.stop();
break;
case utils.Key.ENTER:
if (this.props.submitOnEnter && !e.shiftKey) {
e.preventDefault();
this.stop();
}
break;
default:
break;
}
},
onInput: function onInput() {
var node = React.findDOMNode(this);
var content = this.props.nodeToContent(node);
this.props.onInput && this.props.onInput(content);
}
});
/*
Add Validation to EditorBase
*/
var ValidateEditor = React.createClass({
displayName: "ValidateEditor",
propTypes: {
content: React.PropTypes.string.isRequired,
onDone: React.PropTypes.func.isRequired,
onInput: React.PropTypes.func,
isValid: React.PropTypes.func,
className: React.PropTypes.string
},
getInitialState: function getInitialState() {
return {
currentContent: this.props.content
};
},
componentWillReceiveProps: function componentWillReceiveProps() {
this.setState({ currentContent: this.props.content });
},
onInput: function onInput(content) {
this.setState({ currentContent: content });
this.props.onInput && this.props.onInput(content);
},
render: function render() {
var className = this.props.className || "";
if (this.props.isValid) {
if (this.props.isValid(this.state.currentContent)) {
className += " has-success";
} else {
className += " has-warning";
}
}
return React.createElement(EditorBase, _extends({}, this.props, {
ref: "editor",
className: className,
onDone: this.onDone,
onInput: this.onInput
}));
},
onDone: function onDone(content) {
if (this.props.isValid && !this.props.isValid(content)) {
this.refs.editor.reset();
content = this.props.content;
}
this.props.onDone(content);
}
});
/*
Text Editor with mitmweb-specific convenience features
*/
var ValueEditor = React.createClass({
displayName: "ValueEditor",
mixins: [common.ChildFocus],
propTypes: {
content: React.PropTypes.string.isRequired,
onDone: React.PropTypes.func.isRequired,
inline: React.PropTypes.bool
},
render: function render() {
var tag = this.props.inline ? "span" : "div";
return React.createElement(ValidateEditor, _extends({}, this.props, {
onStop: this.onStop,
tag: tag
}));
},
focus: function focus() {
React.findDOMNode(this).focus();
},
onStop: function onStop() {
this.returnFocus();
}
});
module.exports = {
ValueEditor: ValueEditor
};
},{"../utils.js":26,"./common.js":4,"react":"react"}],6:[function(require,module,exports){
"use strict";
var React = require("react");
var common = require("./common.js");
var Query = require("../actions.js").Query;
var VirtualScrollMixin = require("./virtualscroll.js");
var views = require("../store/view.js");
var _ = require("lodash");
var LogMessage = React.createClass({
displayName: "LogMessage",
render: function render() {
var entry = this.props.entry;
var indicator;
switch (entry.level) {
case "web":
indicator = React.createElement("i", { className: "fa fa-fw fa-html5" });
break;
case "debug":
indicator = React.createElement("i", { className: "fa fa-fw fa-bug" });
break;
default:
indicator = React.createElement("i", { className: "fa fa-fw fa-info" });
}
return React.createElement(
"div",
null,
indicator,
" ",
entry.message
);
},
shouldComponentUpdate: function shouldComponentUpdate() {
return false; // log entries are immutable.
}
});
var EventLogContents = React.createClass({
displayName: "EventLogContents",
contextTypes: {
eventStore: React.PropTypes.object.isRequired
},
mixins: [common.AutoScrollMixin, VirtualScrollMixin],
getInitialState: function getInitialState() {
var filterFn = function filterFn(entry) {
return this.props.filter[entry.level];
};
var view = new views.StoreView(this.context.eventStore, filterFn.bind(this));
view.addListener("add", this.onEventLogChange);
view.addListener("recalculate", this.onEventLogChange);
return {
view: view
};
},
componentWillUnmount: function componentWillUnmount() {
this.state.view.close();
},
filter: function filter(entry) {
return this.props.filter[entry.level];
},
onEventLogChange: function onEventLogChange() {
this.forceUpdate();
},
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
if (nextProps.filter !== this.props.filter) {
this.props.filter = nextProps.filter; // Dirty: Make sure that view filter sees the update.
this.state.view.recalculate();
}
},
getDefaultProps: function getDefaultProps() {
return {
rowHeight: 45,
rowHeightMin: 15,
placeholderTagName: "div"
};
},
renderRow: function renderRow(elem) {
return React.createElement(LogMessage, { key: elem.id, entry: elem });
},
render: function render() {
var entries = this.state.view.list;
var rows = this.renderRows(entries);
return React.createElement(
"pre",
{ onScroll: this.onScroll },
this.getPlaceholderTop(entries.length),
rows,
this.getPlaceholderBottom(entries.length)
);
}
});
var ToggleFilter = React.createClass({
displayName: "ToggleFilter",
toggle: function toggle(e) {
e.preventDefault();
return this.props.toggleLevel(this.props.name);
},
render: function render() {
var className = "label ";
if (this.props.active) {
className += "label-primary";
} else {
className += "label-default";
}
return React.createElement(
"a",
{
href: "#",
className: className,
onClick: this.toggle },
this.props.name
);
}
});
var EventLog = React.createClass({
displayName: "EventLog",
mixins: [common.Navigation],
getInitialState: function getInitialState() {
return {
filter: {
"debug": false,
"info": true,
"web": true
}
};
},
close: function close() {
var d = {};
d[Query.SHOW_EVENTLOG] = undefined;
this.setQuery(d);
},
toggleLevel: function toggleLevel(level) {
var filter = _.extend({}, this.state.filter);
filter[level] = !filter[level];
this.setState({ filter: filter });
},
render: function render() {
return React.createElement(
"div",
{ className: "eventlog" },
React.createElement(
"div",
null,
"Eventlog",
React.createElement(
"div",
{ className: "pull-right" },
React.createElement(ToggleFilter, { name: "debug", active: this.state.filter.debug, toggleLevel: this.toggleLevel }),
React.createElement(ToggleFilter, { name: "info", active: this.state.filter.info, toggleLevel: this.toggleLevel }),
React.createElement(ToggleFilter, { name: "web", active: this.state.filter.web, toggleLevel: this.toggleLevel }),
React.createElement("i", { onClick: this.close, className: "fa fa-close" })
)
),
React.createElement(EventLogContents, { filter: this.state.filter })
);
}
});
module.exports = EventLog;
},{"../actions.js":2,"../store/view.js":25,"./common.js":4,"./virtualscroll.js":19,"lodash":"lodash","react":"react"}],7:[function(require,module,exports){
"use strict";
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var React = require("react");
var RequestUtils = require("../flow/utils.js").RequestUtils;
var ResponseUtils = require("../flow/utils.js").ResponseUtils;
var utils = require("../utils.js");
var TLSColumn = React.createClass({
displayName: "TLSColumn",
statics: {
Title: React.createClass({
displayName: "Title",
render: function render() {
return React.createElement("th", _extends({}, this.props, { className: "col-tls " + (this.props.className || "") }));
}
}),
sortKeyFun: function sortKeyFun(flow) {
return flow.request.scheme;
}
},
render: function render() {
var flow = this.props.flow;
var ssl = flow.request.scheme === "https";
var classes;
if (ssl) {
classes = "col-tls col-tls-https";
} else {
classes = "col-tls col-tls-http";
}
return React.createElement("td", { className: classes });
}
});
var IconColumn = React.createClass({
displayName: "IconColumn",
statics: {
Title: React.createClass({
displayName: "Title",
render: function render() {
return React.createElement("th", _extends({}, this.props, { className: "col-icon " + (this.props.className || "") }));
}
})
},
render: function render() {
var flow = this.props.flow;
var icon;
if (flow.response) {
var contentType = ResponseUtils.getContentType(flow.response);
//TODO: We should assign a type to the flow somewhere else.
if (flow.response.status_code === 304) {
icon = "resource-icon-not-modified";
} else if (300 <= flow.response.status_code && flow.response.status_code < 400) {
icon = "resource-icon-redirect";
} else if (contentType && contentType.indexOf("image") >= 0) {
icon = "resource-icon-image";
} else if (contentType && contentType.indexOf("javascript") >= 0) {
icon = "resource-icon-js";
} else if (contentType && contentType.indexOf("css") >= 0) {
icon = "resource-icon-css";
} else if (contentType && contentType.indexOf("html") >= 0) {
icon = "resource-icon-document";
}
}
if (!icon) {
icon = "resource-icon-plain";
}
icon += " resource-icon";
return React.createElement(
"td",
{ className: "col-icon" },
React.createElement("div", { className: icon })
);
}
});
var PathColumn = React.createClass({
displayName: "PathColumn",
statics: {
Title: React.createClass({
displayName: "Title",
render: function render() {
return React.createElement(
"th",
_extends({}, this.props, { className: "col-path " + (this.props.className || "") }),
"Path"
);
}
}),
sortKeyFun: function sortKeyFun(flow) {
return RequestUtils.pretty_url(flow.request);
}
},
render: function render() {
var flow = this.props.flow;
return React.createElement(
"td",
{ className: "col-path" },
flow.request.is_replay ? React.createElement("i", { className: "fa fa-fw fa-repeat pull-right" }) : null,
flow.intercepted ? React.createElement("i", { className: "fa fa-fw fa-pause pull-right" }) : null,
RequestUtils.pretty_url(flow.request)
);
}
});
var MethodColumn = React.createClass({
displayName: "MethodColumn",
statics: {
Title: React.createClass({
displayName: "Title",
render: function render() {
return React.createElement(
"th",
_extends({}, this.props, { className: "col-method " + (this.props.className || "") }),
"Method"
);
}
}),
sortKeyFun: function sortKeyFun(flow) {
return flow.request.method;
}
},
render: function render() {
var flow = this.props.flow;
return React.createElement(
"td",
{ className: "col-method" },
flow.request.method
);
}
});
var StatusColumn = React.createClass({
displayName: "StatusColumn",
statics: {
Title: React.createClass({
displayName: "Title",
render: function render() {
return React.createElement(
"th",
_extends({}, this.props, { className: "col-status " + (this.props.className || "") }),
"Status"
);
}
}),
sortKeyFun: function sortKeyFun(flow) {
return flow.response ? flow.response.status_code : undefined;
}
},
render: function render() {
var flow = this.props.flow;
var status;
if (flow.response) {
status = flow.response.status_code;
} else {
status = null;
}
return React.createElement(
"td",
{ className: "col-status" },
status
);
}
});
var SizeColumn = React.createClass({
displayName: "SizeColumn",
statics: {
Title: React.createClass({
displayName: "Title",
render: function render() {
return React.createElement(
"th",
_extends({}, this.props, { className: "col-size " + (this.props.className || "") }),
"Size"
);
}
}),
sortKeyFun: function sortKeyFun(flow) {
var total = flow.request.contentLength;
if (flow.response) {
total += flow.response.contentLength || 0;
}
return total;
}
},
render: function render() {
var flow = this.props.flow;
var total = flow.request.contentLength;
if (flow.response) {
total += flow.response.contentLength || 0;
}
var size = utils.formatSize(total);
return React.createElement(
"td",
{ className: "col-size" },
size
);
}
});
var TimeColumn = React.createClass({
displayName: "TimeColumn",
statics: {
Title: React.createClass({
displayName: "Title",
render: function render() {
return React.createElement(
"th",
_extends({}, this.props, { className: "col-time " + (this.props.className || "") }),
"Time"
);
}
}),
sortKeyFun: function sortKeyFun(flow) {
if (flow.response) {
return flow.response.timestamp_end - flow.request.timestamp_start;
}
}
},
render: function render() {
var flow = this.props.flow;
var time;
if (flow.response) {
time = utils.formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start));
} else {
time = "...";
}
return React.createElement(
"td",
{ className: "col-time" },
time
);
}
});
var all_columns = [TLSColumn, IconColumn, PathColumn, MethodColumn, StatusColumn, SizeColumn, TimeColumn];
module.exports = all_columns;
},{"../flow/utils.js":23,"../utils.js":26,"react":"react"}],8:[function(require,module,exports){
"use strict";
var React = require("react");
var common = require("./common.js");
var utils = require("../utils.js");
var _ = require("lodash");
var VirtualScrollMixin = require("./virtualscroll.js");
var flowtable_columns = require("./flowtable-columns.js");
var FlowRow = React.createClass({
displayName: "FlowRow",
render: function render() {
var flow = this.props.flow;
var columns = this.props.columns.map((function (Column) {
return React.createElement(Column, { key: Column.displayName, flow: flow });
}).bind(this));
var className = "";
if (this.props.selected) {
className += " selected";
}
if (this.props.highlighted) {
className += " highlighted";
}
if (flow.intercepted) {
className += " intercepted";
}
if (flow.request) {
className += " has-request";
}
if (flow.response) {
className += " has-response";
}
return React.createElement(
"tr",
{ className: className, onClick: this.props.selectFlow.bind(null, flow) },
columns
);
},
shouldComponentUpdate: function shouldComponentUpdate(nextProps) {
return true;
// Further optimization could be done here
// by calling forceUpdate on flow updates, selection changes and column changes.
//return (
//(this.props.columns.length !== nextProps.columns.length) ||
//(this.props.selected !== nextProps.selected)
//);
}
});
var FlowTableHead = React.createClass({
displayName: "FlowTableHead",
getInitialState: function getInitialState() {
return {
sortColumn: undefined,
sortDesc: false
};
},
onClick: function onClick(Column) {
var sortDesc = this.state.sortDesc;
var hasSort = Column.sortKeyFun;
if (Column === this.state.sortColumn) {
sortDesc = !sortDesc;
this.setState({
sortDesc: sortDesc
});
} else {
this.setState({
sortColumn: hasSort && Column,
sortDesc: false
});
}
var sortKeyFun;
if (!sortDesc) {
sortKeyFun = Column.sortKeyFun;
} else {
sortKeyFun = hasSort && function () {
var k = Column.sortKeyFun.apply(this, arguments);
if (_.isString(k)) {
return utils.reverseString("" + k);
} else {
return -k;
}
};
}
this.props.setSortKeyFun(sortKeyFun);
},
render: function render() {
var columns = this.props.columns.map((function (Column) {
var onClick = this.onClick.bind(this, Column);
var className;
if (this.state.sortColumn === Column) {
if (this.state.sortDesc) {
className = "sort-desc";
} else {
className = "sort-asc";
}
}
return React.createElement(Column.Title, {
key: Column.displayName,
onClick: onClick,
className: className });
}).bind(this));
return React.createElement(
"thead",
null,
React.createElement(
"tr",
null,
columns
)
);
}
});
var ROW_HEIGHT = 32;
var FlowTable = React.createClass({
displayName: "FlowTable",
mixins: [common.StickyHeadMixin, common.AutoScrollMixin, VirtualScrollMixin],
contextTypes: {
view: React.PropTypes.object.isRequired
},
getInitialState: function getInitialState() {
return {
columns: flowtable_columns
};
},
componentWillMount: function componentWillMount() {
this.context.view.addListener("add", this.onChange);
this.context.view.addListener("update", this.onChange);
this.context.view.addListener("remove", this.onChange);
this.context.view.addListener("recalculate", this.onChange);
},
componentWillUnmount: function componentWillUnmount() {
this.context.view.removeListener("add", this.onChange);
this.context.view.removeListener("update", this.onChange);
this.context.view.removeListener("remove", this.onChange);
this.context.view.removeListener("recalculate", this.onChange);
},
getDefaultProps: function getDefaultProps() {
return {
rowHeight: ROW_HEIGHT
};
},
onScrollFlowTable: function onScrollFlowTable() {
this.adjustHead();
this.onScroll();
},
onChange: function onChange() {
this.forceUpdate();
},
scrollIntoView: function scrollIntoView(flow) {
this.scrollRowIntoView(this.context.view.index(flow), this.refs.body.getDOMNode().offsetTop);
},
renderRow: function renderRow(flow) {
var selected = flow === this.props.selected;
var highlighted = this.context.view._highlight && this.context.view._highlight[flow.id];
return React.createElement(FlowRow, { key: flow.id,
ref: flow.id,
flow: flow,
columns: this.state.columns,
selected: selected,
highlighted: highlighted,
selectFlow: this.props.selectFlow
});
},
render: function render() {
var flows = this.context.view.list;
var rows = this.renderRows(flows);
return React.createElement(
"div",
{ className: "flow-table", onScroll: this.onScrollFlowTable },
React.createElement(
"table",
null,
React.createElement(FlowTableHead, { ref: "head",
columns: this.state.columns,
setSortKeyFun: this.props.setSortKeyFun }),
React.createElement(
"tbody",
{ ref: "body" },
this.getPlaceholderTop(flows.length),
rows,
this.getPlaceholderBottom(flows.length)
)
)
);
}
});
module.exports = FlowTable;
},{"../utils.js":26,"./common.js":4,"./flowtable-columns.js":7,"./virtualscroll.js":19,"lodash":"lodash","react":"react"}],9:[function(require,module,exports){
"use strict";
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var React = require("react");
var _ = require("lodash");
var MessageUtils = require("../../flow/utils.js").MessageUtils;
var utils = require("../../utils.js");
var image_regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i;
var ViewImage = React.createClass({
displayName: "ViewImage",
statics: {
matches: function matches(message) {
return image_regex.test(MessageUtils.getContentType(message));
}
},
render: function render() {
var url = MessageUtils.getContentURL(this.props.flow, this.props.message);
return React.createElement(
"div",
{ className: "flowview-image" },
React.createElement("img", { src: url, alt: "preview", className: "img-thumbnail" })
);
}
});
var RawMixin = {
getInitialState: function getInitialState() {
return {
content: undefined,
request: undefined
};
},
requestContent: function requestContent(nextProps) {
if (this.state.request) {
this.state.request.abort();
}
var request = MessageUtils.getContent(nextProps.flow, nextProps.message);
this.setState({
content: undefined,
request: request
});
request.done((function (data) {
this.setState({ content: data });
}).bind(this)).fail((function (jqXHR, textStatus, errorThrown) {
if (textStatus === "abort") {
return;
}
this.setState({ content: "AJAX Error: " + textStatus + "\r\n" + errorThrown });
}).bind(this)).always((function () {
this.setState({ request: undefined });
}).bind(this));
},
componentWillMount: function componentWillMount() {
this.requestContent(this.props);
},
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
if (nextProps.message !== this.props.message) {
this.requestContent(nextProps);
}
},
componentWillUnmount: function componentWillUnmount() {
if (this.state.request) {
this.state.request.abort();
}
},
render: function render() {
if (!this.state.content) {
return React.createElement(
"div",
{ className: "text-center" },
React.createElement("i", { className: "fa fa-spinner fa-spin" })
);
}
return this.renderContent();
}
};
var ViewRaw = React.createClass({
displayName: "ViewRaw",
mixins: [RawMixin],
statics: {
matches: function matches(message) {
return true;
}
},
renderContent: function renderContent() {
return React.createElement(
"pre",
null,
this.state.content
);
}
});
var json_regex = /^application\/json$/i;
var ViewJSON = React.createClass({
displayName: "ViewJSON",
mixins: [RawMixin],
statics: {
matches: function matches(message) {
return json_regex.test(MessageUtils.getContentType(message));
}
},
renderContent: function renderContent() {
var json = this.state.content;
try {
json = JSON.stringify(JSON.parse(json), null, 2);
} catch (e) {}
return React.createElement(
"pre",
null,
json
);
}
});
var ViewAuto = React.createClass({
displayName: "ViewAuto",
statics: {
matches: function matches() {
return false; // don't match itself
},
findView: function findView(message) {
for (var i = 0; i < all.length; i++) {
if (all[i].matches(message)) {
return all[i];
}
}
return all[all.length - 1];
}
},
render: function render() {
var View = ViewAuto.findView(this.props.message);
return React.createElement(View, this.props);
}
});
var all = [ViewAuto, ViewImage, ViewJSON, ViewRaw];
var ContentEmpty = React.createClass({
displayName: "ContentEmpty",
render: function render() {
var message_name = this.props.flow.request === this.props.message ? "request" : "response";
return React.createElement(
"div",
{ className: "alert alert-info" },
"No ",
message_name,
" content."
);
}
});
var ContentMissing = React.createClass({
displayName: "ContentMissing",
render: function render() {
var message_name = this.props.flow.request === this.props.message ? "Request" : "Response";
return React.createElement(
"div",
{ className: "alert alert-info" },
message_name,
" content missing."
);
}
});
var TooLarge = React.createClass({
displayName: "TooLarge",
statics: {
isTooLarge: function isTooLarge(message) {
var max_mb = ViewImage.matches(message) ? 10 : 0.2;
return message.contentLength > 1024 * 1024 * max_mb;
}
},
render: function render() {
var size = utils.formatSize(this.props.message.contentLength);
return React.createElement(
"div",
{ className: "alert alert-warning" },
React.createElement(
"button",
{ onClick: this.props.onClick, className: "btn btn-xs btn-warning pull-right" },
"Display anyway"
),
size,
" content size."
);
}
});
var ViewSelector = React.createClass({
displayName: "ViewSelector",
render: function render() {
var views = [];
for (var i = 0; i < all.length; i++) {
var view = all[i];
var className = "btn btn-default";
if (view === this.props.active) {
className += " active";
}
var text;
if (view === ViewAuto) {
text = "auto: " + ViewAuto.findView(this.props.message).displayName.toLowerCase().replace("view", "");
} else {
text = view.displayName.toLowerCase().replace("view", "");
}
views.push(React.createElement(
"button",
{
key: view.displayName,
onClick: this.props.selectView.bind(null, view),
className: className },
text
));
}
return React.createElement(
"div",
{ className: "view-selector btn-group btn-group-xs" },
views
);
}
});
var ContentView = React.createClass({
displayName: "ContentView",
getInitialState: function getInitialState() {
return {
displayLarge: false,
View: ViewAuto
};
},
propTypes: {
// It may seem a bit weird at the first glance:
// Every view takes the flow and the message as props, e.g.
// <Auto flow={flow} message={flow.request}/>
flow: React.PropTypes.object.isRequired,
message: React.PropTypes.object.isRequired
},
selectView: function selectView(view) {
this.setState({
View: view
});
},
displayLarge: function displayLarge() {
this.setState({ displayLarge: true });
},
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
if (nextProps.message !== this.props.message) {
this.setState(this.getInitialState());
}
},
render: function render() {
var message = this.props.message;
if (message.contentLength === 0) {
return React.createElement(ContentEmpty, this.props);
} else if (message.contentLength === null) {
return React.createElement(ContentMissing, this.props);
} else if (!this.state.displayLarge && TooLarge.isTooLarge(message)) {
return React.createElement(TooLarge, _extends({}, this.props, { onClick: this.displayLarge }));
}
var downloadUrl = MessageUtils.getContentURL(this.props.flow, message);
return React.createElement(
"div",
null,
React.createElement(this.state.View, this.props),
React.createElement(
"div",
{ className: "view-options text-center" },
React.createElement(ViewSelector, { selectView: this.selectView, active: this.state.View, message: message }),
" ",
React.createElement(
"a",
{ className: "btn btn-default btn-xs", href: downloadUrl },
React.createElement("i", { className: "fa fa-download" })
)
)
);
}
});
module.exports = ContentView;
},{"../../flow/utils.js":23,"../../utils.js":26,"lodash":"lodash","react":"react"}],10:[function(require,module,exports){
"use strict";
var React = require("react");
var _ = require("lodash");
var utils = require("../../utils.js");
var TimeStamp = React.createClass({
displayName: "TimeStamp",
render: function render() {
if (!this.props.t) {
//should be return null, but that triggers a React bug.
return React.createElement("tr", null);
}
var ts = utils.formatTimeStamp(this.props.t);
var delta;
if (this.props.deltaTo) {
delta = utils.formatTimeDelta(1000 * (this.props.t - this.props.deltaTo));
delta = React.createElement(
"span",
{ className: "text-muted" },
"(" + delta + ")"
);
} else {
delta = null;
}
return React.createElement(
"tr",
null,
React.createElement(
"td",
null,
this.props.title + ":"
),
React.createElement(
"td",
null,
ts,
" ",
delta
)
);
}
});
var ConnectionInfo = React.createClass({
displayName: "ConnectionInfo",
render: function render() {
var conn = this.props.conn;
var address = conn.address.address.join(":");
var sni = React.createElement("tr", { key: "sni" }); //should be null, but that triggers a React bug.
if (conn.sni) {
sni = React.createElement(
"tr",
{ key: "sni" },
React.createElement(
"td",
null,
React.createElement(
"abbr",
{ title: "TLS Server Name Indication" },
"TLS SNI:"
)
),
React.createElement(
"td",
null,
conn.sni
)
);
}
return React.createElement(
"table",
{ className: "connection-table" },
React.createElement(
"tbody",
null,
React.createElement(
"tr",
{ key: "address" },
React.createElement(
"td",
null,
"Address:"
),
React.createElement(
"td",
null,
address
)
),
sni
)
);
}
});
var CertificateInfo = React.createClass({
displayName: "CertificateInfo",
render: function render() {
//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 React.createElement(
"div",
null,
client_conn.cert ? React.createElement(
"h4",
null,
"Client Certificate"
) : null,
client_conn.cert ? React.createElement(
"pre",
{ style: preStyle },
client_conn.cert
) : null,
server_conn.cert ? React.createElement(
"h4",
null,
"Server Certificate"
) : null,
server_conn.cert ? React.createElement(
"pre",
{ style: preStyle },
server_conn.cert
) : null
);
}
});
var Timing = React.createClass({
displayName: "Timing",
render: function render() {
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 React.createElement(TimeStamp, e);
});
return React.createElement(
"div",
null,
React.createElement(
"h4",
null,
"Timing"
),
React.createElement(
"table",
{ className: "timing-table" },
React.createElement(
"tbody",
null,
rows
)
)
);
}
});
var Details = React.createClass({
displayName: "Details",
render: function render() {
var flow = this.props.flow;
var client_conn = flow.client_conn;
var server_conn = flow.server_conn;
return React.createElement(
"section",
null,
React.createElement(
"h4",
null,
"Client Connection"
),
React.createElement(ConnectionInfo, { conn: client_conn }),
React.createElement(
"h4",
null,
"Server Connection"
),
React.createElement(ConnectionInfo, { conn: server_conn }),
React.createElement(CertificateInfo, { flow: flow }),
React.createElement(Timing, { flow: flow })
);
}
});
module.exports = Details;
},{"../../utils.js":26,"lodash":"lodash","react":"react"}],11:[function(require,module,exports){
"use strict";
var React = require("react");
var _ = require("lodash");
var common = require("../common.js");
var Nav = require("./nav.js");
var Messages = require("./messages.js");
var Details = require("./details.js");
var Prompt = require("../prompt.js");
var allTabs = {
request: Messages.Request,
response: Messages.Response,
error: Messages.Error,
details: Details
};
var FlowView = React.createClass({
displayName: "FlowView",
mixins: [common.StickyHeadMixin, common.Navigation, common.RouterState],
getInitialState: function getInitialState() {
return {
prompt: false
};
},
getTabs: function getTabs(flow) {
var tabs = [];
["request", "response", "error"].forEach(function (e) {
if (flow[e]) {
tabs.push(e);
}
});
tabs.push("details");
return tabs;
},
nextTab: function nextTab(i) {
var tabs = this.getTabs(this.props.flow);
var currentIndex = tabs.indexOf(this.getActive());
// JS modulo operator doesn't correct negative numbers, make sure that we are positive.
var nextIndex = (currentIndex + i + tabs.length) % tabs.length;
this.selectTab(tabs[nextIndex]);
},
selectTab: function selectTab(panel) {
this.replaceWith("flow", {
flowId: this.getParams().flowId,
detailTab: panel
});
},
getActive: function getActive() {
return this.getParams().detailTab;
},
promptEdit: function promptEdit() {
var options;
switch (this.getActive()) {
case "request":
options = ["method", "url", { text: "http version", key: "v" }, "header"
/*, "content"*/];
break;
case "response":
options = [{ text: "http version", key: "v" }, "code", "message", "header"
/*, "content"*/];
break;
case "details":
return;
default:
throw "Unknown tab for edit: " + this.getActive();
}
this.setState({
prompt: {
done: (function (k) {
this.setState({ prompt: false });
if (k) {
this.refs.tab.edit(k);
}
}).bind(this),
options: options
}
});
},
render: function render() {
var flow = this.props.flow;
var tabs = this.getTabs(flow);
var active = this.getActive();
if (!_.contains(tabs, active)) {
if (active === "response" && flow.error) {
active = "error";
} else if (active === "error" && flow.response) {
active = "response";
} else {
active = tabs[0];
}
this.selectTab(active);
}
var prompt = null;
if (this.state.prompt) {
prompt = React.createElement(Prompt, this.state.prompt);
}
var Tab = allTabs[active];
return React.createElement(
"div",
{ className: "flow-detail", onScroll: this.adjustHead },
React.createElement(Nav, { ref: "head",
flow: flow,
tabs: tabs,
active: active,
selectTab: this.selectTab }),
React.createElement(Tab, { ref: "tab", flow: flow }),
prompt
);
}
});
module.exports = FlowView;
},{"../common.js":4,"../prompt.js":17,"./details.js":10,"./messages.js":12,"./nav.js":13,"lodash":"lodash","react":"react"}],12:[function(require,module,exports){
"use strict";
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var React = require("react");
var _ = require("lodash");
var common = require("../common.js");
var actions = require("../../actions.js");
var flowutils = require("../../flow/utils.js");
var utils = require("../../utils.js");
var ContentView = require("./contentview.js");
var ValueEditor = require("../editor.js").ValueEditor;
var Headers = React.createClass({
displayName: "Headers",
propTypes: {
onChange: React.PropTypes.func.isRequired,
message: React.PropTypes.object.isRequired
},
onChange: function onChange(row, col, val) {
var nextHeaders = _.cloneDeep(this.props.message.headers);
nextHeaders[row][col] = val;
if (!nextHeaders[row][0] && !nextHeaders[row][1]) {
// do not delete last row
if (nextHeaders.length === 1) {
nextHeaders[0][0] = "Name";
nextHeaders[0][1] = "Value";
} else {
nextHeaders.splice(row, 1);
// manually move selection target if this has been the last row.
if (row === nextHeaders.length) {
this._nextSel = row - 1 + "-value";
}
}
}
this.props.onChange(nextHeaders);
},
edit: function edit() {
this.refs["0-key"].focus();
},
onTab: function onTab(row, col, e) {
var headers = this.props.message.headers;
if (row === headers.length - 1 && col === 1) {
e.preventDefault();
var nextHeaders = _.cloneDeep(this.props.message.headers);
nextHeaders.push(["Name", "Value"]);
this.props.onChange(nextHeaders);
this._nextSel = row + 1 + "-key";
}
},
componentDidUpdate: function componentDidUpdate() {
if (this._nextSel && this.refs[this._nextSel]) {
this.refs[this._nextSel].focus();
this._nextSel = undefined;
}
},
onRemove: function onRemove(row, col, e) {
if (col === 1) {
e.preventDefault();
this.refs[row + "-key"].focus();
} else if (row > 0) {
e.preventDefault();
this.refs[row - 1 + "-value"].focus();
}
},
render: function render() {
var rows = this.props.message.headers.map((function (header, i) {
var kEdit = React.createElement(HeaderEditor, {
ref: i + "-key",
content: header[0],
onDone: this.onChange.bind(null, i, 0),
onRemove: this.onRemove.bind(null, i, 0),
onTab: this.onTab.bind(null, i, 0) });
var vEdit = React.createElement(HeaderEditor, {
ref: i + "-value",
content: header[1],
onDone: this.onChange.bind(null, i, 1),
onRemove: this.onRemove.bind(null, i, 1),
onTab: this.onTab.bind(null, i, 1) });
return React.createElement(
"tr",
{ key: i },
React.createElement(
"td",
{ className: "header-name" },
kEdit,
":"
),
React.createElement(
"td",
{ className: "header-value" },
vEdit
)
);
}).bind(this));
return React.createElement(
"table",
{ className: "header-table" },
React.createElement(
"tbody",
null,
rows
)
);
}
});
var HeaderEditor = React.createClass({
displayName: "HeaderEditor",
render: function render() {
return React.createElement(ValueEditor, _extends({ ref: "input" }, this.props, { onKeyDown: this.onKeyDown, inline: true }));
},
focus: function focus() {
this.getDOMNode().focus();
},
onKeyDown: function onKeyDown(e) {
switch (e.keyCode) {
case utils.Key.BACKSPACE:
var s = window.getSelection().getRangeAt(0);
if (s.startOffset === 0 && s.endOffset === 0) {
this.props.onRemove(e);
}
break;
case utils.Key.TAB:
if (!e.shiftKey) {
this.props.onTab(e);
}
break;
}
}
});
var RequestLine = React.createClass({
displayName: "RequestLine",
render: function render() {
var flow = this.props.flow;
var url = flowutils.RequestUtils.pretty_url(flow.request);
var httpver = flow.request.http_version;
return React.createElement(
"div",
{ className: "first-line request-line" },
React.createElement(ValueEditor, {
ref: "method",
content: flow.request.method,
onDone: this.onMethodChange,
inline: true }),
" ",
React.createElement(ValueEditor, {
ref: "url",
content: url,
onDone: this.onUrlChange,
isValid: this.isValidUrl,
inline: true }),
" ",
React.createElement(ValueEditor, {
ref: "httpVersion",
content: httpver,
onDone: this.onHttpVersionChange,
isValid: flowutils.isValidHttpVersion,
inline: true })
);
},
isValidUrl: function isValidUrl(url) {
var u = flowutils.parseUrl(url);
return !!u.host;
},
onMethodChange: function onMethodChange(nextMethod) {
actions.FlowActions.update(this.props.flow, { request: { method: nextMethod } });
},
onUrlChange: function onUrlChange(nextUrl) {
var props = flowutils.parseUrl(nextUrl);
props.path = props.path || "";
actions.FlowActions.update(this.props.flow, { request: props });
},
onHttpVersionChange: function onHttpVersionChange(nextVer) {
var ver = flowutils.parseHttpVersion(nextVer);
actions.FlowActions.update(this.props.flow, { request: { http_version: ver } });
}
});
var ResponseLine = React.createClass({
displayName: "ResponseLine",
render: function render() {
var flow = this.props.flow;
var httpver = flow.response.http_version;
return React.createElement(
"div",
{ className: "first-line response-line" },
React.createElement(ValueEditor, {
ref: "httpVersion",
content: httpver,
onDone: this.onHttpVersionChange,
isValid: flowutils.isValidHttpVersion,
inline: true }),
" ",
React.createElement(ValueEditor, {
ref: "code",
content: flow.response.status_code + "",
onDone: this.onCodeChange,
isValid: this.isValidCode,
inline: true }),
" ",
React.createElement(ValueEditor, {
ref: "msg",
content: flow.response.msg,
onDone: this.onMsgChange,
inline: true })
);
},
isValidCode: function isValidCode(code) {
return (/^\d+$/.test(code)
);
},
onHttpVersionChange: function onHttpVersionChange(nextVer) {
var ver = flowutils.parseHttpVersion(nextVer);
actions.FlowActions.update(this.props.flow, { response: { http_version: ver } });
},
onMsgChange: function onMsgChange(nextMsg) {
actions.FlowActions.update(this.props.flow, { response: { msg: nextMsg } });
},
onCodeChange: function onCodeChange(nextCode) {
nextCode = parseInt(nextCode);
actions.FlowActions.update(this.props.flow, { response: { code: nextCode } });
}
});
var Request = React.createClass({
displayName: "Request",
render: function render() {
var flow = this.props.flow;
return React.createElement(
"section",
{ className: "request" },
React.createElement(RequestLine, { ref: "requestLine", flow: flow }),
React.createElement(Headers, { ref: "headers", message: flow.request, onChange: this.onHeaderChange }),
React.createElement("hr", null),
React.createElement(ContentView, { flow: flow, message: flow.request })
);
},
edit: function edit(k) {
switch (k) {
case "m":
this.refs.requestLine.refs.method.focus();
break;
case "u":
this.refs.requestLine.refs.url.focus();
break;
case "v":
this.refs.requestLine.refs.httpVersion.focus();
break;
case "h":
this.refs.headers.edit();
break;
default:
throw "Unimplemented: " + k;
}
},
onHeaderChange: function onHeaderChange(nextHeaders) {
actions.FlowActions.update(this.props.flow, {
request: {
headers: nextHeaders
}
});
}
});
var Response = React.createClass({
displayName: "Response",
render: function render() {
var flow = this.props.flow;
return React.createElement(
"section",
{ className: "response" },
React.createElement(ResponseLine, { ref: "responseLine", flow: flow }),
React.createElement(Headers, { ref: "headers", message: flow.response, onChange: this.onHeaderChange }),
React.createElement("hr", null),
React.createElement(ContentView, { flow: flow, message: flow.response })
);
},
edit: function edit(k) {
switch (k) {
case "c":
this.refs.responseLine.refs.status_code.focus();
break;
case "m":
this.refs.responseLine.refs.msg.focus();
break;
case "v":
this.refs.responseLine.refs.httpVersion.focus();
break;
case "h":
this.refs.headers.edit();
break;
default:
throw "Unimplemented: " + k;
}
},
onHeaderChange: function onHeaderChange(nextHeaders) {
actions.FlowActions.update(this.props.flow, {
response: {
headers: nextHeaders
}
});
}
});
var Error = React.createClass({
displayName: "Error",
render: function render() {
var flow = this.props.flow;
return React.createElement(
"section",
null,
React.createElement(
"div",
{ className: "alert alert-warning" },
flow.error.msg,
React.createElement(
"div",
null,
React.createElement(
"small",
null,
utils.formatTimeStamp(flow.error.timestamp)
)
)
)
);
}
});
module.exports = {
Request: Request,
Response: Response,
Error: Error
};
/*<ResponseLine flow={flow}/>*/ /*<RequestLine flow={flow}/>*/
},{"../../actions.js":2,"../../flow/utils.js":23,"../../utils.js":26,"../common.js":4,"../editor.js":5,"./contentview.js":9,"lodash":"lodash","react":"react"}],13:[function(require,module,exports){
"use strict";
var React = require("react");
var actions = require("../../actions.js");
var NavAction = React.createClass({
displayName: "NavAction",
onClick: function onClick(e) {
e.preventDefault();
this.props.onClick();
},
render: function render() {
return React.createElement(
"a",
{ title: this.props.title,
href: "#",
className: "nav-action",
onClick: this.onClick },
React.createElement("i", { className: "fa fa-fw " + this.props.icon })
);
}
});
var Nav = React.createClass({
displayName: "Nav",
render: function render() {
var flow = this.props.flow;
var tabs = 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 (event) {
this.props.selectTab(e);
event.preventDefault();
}).bind(this);
return React.createElement(
"a",
{ key: e,
href: "#",
className: className,
onClick: onClick },
str
);
}).bind(this));
var acceptButton = null;
if (flow.intercepted) {
acceptButton = React.createElement(NavAction, { title: "[a]ccept intercepted flow", icon: "fa-play", onClick: actions.FlowActions.accept.bind(null, flow) });
}
var revertButton = null;
if (flow.modified) {
revertButton = React.createElement(NavAction, { title: "revert changes to flow [V]", icon: "fa-history", onClick: actions.FlowActions.revert.bind(null, flow) });
}
return React.createElement(
"nav",
{ ref: "head", className: "nav-tabs nav-tabs-sm" },
tabs,
React.createElement(NavAction, { title: "[d]elete flow", icon: "fa-trash", onClick: actions.FlowActions["delete"].bind(null, flow) }),
React.createElement(NavAction, { title: "[D]uplicate flow", icon: "fa-copy", onClick: actions.FlowActions.duplicate.bind(null, flow) }),
React.createElement(NavAction, { disabled: true, title: "[r]eplay flow", icon: "fa-repeat", onClick: actions.FlowActions.replay.bind(null, flow) }),
acceptButton,
revertButton
);
}
});
module.exports = Nav;
},{"../../actions.js":2,"react":"react"}],14:[function(require,module,exports){
"use strict";
var React = require("react");
var common = require("./common.js");
var Footer = React.createClass({
displayName: "Footer",
mixins: [common.SettingsState],
render: function render() {
var mode = this.state.settings.mode;
var intercept = this.state.settings.intercept;
return React.createElement(
"footer",
null,
mode && mode != "regular" ? React.createElement(
"span",
{ className: "label label-success" },
mode,
" mode"
) : null,
" ",
intercept ? React.createElement(
"span",
{ className: "label label-success" },
"Intercept: ",
intercept
) : null
);
}
});
module.exports = Footer;
},{"./common.js":4,"react":"react"}],15:[function(require,module,exports){
"use strict";
var React = require("react");
var $ = require("jquery");
var Filt = require("../filt/filt.js");
var utils = require("../utils.js");
var common = require("./common.js");
var actions = require("../actions.js");
var Query = require("../actions.js").Query;
var FilterDocs = React.createClass({
displayName: "FilterDocs",
statics: {
xhr: false,
doc: false
},
componentWillMount: function componentWillMount() {
if (!FilterDocs.doc) {
FilterDocs.xhr = $.getJSON("/filter-help").done(function (doc) {
FilterDocs.doc = doc;
FilterDocs.xhr = false;
});
}
if (FilterDocs.xhr) {
FilterDocs.xhr.done((function () {
this.forceUpdate();
}).bind(this));
}
},
render: function render() {
if (!FilterDocs.doc) {
return React.createElement("i", { className: "fa fa-spinner fa-spin" });
} else {
var commands = FilterDocs.doc.commands.map(function (c) {
return React.createElement(
"tr",
{ key: c[1] },
React.createElement(
"td",
null,
c[0].replace(" ", " ")
),
React.createElement(
"td",
null,
c[1]
)
);
});
commands.push(React.createElement(
"tr",
{ key: "docs-link" },
React.createElement(
"td",
{ colSpan: "2" },
React.createElement(
"a",
{ href: "https://mitmproxy.org/doc/features/filters.html",
target: "_blank" },
React.createElement("i", { className: "fa fa-external-link" }),
"  mitmproxy docs"
)
)
));
return React.createElement(
"table",
{ className: "table table-condensed" },
React.createElement(
"tbody",
null,
commands
)
);
}
}
});
var FilterInput = React.createClass({
displayName: "FilterInput",
mixins: [common.ChildFocus],
getInitialState: function getInitialState() {
// Consider both focus and mouseover for showing/hiding the tooltip,
// because onBlur of the input is triggered before the click on the tooltip
// finalized, hiding the tooltip just as the user clicks on it.
return {
value: this.props.value,
focus: false,
mousefocus: false
};
},
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
this.setState({ value: nextProps.value });
},
onChange: function onChange(e) {
var nextValue = e.target.value;
this.setState({
value: nextValue
});
// Only propagate valid filters upwards.
if (this.isValid(nextValue)) {
this.props.onChange(nextValue);
}
},
isValid: function isValid(filt) {
try {
Filt.parse(filt || this.state.value);
return true;
} catch (e) {
return false;
}
},
getDesc: function getDesc() {
var desc;
try {
desc = Filt.parse(this.state.value).desc;
} catch (e) {
desc = "" + e;
}
if (desc !== "true") {
return desc;
} else {
return React.createElement(FilterDocs, null);
}
},
onFocus: function onFocus() {
this.setState({ focus: true });
},
onBlur: function onBlur() {
this.setState({ focus: false });
},
onMouseEnter: function onMouseEnter() {
this.setState({ mousefocus: true });
},
onMouseLeave: function onMouseLeave() {
this.setState({ mousefocus: false });
},
onKeyDown: function onKeyDown(e) {
if (e.keyCode === utils.Key.ESC || e.keyCode === utils.Key.ENTER) {
this.blur();
// If closed using ESC/ENTER, hide the tooltip.
this.setState({ mousefocus: false });
}
e.stopPropagation();
},
blur: function blur() {
this.refs.input.getDOMNode().blur();
this.returnFocus();
},
select: function select() {
this.refs.input.getDOMNode().select();
},
render: function render() {
var isValid = this.isValid();
var icon = "fa fa-fw fa-" + this.props.type;
var groupClassName = "filter-input input-group" + (isValid ? "" : " has-error");
var popover;
if (this.state.focus || this.state.mousefocus) {
popover = React.createElement(
"div",
{ className: "popover bottom", onMouseEnter: this.onMouseEnter, onMouseLeave: this.onMouseLeave },
React.createElement("div", { className: "arrow" }),
React.createElement(
"div",
{ className: "popover-content" },
this.getDesc()
)
);
}
return React.createElement(
"div",
{ className: groupClassName },
React.createElement(
"span",
{ className: "input-group-addon" },
React.createElement("i", { className: icon, style: { color: this.props.color } })
),
React.createElement("input", { type: "text", placeholder: this.props.placeholder, className: "form-control",
ref: "input",
onChange: this.onChange,
onFocus: this.onFocus,
onBlur: this.onBlur,
onKeyDown: this.onKeyDown,
value: this.state.value }),
popover
);
}
});
var MainMenu = React.createClass({
displayName: "MainMenu",
mixins: [common.Navigation, common.RouterState, common.SettingsState],
statics: {
title: "Start",
route: "flows"
},
onSearchChange: function onSearchChange(val) {
var d = {};
d[Query.SEARCH] = val;
this.setQuery(d);
},
onHighlightChange: function onHighlightChange(val) {
var d = {};
d[Query.HIGHLIGHT] = val;
this.setQuery(d);
},
onInterceptChange: function onInterceptChange(val) {
actions.SettingsActions.update({ intercept: val });
},
render: function render() {
var search = this.getQuery()[Query.SEARCH] || "";
var highlight = this.getQuery()[Query.HIGHLIGHT] || "";
var intercept = this.state.settings.intercept || "";
return React.createElement(
"div",
null,
React.createElement(
"div",
{ className: "menu-row" },
React.createElement(FilterInput, {
ref: "search",
placeholder: "Search",
type: "search",
color: "black",
value: search,
onChange: this.onSearchChange }),
React.createElement(FilterInput, {
ref: "highlight",
placeholder: "Highlight",
type: "tag",
color: "hsl(48, 100%, 50%)",
value: highlight,
onChange: this.onHighlightChange }),
React.createElement(FilterInput, {
ref: "intercept",
placeholder: "Intercept",
type: "pause",
color: "hsl(208, 56%, 53%)",
value: intercept,
onChange: this.onInterceptChange })
),
React.createElement("div", { className: "clearfix" })
);
}
});
var ViewMenu = React.createClass({
displayName: "ViewMenu",
statics: {
title: "View",
route: "flows"
},
mixins: [common.Navigation, common.RouterState],
toggleEventLog: function toggleEventLog() {
var d = {};
if (this.getQuery()[Query.SHOW_EVENTLOG]) {
d[Query.SHOW_EVENTLOG] = undefined;
} else {
d[Query.SHOW_EVENTLOG] = "t"; // any non-false value will do it, keep it short
}
this.setQuery(d);
},
render: function render() {
var showEventLog = this.getQuery()[Query.SHOW_EVENTLOG];
return React.createElement(
"div",
null,
React.createElement(
"button",
{
className: "btn " + (showEventLog ? "btn-primary" : "btn-default"),
onClick: this.toggleEventLog },
React.createElement("i", { className: "fa fa-database" }),
" Show Eventlog"
),
React.createElement(
"span",
null,
" "
)
);
}
});
var ReportsMenu = React.createClass({
displayName: "ReportsMenu",
statics: {
title: "Visualization",
route: "reports"
},
render: function render() {
return React.createElement(
"div",
null,
"Reports Menu"
);
}
});
var FileMenu = React.createClass({
displayName: "FileMenu",
getInitialState: function getInitialState() {
return {
showFileMenu: false
};
},
handleFileClick: function handleFileClick(e) {
e.preventDefault();
if (!this.state.showFileMenu) {
var close = (function () {
this.setState({ showFileMenu: false });
document.removeEventListener("click", close);
}).bind(this);
document.addEventListener("click", close);
this.setState({
showFileMenu: true
});
}
},
handleNewClick: function handleNewClick(e) {
e.preventDefault();
if (confirm("Delete all flows?")) {
actions.FlowActions.clear();
}
},
handleOpenClick: function handleOpenClick(e) {
e.preventDefault();
console.error("unimplemented: handleOpenClick");
},
handleSaveClick: function handleSaveClick(e) {
e.preventDefault();
console.error("unimplemented: handleSaveClick");
},
handleShutdownClick: function handleShutdownClick(e) {
e.preventDefault();
console.error("unimplemented: handleShutdownClick");
},
render: function render() {
var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : "");
return React.createElement(
"div",
{ className: fileMenuClass },
React.createElement(
"a",
{ href: "#", className: "special", onClick: this.handleFileClick },
" mitmproxy "
),
React.createElement(
"ul",
{ className: "dropdown-menu", role: "menu" },
React.createElement(
"li",
null,
React.createElement(
"a",
{ href: "#", onClick: this.handleNewClick },
React.createElement("i", { className: "fa fa-fw fa-file" }),
"New"
)
),
React.createElement("li", { role: "presentation", className: "divider" }),
React.createElement(
"li",
null,
React.createElement(
"a",
{ href: "http://mitm.it/", target: "_blank" },
React.createElement("i", { className: "fa fa-fw fa-external-link" }),
"Install Certificates..."
)
)
)
);
}
});
var header_entries = [MainMenu, ViewMenu /*, ReportsMenu */];
var Header = React.createClass({
displayName: "Header",
mixins: [common.Navigation],
getInitialState: function getInitialState() {
return {
active: header_entries[0]
};
},
handleClick: function handleClick(active, e) {
e.preventDefault();
this.replaceWith(active.route);
this.setState({ active: active });
},
render: function render() {
var header = header_entries.map((function (entry, i) {
var className;
if (entry === this.state.active) {
className = "active";
} else {
className = "";
}
return React.createElement(
"a",
{ key: i,
href: "#",
className: className,
onClick: this.handleClick.bind(this, entry) },
entry.title
);
}).bind(this));
return React.createElement(
"header",
null,
React.createElement(
"nav",
{ className: "nav-tabs nav-tabs-lg" },
React.createElement(FileMenu, null),
header
),
React.createElement(
"div",
{ className: "menu" },
React.createElement(this.state.active, { ref: "active" })
)
);
}
});
module.exports = {
Header: Header,
MainMenu: MainMenu
};
/*
<li>
<a href="#" onClick={this.handleOpenClick}>
<i className="fa fa-fw fa-folder-open"></i>
Open
</a>
</li>
<li>
<a href="#" onClick={this.handleSaveClick}>
<i className="fa fa-fw fa-save"></i>
Save
</a>
</li>
<li role="presentation" className="divider"></li>
<li>
<a href="#" onClick={this.handleShutdownClick}>
<i className="fa fa-fw fa-plug"></i>
Shutdown
</a>
</li>
*/
},{"../actions.js":2,"../filt/filt.js":22,"../utils.js":26,"./common.js":4,"jquery":"jquery","react":"react"}],16:[function(require,module,exports){
"use strict";
var React = require("react");
var actions = require("../actions.js");
var Query = require("../actions.js").Query;
var utils = require("../utils.js");
var views = require("../store/view.js");
var Filt = require("../filt/filt.js");
var common = require("./common.js");
var FlowTable = require("./flowtable.js");
var FlowView = require("./flowview/index.js");
var MainView = React.createClass({
displayName: "MainView",
mixins: [common.Navigation, common.RouterState],
contextTypes: {
flowStore: React.PropTypes.object.isRequired
},
childContextTypes: {
view: React.PropTypes.object.isRequired
},
getChildContext: function getChildContext() {
return {
view: this.state.view
};
},
getInitialState: function getInitialState() {
var sortKeyFun = false;
var view = new views.StoreView(this.context.flowStore, this.getViewFilt(), sortKeyFun);
view.addListener("recalculate", this.onRecalculate);
view.addListener("add", this.onUpdate);
view.addListener("update", this.onUpdate);
view.addListener("remove", this.onUpdate);
view.addListener("remove", this.onRemove);
return {
view: view,
sortKeyFun: sortKeyFun
};
},
componentWillUnmount: function componentWillUnmount() {
this.state.view.close();
},
getViewFilt: function getViewFilt() {
try {
var filt = Filt.parse(this.getQuery()[Query.SEARCH] || "");
var highlightStr = this.getQuery()[Query.HIGHLIGHT];
var highlight = highlightStr ? Filt.parse(highlightStr) : false;
} catch (e) {
console.error("Error when processing filter: " + e);
}
return function filter_and_highlight(flow) {
if (!this._highlight) {
this._highlight = {};
}
this._highlight[flow.id] = highlight && highlight(flow);
return filt(flow);
};
},
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
var filterChanged = this.props.query[Query.SEARCH] !== nextProps.query[Query.SEARCH];
var highlightChanged = this.props.query[Query.HIGHLIGHT] !== nextProps.query[Query.HIGHLIGHT];
if (filterChanged || highlightChanged) {
this.state.view.recalculate(this.getViewFilt(), this.state.sortKeyFun);
}
},
onRecalculate: function onRecalculate() {
this.forceUpdate();
var selected = this.getSelected();
if (selected) {
this.refs.flowTable.scrollIntoView(selected);
}
},
onUpdate: function onUpdate(flow) {
if (flow.id === this.getParams().flowId) {
this.forceUpdate();
}
},
onRemove: function onRemove(flow_id, index) {
if (flow_id === this.getParams().flowId) {
var flow_to_select = this.state.view.list[Math.min(index, this.state.view.list.length - 1)];
this.selectFlow(flow_to_select);
}
},
setSortKeyFun: function setSortKeyFun(sortKeyFun) {
this.setState({
sortKeyFun: sortKeyFun
});
this.state.view.recalculate(this.getViewFilt(), sortKeyFun);
},
selectFlow: function selectFlow(flow) {
if (flow) {
this.replaceWith("flow", {
flowId: flow.id,
detailTab: this.getParams().detailTab || "request"
});
this.refs.flowTable.scrollIntoView(flow);
} else {
this.replaceWith("flows", {});
}
},
selectFlowRelative: function selectFlowRelative(shift) {
var flows = this.state.view.list;
var index;
if (!this.getParams().flowId) {
if (shift < 0) {
index = flows.length - 1;
} else {
index = 0;
}
} else {
var currFlowId = this.getParams().flowId;
var i = flows.length;
while (i--) {
if (flows[i].id === currFlowId) {
index = i;
break;
}
}
index = Math.min(Math.max(0, index + shift), flows.length - 1);
}
this.selectFlow(flows[index]);
},
onMainKeyDown: function onMainKeyDown(e) {
var flow = this.getSelected();
if (e.ctrlKey) {
return;
}
switch (e.keyCode) {
case utils.Key.K:
case utils.Key.UP:
this.selectFlowRelative(-1);
break;
case utils.Key.J:
case utils.Key.DOWN:
this.selectFlowRelative(+1);
break;
case utils.Key.SPACE:
case utils.Key.PAGE_DOWN:
this.selectFlowRelative(+10);
break;
case utils.Key.PAGE_UP:
this.selectFlowRelative(-10);
break;
case utils.Key.END:
this.selectFlowRelative(+1e10);
break;
case utils.Key.HOME:
this.selectFlowRelative(-1e10);
break;
case utils.Key.ESC:
this.selectFlow(null);
break;
case utils.Key.H:
case utils.Key.LEFT:
if (this.refs.flowDetails) {
this.refs.flowDetails.nextTab(-1);
}
break;
case utils.Key.L:
case utils.Key.TAB:
case utils.Key.RIGHT:
if (this.refs.flowDetails) {
this.refs.flowDetails.nextTab(+1);
}
break;
case utils.Key.C:
if (e.shiftKey) {
actions.FlowActions.clear();
}
break;
case utils.Key.D:
if (flow) {
if (e.shiftKey) {
actions.FlowActions.duplicate(flow);
} else {
actions.FlowActions["delete"](flow);
}
}
break;
case utils.Key.A:
if (e.shiftKey) {
actions.FlowActions.accept_all();
} else if (flow && flow.intercepted) {
actions.FlowActions.accept(flow);
}
break;
case utils.Key.R:
if (!e.shiftKey && flow) {
actions.FlowActions.replay(flow);
}
break;
case utils.Key.V:
if (e.shiftKey && flow && flow.modified) {
actions.FlowActions.revert(flow);
}
break;
case utils.Key.E:
if (this.refs.flowDetails) {
this.refs.flowDetails.promptEdit();
}
break;
case utils.Key.SHIFT:
break;
default:
console.debug("keydown", e.keyCode);
return;
}
e.preventDefault();
},
getSelected: function getSelected() {
return this.context.flowStore.get(this.getParams().flowId);
},
render: function render() {
var selected = this.getSelected();
var details;
if (selected) {
details = [React.createElement(common.Splitter, { key: "splitter" }), React.createElement(FlowView, { key: "flowDetails", ref: "flowDetails", flow: selected })];
} else {
details = null;
}
return React.createElement(
"div",
{ className: "main-view" },
React.createElement(FlowTable, { ref: "flowTable",
selectFlow: this.selectFlow,
setSortKeyFun: this.setSortKeyFun,
selected: selected }),
details
);
}
});
module.exports = MainView;
},{"../actions.js":2,"../filt/filt.js":22,"../store/view.js":25,"../utils.js":26,"./common.js":4,"./flowtable.js":8,"./flowview/index.js":11,"react":"react"}],17:[function(require,module,exports){
"use strict";
var React = require("react");
var _ = require("lodash");
var utils = require("../utils.js");
var common = require("./common.js");
var Prompt = React.createClass({
displayName: "Prompt",
mixins: [common.ChildFocus],
propTypes: {
options: React.PropTypes.array.isRequired,
done: React.PropTypes.func.isRequired,
prompt: React.PropTypes.string
},
componentDidMount: function componentDidMount() {
React.findDOMNode(this).focus();
},
onKeyDown: function onKeyDown(e) {
e.stopPropagation();
e.preventDefault();
var opts = this.getOptions();
for (var i = 0; i < opts.length; i++) {
var k = opts[i].key;
if (utils.Key[k.toUpperCase()] === e.keyCode) {
this.done(k);
return;
}
}
if (e.keyCode === utils.Key.ESC || e.keyCode === utils.Key.ENTER) {
this.done(false);
}
},
onClick: function onClick(e) {
this.done(false);
},
done: function done(ret) {
this.props.done(ret);
this.returnFocus();
},
getOptions: function getOptions() {
var opts = [];
var keyTaken = function keyTaken(k) {
return _.includes(_.pluck(opts, "key"), k);
};
for (var i = 0; i < this.props.options.length; i++) {
var opt = this.props.options[i];
if (_.isString(opt)) {
var str = opt;
while (str.length > 0 && keyTaken(str[0])) {
str = str.substr(1);
}
opt = {
text: opt,
key: str[0]
};
}
if (!opt.text || !opt.key || keyTaken(opt.key)) {
throw "invalid options";
} else {
opts.push(opt);
}
}
return opts;
},
render: function render() {
var opts = this.getOptions();
opts = _.map(opts, (function (o) {
var prefix, suffix;
var idx = o.text.indexOf(o.key);
if (idx !== -1) {
prefix = o.text.substring(0, idx);
suffix = o.text.substring(idx + 1);
} else {
prefix = o.text + " (";
suffix = ")";
}
var onClick = (function (e) {
this.done(o.key);
e.stopPropagation();
}).bind(this);
return React.createElement(
"span",
{
key: o.key,
className: "option",
onClick: onClick },
prefix,
React.createElement(
"strong",
{ className: "text-primary" },
o.key
),
suffix
);
}).bind(this));
return React.createElement(
"div",
{ tabIndex: "0", onKeyDown: this.onKeyDown, onClick: this.onClick, className: "prompt-dialog" },
React.createElement(
"div",
{ className: "prompt-content" },
this.props.prompt || React.createElement(
"strong",
null,
"Select: "
),
opts
)
);
}
});
module.exports = Prompt;
},{"../utils.js":26,"./common.js":4,"lodash":"lodash","react":"react"}],18:[function(require,module,exports){
"use strict";
var React = require("react");
var ReactRouter = require("react-router");
var _ = require("lodash");
var common = require("./common.js");
var MainView = require("./mainview.js");
var Footer = require("./footer.js");
var header = require("./header.js");
var EventLog = require("./eventlog.js");
var store = require("../store/store.js");
var Query = require("../actions.js").Query;
var Key = require("../utils.js").Key;
//TODO: Move out of here, just a stub.
var Reports = React.createClass({
displayName: "Reports",
render: function render() {
return React.createElement(
"div",
null,
"ReportEditor"
);
}
});
var ProxyAppMain = React.createClass({
displayName: "ProxyAppMain",
mixins: [common.RouterState],
childContextTypes: {
settingsStore: React.PropTypes.object.isRequired,
flowStore: React.PropTypes.object.isRequired,
eventStore: React.PropTypes.object.isRequired,
returnFocus: React.PropTypes.func.isRequired
},
componentDidMount: function componentDidMount() {
this.focus();
},
getChildContext: function getChildContext() {
return {
settingsStore: this.state.settingsStore,
flowStore: this.state.flowStore,
eventStore: this.state.eventStore,
returnFocus: this.focus
};
},
getInitialState: function getInitialState() {
var eventStore = new store.EventLogStore();
var flowStore = new store.FlowStore();
var settingsStore = new store.SettingsStore();
// Default Settings before fetch
_.extend(settingsStore.dict, {});
return {
settingsStore: settingsStore,
flowStore: flowStore,
eventStore: eventStore
};
},
focus: function focus() {
React.findDOMNode(this).focus();
},
getMainComponent: function getMainComponent() {
return this.refs.view.refs.__routeHandler__;
},
onKeydown: function onKeydown(e) {
var selectFilterInput = (function (name) {
var headerComponent = this.refs.header;
headerComponent.setState({ active: header.MainMenu }, function () {
headerComponent.refs.active.refs[name].select();
});
}).bind(this);
switch (e.keyCode) {
case Key.I:
selectFilterInput("intercept");
break;
case Key.L:
selectFilterInput("search");
break;
case Key.H:
selectFilterInput("highlight");
break;
default:
var main = this.getMainComponent();
if (main.onMainKeyDown) {
main.onMainKeyDown(e);
}
return; // don't prevent default then
}
e.preventDefault();
},
render: function render() {
var eventlog;
if (this.getQuery()[Query.SHOW_EVENTLOG]) {
eventlog = [React.createElement(common.Splitter, { key: "splitter", axis: "y" }), React.createElement(EventLog, { key: "eventlog" })];
} else {
eventlog = null;
}
return React.createElement(
"div",
{ id: "container", tabIndex: "0", onKeyDown: this.onKeydown },
React.createElement(header.Header, { ref: "header" }),
React.createElement(RouteHandler, { ref: "view", query: this.getQuery() }),
eventlog,
React.createElement(Footer, null)
);
}
});
var Route = ReactRouter.Route;
var RouteHandler = ReactRouter.RouteHandler;
var Redirect = ReactRouter.Redirect;
var DefaultRoute = ReactRouter.DefaultRoute;
var NotFoundRoute = ReactRouter.NotFoundRoute;
var routes = React.createElement(
Route,
{ path: "/", handler: ProxyAppMain },
React.createElement(Route, { name: "flows", path: "flows", handler: MainView }),
React.createElement(Route, { name: "flow", path: "flows/:flowId/:detailTab", handler: MainView }),
React.createElement(Route, { name: "reports", handler: Reports }),
React.createElement(Redirect, { path: "/", to: "flows" })
);
module.exports = {
routes: routes
};
},{"../actions.js":2,"../store/store.js":24,"../utils.js":26,"./common.js":4,"./eventlog.js":6,"./footer.js":14,"./header.js":15,"./mainview.js":16,"lodash":"lodash","react":"react","react-router":"react-router"}],19:[function(require,module,exports){
"use strict";
var React = require("react");
var VirtualScrollMixin = {
getInitialState: function getInitialState() {
return {
start: 0,
stop: 0
};
},
componentWillMount: function componentWillMount() {
if (!this.props.rowHeight) {
console.warn("VirtualScrollMixin: No rowHeight specified", this);
}
},
getPlaceholderTop: function getPlaceholderTop(total) {
var Tag = this.props.placeholderTagName || "tr";
// When a large trunk of elements is removed from the button, start may be far off the viewport.
// To make this issue less severe, limit the top placeholder to the total number of rows.
var style = {
height: Math.min(this.state.start, total) * this.props.rowHeight
};
var spacer = React.createElement(Tag, { key: "placeholder-top", style: style });
if (this.state.start % 2 === 1) {
// fix even/odd rows
return [spacer, React.createElement(Tag, { key: "placeholder-top-2" })];
} else {
return spacer;
}
},
getPlaceholderBottom: function getPlaceholderBottom(total) {
var Tag = this.props.placeholderTagName || "tr";
var style = {
height: Math.max(0, total - this.state.stop) * this.props.rowHeight
};
return React.createElement(Tag, { key: "placeholder-bottom", style: style });
},
componentDidMount: function componentDidMount() {
this.onScroll();
window.addEventListener('resize', this.onScroll);
},
componentWillUnmount: function componentWillUnmount() {
window.removeEventListener('resize', this.onScroll);
},
onScroll: function onScroll() {
var viewport = this.getDOMNode();
var top = viewport.scrollTop;
var height = viewport.offsetHeight;
var start = Math.floor(top / this.props.rowHeight);
var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight));
this.setState({
start: start,
stop: stop
});
},
renderRows: function renderRows(elems) {
var rows = [];
var max = Math.min(elems.length, this.state.stop);
for (var i = this.state.start; i < max; i++) {
var elem = elems[i];
rows.push(this.renderRow(elem));
}
return rows;
},
scrollRowIntoView: function scrollRowIntoView(index, head_height) {
var row_top = index * this.props.rowHeight + head_height;
var row_bottom = row_top + this.props.rowHeight;
var viewport = this.getDOMNode();
var viewport_top = viewport.scrollTop;
var viewport_bottom = viewport_top + viewport.offsetHeight;
// Account for pinned thead
if (row_top - head_height < viewport_top) {
viewport.scrollTop = row_top - head_height;
} else if (row_bottom > viewport_bottom) {
viewport.scrollTop = row_bottom - viewport.offsetHeight;
}
}
};
module.exports = VirtualScrollMixin;
},{"react":"react"}],20:[function(require,module,exports){
"use strict";
var actions = require("./actions.js");
var AppDispatcher = require("./dispatcher.js").AppDispatcher;
function Connection(url) {
if (url[0] === "/") {
url = location.origin.replace("http", "ws") + url;
}
var ws = new WebSocket(url);
ws.onopen = function () {
actions.ConnectionActions.open();
};
ws.onmessage = function (message) {
var m = JSON.parse(message.data);
AppDispatcher.dispatchServerAction(m);
};
ws.onerror = function () {
actions.ConnectionActions.error();
actions.EventLogActions.add_event("WebSocket connection error.");
};
ws.onclose = function () {
actions.ConnectionActions.close();
actions.EventLogActions.add_event("WebSocket connection closed.");
};
return ws;
}
module.exports = Connection;
},{"./actions.js":2,"./dispatcher.js":21}],21:[function(require,module,exports){
"use strict";
var flux = require("flux");
var PayloadSources = {
VIEW: "view",
SERVER: "server"
};
var AppDispatcher = new flux.Dispatcher();
AppDispatcher.dispatchViewAction = function (action) {
action.source = PayloadSources.VIEW;
this.dispatch(action);
};
AppDispatcher.dispatchServerAction = function (action) {
action.source = PayloadSources.SERVER;
this.dispatch(action);
};
module.exports = {
AppDispatcher: AppDispatcher
};
},{"flux":"flux"}],22:[function(require,module,exports){
"use strict";
module.exports = (function () {
/*
* Generated by PEG.js 0.8.0.
*
* http://pegjs.majda.cz/
*/
function peg$subclass(child, parent) {
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
}
function SyntaxError(message, expected, found, offset, line, column) {
this.message = message;
this.expected = expected;
this.found = found;
this.offset = offset;
this.line = line;
this.column = column;
this.name = "SyntaxError";
}
peg$subclass(SyntaxError, Error);
function parse(input) {
var options = arguments.length > 1 ? arguments[1] : {},
peg$FAILED = {},
peg$startRuleFunctions = { start: peg$parsestart },
peg$startRuleFunction = peg$parsestart,
peg$c0 = { type: "other", description: "filter expression" },
peg$c1 = peg$FAILED,
peg$c2 = function peg$c2(orExpr) {
return orExpr;
},
peg$c3 = [],
peg$c4 = function peg$c4() {
return trueFilter;
},
peg$c5 = { type: "other", description: "whitespace" },
peg$c6 = /^[ \t\n\r]/,
peg$c7 = { type: "class", value: "[ \\t\\n\\r]", description: "[ \\t\\n\\r]" },
peg$c8 = { type: "other", description: "control character" },
peg$c9 = /^[|&!()~"]/,
peg$c10 = { type: "class", value: "[|&!()~\"]", description: "[|&!()~\"]" },
peg$c11 = { type: "other", description: "optional whitespace" },
peg$c12 = "|",
peg$c13 = { type: "literal", value: "|", description: "\"|\"" },
peg$c14 = function peg$c14(first, second) {
return or(first, second);
},
peg$c15 = "&",
peg$c16 = { type: "literal", value: "&", description: "\"&\"" },
peg$c17 = function peg$c17(first, second) {
return and(first, second);
},
peg$c18 = "!",
peg$c19 = { type: "literal", value: "!", description: "\"!\"" },
peg$c20 = function peg$c20(expr) {
return not(expr);
},
peg$c21 = "(",
peg$c22 = { type: "literal", value: "(", description: "\"(\"" },
peg$c23 = ")",
peg$c24 = { type: "literal", value: ")", description: "\")\"" },
peg$c25 = function peg$c25(expr) {
return binding(expr);
},
peg$c26 = "~a",
peg$c27 = { type: "literal", value: "~a", description: "\"~a\"" },
peg$c28 = function peg$c28() {
return assetFilter;
},
peg$c29 = "~e",
peg$c30 = { type: "literal", value: "~e", description: "\"~e\"" },
peg$c31 = function peg$c31() {
return errorFilter;
},
peg$c32 = "~q",
peg$c33 = { type: "literal", value: "~q", description: "\"~q\"" },
peg$c34 = function peg$c34() {
return noResponseFilter;
},
peg$c35 = "~s",
peg$c36 = { type: "literal", value: "~s", description: "\"~s\"" },
peg$c37 = function peg$c37() {
return responseFilter;
},
peg$c38 = "true",
peg$c39 = { type: "literal", value: "true", description: "\"true\"" },
peg$c40 = function peg$c40() {
return trueFilter;
},
peg$c41 = "false",
peg$c42 = { type: "literal", value: "false", description: "\"false\"" },
peg$c43 = function peg$c43() {
return falseFilter;
},
peg$c44 = "~c",
peg$c45 = { type: "literal", value: "~c", description: "\"~c\"" },
peg$c46 = function peg$c46(s) {
return responseCode(s);
},
peg$c47 = "~d",
peg$c48 = { type: "literal", value: "~d", description: "\"~d\"" },
peg$c49 = function peg$c49(s) {
return domain(s);
},
peg$c50 = "~h",
peg$c51 = { type: "literal", value: "~h", description: "\"~h\"" },
peg$c52 = function peg$c52(s) {
return header(s);
},
peg$c53 = "~hq",
peg$c54 = { type: "literal", value: "~hq", description: "\"~hq\"" },
peg$c55 = function peg$c55(s) {
return requestHeader(s);
},
peg$c56 = "~hs",
peg$c57 = { type: "literal", value: "~hs", description: "\"~hs\"" },
peg$c58 = function peg$c58(s) {
return responseHeader(s);
},
peg$c59 = "~m",
peg$c60 = { type: "literal", value: "~m", description: "\"~m\"" },
peg$c61 = function peg$c61(s) {
return method(s);
},
peg$c62 = "~t",
peg$c63 = { type: "literal", value: "~t", description: "\"~t\"" },
peg$c64 = function peg$c64(s) {
return contentType(s);
},
peg$c65 = "~tq",
peg$c66 = { type: "literal", value: "~tq", description: "\"~tq\"" },
peg$c67 = function peg$c67(s) {
return requestContentType(s);
},
peg$c68 = "~ts",
peg$c69 = { type: "literal", value: "~ts", description: "\"~ts\"" },
peg$c70 = function peg$c70(s) {
return responseContentType(s);
},
peg$c71 = "~u",
peg$c72 = { type: "literal", value: "~u", description: "\"~u\"" },
peg$c73 = function peg$c73(s) {
return url(s);
},
peg$c74 = { type: "other", description: "integer" },
peg$c75 = null,
peg$c76 = /^['"]/,
peg$c77 = { type: "class", value: "['\"]", description: "['\"]" },
peg$c78 = /^[0-9]/,
peg$c79 = { type: "class", value: "[0-9]", description: "[0-9]" },
peg$c80 = function peg$c80(digits) {
return parseInt(digits.join(""), 10);
},
peg$c81 = { type: "other", description: "string" },
peg$c82 = "\"",
peg$c83 = { type: "literal", value: "\"", description: "\"\\\"\"" },
peg$c84 = function peg$c84(chars) {
return chars.join("");
},
peg$c85 = "'",
peg$c86 = { type: "literal", value: "'", description: "\"'\"" },
peg$c87 = void 0,
peg$c88 = /^["\\]/,
peg$c89 = { type: "class", value: "[\"\\\\]", description: "[\"\\\\]" },
peg$c90 = { type: "any", description: "any character" },
peg$c91 = function peg$c91(char) {
return char;
},
peg$c92 = "\\",
peg$c93 = { type: "literal", value: "\\", description: "\"\\\\\"" },
peg$c94 = /^['\\]/,
peg$c95 = { type: "class", value: "['\\\\]", description: "['\\\\]" },
peg$c96 = /^['"\\]/,
peg$c97 = { type: "class", value: "['\"\\\\]", description: "['\"\\\\]" },
peg$c98 = "n",
peg$c99 = { type: "literal", value: "n", description: "\"n\"" },
peg$c100 = function peg$c100() {
return "\n";
},
peg$c101 = "r",
peg$c102 = { type: "literal", value: "r", description: "\"r\"" },
peg$c103 = function peg$c103() {
return "\r";
},
peg$c104 = "t",
peg$c105 = { type: "literal", value: "t", description: "\"t\"" },
peg$c106 = function peg$c106() {
return "\t";
},
peg$currPos = 0,
peg$reportedPos = 0,
peg$cachedPos = 0,
peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
peg$maxFailPos = 0,
peg$maxFailExpected = [],
peg$silentFails = 0,
peg$result;
if ("startRule" in options) {
if (!(options.startRule in peg$startRuleFunctions)) {
throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
}
peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
}
function text() {
return input.substring(peg$reportedPos, peg$currPos);
}
function offset() {
return peg$reportedPos;
}
function line() {
return peg$computePosDetails(peg$reportedPos).line;
}
function column() {
return peg$computePosDetails(peg$reportedPos).column;
}
function expected(description) {
throw peg$buildException(null, [{ type: "other", description: description }], peg$reportedPos);
}
function error(message) {
throw peg$buildException(message, null, peg$reportedPos);
}
function peg$computePosDetails(pos) {
function advance(details, startPos, endPos) {
var p, ch;
for (p = startPos; p < endPos; p++) {
ch = input.charAt(p);
if (ch === "\n") {
if (!details.seenCR) {
details.line++;
}
details.column = 1;
details.seenCR = false;
} else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
details.line++;
details.column = 1;
details.seenCR = true;
} else {
details.column++;
details.seenCR = false;
}
}
}
if (peg$cachedPos !== pos) {
if (peg$cachedPos > pos) {
peg$cachedPos = 0;
peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
}
advance(peg$cachedPosDetails, peg$cachedPos, pos);
peg$cachedPos = pos;
}
return peg$cachedPosDetails;
}
function peg$fail(expected) {
if (peg$currPos < peg$maxFailPos) {
return;
}
if (peg$currPos > peg$maxFailPos) {
peg$maxFailPos = peg$currPos;
peg$maxFailExpected = [];
}
peg$maxFailExpected.push(expected);
}
function peg$buildException(message, expected, pos) {
function cleanupExpected(expected) {
var i = 1;
expected.sort(function (a, b) {
if (a.description < b.description) {
return -1;
} else if (a.description > b.description) {
return 1;
} else {
return 0;
}
});
while (i < expected.length) {
if (expected[i - 1] === expected[i]) {
expected.splice(i, 1);
} else {
i++;
}
}
}
function buildMessage(expected, found) {
function stringEscape(s) {
function hex(ch) {
return ch.charCodeAt(0).toString(16).toUpperCase();
}
return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\x08/g, '\\b').replace(/\t/g, '\\t').replace(/\n/g, '\\n').replace(/\f/g, '\\f').replace(/\r/g, '\\r').replace(/[\x00-\x07\x0B\x0E\x0F]/g, function (ch) {
return '\\x0' + hex(ch);
}).replace(/[\x10-\x1F\x80-\xFF]/g, function (ch) {
return '\\x' + hex(ch);
}).replace(/[\u0180-\u0FFF]/g, function (ch) {
return "\\u0" + hex(ch);
}).replace(/[\u1080-\uFFFF]/g, function (ch) {
return "\\u" + hex(ch);
});
}
var expectedDescs = new Array(expected.length),
expectedDesc,
foundDesc,
i;
for (i = 0; i < expected.length; i++) {
expectedDescs[i] = expected[i].description;
}
expectedDesc = expected.length > 1 ? expectedDescs.slice(0, -1).join(", ") + " or " + expectedDescs[expected.length - 1] : expectedDescs[0];
foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
return "Expected " + expectedDesc + " but " + foundDesc + " found.";
}
var posDetails = peg$computePosDetails(pos),
found = pos < input.length ? input.charAt(pos) : null;
if (expected !== null) {
cleanupExpected(expected);
}
return new SyntaxError(message !== null ? message : buildMessage(expected, found), expected, found, pos, posDetails.line, posDetails.column);
}
function peg$parsestart() {
var s0, s1, s2, s3;
peg$silentFails++;
s0 = peg$currPos;
s1 = peg$parse__();
if (s1 !== peg$FAILED) {
s2 = peg$parseOrExpr();
if (s2 !== peg$FAILED) {
s3 = peg$parse__();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c2(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
s1 = [];
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c4();
}
s0 = s1;
}
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c0);
}
}
return s0;
}
function peg$parsews() {
var s0, s1;
peg$silentFails++;
if (peg$c6.test(input.charAt(peg$currPos))) {
s0 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s0 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c7);
}
}
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c5);
}
}
return s0;
}
function peg$parsecc() {
var s0, s1;
peg$silentFails++;
if (peg$c9.test(input.charAt(peg$currPos))) {
s0 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s0 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c10);
}
}
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c8);
}
}
return s0;
}
function peg$parse__() {
var s0, s1;
peg$silentFails++;
s0 = [];
s1 = peg$parsews();
while (s1 !== peg$FAILED) {
s0.push(s1);
s1 = peg$parsews();
}
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c11);
}
}
return s0;
}
function peg$parseOrExpr() {
var s0, s1, s2, s3, s4, s5;
s0 = peg$currPos;
s1 = peg$parseAndExpr();
if (s1 !== peg$FAILED) {
s2 = peg$parse__();
if (s2 !== peg$FAILED) {
if (input.charCodeAt(peg$currPos) === 124) {
s3 = peg$c12;
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c13);
}
}
if (s3 !== peg$FAILED) {
s4 = peg$parse__();
if (s4 !== peg$FAILED) {
s5 = peg$parseOrExpr();
if (s5 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c14(s1, s5);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$parseAndExpr();
}
return s0;
}
function peg$parseAndExpr() {
var s0, s1, s2, s3, s4, s5;
s0 = peg$currPos;
s1 = peg$parseNotExpr();
if (s1 !== peg$FAILED) {
s2 = peg$parse__();
if (s2 !== peg$FAILED) {
if (input.charCodeAt(peg$currPos) === 38) {
s3 = peg$c15;
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c16);
}
}
if (s3 !== peg$FAILED) {
s4 = peg$parse__();
if (s4 !== peg$FAILED) {
s5 = peg$parseAndExpr();
if (s5 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c17(s1, s5);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
s1 = peg$parseNotExpr();
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseAndExpr();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c17(s1, s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$parseNotExpr();
}
}
return s0;
}
function peg$parseNotExpr() {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 33) {
s1 = peg$c18;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c19);
}
}
if (s1 !== peg$FAILED) {
s2 = peg$parse__();
if (s2 !== peg$FAILED) {
s3 = peg$parseNotExpr();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c20(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$parseBindingExpr();
}
return s0;
}
function peg$parseBindingExpr() {
var s0, s1, s2, s3, s4, s5;
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 40) {
s1 = peg$c21;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c22);
}
}
if (s1 !== peg$FAILED) {
s2 = peg$parse__();
if (s2 !== peg$FAILED) {
s3 = peg$parseOrExpr();
if (s3 !== peg$FAILED) {
s4 = peg$parse__();
if (s4 !== peg$FAILED) {
if (input.charCodeAt(peg$currPos) === 41) {
s5 = peg$c23;
peg$currPos++;
} else {
s5 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c24);
}
}
if (s5 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c25(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$parseExpr();
}
return s0;
}
function peg$parseExpr() {
var s0;
s0 = peg$parseNullaryExpr();
if (s0 === peg$FAILED) {
s0 = peg$parseUnaryExpr();
}
return s0;
}
function peg$parseNullaryExpr() {
var s0, s1;
s0 = peg$parseBooleanLiteral();
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c26) {
s1 = peg$c26;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c27);
}
}
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c28();
}
s0 = s1;
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c29) {
s1 = peg$c29;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c30);
}
}
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c31();
}
s0 = s1;
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c32) {
s1 = peg$c32;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c33);
}
}
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c34();
}
s0 = s1;
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c35) {
s1 = peg$c35;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c36);
}
}
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c37();
}
s0 = s1;
}
}
}
}
return s0;
}
function peg$parseBooleanLiteral() {
var s0, s1;
s0 = peg$currPos;
if (input.substr(peg$currPos, 4) === peg$c38) {
s1 = peg$c38;
peg$currPos += 4;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c39);
}
}
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c40();
}
s0 = s1;
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 5) === peg$c41) {
s1 = peg$c41;
peg$currPos += 5;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c42);
}
}
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c43();
}
s0 = s1;
}
return s0;
}
function peg$parseUnaryExpr() {
var s0, s1, s2, s3;
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c44) {
s1 = peg$c44;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c45);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseIntegerLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c46(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c47) {
s1 = peg$c47;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c48);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseStringLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c49(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c50) {
s1 = peg$c50;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c51);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseStringLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c52(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 3) === peg$c53) {
s1 = peg$c53;
peg$currPos += 3;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c54);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseStringLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c55(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 3) === peg$c56) {
s1 = peg$c56;
peg$currPos += 3;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c57);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseStringLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c58(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c59) {
s1 = peg$c59;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c60);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseStringLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c61(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c62) {
s1 = peg$c62;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c63);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseStringLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c64(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 3) === peg$c65) {
s1 = peg$c65;
peg$currPos += 3;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c66);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseStringLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c67(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 3) === peg$c68) {
s1 = peg$c68;
peg$currPos += 3;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c69);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseStringLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c70(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.substr(peg$currPos, 2) === peg$c71) {
s1 = peg$c71;
peg$currPos += 2;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c72);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parsews();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parsews();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
s3 = peg$parseStringLiteral();
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c73(s3);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
s1 = peg$parseStringLiteral();
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c73(s1);
}
s0 = s1;
}
}
}
}
}
}
}
}
}
}
return s0;
}
function peg$parseIntegerLiteral() {
var s0, s1, s2, s3;
peg$silentFails++;
s0 = peg$currPos;
if (peg$c76.test(input.charAt(peg$currPos))) {
s1 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c77);
}
}
if (s1 === peg$FAILED) {
s1 = peg$c75;
}
if (s1 !== peg$FAILED) {
s2 = [];
if (peg$c78.test(input.charAt(peg$currPos))) {
s3 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c79);
}
}
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
if (peg$c78.test(input.charAt(peg$currPos))) {
s3 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c79);
}
}
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
if (peg$c76.test(input.charAt(peg$currPos))) {
s3 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c77);
}
}
if (s3 === peg$FAILED) {
s3 = peg$c75;
}
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c80(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c74);
}
}
return s0;
}
function peg$parseStringLiteral() {
var s0, s1, s2, s3;
peg$silentFails++;
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 34) {
s1 = peg$c82;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c83);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parseDoubleStringChar();
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parseDoubleStringChar();
}
if (s2 !== peg$FAILED) {
if (input.charCodeAt(peg$currPos) === 34) {
s3 = peg$c82;
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c83);
}
}
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c84(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 39) {
s1 = peg$c85;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c86);
}
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parseSingleStringChar();
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parseSingleStringChar();
}
if (s2 !== peg$FAILED) {
if (input.charCodeAt(peg$currPos) === 39) {
s3 = peg$c85;
peg$currPos++;
} else {
s3 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c86);
}
}
if (s3 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c84(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
s1 = peg$currPos;
peg$silentFails++;
s2 = peg$parsecc();
peg$silentFails--;
if (s2 === peg$FAILED) {
s1 = peg$c87;
} else {
peg$currPos = s1;
s1 = peg$c1;
}
if (s1 !== peg$FAILED) {
s2 = [];
s3 = peg$parseUnquotedStringChar();
if (s3 !== peg$FAILED) {
while (s3 !== peg$FAILED) {
s2.push(s3);
s3 = peg$parseUnquotedStringChar();
}
} else {
s2 = peg$c1;
}
if (s2 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c84(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
}
}
peg$silentFails--;
if (s0 === peg$FAILED) {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c81);
}
}
return s0;
}
function peg$parseDoubleStringChar() {
var s0, s1, s2;
s0 = peg$currPos;
s1 = peg$currPos;
peg$silentFails++;
if (peg$c88.test(input.charAt(peg$currPos))) {
s2 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c89);
}
}
peg$silentFails--;
if (s2 === peg$FAILED) {
s1 = peg$c87;
} else {
peg$currPos = s1;
s1 = peg$c1;
}
if (s1 !== peg$FAILED) {
if (input.length > peg$currPos) {
s2 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c90);
}
}
if (s2 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c91(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 92) {
s1 = peg$c92;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c93);
}
}
if (s1 !== peg$FAILED) {
s2 = peg$parseEscapeSequence();
if (s2 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c91(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
}
return s0;
}
function peg$parseSingleStringChar() {
var s0, s1, s2;
s0 = peg$currPos;
s1 = peg$currPos;
peg$silentFails++;
if (peg$c94.test(input.charAt(peg$currPos))) {
s2 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c95);
}
}
peg$silentFails--;
if (s2 === peg$FAILED) {
s1 = peg$c87;
} else {
peg$currPos = s1;
s1 = peg$c1;
}
if (s1 !== peg$FAILED) {
if (input.length > peg$currPos) {
s2 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c90);
}
}
if (s2 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c91(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 92) {
s1 = peg$c92;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c93);
}
}
if (s1 !== peg$FAILED) {
s2 = peg$parseEscapeSequence();
if (s2 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c91(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
}
return s0;
}
function peg$parseUnquotedStringChar() {
var s0, s1, s2;
s0 = peg$currPos;
s1 = peg$currPos;
peg$silentFails++;
s2 = peg$parsews();
peg$silentFails--;
if (s2 === peg$FAILED) {
s1 = peg$c87;
} else {
peg$currPos = s1;
s1 = peg$c1;
}
if (s1 !== peg$FAILED) {
if (input.length > peg$currPos) {
s2 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c90);
}
}
if (s2 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c91(s2);
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$c1;
}
} else {
peg$currPos = s0;
s0 = peg$c1;
}
return s0;
}
function peg$parseEscapeSequence() {
var s0, s1;
if (peg$c96.test(input.charAt(peg$currPos))) {
s0 = input.charAt(peg$currPos);
peg$currPos++;
} else {
s0 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c97);
}
}
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 110) {
s1 = peg$c98;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c99);
}
}
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c100();
}
s0 = s1;
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 114) {
s1 = peg$c101;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c102);
}
}
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c103();
}
s0 = s1;
if (s0 === peg$FAILED) {
s0 = peg$currPos;
if (input.charCodeAt(peg$currPos) === 116) {
s1 = peg$c104;
peg$currPos++;
} else {
s1 = peg$FAILED;
if (peg$silentFails === 0) {
peg$fail(peg$c105);
}
}
if (s1 !== peg$FAILED) {
peg$reportedPos = s0;
s1 = peg$c106();
}
s0 = s1;
}
}
}
return s0;
}
var flowutils = require("../flow/utils.js");
function or(first, second) {
// Add explicit function names to ease debugging.
function orFilter() {
return first.apply(this, arguments) || second.apply(this, arguments);
}
orFilter.desc = first.desc + " or " + second.desc;
return orFilter;
}
function and(first, second) {
function andFilter() {
return first.apply(this, arguments) && second.apply(this, arguments);
}
andFilter.desc = first.desc + " and " + second.desc;
return andFilter;
}
function not(expr) {
function notFilter() {
return !expr.apply(this, arguments);
}
notFilter.desc = "not " + expr.desc;
return notFilter;
}
function binding(expr) {
function bindingFilter() {
return expr.apply(this, arguments);
}
bindingFilter.desc = "(" + expr.desc + ")";
return bindingFilter;
}
function trueFilter(flow) {
return true;
}
trueFilter.desc = "true";
function falseFilter(flow) {
return false;
}
falseFilter.desc = "false";
var ASSET_TYPES = [new RegExp("text/javascript"), new RegExp("application/x-javascript"), new RegExp("application/javascript"), new RegExp("text/css"), new RegExp("image/.*"), new RegExp("application/x-shockwave-flash")];
function assetFilter(flow) {
if (flow.response) {
var ct = flowutils.ResponseUtils.getContentType(flow.response);
var i = ASSET_TYPES.length;
while (i--) {
if (ASSET_TYPES[i].test(ct)) {
return true;
}
}
}
return false;
}
assetFilter.desc = "is asset";
function responseCode(code) {
function responseCodeFilter(flow) {
return flow.response && flow.response.status_code === code;
}
responseCodeFilter.desc = "resp. code is " + code;
return responseCodeFilter;
}
function domain(regex) {
regex = new RegExp(regex, "i");
function domainFilter(flow) {
return flow.request && regex.test(flow.request.host);
}
domainFilter.desc = "domain matches " + regex;
return domainFilter;
}
function errorFilter(flow) {
return !!flow.error;
}
errorFilter.desc = "has error";
function header(regex) {
regex = new RegExp(regex, "i");
function headerFilter(flow) {
return flow.request && flowutils.RequestUtils.match_header(flow.request, regex) || flow.response && flowutils.ResponseUtils.match_header(flow.response, regex);
}
headerFilter.desc = "header matches " + regex;
return headerFilter;
}
function requestHeader(regex) {
regex = new RegExp(regex, "i");
function requestHeaderFilter(flow) {
return flow.request && flowutils.RequestUtils.match_header(flow.request, regex);
}
requestHeaderFilter.desc = "req. header matches " + regex;
return requestHeaderFilter;
}
function responseHeader(regex) {
regex = new RegExp(regex, "i");
function responseHeaderFilter(flow) {
return flow.response && flowutils.ResponseUtils.match_header(flow.response, regex);
}
responseHeaderFilter.desc = "resp. header matches " + regex;
return responseHeaderFilter;
}
function method(regex) {
regex = new RegExp(regex, "i");
function methodFilter(flow) {
return flow.request && regex.test(flow.request.method);
}
methodFilter.desc = "method matches " + regex;
return methodFilter;
}
function noResponseFilter(flow) {
return flow.request && !flow.response;
}
noResponseFilter.desc = "has no response";
function responseFilter(flow) {
return !!flow.response;
}
responseFilter.desc = "has response";
function contentType(regex) {
regex = new RegExp(regex, "i");
function contentTypeFilter(flow) {
return flow.request && regex.test(flowutils.RequestUtils.getContentType(flow.request)) || flow.response && regex.test(flowutils.ResponseUtils.getContentType(flow.response));
}
contentTypeFilter.desc = "content type matches " + regex;
return contentTypeFilter;
}
function requestContentType(regex) {
regex = new RegExp(regex, "i");
function requestContentTypeFilter(flow) {
return flow.request && regex.test(flowutils.RequestUtils.getContentType(flow.request));
}
requestContentTypeFilter.desc = "req. content type matches " + regex;
return requestContentTypeFilter;
}
function responseContentType(regex) {
regex = new RegExp(regex, "i");
function responseContentTypeFilter(flow) {
return flow.response && regex.test(flowutils.ResponseUtils.getContentType(flow.response));
}
responseContentTypeFilter.desc = "resp. content type matches " + regex;
return responseContentTypeFilter;
}
function url(regex) {
regex = new RegExp(regex, "i");
function urlFilter(flow) {
return flow.request && regex.test(flowutils.RequestUtils.pretty_url(flow.request));
}
urlFilter.desc = "url matches " + regex;
return urlFilter;
}
peg$result = peg$startRuleFunction();
if (peg$result !== peg$FAILED && peg$currPos === input.length) {
return peg$result;
} else {
if (peg$result !== peg$FAILED && peg$currPos < input.length) {
peg$fail({ type: "end", description: "end of input" });
}
throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
}
}
return {
SyntaxError: SyntaxError,
parse: parse
};
})();
},{"../flow/utils.js":23}],23:[function(require,module,exports){
"use strict";
var _ = require("lodash");
var $ = require("jquery");
var defaultPorts = {
"http": 80,
"https": 443
};
var MessageUtils = {
getContentType: function getContentType(message) {
var ct = this.get_first_header(message, /^Content-Type$/i);
if (ct) {
return ct.split(";")[0].trim();
}
},
get_first_header: function get_first_header(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];
},
match_header: function match_header(message, regex) {
var headers = message.headers;
var i = headers.length;
while (i--) {
if (regex.test(headers[i].join(" "))) {
return headers[i];
}
}
return false;
},
getContentURL: function getContentURL(flow, message) {
if (message === flow.request) {
message = "request";
} else if (message === flow.response) {
message = "response";
}
return "/flows/" + flow.id + "/" + message + "/content";
},
getContent: function getContent(flow, message) {
var url = MessageUtils.getContentURL(flow, message);
return $.get(url);
}
};
var RequestUtils = _.extend(MessageUtils, {
pretty_host: function pretty_host(request) {
//FIXME: Add hostheader
return request.host;
},
pretty_url: function pretty_url(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, {});
var parseUrl_regex = /^(?:(https?):\/\/)?([^\/:]+)?(?::(\d+))?(\/.*)?$/i;
var parseUrl = function parseUrl(url) {
//there are many correct ways to parse a URL,
//however, a mitmproxy user may also wish to generate a not-so-correct URL. ;-)
var parts = parseUrl_regex.exec(url);
if (!parts) {
return false;
}
var scheme = parts[1],
host = parts[2],
port = parseInt(parts[3]),
path = parts[4];
if (scheme) {
port = port || defaultPorts[scheme];
}
var ret = {};
if (scheme) {
ret.scheme = scheme;
}
if (host) {
ret.host = host;
}
if (port) {
ret.port = port;
}
if (path) {
ret.path = path;
}
return ret;
};
var isValidHttpVersion_regex = /^HTTP\/\d+(\.\d+)*$/i;
var isValidHttpVersion = function isValidHttpVersion(httpVersion) {
return isValidHttpVersion_regex.test(httpVersion);
};
var parseHttpVersion = function parseHttpVersion(httpVersion) {
httpVersion = httpVersion.replace("HTTP/", "").split(".");
return _.map(httpVersion, function (x) {
return parseInt(x);
});
};
module.exports = {
ResponseUtils: ResponseUtils,
RequestUtils: RequestUtils,
MessageUtils: MessageUtils,
parseUrl: parseUrl,
parseHttpVersion: parseHttpVersion,
isValidHttpVersion: isValidHttpVersion
};
},{"jquery":"jquery","lodash":"lodash"}],24:[function(require,module,exports){
"use strict";
var _ = require("lodash");
var $ = require("jquery");
var EventEmitter = require('events').EventEmitter;
var utils = require("../utils.js");
var actions = require("../actions.js");
var dispatcher = require("../dispatcher.js");
function ListStore() {
EventEmitter.call(this);
this.reset();
}
_.extend(ListStore.prototype, EventEmitter.prototype, {
add: function add(elem) {
if (elem.id in this._pos_map) {
return;
}
this._pos_map[elem.id] = this.list.length;
this.list.push(elem);
this.emit("add", elem);
},
update: function update(elem) {
if (!(elem.id in this._pos_map)) {
return;
}
this.list[this._pos_map[elem.id]] = elem;
this.emit("update", elem);
},
remove: function remove(elem_id) {
if (!(elem_id in this._pos_map)) {
return;
}
this.list.splice(this._pos_map[elem_id], 1);
this._build_map();
this.emit("remove", elem_id);
},
reset: function reset(elems) {
this.list = elems || [];
this._build_map();
this.emit("recalculate");
},
_build_map: function _build_map() {
this._pos_map = {};
for (var i = 0; i < this.list.length; i++) {
var elem = this.list[i];
this._pos_map[elem.id] = i;
}
},
get: function get(elem_id) {
return this.list[this._pos_map[elem_id]];
},
index: function index(elem_id) {
return this._pos_map[elem_id];
}
});
function DictStore() {
EventEmitter.call(this);
this.reset();
}
_.extend(DictStore.prototype, EventEmitter.prototype, {
update: function update(dict) {
_.merge(this.dict, dict);
this.emit("recalculate");
},
reset: function reset(dict) {
this.dict = dict || {};
this.emit("recalculate");
}
});
function LiveStoreMixin(type) {
this.type = type;
this._updates_before_fetch = undefined;
this._fetchxhr = false;
this.handle = this.handle.bind(this);
dispatcher.AppDispatcher.register(this.handle);
// Avoid double-fetch on startup.
if (!(window.ws && window.ws.readyState === WebSocket.CONNECTING)) {
this.fetch();
}
}
_.extend(LiveStoreMixin.prototype, {
handle: function handle(event) {
if (event.type === actions.ActionTypes.CONNECTION_OPEN) {
return this.fetch();
}
if (event.type === this.type) {
if (event.cmd === actions.StoreCmds.RESET) {
this.fetch(event.data);
} else if (this._updates_before_fetch) {
console.log("defer update", event);
this._updates_before_fetch.push(event);
} else {
this[event.cmd](event.data);
}
}
},
close: function close() {
dispatcher.AppDispatcher.unregister(this.handle);
},
fetch: function fetch(data) {
console.log("fetch " + this.type);
if (this._fetchxhr) {
this._fetchxhr.abort();
}
this._updates_before_fetch = []; // (JS: empty array is true)
if (data) {
this.handle_fetch(data);
} else {
this._fetchxhr = $.getJSON("/" + this.type).done((function (message) {
this.handle_fetch(message.data);
}).bind(this)).fail((function () {
EventLogActions.add_event("Could not fetch " + this.type);
}).bind(this));
}
},
handle_fetch: function handle_fetch(data) {
this._fetchxhr = false;
console.log(this.type + " fetched.", this._updates_before_fetch);
this.reset(data);
var updates = this._updates_before_fetch;
this._updates_before_fetch = false;
for (var i = 0; i < updates.length; i++) {
this.handle(updates[i]);
}
}
});
function LiveListStore(type) {
ListStore.call(this);
LiveStoreMixin.call(this, type);
}
_.extend(LiveListStore.prototype, ListStore.prototype, LiveStoreMixin.prototype);
function LiveDictStore(type) {
DictStore.call(this);
LiveStoreMixin.call(this, type);
}
_.extend(LiveDictStore.prototype, DictStore.prototype, LiveStoreMixin.prototype);
function FlowStore() {
return new LiveListStore(actions.ActionTypes.FLOW_STORE);
}
function SettingsStore() {
return new LiveDictStore(actions.ActionTypes.SETTINGS_STORE);
}
function EventLogStore() {
LiveListStore.call(this, actions.ActionTypes.EVENT_STORE);
}
_.extend(EventLogStore.prototype, LiveListStore.prototype, {
fetch: function fetch() {
LiveListStore.prototype.fetch.apply(this, arguments);
// Make sure to display updates even if fetching all events failed.
// This way, we can send "fetch failed" log messages to the log.
if (this._fetchxhr) {
this._fetchxhr.fail((function () {
this.handle_fetch(null);
}).bind(this));
}
}
});
module.exports = {
EventLogStore: EventLogStore,
SettingsStore: SettingsStore,
FlowStore: FlowStore
};
},{"../actions.js":2,"../dispatcher.js":21,"../utils.js":26,"events":1,"jquery":"jquery","lodash":"lodash"}],25:[function(require,module,exports){
"use strict";
var EventEmitter = require('events').EventEmitter;
var _ = require("lodash");
var utils = require("../utils.js");
function SortByStoreOrder(elem) {
return this.store.index(elem.id);
}
var default_sort = SortByStoreOrder;
var default_filt = function default_filt(elem) {
return true;
};
function StoreView(store, filt, sortfun) {
EventEmitter.call(this);
this.store = store;
this.add = this.add.bind(this);
this.update = this.update.bind(this);
this.remove = this.remove.bind(this);
this.recalculate = this.recalculate.bind(this);
this.store.addListener("add", this.add);
this.store.addListener("update", this.update);
this.store.addListener("remove", this.remove);
this.store.addListener("recalculate", this.recalculate);
this.recalculate(filt, sortfun);
}
_.extend(StoreView.prototype, EventEmitter.prototype, {
close: function close() {
this.store.removeListener("add", this.add);
this.store.removeListener("update", this.update);
this.store.removeListener("remove", this.remove);
this.store.removeListener("recalculate", this.recalculate);
this.removeAllListeners();
},
recalculate: function recalculate(filt, sortfun) {
filt = filt || this.filt || default_filt;
sortfun = sortfun || this.sortfun || default_sort;
filt = filt.bind(this);
sortfun = sortfun.bind(this);
this.filt = filt;
this.sortfun = sortfun;
this.list = this.store.list.filter(filt);
this.list.sort(function (a, b) {
var akey = sortfun(a);
var bkey = sortfun(b);
if (akey < bkey) {
return -1;
} else if (akey > bkey) {
return 1;
} else {
return 0;
}
});
this.emit("recalculate");
},
index: function index(elem) {
return _.sortedIndex(this.list, elem, this.sortfun);
},
add: function add(elem) {
if (this.filt(elem)) {
var idx = this.index(elem);
if (idx === this.list.length) {
//happens often, .push is way faster.
this.list.push(elem);
} else {
this.list.splice(idx, 0, elem);
}
this.emit("add", elem, idx);
}
},
update: function update(elem) {
var idx;
var i = this.list.length;
// Search from the back, we usually update the latest entries.
while (i--) {
if (this.list[i].id === elem.id) {
idx = i;
break;
}
}
if (idx === -1) {
//not contained in list
this.add(elem);
} else if (!this.filt(elem)) {
this.remove(elem.id);
} else {
if (this.sortfun(this.list[idx]) !== this.sortfun(elem)) {
//sortpos has changed
this.remove(this.list[idx]);
this.add(elem);
} else {
this.list[idx] = elem;
this.emit("update", elem, idx);
}
}
},
remove: function remove(elem_id) {
var idx = this.list.length;
while (idx--) {
if (this.list[idx].id === elem_id) {
this.list.splice(idx, 1);
this.emit("remove", elem_id, idx);
break;
}
}
}
});
module.exports = {
StoreView: StoreView
};
},{"../utils.js":26,"events":1,"lodash":"lodash"}],26:[function(require,module,exports){
"use strict";
var $ = require("jquery");
var _ = require("lodash");
var actions = require("./actions.js");
window.$ = $;
window._ = _;
window.React = require("react");
var Key = {
UP: 38,
DOWN: 40,
PAGE_UP: 33,
PAGE_DOWN: 34,
HOME: 36,
END: 35,
LEFT: 37,
RIGHT: 39,
ENTER: 13,
ESC: 27,
TAB: 9,
SPACE: 32,
BACKSPACE: 8,
SHIFT: 16
};
// Add A-Z
for (var i = 65; i <= 90; i++) {
Key[String.fromCharCode(i)] = i;
}
var formatSize = function formatSize(bytes) {
if (bytes === 0) return "0";
var prefix = ["b", "kb", "mb", "gb", "tb"];
for (var i = 0; i < prefix.length; i++) {
if (Math.pow(1024, i + 1) > bytes) {
break;
}
}
var precision;
if (bytes % Math.pow(1024, i) === 0) precision = 0;else precision = 1;
return (bytes / Math.pow(1024, i)).toFixed(precision) + prefix[i];
};
var formatTimeDelta = function formatTimeDelta(milliseconds) {
var time = milliseconds;
var prefix = ["ms", "s", "min", "h"];
var div = [1000, 60, 60];
var i = 0;
while (Math.abs(time) >= div[i] && i < div.length) {
time = time / div[i];
i++;
}
return Math.round(time) + prefix[i];
};
var formatTimeStamp = function formatTimeStamp(seconds) {
var ts = new Date(seconds * 1000).toISOString();
return ts.replace("T", " ").replace("Z", "");
};
// At some places, we need to sort strings alphabetically descending,
// but we can only provide a key function.
// This beauty "reverses" a JS string.
var end = String.fromCharCode(0xffff);
function reverseString(s) {
return String.fromCharCode.apply(String, _.map(s.split(""), function (c) {
return 0xffff - c.charCodeAt(0);
})) + end;
}
function getCookie(name) {
var r = document.cookie.match(new RegExp("\\b" + name + "=([^;]*)\\b"));
return r ? r[1] : undefined;
}
var xsrf = $.param({ _xsrf: getCookie("_xsrf") });
//Tornado XSRF Protection.
$.ajaxPrefilter(function (options) {
if (["post", "put", "delete"].indexOf(options.type.toLowerCase()) >= 0 && options.url[0] === "/") {
if (options.url.indexOf("?") === -1) {
options.url += "?" + xsrf;
} else {
options.url += "&" + xsrf;
}
}
});
// Log AJAX Errors
$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
if (thrownError === "abort") {
return;
}
var message = jqXHR.responseText;
console.error(thrownError, message, arguments);
actions.EventLogActions.add_event(thrownError + ": " + message);
alert(message);
});
module.exports = {
formatSize: formatSize,
formatTimeDelta: formatTimeDelta,
formatTimeStamp: formatTimeStamp,
reverseString: reverseString,
Key: Key
};
},{"./actions.js":2,"jquery":"jquery","lodash":"lodash","react":"react"}]},{},[3])
//# sourceMappingURL=app.js.map