aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mitmproxy/contentviews/image/__init__.py1
-rw-r--r--mitmproxy/contentviews/image/image_parser.py30
-rw-r--r--mitmproxy/contentviews/image/view.py (renamed from mitmproxy/contentviews/image.py)10
-rw-r--r--mitmproxy/contrib/kaitaistruct/png.py289
-rw-r--r--mitmproxy/proxy/modes/socks_proxy.py2
-rw-r--r--setup.py1
-rw-r--r--test/mitmproxy/contentviews/test_image_parser.py76
-rw-r--r--test/mitmproxy/data/png_parser/aspect.pngbin0 -> 1230326 bytes
-rw-r--r--test/mitmproxy/data/png_parser/ct0n0g04.pngbin0 -> 273 bytes
-rw-r--r--test/mitmproxy/data/png_parser/ct1n0g04.pngbin0 -> 792 bytes
-rw-r--r--test/mitmproxy/data/png_parser/cten0g04.pngbin0 -> 742 bytes
-rw-r--r--test/mitmproxy/data/png_parser/ctzn0g04.pngbin0 -> 753 bytes
-rw-r--r--test/mitmproxy/data/png_parser/g07n0g16.pngbin0 -> 321 bytes
-rw-r--r--test/mitmproxy/test_server.py22
-rw-r--r--tox.ini2
15 files changed, 430 insertions, 3 deletions
diff --git a/mitmproxy/contentviews/image/__init__.py b/mitmproxy/contentviews/image/__init__.py
new file mode 100644
index 00000000..0d0f06e0
--- /dev/null
+++ b/mitmproxy/contentviews/image/__init__.py
@@ -0,0 +1 @@
+from .view import ViewImage # noqa
diff --git a/mitmproxy/contentviews/image/image_parser.py b/mitmproxy/contentviews/image/image_parser.py
new file mode 100644
index 00000000..0af58a88
--- /dev/null
+++ b/mitmproxy/contentviews/image/image_parser.py
@@ -0,0 +1,30 @@
+import io
+import typing
+
+from kaitaistruct import KaitaiStream
+
+from mitmproxy.contrib.kaitaistruct import png
+
+Metadata = typing.List[typing.Tuple[str, str]]
+
+
+def parse_png(data: bytes) -> Metadata:
+ img = png.Png(KaitaiStream(io.BytesIO(data)))
+ parts = [
+ ('Format', 'Portable network graphics')
+ ]
+ parts.append(('Size', "{0} x {1} px".format(img.ihdr.width, img.ihdr.height)))
+ for chunk in img.chunks:
+ if chunk.type == 'gAMA':
+ parts.append(('gamma', str(chunk.body.gamma_int / 100000)))
+ elif chunk.type == 'pHYs':
+ aspectx = chunk.body.pixels_per_unit_x
+ aspecty = chunk.body.pixels_per_unit_y
+ parts.append(('aspect', "{0} x {1}".format(aspectx, aspecty)))
+ elif chunk.type == 'tEXt':
+ parts.append((chunk.body.keyword, chunk.body.text))
+ elif chunk.type == 'iTXt':
+ parts.append((chunk.body.keyword, chunk.body.text))
+ elif chunk.type == 'zTXt':
+ parts.append((chunk.body.keyword, chunk.body.text_datastream.decode('iso8859-1')))
+ return parts
diff --git a/mitmproxy/contentviews/image.py b/mitmproxy/contentviews/image/view.py
index 57b1fffb..08a70795 100644
--- a/mitmproxy/contentviews/image.py
+++ b/mitmproxy/contentviews/image/view.py
@@ -1,10 +1,13 @@
import io
+import imghdr
from PIL import ExifTags
from PIL import Image
from mitmproxy.types import multidict
-from . import base
+from . import image_parser
+
+from mitmproxy.contentviews import base
class ViewImage(base.View):
@@ -19,6 +22,11 @@ class ViewImage(base.View):
]
def __call__(self, data, **metadata):
+ if imghdr.what('', h=data) == 'png':
+ f = "PNG"
+ parts = image_parser.parse_png(data)
+ fmt = base.format_dict(multidict.MultiDict(parts))
+ return "%s image" % f, fmt
try:
img = Image.open(io.BytesIO(data))
except IOError:
diff --git a/mitmproxy/contrib/kaitaistruct/png.py b/mitmproxy/contrib/kaitaistruct/png.py
new file mode 100644
index 00000000..5b0e3ca3
--- /dev/null
+++ b/mitmproxy/contrib/kaitaistruct/png.py
@@ -0,0 +1,289 @@
+# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
+# The source was png.ksy from here - https://github.com/kaitai-io/kaitai_struct_formats/blob/9370c720b7d2ad329102d89bdc880ba6a706ef26/image/png.ksy
+
+import array
+import struct
+import zlib
+from enum import Enum
+
+from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO
+
+
+class Png(KaitaiStruct):
+
+ class ColorType(Enum):
+ greyscale = 0
+ truecolor = 2
+ indexed = 3
+ greyscale_alpha = 4
+ truecolor_alpha = 6
+
+ class PhysUnit(Enum):
+ unknown = 0
+ meter = 1
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.magic = self._io.ensure_fixed_contents(8, struct.pack('8b', -119, 80, 78, 71, 13, 10, 26, 10))
+ self.ihdr_len = self._io.ensure_fixed_contents(4, struct.pack('4b', 0, 0, 0, 13))
+ self.ihdr_type = self._io.ensure_fixed_contents(4, struct.pack('4b', 73, 72, 68, 82))
+ self.ihdr = self._root.IhdrChunk(self._io, self, self._root)
+ self.ihdr_crc = self._io.read_bytes(4)
+ self.chunks = []
+ while not self._io.is_eof():
+ self.chunks.append(self._root.Chunk(self._io, self, self._root))
+
+
+ class Rgb(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.r = self._io.read_u1()
+ self.g = self._io.read_u1()
+ self.b = self._io.read_u1()
+
+
+ class Chunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.len = self._io.read_u4be()
+ self.type = self._io.read_str_byte_limit(4, "UTF-8")
+ _on = self.type
+ if _on == u"iTXt":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.InternationalTextChunk(io, self, self._root)
+ elif _on == u"gAMA":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.GamaChunk(io, self, self._root)
+ elif _on == u"tIME":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.TimeChunk(io, self, self._root)
+ elif _on == u"PLTE":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.PlteChunk(io, self, self._root)
+ elif _on == u"bKGD":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.BkgdChunk(io, self, self._root)
+ elif _on == u"pHYs":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.PhysChunk(io, self, self._root)
+ elif _on == u"tEXt":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.TextChunk(io, self, self._root)
+ elif _on == u"cHRM":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.ChrmChunk(io, self, self._root)
+ elif _on == u"sRGB":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.SrgbChunk(io, self, self._root)
+ elif _on == u"zTXt":
+ self._raw_body = self._io.read_bytes(self.len)
+ io = KaitaiStream(BytesIO(self._raw_body))
+ self.body = self._root.CompressedTextChunk(io, self, self._root)
+ else:
+ self.body = self._io.read_bytes(self.len)
+ self.crc = self._io.read_bytes(4)
+
+
+ class BkgdIndexed(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.palette_index = self._io.read_u1()
+
+
+ class Point(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.x_int = self._io.read_u4be()
+ self.y_int = self._io.read_u4be()
+
+ @property
+ def x(self):
+ if hasattr(self, '_m_x'):
+ return self._m_x
+
+ self._m_x = (self.x_int / 100000.0)
+ return self._m_x
+
+ @property
+ def y(self):
+ if hasattr(self, '_m_y'):
+ return self._m_y
+
+ self._m_y = (self.y_int / 100000.0)
+ return self._m_y
+
+
+ class BkgdGreyscale(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.value = self._io.read_u2be()
+
+
+ class ChrmChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.white_point = self._root.Point(self._io, self, self._root)
+ self.red = self._root.Point(self._io, self, self._root)
+ self.green = self._root.Point(self._io, self, self._root)
+ self.blue = self._root.Point(self._io, self, self._root)
+
+
+ class IhdrChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.width = self._io.read_u4be()
+ self.height = self._io.read_u4be()
+ self.bit_depth = self._io.read_u1()
+ self.color_type = self._root.ColorType(self._io.read_u1())
+ self.compression_method = self._io.read_u1()
+ self.filter_method = self._io.read_u1()
+ self.interlace_method = self._io.read_u1()
+
+
+ class PlteChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.entries = []
+ while not self._io.is_eof():
+ self.entries.append(self._root.Rgb(self._io, self, self._root))
+
+
+
+ class SrgbChunk(KaitaiStruct):
+
+ class Intent(Enum):
+ perceptual = 0
+ relative_colorimetric = 1
+ saturation = 2
+ absolute_colorimetric = 3
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.render_intent = self._root.Intent(self._io.read_u1())
+
+
+ class CompressedTextChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.keyword = self._io.read_strz("UTF-8", 0, False, True, True)
+ self.compression_method = self._io.read_u1()
+ self._raw_text_datastream = self._io.read_bytes_full()
+ self.text_datastream = zlib.decompress(self._raw_text_datastream)
+
+
+ class BkgdTruecolor(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.red = self._io.read_u2be()
+ self.green = self._io.read_u2be()
+ self.blue = self._io.read_u2be()
+
+
+ class GamaChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.gamma_int = self._io.read_u4be()
+
+ @property
+ def gamma_ratio(self):
+ if hasattr(self, '_m_gamma_ratio'):
+ return self._m_gamma_ratio
+
+ self._m_gamma_ratio = (100000.0 / self.gamma_int)
+ return self._m_gamma_ratio
+
+
+ class BkgdChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ _on = self._root.ihdr.color_type
+ if _on == self._root.ColorType.greyscale_alpha:
+ self.bkgd = self._root.BkgdGreyscale(self._io, self, self._root)
+ elif _on == self._root.ColorType.indexed:
+ self.bkgd = self._root.BkgdIndexed(self._io, self, self._root)
+ elif _on == self._root.ColorType.greyscale:
+ self.bkgd = self._root.BkgdGreyscale(self._io, self, self._root)
+ elif _on == self._root.ColorType.truecolor_alpha:
+ self.bkgd = self._root.BkgdTruecolor(self._io, self, self._root)
+ elif _on == self._root.ColorType.truecolor:
+ self.bkgd = self._root.BkgdTruecolor(self._io, self, self._root)
+
+
+ class PhysChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.pixels_per_unit_x = self._io.read_u4be()
+ self.pixels_per_unit_y = self._io.read_u4be()
+ self.unit = self._root.PhysUnit(self._io.read_u1())
+
+
+ class InternationalTextChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.keyword = self._io.read_strz("UTF-8", 0, False, True, True)
+ self.compression_flag = self._io.read_u1()
+ self.compression_method = self._io.read_u1()
+ self.language_tag = self._io.read_strz("ASCII", 0, False, True, True)
+ self.translated_keyword = self._io.read_strz("UTF-8", 0, False, True, True)
+ self.text = self._io.read_str_eos("UTF-8")
+
+
+ class TextChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.keyword = self._io.read_strz("iso8859-1", 0, False, True, True)
+ self.text = self._io.read_str_eos("iso8859-1")
+
+
+ class TimeChunk(KaitaiStruct):
+ def __init__(self, _io, _parent=None, _root=None):
+ self._io = _io
+ self._parent = _parent
+ self._root = _root if _root else self
+ self.year = self._io.read_u2be()
+ self.month = self._io.read_u1()
+ self.day = self._io.read_u1()
+ self.hour = self._io.read_u1()
+ self.minute = self._io.read_u1()
+ self.second = self._io.read_u1()
diff --git a/mitmproxy/proxy/modes/socks_proxy.py b/mitmproxy/proxy/modes/socks_proxy.py
index 3121b731..001a5ed3 100644
--- a/mitmproxy/proxy/modes/socks_proxy.py
+++ b/mitmproxy/proxy/modes/socks_proxy.py
@@ -30,7 +30,7 @@ class Socks5Proxy(protocol.Layer, protocol.ServerConnectionMixin):
if connect_request.msg != socks.CMD.CONNECT:
raise socks.SocksError(
socks.REP.COMMAND_NOT_SUPPORTED,
- "mitmproxy only supports SOCKS5 CONNECT."
+ "mitmproxy only supports SOCKS5 CONNECT"
)
# We always connect lazily, but we need to pretend to the client that we connected.
diff --git a/setup.py b/setup.py
index 85eece95..406f9e6a 100644
--- a/setup.py
+++ b/setup.py
@@ -71,6 +71,7 @@ setup(
"html2text>=2016.1.8, <=2016.9.19",
"hyperframe>=4.0.1, <5",
"jsbeautifier>=1.6.3, <1.7",
+ "kaitaistruct>=0.5, <0.6",
"Pillow>=3.2, <4.1",
"passlib>=1.6.5, <1.8",
"pyasn1>=0.1.9, <0.2",
diff --git a/test/mitmproxy/contentviews/test_image_parser.py b/test/mitmproxy/contentviews/test_image_parser.py
new file mode 100644
index 00000000..62a07f56
--- /dev/null
+++ b/test/mitmproxy/contentviews/test_image_parser.py
@@ -0,0 +1,76 @@
+import pytest
+
+from mitmproxy.contentviews.image import image_parser
+from mitmproxy.test import tutils
+
+
+@pytest.mark.parametrize("filename, metadata", {
+ # no textual data
+ "mitmproxy/data/png_parser/ct0n0g04.png": [
+ ('Format', 'Portable network graphics'),
+ ('Size', '32 x 32 px'),
+ ('gamma', '1.0')
+ ],
+ # with textual data
+ "mitmproxy/data/png_parser/ct1n0g04.png": [
+ ('Format', 'Portable network graphics'),
+ ('Size', '32 x 32 px'),
+ ('gamma', '1.0'),
+ ('Title', 'PngSuite'),
+ ('Author', 'Willem A.J. van Schaik\n(willem@schaik.com)'),
+ ('Copyright', 'Copyright Willem van Schaik, Singapore 1995-96'),
+ ('Description', 'A compilation of a set of images created to test the\n'
+ 'various color-types of the PNG format. Included are\nblack&white, color,'
+ ' paletted, with alpha channel, with\ntransparency formats. All bit-depths'
+ ' allowed according\nto the spec are present.'),
+ ('Software', 'Created on a NeXTstation color using "pnmtopng".'),
+ ('Disclaimer', 'Freeware.')
+ ],
+ # with compressed textual data
+ "mitmproxy/data/png_parser/ctzn0g04.png": [
+ ('Format', 'Portable network graphics'),
+ ('Size', '32 x 32 px'),
+ ('gamma', '1.0'),
+ ('Title', 'PngSuite'),
+ ('Author', 'Willem A.J. van Schaik\n(willem@schaik.com)'),
+ ('Copyright', 'Copyright Willem van Schaik, Singapore 1995-96'),
+ ('Description', 'A compilation of a set of images created to test the\n'
+ 'various color-types of the PNG format. Included are\nblack&white, color,'
+ ' paletted, with alpha channel, with\ntransparency formats. All bit-depths'
+ ' allowed according\nto the spec are present.'),
+ ('Software', 'Created on a NeXTstation color using "pnmtopng".'),
+ ('Disclaimer', 'Freeware.')
+ ],
+ # UTF-8 international text - english
+ "mitmproxy/data/png_parser/cten0g04.png": [
+ ('Format', 'Portable network graphics'),
+ ('Size', '32 x 32 px'),
+ ('gamma', '1.0'),
+ ('Title', 'PngSuite'),
+ ('Author', 'Willem van Schaik (willem@schaik.com)'),
+ ('Copyright', 'Copyright Willem van Schaik, Canada 2011'),
+ ('Description', 'A compilation of a set of images created to test the '
+ 'various color-types of the PNG format. Included are black&white, color,'
+ ' paletted, with alpha channel, with transparency formats. All bit-depths'
+ ' allowed according to the spec are present.'),
+ ('Software', 'Created on a NeXTstation color using "pnmtopng".'),
+ ('Disclaimer', 'Freeware.')
+ ],
+ # check gamma value
+ "mitmproxy/data/png_parser/g07n0g16.png": [
+ ('Format', 'Portable network graphics'),
+ ('Size', '32 x 32 px'),
+ ('gamma', '0.7')
+ ],
+ # check aspect value
+ "mitmproxy/data/png_parser/aspect.png": [
+ ('Format', 'Portable network graphics'),
+ ('Size', '1280 x 798 px'),
+ ('aspect', '72 x 72'),
+ ('date:create', '2012-07-11T14:04:52-07:00'),
+ ('date:modify', '2012-07-11T14:04:52-07:00')
+ ],
+}.items())
+def test_parse_png(filename, metadata):
+ with open(tutils.test_data.path(filename), "rb") as f:
+ assert metadata == image_parser.parse_png(f.read())
diff --git a/test/mitmproxy/data/png_parser/aspect.png b/test/mitmproxy/data/png_parser/aspect.png
new file mode 100644
index 00000000..17c01913
--- /dev/null
+++ b/test/mitmproxy/data/png_parser/aspect.png
Binary files differ
diff --git a/test/mitmproxy/data/png_parser/ct0n0g04.png b/test/mitmproxy/data/png_parser/ct0n0g04.png
new file mode 100644
index 00000000..40d1e062
--- /dev/null
+++ b/test/mitmproxy/data/png_parser/ct0n0g04.png
Binary files differ
diff --git a/test/mitmproxy/data/png_parser/ct1n0g04.png b/test/mitmproxy/data/png_parser/ct1n0g04.png
new file mode 100644
index 00000000..3ba110aa
--- /dev/null
+++ b/test/mitmproxy/data/png_parser/ct1n0g04.png
Binary files differ
diff --git a/test/mitmproxy/data/png_parser/cten0g04.png b/test/mitmproxy/data/png_parser/cten0g04.png
new file mode 100644
index 00000000..a6a56faf
--- /dev/null
+++ b/test/mitmproxy/data/png_parser/cten0g04.png
Binary files differ
diff --git a/test/mitmproxy/data/png_parser/ctzn0g04.png b/test/mitmproxy/data/png_parser/ctzn0g04.png
new file mode 100644
index 00000000..b4401c9c
--- /dev/null
+++ b/test/mitmproxy/data/png_parser/ctzn0g04.png
Binary files differ
diff --git a/test/mitmproxy/data/png_parser/g07n0g16.png b/test/mitmproxy/data/png_parser/g07n0g16.png
new file mode 100644
index 00000000..d6a47c2d
--- /dev/null
+++ b/test/mitmproxy/data/png_parser/g07n0g16.png
Binary files differ
diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py
index 272fc0e0..86fc6ba0 100644
--- a/test/mitmproxy/test_server.py
+++ b/test/mitmproxy/test_server.py
@@ -503,6 +503,7 @@ class TestSocks5(tservers.SocksModeTest):
f = p.request("get:/p/200")
assert f.status_code == 502
assert b"SOCKS5 mode failure" in f.content
+ assert b"Invalid SOCKS version. Expected 0x05, got 0x47" in f.content
def test_no_connect(self):
"""
@@ -526,6 +527,27 @@ class TestSocks5(tservers.SocksModeTest):
f = p.request("get:/p/200") # the request doesn't matter, error response from handshake will be read anyway.
assert f.status_code == 502
assert b"SOCKS5 mode failure" in f.content
+ assert b"mitmproxy only supports SOCKS5 CONNECT" in f.content
+
+ def test_with_authentication(self):
+ p = self.pathoc()
+ with p.connect():
+ socks.ClientGreeting(
+ socks.VERSION.SOCKS5,
+ [socks.METHOD.USERNAME_PASSWORD]
+ ).to_file(p.wfile)
+ socks.Message(
+ socks.VERSION.SOCKS5,
+ socks.CMD.BIND,
+ socks.ATYP.DOMAINNAME,
+ ("example.com", 8080)
+ ).to_file(p.wfile)
+
+ p.wfile.flush()
+ f = p.request("get:/p/200") # the request doesn't matter, error response from handshake will be read anyway.
+ assert f.status_code == 502
+ assert b"SOCKS5 mode failure" in f.content
+ assert b"mitmproxy only supports SOCKS without authentication" in f.content
class TestSocks5SSL(tservers.SocksModeTest):
diff --git a/tox.ini b/tox.ini
index 16f4d664..fafa7220 100644
--- a/tox.ini
+++ b/tox.ini
@@ -15,7 +15,7 @@ commands =
--full-cov=mitmproxy/addons/ \
--full-cov=mitmproxy/contentviews/ --no-full-cov=mitmproxy/contentviews/__init__.py --no-full-cov=mitmproxy/contentviews/protobuf.py --no-full-cov=mitmproxy/contentviews/wbxml.py --no-full-cov=mitmproxy/contentviews/xml_html.py \
--full-cov=mitmproxy/net/ --no-full-cov=mitmproxy/net/check.py --no-full-cov=mitmproxy/net/socks.py --no-full-cov=mitmproxy/net/tcp.py --no-full-cov=mitmproxy/net/http/cookies.py --no-full-cov=mitmproxy/net/http/encoding.py --no-full-cov=mitmproxy/net/http/message.py --no-full-cov=mitmproxy/net/http/request.py --no-full-cov=mitmproxy/net/http/response.py --no-full-cov=mitmproxy/net/http/url.py \
- --full-cov=mitmproxy/proxy/ --no-full-cov=mitmproxy/proxy/protocol/ --no-full-cov=mitmproxy/proxy/modes/socks_proxy.py --no-full-cov=mitmproxy/proxy/config.py --no-full-cov=mitmproxy/proxy/root_context.py --no-full-cov=mitmproxy/proxy/server.py \
+ --full-cov=mitmproxy/proxy/ --no-full-cov=mitmproxy/proxy/protocol/ --no-full-cov=mitmproxy/proxy/config.py --no-full-cov=mitmproxy/proxy/root_context.py --no-full-cov=mitmproxy/proxy/server.py \
--full-cov=mitmproxy/script/ \
--full-cov=mitmproxy/test/ \
--full-cov=mitmproxy/types/ --no-full-cov=mitmproxy/types/basethread.py \