diff options
-rw-r--r-- | mitmproxy/console/help.py | 3 | ||||
-rw-r--r-- | mitmproxy/console/master.py | 10 | ||||
-rw-r--r-- | mitmproxy/console/window.py | 52 | ||||
-rw-r--r-- | mitmproxy/web/static/images/favicon.ico | bin | 0 -> 365133 bytes | |||
-rw-r--r-- | mitmproxy/web/templates/index.html | 3 | ||||
-rw-r--r-- | release/setup.py | 2 | ||||
-rw-r--r-- | setup.py | 8 | ||||
-rw-r--r-- | tox.ini | 2 | ||||
-rw-r--r-- | web/package.json | 1 | ||||
-rw-r--r-- | web/src/images/favicon.ico | bin | 0 -> 365133 bytes | |||
-rw-r--r-- | web/src/js/__tests__/ducks/flowViewSpec.js (renamed from web/src/js/__tests__/ducks/flowView.js) | 0 | ||||
-rw-r--r-- | web/src/js/__tests__/ducks/flowsSpec.js (renamed from web/src/js/__tests__/ducks/flows.js) | 0 | ||||
-rw-r--r-- | web/src/js/__tests__/ducks/ui/headerSpec.js (renamed from web/src/js/__tests__/ducks/ui.js) | 10 | ||||
-rw-r--r-- | web/src/js/__tests__/ducks/utils/listSpec.js (renamed from web/src/js/__tests__/ducks/utils/list.js) | 0 | ||||
-rw-r--r-- | web/src/js/__tests__/ducks/utils/viewSpec.js (renamed from web/src/js/__tests__/ducks/utils/view.js) | 6 | ||||
-rwxr-xr-x | web/src/js/ducks/utils/view.js | 54 | ||||
-rw-r--r-- | web/src/templates/index.html | 3 |
17 files changed, 103 insertions, 51 deletions
diff --git a/mitmproxy/console/help.py b/mitmproxy/console/help.py index ff4a072f..8024dc31 100644 --- a/mitmproxy/console/help.py +++ b/mitmproxy/console/help.py @@ -49,12 +49,11 @@ class HelpView(urwid.ListBox): text.append(urwid.Text([("head", "\n\nGlobal keys:\n")])) keys = [ - ("c", "client replay of HTTP requests"), ("i", "set interception pattern"), ("o", "options"), ("q", "quit / return to previous page"), ("Q", "quit without confirm prompt"), - ("S", "server replay of HTTP responses"), + ("R", "replay of HTTP requests/responses"), ] text.extend( common.format_keyvals(keys, key="key", val="text", indent=4) diff --git a/mitmproxy/console/master.py b/mitmproxy/console/master.py index 87c2cbf2..9a9addc5 100644 --- a/mitmproxy/console/master.py +++ b/mitmproxy/console/master.py @@ -13,6 +13,7 @@ import tempfile import traceback import weakref +import six import urwid from typing import Optional # noqa @@ -408,8 +409,13 @@ class ConsoleMaster(flow.FlowMaster): def spawn_editor(self, data): text = not isinstance(data, bytes) fd, name = tempfile.mkstemp('', "mproxy", text=text) - os.write(fd, data) - os.close(fd) + if six.PY2: + os.close(fd) + with open(name, "w" if text else "wb") as f: + f.write(data) + else: + with open(fd, "w" if text else "wb") as f: + f.write(data) # if no EDITOR is set, assume 'vi' c = os.environ.get("EDITOR") or "vi" cmd = shlex.split(c) diff --git a/mitmproxy/console/window.py b/mitmproxy/console/window.py index 25780daf..b24718be 100644 --- a/mitmproxy/console/window.py +++ b/mitmproxy/console/window.py @@ -38,15 +38,12 @@ class Window(urwid.Frame): return False return True - def keypress(self, size, k): - k = super(self.__class__, self).keypress(size, k) - if k == "?": - self.master.view_help(self.helpctx) - elif k == "c": + def handle_replay(self, k): + if k == "c": if not self.master.client_playback: signals.status_prompt_path.send( self, - prompt = "Client replay", + prompt = "Client replay path", callback = self.master.client_playback_path ) else: @@ -59,20 +56,7 @@ class Window(urwid.Frame): ), callback = self.master.stop_client_playback_prompt, ) - elif k == "i": - signals.status_prompt.send( - self, - prompt = "Intercept filter", - text = self.master.state.intercept_txt, - callback = self.master.set_intercept - ) - elif k == "o": - self.master.view_options() - elif k == "Q": - raise urwid.ExitMainLoop - elif k == "q": - signals.pop_view_state.send(self) - elif k == "S": + elif k == "s": if not self.master.server_playback: signals.status_prompt_path.send( self, @@ -89,5 +73,33 @@ class Window(urwid.Frame): ), callback = self.master.stop_server_playback_prompt, ) + + def keypress(self, size, k): + k = super(self.__class__, self).keypress(size, k) + if k == "?": + self.master.view_help(self.helpctx) + elif k == "i": + signals.status_prompt.send( + self, + prompt = "Intercept filter", + text = self.master.state.intercept_txt, + callback = self.master.set_intercept + ) + elif k == "o": + self.master.view_options() + elif k == "Q": + raise urwid.ExitMainLoop + elif k == "q": + signals.pop_view_state.send(self) + elif k == "R": + signals.status_prompt_onekey.send( + self, + prompt = "Replay", + keys = ( + ("client", "c"), + ("server", "s"), + ), + callback = self.handle_replay, + ) else: return k diff --git a/mitmproxy/web/static/images/favicon.ico b/mitmproxy/web/static/images/favicon.ico Binary files differnew file mode 100644 index 00000000..bfd2fde7 --- /dev/null +++ b/mitmproxy/web/static/images/favicon.ico diff --git a/mitmproxy/web/templates/index.html b/mitmproxy/web/templates/index.html index 165d7d3d..db9d2ecb 100644 --- a/mitmproxy/web/templates/index.html +++ b/mitmproxy/web/templates/index.html @@ -6,10 +6,11 @@ <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/vendor.css"/> <link rel="stylesheet" href="/static/app.css"/> + <link rel="icon" href="/static/images/favicon.ico" type="image/x-icon"/> <script src="/static/vendor.js"></script> <script src="/static/app.js"></script> </head> <body> <div id="mitmproxy"></div> </body> -</html>
\ No newline at end of file +</html> diff --git a/release/setup.py b/release/setup.py index 601654e5..b8eb6eec 100644 --- a/release/setup.py +++ b/release/setup.py @@ -6,7 +6,7 @@ setup( py_modules=["rtool"], install_requires=[ "click>=6.2, <7.0", - "twine>=1.6.5, <1.7", + "twine>=1.6.5, <1.8", "virtualenv>=14.0.5, <15.1", "wheel>=0.29.0, <0.30", "six>=1.10.0, <1.11", @@ -71,7 +71,7 @@ setup( "h2>=2.4.0, <3", "html2text>=2016.1.8, <=2016.5.29", "hyperframe>=4.0.1, <5", - "lxml>=3.5.0, <3.7", + "lxml>=3.5.0, <=3.6.0", # no wheels for 3.6.1 yet. "Pillow>=3.2, <3.4", "passlib>=1.6.5, <1.7", "pyasn1>=0.1.9, <0.2", @@ -80,7 +80,7 @@ setup( "pyperclip>=1.5.22, <1.6", "requests>=2.9.1, <2.11", "six>=1.10, <1.11", - "tornado>=4.3, <4.4", + "tornado>=4.3, <4.5", "urwid>=1.3.1, <1.4", "watchdog>=0.8.3, <0.9", ], @@ -116,9 +116,9 @@ setup( # "pyamf>=0.8.0, <0.9", ], 'examples': [ - "beautifulsoup4>=4.4.1, <4.5", + "beautifulsoup4>=4.4.1, <4.6", "harparser>=0.2, <0.3", - "pytz>=2015.07.0, <=2016.4", + "pytz>=2015.07.0, <=2016.6.1", ] } ) @@ -17,5 +17,5 @@ changedir = docs commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html [testenv:lint] -deps = flake8>=2.6.2, <3 +deps = flake8>=2.6.2, <3.1 commands = flake8 --jobs 8 --count mitmproxy netlib pathod examples test diff --git a/web/package.json b/web/package.json index 302803f2..fb2c8c30 100644 --- a/web/package.json +++ b/web/package.json @@ -7,6 +7,7 @@ "start": "gulp" }, "jest": { + "testRegex": "__tests__/.*\\Spec.js$", "testPathDirs": [ "<rootDir>/src/js" ], diff --git a/web/src/images/favicon.ico b/web/src/images/favicon.ico Binary files differnew file mode 100644 index 00000000..bfd2fde7 --- /dev/null +++ b/web/src/images/favicon.ico diff --git a/web/src/js/__tests__/ducks/flowView.js b/web/src/js/__tests__/ducks/flowViewSpec.js index d5d9a6d9..d5d9a6d9 100644 --- a/web/src/js/__tests__/ducks/flowView.js +++ b/web/src/js/__tests__/ducks/flowViewSpec.js diff --git a/web/src/js/__tests__/ducks/flows.js b/web/src/js/__tests__/ducks/flowsSpec.js index 2b261cb1..2b261cb1 100644 --- a/web/src/js/__tests__/ducks/flows.js +++ b/web/src/js/__tests__/ducks/flowsSpec.js diff --git a/web/src/js/__tests__/ducks/ui.js b/web/src/js/__tests__/ducks/ui/headerSpec.js index d3242815..8968e636 100644 --- a/web/src/js/__tests__/ducks/ui.js +++ b/web/src/js/__tests__/ducks/ui/headerSpec.js @@ -1,10 +1,10 @@ -jest.unmock('../../ducks/ui') -jest.unmock('../../ducks/flows') +jest.unmock('../../../ducks/ui/header') +jest.unmock('../../../ducks/flows') -import reducer, { setActiveMenu } from '../../ducks/ui' -import * as flowActions from '../../ducks/flows' +import reducer, { setActiveMenu } from '../../../ducks/ui/header' +import * as flowActions from '../../../ducks/flows' -describe('ui reducer', () => { +describe('header reducer', () => { it('should return the initial state', () => { expect(reducer(undefined, {}).activeMenu).toEqual('Start') }) diff --git a/web/src/js/__tests__/ducks/utils/list.js b/web/src/js/__tests__/ducks/utils/listSpec.js index 72d162f2..72d162f2 100644 --- a/web/src/js/__tests__/ducks/utils/list.js +++ b/web/src/js/__tests__/ducks/utils/listSpec.js diff --git a/web/src/js/__tests__/ducks/utils/view.js b/web/src/js/__tests__/ducks/utils/viewSpec.js index f0b147da..af3da173 100644 --- a/web/src/js/__tests__/ducks/utils/view.js +++ b/web/src/js/__tests__/ducks/utils/viewSpec.js @@ -66,11 +66,13 @@ describe('view reduce', () => { it('should update item', () => { const state = createState([ { id: 1, val: 1 }, - { id: 2, val: 2 } + { id: 2, val: 2 }, + { id: 3, val: 3 } ]) const result = createState([ { id: 1, val: 1 }, - { id: 2, val: 3 } + { id: 2, val: 3 }, + { id: 3, val: 3 } ]) expect(reduce(state, view.update({ id: 2, val: 3 }))).toEqual(result) }) diff --git a/web/src/js/ducks/utils/view.js b/web/src/js/ducks/utils/view.js index c00f00bd..6bf0a63e 100755 --- a/web/src/js/ducks/utils/view.js +++ b/web/src/js/ducks/utils/view.js @@ -54,21 +54,29 @@ export default function reduce(state = defaultState, action) { } case UPDATE: - if (state.indexOf[action.item.id] == null) { - return + let hasOldItem = state.indexOf[action.item.id] !== null && state.indexOf[action.item.id] !== undefined + let hasNewItem = action.filter(action.item) + if (!hasNewItem && !hasOldItem) { + return state } - const nextState = { - ...state, - ...sortedRemove(state, action.item.id), + if (hasNewItem && !hasOldItem) { + return { + ...state, + ...sortedInsert(state, action.item, action.sort) + } } - if (!action.filter(action.item)) { - return nextState + if (!hasNewItem && hasOldItem) { + return { + ...state, + ...sortedRemove(state, action.item.id) + } } - return { - ...nextState, - ...sortedInsert(nextState, action.item, action.sort) + if (hasNewItem && hasOldItem) { + return { + ...state, + ...sortedUpdate(state, action.item, action.sort), + } } - case RECEIVE: { const data = action.list.filter(action.filter).sort(action.sort) @@ -110,7 +118,7 @@ export function receive(list, filter = defaultFilter, sort = defaultSort) { function sortedInsert(state, item, sort) { const index = sortedIndex(state.data, item, sort) - const data = [...state.data] + const data = [ ...state.data ] const indexOf = { ...state.indexOf } data.splice(index, 0, item) @@ -134,6 +142,28 @@ function sortedRemove(state, id) { return { data, indexOf } } +function sortedUpdate(state, item, sort) { + let data = [ ...state.data ] + let indexOf = { ...state.indexOf } + let index = indexOf[item.id] + data[index] = item + while (index + 1 < data.length && sort(data[index], data[index + 1]) > 0) { + data[index] = data[index + 1] + data[index + 1] = item + indexOf[item.id] = index + 1 + indexOf[data[index].id] = index + ++index + } + while (index > 0 && sort(data[index], data[index - 1]) < 0) { + data[index] = data[index - 1] + data[index - 1] = item + indexOf[item.id] = index - 1 + indexOf[data[index].id] = index + --index + } + return { data, indexOf } +} + function sortedIndex(list, item, sort) { let low = 0 let high = list.length diff --git a/web/src/templates/index.html b/web/src/templates/index.html index 165d7d3d..db9d2ecb 100644 --- a/web/src/templates/index.html +++ b/web/src/templates/index.html @@ -6,10 +6,11 @@ <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/vendor.css"/> <link rel="stylesheet" href="/static/app.css"/> + <link rel="icon" href="/static/images/favicon.ico" type="image/x-icon"/> <script src="/static/vendor.js"></script> <script src="/static/app.js"></script> </head> <body> <div id="mitmproxy"></div> </body> -</html>
\ No newline at end of file +</html> |