aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mitmproxy/addons/__init__.py4
-rw-r--r--mitmproxy/addons/disable_h2c.py41
-rw-r--r--mitmproxy/addons/disable_h2c_upgrade.py21
-rw-r--r--test/mitmproxy/addons/test_disable_h2c.py39
-rw-r--r--test/mitmproxy/addons/test_disable_h2c_upgrade.py17
-rw-r--r--web/src/js/__tests__/ducks/flowViewSpec.js67
-rw-r--r--web/src/js/__tests__/ducks/utils/listSpec.js64
-rw-r--r--web/src/js/__tests__/ducks/utils/viewSpec.js156
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]))
- }
-}