diff options
| -rw-r--r-- | mitmproxy/addons/__init__.py | 4 | ||||
| -rw-r--r-- | mitmproxy/addons/disable_h2c.py | 41 | ||||
| -rw-r--r-- | mitmproxy/addons/disable_h2c_upgrade.py | 21 | ||||
| -rw-r--r-- | test/mitmproxy/addons/test_disable_h2c.py | 39 | ||||
| -rw-r--r-- | test/mitmproxy/addons/test_disable_h2c_upgrade.py | 17 | ||||
| -rw-r--r-- | web/src/js/__tests__/ducks/flowViewSpec.js | 67 | ||||
| -rw-r--r-- | web/src/js/__tests__/ducks/utils/listSpec.js | 64 | ||||
| -rw-r--r-- | web/src/js/__tests__/ducks/utils/viewSpec.js | 156 |
8 files changed, 82 insertions, 327 deletions
diff --git a/mitmproxy/addons/__init__.py b/mitmproxy/addons/__init__.py index 16510640..80e3b2cb 100644 --- a/mitmproxy/addons/__init__.py +++ b/mitmproxy/addons/__init__.py @@ -4,7 +4,7 @@ from mitmproxy.addons import check_alpn from mitmproxy.addons import check_ca from mitmproxy.addons import clientplayback from mitmproxy.addons import core_option_validation -from mitmproxy.addons import disable_h2c_upgrade +from mitmproxy.addons import disable_h2c from mitmproxy.addons import onboarding from mitmproxy.addons import proxyauth from mitmproxy.addons import replace @@ -26,7 +26,7 @@ def default_addons(): check_alpn.CheckALPN(), check_ca.CheckCA(), clientplayback.ClientPlayback(), - disable_h2c_upgrade.DisableH2CleartextUpgrade(), + disable_h2c.DisableH2C(), onboarding.Onboarding(), proxyauth.ProxyAuth(), replace.Replace(), diff --git a/mitmproxy/addons/disable_h2c.py b/mitmproxy/addons/disable_h2c.py new file mode 100644 index 00000000..b43d5207 --- /dev/null +++ b/mitmproxy/addons/disable_h2c.py @@ -0,0 +1,41 @@ +import mitmproxy + + +class DisableH2C: + + """ + We currently only support HTTP/2 over a TLS connection. + + Some clients try to upgrade a connection from HTTP/1.1 to h2c. We need to + remove those headers to avoid protocol errors if one endpoints suddenly + starts sending HTTP/2 frames. + + Some clients might use HTTP/2 Prior Knowledge to directly initiate a session + by sending the connection preface. We just kill those flows. + """ + + def configure(self, options, updated): + pass + + def process_flow(self, f): + if f.request.headers.get('upgrade', '') == 'h2c': + mitmproxy.ctx.log.warn("HTTP/2 cleartext connections (h2c upgrade requests) are currently not supported.") + del f.request.headers['upgrade'] + if 'connection' in f.request.headers: + del f.request.headers['connection'] + if 'http2-settings' in f.request.headers: + del f.request.headers['http2-settings'] + + is_connection_preface = ( + f.request.method == 'PRI' and + f.request.path == '*' and + f.request.http_version == 'HTTP/2.0' + ) + if is_connection_preface: + f.kill() + mitmproxy.ctx.log.warn("Initiating HTTP/2 connections with prior knowledge are currently not supported.") + + # Handlers + + def request(self, f): + self.process_flow(f) diff --git a/mitmproxy/addons/disable_h2c_upgrade.py b/mitmproxy/addons/disable_h2c_upgrade.py deleted file mode 100644 index f4a36d5f..00000000 --- a/mitmproxy/addons/disable_h2c_upgrade.py +++ /dev/null @@ -1,21 +0,0 @@ -class DisableH2CleartextUpgrade: - - """ - We currently only support HTTP/2 over a TLS connection. Some clients try - to upgrade a connection from HTTP/1.1 to h2c, so we need to remove those - headers to avoid protocol errors if one endpoints suddenly starts sending - HTTP/2 frames. - """ - - def process_flow(self, f): - if f.request.headers.get('upgrade', '') == 'h2c': - del f.request.headers['upgrade'] - if 'connection' in f.request.headers: - del f.request.headers['connection'] - if 'http2-settings' in f.request.headers: - del f.request.headers['http2-settings'] - - # Handlers - - def request(self, f): - self.process_flow(f) diff --git a/test/mitmproxy/addons/test_disable_h2c.py b/test/mitmproxy/addons/test_disable_h2c.py new file mode 100644 index 00000000..d4df8390 --- /dev/null +++ b/test/mitmproxy/addons/test_disable_h2c.py @@ -0,0 +1,39 @@ +import io +from mitmproxy import http +from mitmproxy.addons import disable_h2c +from mitmproxy.net.http import http1 +from mitmproxy.exceptions import Kill +from mitmproxy.test import tflow +from mitmproxy.test import taddons + + +class TestDisableH2CleartextUpgrade: + def test_upgrade(self): + with taddons.context() as tctx: + a = disable_h2c.DisableH2C() + tctx.configure(a) + + f = tflow.tflow() + f.request.headers['upgrade'] = 'h2c' + f.request.headers['connection'] = 'foo' + f.request.headers['http2-settings'] = 'bar' + + a.request(f) + assert 'upgrade' not in f.request.headers + assert 'connection' not in f.request.headers + assert 'http2-settings' not in f.request.headers + + def test_prior_knowledge(self): + with taddons.context() as tctx: + a = disable_h2c.DisableH2C() + tctx.configure(a) + + b = io.BytesIO(b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") + f = tflow.tflow() + f.request = http.HTTPRequest.wrap(http1.read_request(b)) + f.reply.handle() + f.intercept() + + a.request(f) + assert not f.killable + assert f.reply.value == Kill diff --git a/test/mitmproxy/addons/test_disable_h2c_upgrade.py b/test/mitmproxy/addons/test_disable_h2c_upgrade.py deleted file mode 100644 index 6cab713d..00000000 --- a/test/mitmproxy/addons/test_disable_h2c_upgrade.py +++ /dev/null @@ -1,17 +0,0 @@ -from mitmproxy.addons import disable_h2c_upgrade -from mitmproxy.test import tflow - - -class TestTermLog: - def test_simple(self): - a = disable_h2c_upgrade.DisableH2CleartextUpgrade() - - f = tflow.tflow() - f.request.headers['upgrade'] = 'h2c' - f.request.headers['connection'] = 'foo' - f.request.headers['http2-settings'] = 'bar' - - a.request(f) - assert 'upgrade' not in f.request.headers - assert 'connection' not in f.request.headers - assert 'http2-settings' not in f.request.headers diff --git a/web/src/js/__tests__/ducks/flowViewSpec.js b/web/src/js/__tests__/ducks/flowViewSpec.js deleted file mode 100644 index d5d9a6d9..00000000 --- a/web/src/js/__tests__/ducks/flowViewSpec.js +++ /dev/null @@ -1,67 +0,0 @@ -jest.unmock('../../ducks/flows') -jest.unmock('../../ducks/flowView') -jest.unmock('../../ducks/utils/view') -jest.unmock('../../ducks/utils/list') -jest.unmock('./tutils') - -import { createStore } from './tutils' - -import flows, * as flowActions from '../../ducks/flows' -import flowView, * as flowViewActions from '../../ducks/flowView' - - -function testStore() { - let store = createStore({ - flows, - flowView - }) - for (let i of [1, 2, 3, 4]) { - store.dispatch( - flowActions.addFlow({ id: i }) - ) - } - return store -} - -describe('select relative', () => { - - function testSelect(start, relative, result) { - const store = testStore() - store.dispatch(flowActions.select(start)) - expect(store.getState().flows.selected).toEqual(start ? [start] : []) - store.dispatch(flowViewActions.selectRelative(relative)) - expect(store.getState().flows.selected).toEqual([result]) - } - - describe('previous', () => { - - it('should select the previous flow', () => { - testSelect(3, -1, 2) - }) - - it('should not changed when first flow is selected', () => { - testSelect(1, -1, 1) - }) - - it('should select first flow if no flow is selected', () => { - testSelect(undefined, -1, 1) - }) - - }) - - describe('next', () => { - - it('should select the next flow', () => { - testSelect(2, 1, 3) - }) - - it('should not changed when last flow is selected', () => { - testSelect(4, 1, 4) - }) - - it('should select last flow if no flow is selected', () => { - testSelect(undefined, 1, 4) - }) - - }) -}) diff --git a/web/src/js/__tests__/ducks/utils/listSpec.js b/web/src/js/__tests__/ducks/utils/listSpec.js deleted file mode 100644 index 0f5d0f34..00000000 --- a/web/src/js/__tests__/ducks/utils/listSpec.js +++ /dev/null @@ -1,64 +0,0 @@ -jest.unmock('lodash') -jest.unmock('../../../ducks/utils/list') - -import reduce, * as list from '../../../ducks/utils/list' -import _ from 'lodash' - -describe('list reduce', () => { - - it('should add item', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 1 }, - { id: 2 }, - { id: 3 } - ]) - expect(reduce(state, list.add({ id: 3 }))).toEqual(result) - }) - - it('should update item', () => { - const state = createState([ - { id: 1, val: 1 }, - { id: 2, val: 2 } - ]) - const result = createState([ - { id: 1, val: 1 }, - { id: 2, val: 3 } - ]) - expect(reduce(state, list.update({ id: 2, val: 3 }))).toEqual(result) - }) - - it('should remove item', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 1 } - ]) - result.byId[2] = result.indexOf[2] = null - expect(reduce(state, list.remove(2))).toEqual(result) - }) - - it('should replace all items', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 1 } - ]) - expect(reduce(state, list.receive([{ id: 1 }]))).toEqual(result) - }) -}) - -function createState(items) { - return { - data: items, - byId: _.fromPairs(items.map((item, index) => [item.id, item])), - indexOf: _.fromPairs(items.map((item, index) => [item.id, index])) - } -} diff --git a/web/src/js/__tests__/ducks/utils/viewSpec.js b/web/src/js/__tests__/ducks/utils/viewSpec.js deleted file mode 100644 index af3da173..00000000 --- a/web/src/js/__tests__/ducks/utils/viewSpec.js +++ /dev/null @@ -1,156 +0,0 @@ -jest.unmock('../../../ducks/utils/view') -jest.unmock('lodash') - -import reduce, * as view from '../../../ducks/utils/view' -import _ from 'lodash' - -describe('view reduce', () => { - - it('should filter items', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 1 } - ]) - expect(reduce(state, view.updateFilter(state.data, item => item.id === 1))).toEqual(result) - }) - - it('should sort items', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 2 }, - { id: 1 } - ]) - expect(reduce(state, view.updateSort((a, b) => b.id - a.id))).toEqual(result) - }) - - it('should add item', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 1 }, - { id: 2 }, - { id: 3 } - ]) - expect(reduce(state, view.add({ id: 3 }))).toEqual(result) - }) - - it('should add item in place', () => { - const state = createState([ - { id: 1 } - ]) - const result = createState([ - { id: 3 }, - { id: 1 } - ]) - expect(reduce(state, view.add({ id: 3 }, undefined, (a, b) => b.id - a.id))).toEqual(result) - }) - - it('should filter added item', () => { - const state = createState([ - { id: 1 } - ]) - const result = createState([ - { id: 1 } - ]) - expect(reduce(state, view.add({ id: 3 }, i => i.id === 1))).toEqual(result) - }) - - it('should update item', () => { - const state = createState([ - { id: 1, val: 1 }, - { id: 2, val: 2 }, - { id: 3, val: 3 } - ]) - const result = createState([ - { id: 1, val: 1 }, - { id: 2, val: 3 }, - { id: 3, val: 3 } - ]) - expect(reduce(state, view.update({ id: 2, val: 3 }))).toEqual(result) - }) - - it('should sort updated item', () => { - const state = createState([ - { id: 1, val: 1 }, - { id: 2, val: 2 } - ]) - const result = createState([ - { id: 2, val: 3 }, - { id: 1, val: 1 } - ]) - expect(reduce(state, view.update({ id: 2, val: 3 }, undefined, (a, b) => b.id - a.id))).toEqual(result) - }) - - it('should filter updated item', () => { - const state = createState([ - { id: 1, val: 1 }, - { id: 2, val: 2 } - ]) - const result = createState([ - { id: 1, val: 1 } - ]) - result.indexOf[2] = null - expect(reduce(state, view.update({ id: 2, val: 3 }, i => i.id === i.val))).toEqual(result) - }) - - it('should remove item', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 1 } - ]) - result.indexOf[2] = null - expect(reduce(state, view.remove(2))).toEqual(result) - }) - - it('should replace items', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 1 } - ]) - expect(reduce(state, view.receive([{ id: 1 }]))).toEqual(result) - }) - - it('should sort received items', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 2 }, - { id: 1 } - ]) - expect(reduce(state, view.receive([{ id: 1 }, { id: 2 }], undefined, (a, b) => b.id - a.id))).toEqual(result) - }) - - it('should filter received', () => { - const state = createState([ - { id: 1 }, - { id: 2 } - ]) - const result = createState([ - { id: 1 } - ]) - expect(reduce(state, view.receive([{ id: 1 }, { id: 2 }], i => i.id === 1))).toEqual(result) - }) -}) - -function createState(items) { - return { - data: items, - indexOf: _.fromPairs(items.map((item, index) => [item.id, index])) - } -} |
