mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-25 18:03:50 +00:00
simplify ALPN and OpenSSL on macOS
This commit is contained in:
parent
741c2b7b66
commit
1a36efbb6a
34
.travis.yml
34
.travis.yml
@ -1,15 +1,6 @@
|
|||||||
sudo: false
|
sudo: false
|
||||||
language: python
|
language: python
|
||||||
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources:
|
|
||||||
# Debian sid currently holds OpenSSL 1.0.2
|
|
||||||
# change this with future releases!
|
|
||||||
- debian-sid
|
|
||||||
packages:
|
|
||||||
- libssl-dev
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- CI_DEPS=codecov>=2.0.5
|
- CI_DEPS=codecov>=2.0.5
|
||||||
@ -25,9 +16,21 @@ matrix:
|
|||||||
language: generic
|
language: generic
|
||||||
env: TOXENV=py35 BDIST=1
|
env: TOXENV=py35 BDIST=1
|
||||||
- python: 3.5
|
- python: 3.5
|
||||||
env: TOXENV=py35 BDIST=1
|
env: TOXENV=py35 OPENSSL_OLD
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- libssl-dev
|
||||||
- python: 3.5
|
- python: 3.5
|
||||||
env: TOXENV=py35 NO_ALPN=1
|
env: TOXENV=py35 BDIST=1 OPENSSL_ALPN
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
# Debian sid currently holds OpenSSL 1.1.0
|
||||||
|
# change this with future releases!
|
||||||
|
- debian-sid
|
||||||
|
packages:
|
||||||
|
- libssl-dev
|
||||||
- python: 3.5
|
- python: 3.5
|
||||||
env: TOXENV=docs
|
env: TOXENV=docs
|
||||||
git:
|
git:
|
||||||
@ -39,10 +42,8 @@ install:
|
|||||||
- |
|
- |
|
||||||
if [[ $TRAVIS_OS_NAME == "osx" ]]
|
if [[ $TRAVIS_OS_NAME == "osx" ]]
|
||||||
then
|
then
|
||||||
brew update || brew update # try again if it fails
|
brew update || brew update
|
||||||
brew upgrade
|
brew outdated pyenv || brew upgrade pyenv
|
||||||
brew reinstall openssl
|
|
||||||
brew reinstall pyenv
|
|
||||||
eval "$(pyenv init -)"
|
eval "$(pyenv init -)"
|
||||||
env PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install --skip-existing 3.5.2
|
env PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install --skip-existing 3.5.2
|
||||||
pyenv global 3.5.2
|
pyenv global 3.5.2
|
||||||
@ -52,8 +53,8 @@ install:
|
|||||||
- pip install tox
|
- pip install tox
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
- tox -- --cov mitmproxy --cov pathod -v
|
||||||
- |
|
- |
|
||||||
tox -- --cov mitmproxy --cov pathod -v
|
|
||||||
if [[ $BDIST == "1" ]]
|
if [[ $BDIST == "1" ]]
|
||||||
then
|
then
|
||||||
git fetch --unshallow --tags
|
git fetch --unshallow --tags
|
||||||
@ -80,3 +81,4 @@ cache:
|
|||||||
directories:
|
directories:
|
||||||
- $HOME/.pyenv
|
- $HOME/.pyenv
|
||||||
- $HOME/.cache/pip
|
- $HOME/.cache/pip
|
||||||
|
# - $HOME/build/mitmproxy/mitmproxy/.tox
|
||||||
|
@ -30,10 +30,7 @@ version_check.check_pyopenssl_version()
|
|||||||
socket_fileobject = socket.SocketIO
|
socket_fileobject = socket.SocketIO
|
||||||
|
|
||||||
EINTR = 4
|
EINTR = 4
|
||||||
if os.environ.get("NO_ALPN"):
|
HAS_ALPN = SSL._lib.Cryptography_HAS_ALPN
|
||||||
HAS_ALPN = False
|
|
||||||
else:
|
|
||||||
HAS_ALPN = SSL._lib.Cryptography_HAS_ALPN
|
|
||||||
|
|
||||||
# To enable all SSL methods use: SSLv23
|
# To enable all SSL methods use: SSLv23
|
||||||
# then add options to disable certain methods
|
# then add options to disable certain methods
|
||||||
|
14
test/conftest.py
Normal file
14
test/conftest.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import pytest
|
||||||
|
import OpenSSL
|
||||||
|
import mitmproxy.net.tcp
|
||||||
|
|
||||||
|
|
||||||
|
requires_alpn = pytest.mark.skipif(
|
||||||
|
not mitmproxy.net.tcp.HAS_ALPN,
|
||||||
|
reason='requires OpenSSL with ALPN support')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def disable_alpn(monkeypatch):
|
||||||
|
monkeypatch.setattr(mitmproxy.net.tcp, 'HAS_ALPN', False)
|
||||||
|
monkeypatch.setattr(OpenSSL.SSL._lib, 'Cryptography_HAS_ALPN', False)
|
@ -6,7 +6,7 @@ import random
|
|||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
import mock
|
import mock
|
||||||
|
import pytest
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
|
|
||||||
from mitmproxy import certs
|
from mitmproxy import certs
|
||||||
@ -15,6 +15,7 @@ from mitmproxy.test import tutils
|
|||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
|
|
||||||
from . import tservers
|
from . import tservers
|
||||||
|
from ...conftest import requires_alpn
|
||||||
|
|
||||||
|
|
||||||
class EchoHandler(tcp.BaseHandler):
|
class EchoHandler(tcp.BaseHandler):
|
||||||
@ -526,40 +527,47 @@ class TestTimeOut(tservers.ServerTestBase):
|
|||||||
tutils.raises(exceptions.TcpTimeout, c.rfile.read, 10)
|
tutils.raises(exceptions.TcpTimeout, c.rfile.read, 10)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCryptographyALPN:
|
||||||
|
|
||||||
|
def test_has_alpn(self):
|
||||||
|
if 'OPENSSL_ALPN' in os.environ:
|
||||||
|
assert tcp.HAS_ALPN
|
||||||
|
assert SSL._lib.Cryptography_HAS_ALPN
|
||||||
|
elif 'OPENSSL_OLD' in os.environ:
|
||||||
|
assert not tcp.HAS_ALPN
|
||||||
|
assert not SSL._lib.Cryptography_HAS_ALPN
|
||||||
|
|
||||||
|
|
||||||
class TestALPNClient(tservers.ServerTestBase):
|
class TestALPNClient(tservers.ServerTestBase):
|
||||||
handler = ALPNHandler
|
handler = ALPNHandler
|
||||||
ssl = dict(
|
ssl = dict(
|
||||||
alpn_select=b"bar"
|
alpn_select=b"bar"
|
||||||
)
|
)
|
||||||
|
|
||||||
if tcp.HAS_ALPN:
|
@requires_alpn
|
||||||
def test_alpn(self):
|
@pytest.mark.parametrize('has_alpn,alpn_protos, expected_negotiated, expected_response', [
|
||||||
c = tcp.TCPClient(("127.0.0.1", self.port))
|
(True, [b"foo", b"bar", b"fasel"], b'bar', b'bar'),
|
||||||
with c.connect():
|
(True, [], b'', b'NONE'),
|
||||||
c.convert_to_ssl(alpn_protos=[b"foo", b"bar", b"fasel"])
|
(True, None, b'', b'NONE'),
|
||||||
assert c.get_alpn_proto_negotiated() == b"bar"
|
(False, [b"foo", b"bar", b"fasel"], b'', b'NONE'),
|
||||||
assert c.rfile.readline().strip() == b"bar"
|
(False, [], b'', b'NONE'),
|
||||||
|
(False, None, b'', b'NONE'),
|
||||||
|
])
|
||||||
|
def test_alpn(self, monkeypatch, has_alpn, alpn_protos, expected_negotiated, expected_response):
|
||||||
|
monkeypatch.setattr(tcp, 'HAS_ALPN', has_alpn)
|
||||||
|
monkeypatch.setattr(SSL._lib, 'Cryptography_HAS_ALPN', has_alpn)
|
||||||
|
|
||||||
def test_no_alpn(self):
|
|
||||||
c = tcp.TCPClient(("127.0.0.1", self.port))
|
c = tcp.TCPClient(("127.0.0.1", self.port))
|
||||||
with c.connect():
|
with c.connect():
|
||||||
c.convert_to_ssl()
|
c.convert_to_ssl(alpn_protos=alpn_protos)
|
||||||
assert c.get_alpn_proto_negotiated() == b""
|
assert c.get_alpn_proto_negotiated() == expected_negotiated
|
||||||
assert c.rfile.readline().strip() == b"NONE"
|
assert c.rfile.readline().strip() == expected_response
|
||||||
|
|
||||||
else:
|
|
||||||
def test_none_alpn(self):
|
|
||||||
c = tcp.TCPClient(("127.0.0.1", self.port))
|
|
||||||
with c.connect():
|
|
||||||
c.convert_to_ssl(alpn_protos=[b"foo", b"bar", b"fasel"])
|
|
||||||
assert c.get_alpn_proto_negotiated() == b""
|
|
||||||
assert c.rfile.readline() == b"NONE"
|
|
||||||
|
|
||||||
|
|
||||||
class TestNoSSLNoALPNClient(tservers.ServerTestBase):
|
class TestNoSSLNoALPNClient(tservers.ServerTestBase):
|
||||||
handler = ALPNHandler
|
handler = ALPNHandler
|
||||||
|
|
||||||
def test_no_ssl_no_alpn(self):
|
def test_no_ssl_no_alpn(self, disable_alpn):
|
||||||
c = tcp.TCPClient(("127.0.0.1", self.port))
|
c = tcp.TCPClient(("127.0.0.1", self.port))
|
||||||
with c.connect():
|
with c.connect():
|
||||||
assert c.get_alpn_proto_negotiated() == b""
|
assert c.get_alpn_proto_negotiated() == b""
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import traceback
|
import traceback
|
||||||
@ -17,6 +16,7 @@ from mitmproxy import exceptions
|
|||||||
from mitmproxy.net.http import http1, http2
|
from mitmproxy.net.http import http1, http2
|
||||||
|
|
||||||
from .. import tservers
|
from .. import tservers
|
||||||
|
from ...conftest import requires_alpn
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logging.getLogger("hyper.packages.hpack.hpack").setLevel(logging.WARNING)
|
logging.getLogger("hyper.packages.hpack.hpack").setLevel(logging.WARNING)
|
||||||
@ -27,11 +27,6 @@ logging.getLogger("PIL.Image").setLevel(logging.WARNING)
|
|||||||
logging.getLogger("PIL.PngImagePlugin").setLevel(logging.WARNING)
|
logging.getLogger("PIL.PngImagePlugin").setLevel(logging.WARNING)
|
||||||
|
|
||||||
|
|
||||||
requires_alpn = pytest.mark.skipif(
|
|
||||||
not mitmproxy.net.tcp.HAS_ALPN,
|
|
||||||
reason='requires OpenSSL with ALPN support')
|
|
||||||
|
|
||||||
|
|
||||||
# inspect the log:
|
# inspect the log:
|
||||||
# for msg in self.proxy.tmaster.tlog:
|
# for msg in self.proxy.tmaster.tlog:
|
||||||
# print(msg)
|
# print(msg)
|
||||||
|
@ -51,14 +51,14 @@ class TestDumpMaster(mastertest.MasterTest):
|
|||||||
assert "error" in o.tfile.getvalue()
|
assert "error" in o.tfile.getvalue()
|
||||||
|
|
||||||
def test_replay(self):
|
def test_replay(self):
|
||||||
o = dump.Options(server_replay=["nonexistent"], replay_kill_extra=True)
|
o = dump.Options(http2=False, server_replay=["nonexistent"], replay_kill_extra=True)
|
||||||
tutils.raises(exceptions.OptionsError, dump.DumpMaster, o, proxy.DummyServer())
|
tutils.raises(exceptions.OptionsError, dump.DumpMaster, o, proxy.DummyServer())
|
||||||
|
|
||||||
with tutils.tmpdir() as t:
|
with tutils.tmpdir() as t:
|
||||||
p = os.path.join(t, "rep")
|
p = os.path.join(t, "rep")
|
||||||
self.flowfile(p)
|
self.flowfile(p)
|
||||||
|
|
||||||
o = dump.Options(server_replay=[p], replay_kill_extra=True)
|
o = dump.Options(http2=False, server_replay=[p], replay_kill_extra=True)
|
||||||
o.verbosity = 0
|
o.verbosity = 0
|
||||||
o.flow_detail = 0
|
o.flow_detail = 0
|
||||||
m = dump.DumpMaster(o, proxy.DummyServer())
|
m = dump.DumpMaster(o, proxy.DummyServer())
|
||||||
@ -66,13 +66,13 @@ class TestDumpMaster(mastertest.MasterTest):
|
|||||||
self.cycle(m, b"content")
|
self.cycle(m, b"content")
|
||||||
self.cycle(m, b"content")
|
self.cycle(m, b"content")
|
||||||
|
|
||||||
o = dump.Options(server_replay=[p], replay_kill_extra=False)
|
o = dump.Options(http2=False, server_replay=[p], replay_kill_extra=False)
|
||||||
o.verbosity = 0
|
o.verbosity = 0
|
||||||
o.flow_detail = 0
|
o.flow_detail = 0
|
||||||
m = dump.DumpMaster(o, proxy.DummyServer())
|
m = dump.DumpMaster(o, proxy.DummyServer())
|
||||||
self.cycle(m, b"nonexistent")
|
self.cycle(m, b"nonexistent")
|
||||||
|
|
||||||
o = dump.Options(client_replay=[p], replay_kill_extra=False)
|
o = dump.Options(http2=False, client_replay=[p], replay_kill_extra=False)
|
||||||
o.verbosity = 0
|
o.verbosity = 0
|
||||||
o.flow_detail = 0
|
o.flow_detail = 0
|
||||||
m = dump.DumpMaster(o, proxy.DummyServer())
|
m = dump.DumpMaster(o, proxy.DummyServer())
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import io
|
import io
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
|
import pytest
|
||||||
|
|
||||||
from mitmproxy.net import http
|
from mitmproxy.net import http
|
||||||
from mitmproxy.net import tcp
|
|
||||||
from mitmproxy.net.http import http1
|
from mitmproxy.net.http import http1
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
|
|
||||||
@ -11,6 +11,7 @@ from pathod.protocols.http2 import HTTP2StateProtocol
|
|||||||
|
|
||||||
from mitmproxy.test import tutils
|
from mitmproxy.test import tutils
|
||||||
from . import tservers
|
from . import tservers
|
||||||
|
from ..conftest import requires_alpn
|
||||||
|
|
||||||
|
|
||||||
def test_response():
|
def test_response():
|
||||||
@ -211,8 +212,7 @@ class TestDaemonHTTP2(PathocTestDaemon):
|
|||||||
ssl = True
|
ssl = True
|
||||||
explain = False
|
explain = False
|
||||||
|
|
||||||
if tcp.HAS_ALPN:
|
@requires_alpn
|
||||||
|
|
||||||
def test_http2(self):
|
def test_http2(self):
|
||||||
c = pathoc.Pathoc(
|
c = pathoc.Pathoc(
|
||||||
("127.0.0.1", self.d.port),
|
("127.0.0.1", self.d.port),
|
||||||
@ -227,6 +227,7 @@ class TestDaemonHTTP2(PathocTestDaemon):
|
|||||||
)
|
)
|
||||||
assert c.protocol == http1
|
assert c.protocol == http1
|
||||||
|
|
||||||
|
@requires_alpn
|
||||||
def test_http2_alpn(self):
|
def test_http2_alpn(self):
|
||||||
c = pathoc.Pathoc(
|
c = pathoc.Pathoc(
|
||||||
("127.0.0.1", self.d.port),
|
("127.0.0.1", self.d.port),
|
||||||
@ -243,6 +244,7 @@ class TestDaemonHTTP2(PathocTestDaemon):
|
|||||||
_, kwargs = c.convert_to_ssl.call_args
|
_, kwargs = c.convert_to_ssl.call_args
|
||||||
assert set(kwargs['alpn_protos']) == set([b'http/1.1', b'h2'])
|
assert set(kwargs['alpn_protos']) == set([b'http/1.1', b'h2'])
|
||||||
|
|
||||||
|
@requires_alpn
|
||||||
def test_request(self):
|
def test_request(self):
|
||||||
c = pathoc.Pathoc(
|
c = pathoc.Pathoc(
|
||||||
("127.0.0.1", self.d.port),
|
("127.0.0.1", self.d.port),
|
||||||
@ -253,3 +255,14 @@ class TestDaemonHTTP2(PathocTestDaemon):
|
|||||||
with c.connect():
|
with c.connect():
|
||||||
resp = c.request("get:/p/200")
|
resp = c.request("get:/p/200")
|
||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
def test_failing_request(self, disable_alpn):
|
||||||
|
c = pathoc.Pathoc(
|
||||||
|
("127.0.0.1", self.d.port),
|
||||||
|
fp=None,
|
||||||
|
ssl=True,
|
||||||
|
use_http2=True,
|
||||||
|
)
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
with c.connect():
|
||||||
|
c.request("get:/p/200")
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import io
|
import io
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from pathod import pathod
|
from pathod import pathod
|
||||||
from mitmproxy.net import tcp
|
from mitmproxy.net import tcp
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy.test import tutils
|
from mitmproxy.test import tutils
|
||||||
|
|
||||||
from . import tservers
|
from . import tservers
|
||||||
|
from ..conftest import requires_alpn
|
||||||
|
|
||||||
|
|
||||||
class TestPathod:
|
class TestPathod:
|
||||||
@ -257,8 +260,11 @@ class TestHTTP2(tservers.DaemonTests):
|
|||||||
ssl = True
|
ssl = True
|
||||||
nohang = True
|
nohang = True
|
||||||
|
|
||||||
if tcp.HAS_ALPN:
|
@requires_alpn
|
||||||
|
|
||||||
def test_http2(self):
|
def test_http2(self):
|
||||||
r, _ = self.pathoc(["GET:/"], ssl=True, use_http2=True)
|
r, _ = self.pathoc(["GET:/"], ssl=True, use_http2=True)
|
||||||
assert r[0].status_code == 800
|
assert r[0].status_code == 800
|
||||||
|
|
||||||
|
def test_no_http2(self, disable_alpn):
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
r, _ = self.pathoc(["GET:/"], ssl=True, use_http2=True)
|
||||||
|
@ -11,6 +11,8 @@ from ..mitmproxy.net import tservers as net_tservers
|
|||||||
|
|
||||||
from pathod.protocols.http2 import HTTP2StateProtocol, TCPHandler
|
from pathod.protocols.http2 import HTTP2StateProtocol, TCPHandler
|
||||||
|
|
||||||
|
from ..conftest import requires_alpn
|
||||||
|
|
||||||
|
|
||||||
class TestTCPHandlerWrapper:
|
class TestTCPHandlerWrapper:
|
||||||
def test_wrapped(self):
|
def test_wrapped(self):
|
||||||
@ -66,14 +68,13 @@ class TestProtocol:
|
|||||||
assert mock_server_method.called
|
assert mock_server_method.called
|
||||||
|
|
||||||
|
|
||||||
|
@requires_alpn
|
||||||
class TestCheckALPNMatch(net_tservers.ServerTestBase):
|
class TestCheckALPNMatch(net_tservers.ServerTestBase):
|
||||||
handler = EchoHandler
|
handler = EchoHandler
|
||||||
ssl = dict(
|
ssl = dict(
|
||||||
alpn_select=b'h2',
|
alpn_select=b'h2',
|
||||||
)
|
)
|
||||||
|
|
||||||
if tcp.HAS_ALPN:
|
|
||||||
|
|
||||||
def test_check_alpn(self):
|
def test_check_alpn(self):
|
||||||
c = tcp.TCPClient(("127.0.0.1", self.port))
|
c = tcp.TCPClient(("127.0.0.1", self.port))
|
||||||
with c.connect():
|
with c.connect():
|
||||||
@ -82,14 +83,13 @@ class TestCheckALPNMatch(net_tservers.ServerTestBase):
|
|||||||
assert protocol.check_alpn()
|
assert protocol.check_alpn()
|
||||||
|
|
||||||
|
|
||||||
|
@requires_alpn
|
||||||
class TestCheckALPNMismatch(net_tservers.ServerTestBase):
|
class TestCheckALPNMismatch(net_tservers.ServerTestBase):
|
||||||
handler = EchoHandler
|
handler = EchoHandler
|
||||||
ssl = dict(
|
ssl = dict(
|
||||||
alpn_select=None,
|
alpn_select=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
if tcp.HAS_ALPN:
|
|
||||||
|
|
||||||
def test_check_alpn(self):
|
def test_check_alpn(self):
|
||||||
c = tcp.TCPClient(("127.0.0.1", self.port))
|
c = tcp.TCPClient(("127.0.0.1", self.port))
|
||||||
with c.connect():
|
with c.connect():
|
||||||
|
2
tox.ini
2
tox.ini
@ -8,7 +8,7 @@ basepython = python3.5
|
|||||||
deps =
|
deps =
|
||||||
{env:CI_DEPS:}
|
{env:CI_DEPS:}
|
||||||
-rrequirements.txt
|
-rrequirements.txt
|
||||||
passenv = CODECOV_TOKEN CI CI_* TRAVIS TRAVIS_* APPVEYOR APPVEYOR_* SNAPSHOT_*
|
passenv = CODECOV_TOKEN CI CI_* TRAVIS TRAVIS_* APPVEYOR APPVEYOR_* SNAPSHOT_* OPENSSL_*
|
||||||
setenv = HOME = {envtmpdir}
|
setenv = HOME = {envtmpdir}
|
||||||
commands =
|
commands =
|
||||||
mitmdump --sysinfo
|
mitmdump --sysinfo
|
||||||
|
Loading…
Reference in New Issue
Block a user