diff options
author | Jason <jason.daurus@gmail.com> | 2016-06-18 14:18:24 +0800 |
---|---|---|
committer | Jason <jason.daurus@gmail.com> | 2016-06-18 14:18:24 +0800 |
commit | 9cb5b0af9db83d84af0bdb45d56a9755b400c212 (patch) | |
tree | a2f2c6985f8a2230be3b8796567e678733e03b7f /web/src | |
parent | 6c0511b06fdc359ec4c48879f803c80d7fbeb34c (diff) | |
parent | 23b976a999f41439e83c1010474ec9dc680b8486 (diff) | |
download | mitmproxy-9cb5b0af9db83d84af0bdb45d56a9755b400c212.tar.gz mitmproxy-9cb5b0af9db83d84af0bdb45d56a9755b400c212.tar.bz2 mitmproxy-9cb5b0af9db83d84af0bdb45d56a9755b400c212.zip |
Merge branch 'master' of github.com:mitmproxy/mitmproxy into websocket
Conflicts:
mitmproxy/web/static/app.js
web/src/js/components/ProxyApp.jsx
web/src/js/connection.js
Diffstat (limited to 'web/src')
-rw-r--r-- | web/src/js/components/Header/MainMenu.jsx | 11 | ||||
-rw-r--r-- | web/src/js/components/ProxyApp.jsx | 77 | ||||
-rw-r--r-- | web/src/js/ducks/index.js | 2 | ||||
-rw-r--r-- | web/src/js/ducks/settings.js | 77 | ||||
-rw-r--r-- | web/src/js/ducks/websocket.js | 29 | ||||
-rw-r--r-- | web/src/js/store/store.js | 96 | ||||
-rw-r--r-- | web/src/js/store/view.js | 0 | ||||
-rw-r--r-- | web/src/js/utils.js | 18 |
8 files changed, 145 insertions, 165 deletions
diff --git a/web/src/js/components/Header/MainMenu.jsx b/web/src/js/components/Header/MainMenu.jsx index 86bf961a..7b0b542c 100644 --- a/web/src/js/components/Header/MainMenu.jsx +++ b/web/src/js/components/Header/MainMenu.jsx @@ -1,9 +1,10 @@ import React, { Component, PropTypes } from 'react' -import { SettingsActions } from "../../actions.js" import FilterInput from './FilterInput' import { Query } from '../../actions.js' +import {setInterceptPattern} from "../../ducks/settings" +import { connect } from 'react-redux' -export default class MainMenu extends Component { +class MainMenu extends Component { static title = 'Start' static route = 'flows' @@ -28,7 +29,7 @@ export default class MainMenu extends Component { } onInterceptChange(val) { - SettingsActions.update({ intercept: val }) + this.props.setInterceptPattern(val); } render() { @@ -71,3 +72,7 @@ export default class MainMenu extends Component { ) } } + +export default connect(undefined, { + setInterceptPattern +})(MainMenu); diff --git a/web/src/js/components/ProxyApp.jsx b/web/src/js/components/ProxyApp.jsx index 11c321e7..89bd95fd 100644 --- a/web/src/js/components/ProxyApp.jsx +++ b/web/src/js/components/ProxyApp.jsx @@ -7,7 +7,6 @@ import { init as appInit, destruct as appDestruct } from '../ducks/app' import Header from './Header' import EventLog from './EventLog' import Footer from './Footer' -import { SettingsStore } from '../store/store.js' import { Key } from '../utils.js' class ProxyAppMain extends Component { @@ -23,17 +22,9 @@ class ProxyAppMain extends Component { constructor(props, context) { super(props, context) - this.settingsStore = new SettingsStore() - - // Default Settings before fetch - _.extend(this.settingsStore.dict, {}) - - this.state = { settings: this.settingsStore.dict } - this.focus = this.focus.bind(this) this.onKeyDown = this.onKeyDown.bind(this) this.updateLocation = this.updateLocation.bind(this) - this.onSettingsChange = this.onSettingsChange.bind(this) } componentWillMount() { @@ -41,53 +32,14 @@ class ProxyAppMain extends Component { } /** - * @todo move to actions - */ - updateLocation(pathname, queryUpdate) { - if (pathname === undefined) { - pathname = this.props.location.pathname - } - const query = this.props.location.query - for (const key of Object.keys(queryUpdate || {})) { - query[key] = queryUpdate[key] || undefined - } - this.context.router.replace({ pathname, query }) - } - - /** - * @todo pass in with props - */ - 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.props.location.query) - } - - /** - * @todo remove settings store - * @todo connect websocket here * @todo listen to window's key events */ componentDidMount() { this.focus() - this.settingsStore.addListener('recalculate', this.onSettingsChange) } - /** - * @todo remove settings store - * @todo disconnect websocket here - * @todo stop listening to window's key events - */ componentWillUnmount() { this.props.appDestruct() - this.settingsStore.removeListener('recalculate', this.onSettingsChange) - } - - /** - * @todo move to actions - */ - onSettingsChange() { - this.setState({ settings: this.settingsStore.dict }) } /** @@ -144,9 +96,31 @@ class ProxyAppMain extends Component { e.preventDefault() } + /** + * @todo move to actions + */ + updateLocation(pathname, queryUpdate) { + if (pathname === undefined) { + pathname = this.props.location.pathname + } + const query = this.props.location.query + for (const key of Object.keys(queryUpdate || {})) { + query[key] = queryUpdate[key] || undefined + } + this.context.router.replace({ pathname, query }) + } + + /** + * @todo pass in with props + */ + 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.props.location.query) + } + render() { - const { showEventLog, location, children } = this.props - const { settings } = this.state + const { showEventLog, location, children, settings } = this.props const query = this.getQuery() return ( <div id="container" tabIndex="0" onKeyDown={this.onKeyDown}> @@ -166,7 +140,8 @@ class ProxyAppMain extends Component { export default connect( state => ({ - showEventLog: state.eventLog.visible + showEventLog: state.eventLog.visible, + settings: state.settings.settings, }), { appInit, diff --git a/web/src/js/ducks/index.js b/web/src/js/ducks/index.js index fee4d792..ffde1a64 100644 --- a/web/src/js/ducks/index.js +++ b/web/src/js/ducks/index.js @@ -2,12 +2,14 @@ import {combineReducers} from 'redux' import eventLog from './eventLog' import websocket from './websocket' import flows from './flows' +import settings from './settings' import ui from './ui' const rootReducer = combineReducers({ eventLog, websocket, flows, + settings, ui }) diff --git a/web/src/js/ducks/settings.js b/web/src/js/ducks/settings.js new file mode 100644 index 00000000..73c62120 --- /dev/null +++ b/web/src/js/ducks/settings.js @@ -0,0 +1,77 @@ +import {fetchApi} from "../utils"; + +export const REQUEST_SETTINGS = "REQUEST_SETTINGS" +export const RECEIVE_SETTINGS = "RECEIVE_SETTINGS" +export const UPDATE_SETTINGS = "UPDATE_SETTINGS" + +const defaultState = { + settings: {}, + isFetching: false, + actionsDuringFetch: [], +} + +export default function reducer(state = defaultState, action) { + switch (action.type) { + + case REQUEST_SETTINGS: + return { + ...state, + isFetching: true + } + + case RECEIVE_SETTINGS: + let s = { + settings: action.settings, + isFetching: false, + actionsDuringFetch: [], + } + for (action of state.actionsDuringFetch) { + s = reducer(s, action) + } + return s + + case UPDATE_SETTINGS: + if (state.isFetching) { + return { + ...state, + actionsDuringFetch: [...state.actionsDuringFetch, action] + } + } + return { + ...state, + settings: {...state.settings, ...action.settings} + } + + default: + return state + } +} + +export function updateSettings(event) { + /* This action creator takes all WebSocket events */ + if (event.cmd === "update") { + return { + type: UPDATE_SETTINGS, + settings: event.data + } + } + console.error("unknown settings update", event) +} + +export function fetchSettings() { + return dispatch => { + dispatch({type: REQUEST_SETTINGS}) + + return fetchApi("/settings") + .then(response => response.json()) + .then(json => + dispatch({type: RECEIVE_SETTINGS, settings: json.data}) + ) + // TODO: Error handling + } +} + +export function setInterceptPattern(intercept) { + return dispatch => + fetchApi.put("/settings", {intercept}) +} diff --git a/web/src/js/ducks/websocket.js b/web/src/js/ducks/websocket.js index 0d0556ad..766f7236 100644 --- a/web/src/js/ducks/websocket.js +++ b/web/src/js/ducks/websocket.js @@ -1,7 +1,8 @@ import { ConnectionActions } from '../actions.js' import { AppDispatcher } from '../dispatcher.js' import * as eventLogActions from './eventLog' -import * as flowActions from './flows' +import * as flowsActions from './flows' +import * as settingsActions from './settings' export const CONNECT = 'WEBSOCKET_CONNECT' export const CONNECTED = 'WEBSOCKET_CONNECTED' @@ -62,15 +63,8 @@ export function onConnect() { // workaround to make sure that our state is already available. return dispatch => { dispatch({ type: CONNECTED }) - dispatch(flowActions.fetchFlows()).then(() => ConnectionActions.open()) - } -} - -export function onDisconnect() { - return dispatch => { - ConnectionActions.close() - dispatch(eventLogActions.addLogEntry('WebSocket connection closed.')) - dispatch({ type: DISCONNECTED }) + dispatch(settingsActions.fetchSettings()) + dispatch(flowsActions.fetchFlows()).then(() => ConnectionActions.open()) } } @@ -85,8 +79,11 @@ export function onMessage(msg) { case eventLogActions.UPDATE_LOG: return dispatch(eventLogActions.updateLogEntries(data)) - case flowActions.UPDATE_FLOWS: - return dispatch(flowActions.updateFlows(data)) + case flowsActions.UPDATE_FLOWS: + return dispatch(flowsActions.updateFlows(data)) + + case settingsActions.UPDATE_SETTINGS: + return dispatch(settingsActions.updateSettings(message)) default: console.warn('unknown message', data) @@ -96,6 +93,14 @@ export function onMessage(msg) { } } +export function onDisconnect() { + return dispatch => { + ConnectionActions.close() + dispatch(eventLogActions.addLogEntry('WebSocket connection closed.')) + dispatch({ type: DISCONNECTED }) + } +} + export function onError(error) { // @todo let event log subscribe WebSocketActions.ERROR return dispatch => { diff --git a/web/src/js/store/store.js b/web/src/js/store/store.js deleted file mode 100644 index f3e2074f..00000000 --- a/web/src/js/store/store.js +++ /dev/null @@ -1,96 +0,0 @@ - -import _ from "lodash"; -import $ from "jquery"; -import {EventEmitter} from 'events'; -import {ActionTypes, StoreCmds} from "../actions.js"; -import {AppDispatcher} from "../dispatcher.js"; - - -function DictStore() { - EventEmitter.call(this); - this.reset(); -} -_.extend(DictStore.prototype, EventEmitter.prototype, { - update: function (dict) { - _.merge(this.dict, dict); - this.emit("recalculate"); - }, - reset: function (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); - AppDispatcher.register(this.handle); - - // Avoid double-fetch on startup. - if (!(window.ws && window.ws.readyState === WebSocket.CONNECTING)) { - this.fetch(); - } -} -_.extend(LiveStoreMixin.prototype, { - handle: function (event) { - if (event.type === ActionTypes.CONNECTION_OPEN) { - return this.fetch(); - } - if (event.type === this.type) { - if (event.cmd === 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 () { - AppDispatcher.unregister(this.handle); - }, - fetch: function (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 () { - console.error("Could not fetch " + this.type) - }.bind(this)); - } - }, - handle_fetch: function (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 LiveDictStore(type) { - DictStore.call(this); - LiveStoreMixin.call(this, type); -} -_.extend(LiveDictStore.prototype, DictStore.prototype, LiveStoreMixin.prototype); - - -export function SettingsStore() { - return new LiveDictStore(ActionTypes.SETTINGS_STORE); -}
\ No newline at end of file diff --git a/web/src/js/store/view.js b/web/src/js/store/view.js deleted file mode 100644 index e69de29b..00000000 --- a/web/src/js/store/view.js +++ /dev/null diff --git a/web/src/js/utils.js b/web/src/js/utils.js index 2e5c3005..2e25016e 100644 --- a/web/src/js/utils.js +++ b/web/src/js/utils.js @@ -109,7 +109,19 @@ export function fetchApi(url, options) { url += "&" + xsrf; } return fetch(url, { - ...options, - credentials: 'same-origin' + credentials: 'same-origin', + ...options }); -}
\ No newline at end of file +} + +fetchApi.put = (url, json, options) => fetchApi( + url, + { + method: "PUT", + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(json), + ...options + } +) |