mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 00:01:36 +00:00
move Connections to mitmproxy.connection
This commit is contained in:
parent
d68c364b35
commit
dc6c5f55cd
@ -14,9 +14,10 @@ from mitmproxy.addons.proxyserver import AsyncReply
|
||||
from mitmproxy.hooks import UpdateHook
|
||||
from mitmproxy.net import server_spec
|
||||
from mitmproxy.options import Options
|
||||
from mitmproxy.proxy.context import Context
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy import commands, events, layers, server
|
||||
from mitmproxy.proxy.context import ConnectionState, Context, Server
|
||||
from mitmproxy.connection import ConnectionState, Server
|
||||
from mitmproxy.proxy.layer import CommandGenerator
|
||||
from mitmproxy.utils import asyncio_utils
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import re
|
||||
from typing import Type, Sequence, Union, Tuple, Any, Iterable, Optional, List
|
||||
|
||||
from mitmproxy import ctx, exceptions
|
||||
from mitmproxy import ctx, exceptions, connection
|
||||
from mitmproxy.net.tls import is_tls_record_magic
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy import context, layer, layers
|
||||
@ -43,7 +43,7 @@ class NextLayer:
|
||||
re.compile(x, re.IGNORECASE) for x in ctx.options.allow_hosts
|
||||
]
|
||||
|
||||
def ignore_connection(self, server_address: Optional[context.Address], data_client: bytes) -> Optional[bool]:
|
||||
def ignore_connection(self, server_address: Optional[connection.Address], data_client: bytes) -> Optional[bool]:
|
||||
"""
|
||||
Returns:
|
||||
True, if the connection should be ignored.
|
||||
|
@ -7,11 +7,10 @@ from typing import Tuple
|
||||
import ldap3
|
||||
import passlib.apache
|
||||
|
||||
from mitmproxy import ctx
|
||||
from mitmproxy import ctx, connection
|
||||
from mitmproxy import exceptions
|
||||
from mitmproxy import http
|
||||
from mitmproxy.net.http import status_codes
|
||||
from mitmproxy.proxy import context
|
||||
|
||||
REALM = "mitmproxy"
|
||||
|
||||
@ -48,7 +47,7 @@ class ProxyAuth:
|
||||
self.singleuser = None
|
||||
self.ldapconn = None
|
||||
self.ldapserver = None
|
||||
self.authenticated: MutableMapping[context.Client, Tuple[str, str]] = weakref.WeakKeyDictionary()
|
||||
self.authenticated: MutableMapping[connection.Client, Tuple[str, str]] = weakref.WeakKeyDictionary()
|
||||
"""Contains all connections that are permanently authenticated after an HTTP CONNECT"""
|
||||
|
||||
def load(self, loader):
|
||||
|
@ -3,7 +3,7 @@ from pathlib import Path
|
||||
from typing import List, Optional, TypedDict, Any
|
||||
|
||||
from OpenSSL import SSL
|
||||
from mitmproxy import certs, ctx, exceptions
|
||||
from mitmproxy import certs, ctx, exceptions, connection
|
||||
from mitmproxy.net import tls as net_tls
|
||||
from mitmproxy.options import CONF_BASENAME
|
||||
from mitmproxy.proxy import context
|
||||
@ -113,8 +113,8 @@ class TlsConfig:
|
||||
self.create_proxy_server_ssl_conn(tls_start)
|
||||
|
||||
def create_client_proxy_ssl_conn(self, tls_start: tls.TlsStartData) -> None:
|
||||
client: context.Client = tls_start.context.client
|
||||
server: context.Server = tls_start.context.server
|
||||
client: connection.Client = tls_start.context.client
|
||||
server: connection.Server = tls_start.context.server
|
||||
|
||||
entry = self.get_cert(tls_start.context)
|
||||
|
||||
@ -149,8 +149,8 @@ class TlsConfig:
|
||||
tls_start.ssl_conn.set_accept_state()
|
||||
|
||||
def create_proxy_server_ssl_conn(self, tls_start: tls.TlsStartData) -> None:
|
||||
client: context.Client = tls_start.context.client
|
||||
server: context.Server = tls_start.context.server
|
||||
client: connection.Client = tls_start.context.client
|
||||
server: connection.Server = tls_start.context.server
|
||||
assert server.address
|
||||
|
||||
if ctx.options.ssl_insecure:
|
||||
|
@ -15,14 +15,15 @@ import blinker
|
||||
import sortedcontainers
|
||||
|
||||
import mitmproxy.flow
|
||||
from mitmproxy import flowfilter, hooks
|
||||
from mitmproxy import exceptions
|
||||
from mitmproxy import command
|
||||
from mitmproxy import ctx
|
||||
from mitmproxy import io
|
||||
from mitmproxy import exceptions
|
||||
from mitmproxy import hooks
|
||||
from mitmproxy import connection
|
||||
from mitmproxy import flowfilter
|
||||
from mitmproxy import http
|
||||
from mitmproxy import io
|
||||
from mitmproxy import tcp
|
||||
from mitmproxy.proxy import context
|
||||
from mitmproxy.utils import human
|
||||
|
||||
|
||||
@ -133,15 +134,15 @@ class View(collections.abc.Sequence):
|
||||
|
||||
self.default_order = OrderRequestStart(self)
|
||||
self.orders = dict(
|
||||
time = OrderRequestStart(self), method = OrderRequestMethod(self),
|
||||
url = OrderRequestURL(self), size = OrderKeySize(self),
|
||||
time=OrderRequestStart(self), method=OrderRequestMethod(self),
|
||||
url=OrderRequestURL(self), size=OrderKeySize(self),
|
||||
)
|
||||
self.order_key = self.default_order
|
||||
self.order_reversed = False
|
||||
self.focus_follow = False
|
||||
|
||||
self._view = sortedcontainers.SortedListWithKey(
|
||||
key = self.order_key
|
||||
key=self.order_key
|
||||
)
|
||||
|
||||
# The sig_view* signals broadcast events that affect the view. That is,
|
||||
@ -461,8 +462,8 @@ class View(collections.abc.Sequence):
|
||||
except ValueError as e:
|
||||
raise exceptions.CommandError("Invalid URL: %s" % e)
|
||||
|
||||
c = context.Client(("", 0), ("", 0), req.timestamp_start - 0.0001)
|
||||
s = context.Server((req.host, req.port))
|
||||
c = connection.Client(("", 0), ("", 0), req.timestamp_start - 0.0001)
|
||||
s = connection.Server((req.host, req.port))
|
||||
|
||||
f = http.HTTPFlow(c, s)
|
||||
f.request = req
|
||||
@ -622,6 +623,7 @@ class Focus:
|
||||
"""
|
||||
Tracks a focus element within a View.
|
||||
"""
|
||||
|
||||
def __init__(self, v: View) -> None:
|
||||
self.view = v
|
||||
self._flow: typing.Optional[mitmproxy.flow.Flow] = None
|
||||
|
374
mitmproxy/connection.py
Normal file
374
mitmproxy/connection.py
Normal file
@ -0,0 +1,374 @@
|
||||
import uuid
|
||||
import warnings
|
||||
from abc import ABCMeta
|
||||
from enum import Flag
|
||||
from typing import Literal, Optional, Sequence, Tuple, Union
|
||||
|
||||
from mitmproxy import certs
|
||||
from mitmproxy.coretypes import serializable
|
||||
from mitmproxy.net import server_spec
|
||||
from mitmproxy.utils import human
|
||||
|
||||
|
||||
class ConnectionState(Flag):
|
||||
"""The current state of the underlying socket."""
|
||||
CLOSED = 0
|
||||
CAN_READ = 1
|
||||
CAN_WRITE = 2
|
||||
OPEN = CAN_READ | CAN_WRITE
|
||||
|
||||
|
||||
# practically speaking we may have IPv6 addresses with flowinfo and scope_id,
|
||||
# but type checking isn't good enough to properly handle tuple unions.
|
||||
# this version at least provides useful type checking messages.
|
||||
Address = Tuple[str, int]
|
||||
|
||||
|
||||
class Connection(serializable.Serializable, metaclass=ABCMeta):
|
||||
"""
|
||||
Base class for client and server connections.
|
||||
|
||||
The connection object only exposes metadata about the connection, but not the underlying socket object.
|
||||
This is intentional, all I/O should be handled by mitmproxy.proxy.server exclusively.
|
||||
"""
|
||||
# all connections have a unique id. While
|
||||
# f.client_conn == f2.client_conn already holds true for live flows (where we have object identity),
|
||||
# we also want these semantics for recorded flows.
|
||||
id: str
|
||||
"""A unique UUID to identify the connection."""
|
||||
state: ConnectionState
|
||||
"""The current connection state."""
|
||||
peername: Optional[Address]
|
||||
"""The remote's `(ip, port)` tuple for this connection."""
|
||||
sockname: Optional[Address]
|
||||
"""Our local `(ip, port)` tuple for this connection."""
|
||||
error: Optional[str] = None
|
||||
"""A string describing the connection error."""
|
||||
|
||||
tls: bool = False
|
||||
"""
|
||||
`True` if TLS should be established, `False` otherwise.
|
||||
Note that this property only describes if a connection should eventually be protected using TLS.
|
||||
To check if TLS has already been established, use `Connection.tls_established`.
|
||||
"""
|
||||
certificate_list: Sequence[certs.Cert] = ()
|
||||
"""
|
||||
The TLS certificate list as sent by the peer.
|
||||
The first certificate is the end-entity certificate.
|
||||
|
||||
> [RFC 8446] Prior to TLS 1.3, "certificate_list" ordering required each
|
||||
> certificate to certify the one immediately preceding it; however,
|
||||
> some implementations allowed some flexibility. Servers sometimes
|
||||
> send both a current and deprecated intermediate for transitional
|
||||
> purposes, and others are simply configured incorrectly, but these
|
||||
> cases can nonetheless be validated properly. For maximum
|
||||
> compatibility, all implementations SHOULD be prepared to handle
|
||||
> potentially extraneous certificates and arbitrary orderings from any
|
||||
> TLS version, with the exception of the end-entity certificate which
|
||||
> MUST be first.
|
||||
"""
|
||||
alpn: Optional[bytes] = None
|
||||
"""The application-layer protocol as negotiated using
|
||||
[ALPN](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation)."""
|
||||
alpn_offers: Sequence[bytes] = ()
|
||||
"""The ALPN offers as sent in the ClientHello."""
|
||||
# we may want to add SSL_CIPHER_description here, but that's currently not exposed by cryptography
|
||||
cipher: Optional[str] = None
|
||||
"""The active cipher name as returned by OpenSSL's `SSL_CIPHER_get_name`."""
|
||||
cipher_list: Sequence[str] = ()
|
||||
"""Ciphers accepted by the proxy server on this connection."""
|
||||
tls_version: Optional[str] = None
|
||||
"""The active TLS version."""
|
||||
sni: Union[str, Literal[True], None]
|
||||
"""
|
||||
The [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) sent in the ClientHello.
|
||||
For server connections, this value may also be set to `True`, which means "use `Server.address`".
|
||||
"""
|
||||
|
||||
timestamp_end: Optional[float] = None
|
||||
"""*Timestamp:* Connection has been closed."""
|
||||
timestamp_tls_setup: Optional[float] = None
|
||||
"""*Timestamp:* TLS handshake has been completed successfully."""
|
||||
|
||||
@property
|
||||
def connected(self) -> bool:
|
||||
"""`True` if Connection.state is ConnectionState.OPEN, `False` otherwise. Read-only."""
|
||||
return self.state is ConnectionState.OPEN
|
||||
|
||||
@property
|
||||
def tls_established(self) -> bool:
|
||||
"""`True` if TLS has been established, `False` otherwise. Read-only."""
|
||||
return self.timestamp_tls_setup is not None
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Connection):
|
||||
return self.id == other.id
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.id)
|
||||
|
||||
def __repr__(self):
|
||||
attrs = repr({
|
||||
k: {
|
||||
"cipher_list": lambda: f"<{len(v)} ciphers>",
|
||||
"id": lambda: f"…{v[-6:]}"
|
||||
}.get(k, lambda: v)()
|
||||
for k, v in self.__dict__.items()
|
||||
})
|
||||
return f"{type(self).__name__}({attrs})"
|
||||
|
||||
@property
|
||||
def alpn_proto_negotiated(self) -> Optional[bytes]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for Connection.alpn."""
|
||||
warnings.warn("Connection.alpn_proto_negotiated is deprecated, use Connection.alpn instead.",
|
||||
DeprecationWarning)
|
||||
return self.alpn
|
||||
|
||||
|
||||
class Client(Connection):
|
||||
"""A connection between a client and mitmproxy."""
|
||||
peername: Address
|
||||
"""The client's address."""
|
||||
sockname: Address
|
||||
"""The local address we received this connection on."""
|
||||
|
||||
mitmcert: Optional[certs.Cert] = None
|
||||
"""
|
||||
The certificate used by mitmproxy to establish TLS with the client.
|
||||
"""
|
||||
sni: Union[str, None] = None
|
||||
"""The Server Name Indication sent by the client."""
|
||||
|
||||
timestamp_start: float
|
||||
"""*Timestamp:* TCP SYN received"""
|
||||
|
||||
def __init__(self, peername, sockname, timestamp_start):
|
||||
self.id = str(uuid.uuid4())
|
||||
self.peername = peername
|
||||
self.sockname = sockname
|
||||
self.timestamp_start = timestamp_start
|
||||
self.state = ConnectionState.OPEN
|
||||
|
||||
def __str__(self):
|
||||
if self.alpn:
|
||||
tls_state = f", alpn={self.alpn.decode(errors='replace')}"
|
||||
elif self.tls_established:
|
||||
tls_state = ", tls"
|
||||
else:
|
||||
tls_state = ""
|
||||
return f"Client({human.format_address(self.peername)}, state={self.state.name.lower()}{tls_state})"
|
||||
|
||||
def get_state(self):
|
||||
# Important: Retain full compatibility with old proxy core for now!
|
||||
# This means we need to add all new fields to the old implementation.
|
||||
return {
|
||||
'address': self.peername,
|
||||
'alpn': self.alpn,
|
||||
'cipher_name': self.cipher,
|
||||
'id': self.id,
|
||||
'mitmcert': self.mitmcert.get_state() if self.mitmcert is not None else None,
|
||||
'sni': self.sni,
|
||||
'timestamp_end': self.timestamp_end,
|
||||
'timestamp_start': self.timestamp_start,
|
||||
'timestamp_tls_setup': self.timestamp_tls_setup,
|
||||
'tls_established': self.tls_established,
|
||||
'tls_extensions': [],
|
||||
'tls_version': self.tls_version,
|
||||
# only used in sans-io
|
||||
'state': self.state.value,
|
||||
'sockname': self.sockname,
|
||||
'error': self.error,
|
||||
'tls': self.tls,
|
||||
'certificate_list': [x.get_state() for x in self.certificate_list],
|
||||
'alpn_offers': self.alpn_offers,
|
||||
'cipher_list': self.cipher_list,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_state(cls, state) -> "Client":
|
||||
client = Client(
|
||||
state["address"],
|
||||
("mitmproxy", 8080),
|
||||
state["timestamp_start"]
|
||||
)
|
||||
client.set_state(state)
|
||||
return client
|
||||
|
||||
def set_state(self, state):
|
||||
self.peername = tuple(state["address"]) if state["address"] else None
|
||||
self.alpn = state["alpn"]
|
||||
self.cipher = state["cipher_name"]
|
||||
self.id = state["id"]
|
||||
self.sni = state["sni"]
|
||||
self.timestamp_end = state["timestamp_end"]
|
||||
self.timestamp_start = state["timestamp_start"]
|
||||
self.timestamp_tls_setup = state["timestamp_tls_setup"]
|
||||
self.tls_version = state["tls_version"]
|
||||
# only used in sans-io
|
||||
self.state = ConnectionState(state["state"])
|
||||
self.sockname = tuple(state["sockname"]) if state["sockname"] else None
|
||||
self.error = state["error"]
|
||||
self.tls = state["tls"]
|
||||
self.certificate_list = [certs.Cert.from_state(x) for x in state["certificate_list"]]
|
||||
self.mitmcert = certs.Cert.from_state(state["mitmcert"]) if state["mitmcert"] is not None else None
|
||||
self.alpn_offers = state["alpn_offers"]
|
||||
self.cipher_list = state["cipher_list"]
|
||||
|
||||
@property
|
||||
def address(self): # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for Client.peername."""
|
||||
warnings.warn("Client.address is deprecated, use Client.peername instead.", DeprecationWarning, stacklevel=2)
|
||||
return self.peername
|
||||
|
||||
@address.setter
|
||||
def address(self, x): # pragma: no cover
|
||||
warnings.warn("Client.address is deprecated, use Client.peername instead.", DeprecationWarning, stacklevel=2)
|
||||
self.peername = x
|
||||
|
||||
@property
|
||||
def cipher_name(self) -> Optional[str]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for Connection.cipher."""
|
||||
warnings.warn("Client.cipher_name is deprecated, use Client.cipher instead.", DeprecationWarning, stacklevel=2)
|
||||
return self.cipher
|
||||
|
||||
@property
|
||||
def clientcert(self) -> Optional[certs.Cert]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for Connection.certificate_list[0]."""
|
||||
warnings.warn("Client.clientcert is deprecated, use Client.certificate_list instead.", DeprecationWarning,
|
||||
stacklevel=2)
|
||||
if self.certificate_list:
|
||||
return self.certificate_list[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
@clientcert.setter
|
||||
def clientcert(self, val): # pragma: no cover
|
||||
warnings.warn("Client.clientcert is deprecated, use Client.certificate_list instead.", DeprecationWarning)
|
||||
if val:
|
||||
self.certificate_list = [val]
|
||||
else:
|
||||
self.certificate_list = []
|
||||
|
||||
|
||||
class Server(Connection):
|
||||
"""A connection between mitmproxy and an upstream server."""
|
||||
|
||||
peername: Optional[Address] = None
|
||||
"""The server's resolved `(ip, port)` tuple. Will be set during connection establishment."""
|
||||
sockname: Optional[Address] = None
|
||||
address: Optional[Address]
|
||||
"""The server's `(host, port)` address tuple. The host can either be a domain or a plain IP address."""
|
||||
|
||||
timestamp_start: Optional[float] = None
|
||||
"""*Timestamp:* TCP SYN sent."""
|
||||
timestamp_tcp_setup: Optional[float] = None
|
||||
"""*Timestamp:* TCP ACK received."""
|
||||
|
||||
sni: Union[str, Literal[True], None] = True
|
||||
via: Optional[server_spec.ServerSpec] = None
|
||||
"""An optional proxy server specification via which the connection should be established."""
|
||||
|
||||
def __init__(self, address: Optional[Address]):
|
||||
self.id = str(uuid.uuid4())
|
||||
self.address = address
|
||||
self.state = ConnectionState.CLOSED
|
||||
|
||||
def __str__(self):
|
||||
if self.alpn:
|
||||
tls_state = f", alpn={self.alpn.decode(errors='replace')}"
|
||||
elif self.tls_established:
|
||||
tls_state = ", tls"
|
||||
else:
|
||||
tls_state = ""
|
||||
if self.sockname:
|
||||
local_port = f", src_port={self.sockname[1]}"
|
||||
else:
|
||||
local_port = ""
|
||||
return f"Server({human.format_address(self.address)}, state={self.state.name.lower()}{tls_state}{local_port})"
|
||||
|
||||
def get_state(self):
|
||||
return {
|
||||
'address': self.address,
|
||||
'alpn': self.alpn,
|
||||
'id': self.id,
|
||||
'ip_address': self.peername,
|
||||
'sni': self.sni,
|
||||
'source_address': self.sockname,
|
||||
'timestamp_end': self.timestamp_end,
|
||||
'timestamp_start': self.timestamp_start,
|
||||
'timestamp_tcp_setup': self.timestamp_tcp_setup,
|
||||
'timestamp_tls_setup': self.timestamp_tls_setup,
|
||||
'tls_established': self.tls_established,
|
||||
'tls_version': self.tls_version,
|
||||
'via': None,
|
||||
# only used in sans-io
|
||||
'state': self.state.value,
|
||||
'error': self.error,
|
||||
'tls': self.tls,
|
||||
'certificate_list': [x.get_state() for x in self.certificate_list],
|
||||
'alpn_offers': self.alpn_offers,
|
||||
'cipher_name': self.cipher,
|
||||
'cipher_list': self.cipher_list,
|
||||
'via2': self.via,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_state(cls, state) -> "Server":
|
||||
server = Server(None)
|
||||
server.set_state(state)
|
||||
return server
|
||||
|
||||
def set_state(self, state):
|
||||
self.address = tuple(state["address"]) if state["address"] else None
|
||||
self.alpn = state["alpn"]
|
||||
self.id = state["id"]
|
||||
self.peername = tuple(state["ip_address"]) if state["ip_address"] else None
|
||||
self.sni = state["sni"]
|
||||
self.sockname = tuple(state["source_address"]) if state["source_address"] else None
|
||||
self.timestamp_end = state["timestamp_end"]
|
||||
self.timestamp_start = state["timestamp_start"]
|
||||
self.timestamp_tcp_setup = state["timestamp_tcp_setup"]
|
||||
self.timestamp_tls_setup = state["timestamp_tls_setup"]
|
||||
self.tls_version = state["tls_version"]
|
||||
self.state = ConnectionState(state["state"])
|
||||
self.error = state["error"]
|
||||
self.tls = state["tls"]
|
||||
self.certificate_list = [certs.Cert.from_state(x) for x in state["certificate_list"]]
|
||||
self.alpn_offers = state["alpn_offers"]
|
||||
self.cipher = state["cipher_name"]
|
||||
self.cipher_list = state["cipher_list"]
|
||||
self.via = state["via2"]
|
||||
|
||||
@property
|
||||
def ip_address(self) -> Optional[Address]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for `Server.peername`."""
|
||||
warnings.warn("Server.ip_address is deprecated, use Server.peername instead.", DeprecationWarning, stacklevel=2)
|
||||
return self.peername
|
||||
|
||||
@property
|
||||
def cert(self) -> Optional[certs.Cert]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for `Connection.certificate_list[0]`."""
|
||||
warnings.warn("Server.cert is deprecated, use Server.certificate_list instead.", DeprecationWarning,
|
||||
stacklevel=2)
|
||||
if self.certificate_list:
|
||||
return self.certificate_list[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
@cert.setter
|
||||
def cert(self, val): # pragma: no cover
|
||||
warnings.warn("Server.cert is deprecated, use Server.certificate_list instead.", DeprecationWarning,
|
||||
stacklevel=2)
|
||||
if val:
|
||||
self.certificate_list = [val]
|
||||
else:
|
||||
self.certificate_list = []
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Connection",
|
||||
"Client",
|
||||
"Server",
|
||||
"ConnectionState"
|
||||
]
|
@ -2,11 +2,10 @@ import time
|
||||
import typing # noqa
|
||||
import uuid
|
||||
|
||||
from mitmproxy import controller
|
||||
from mitmproxy import controller, connection
|
||||
from mitmproxy import exceptions
|
||||
from mitmproxy import stateobject
|
||||
from mitmproxy import version
|
||||
from mitmproxy.proxy import context
|
||||
|
||||
|
||||
class Error(stateobject.StateObject):
|
||||
@ -55,18 +54,17 @@ class Error(stateobject.StateObject):
|
||||
|
||||
|
||||
class Flow(stateobject.StateObject):
|
||||
|
||||
"""
|
||||
A Flow is a collection of objects representing a single transaction.
|
||||
This class is usually subclassed for each protocol, e.g. HTTPFlow.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: str,
|
||||
client_conn: context.Client,
|
||||
server_conn: context.Server,
|
||||
live: bool=None
|
||||
self,
|
||||
type: str,
|
||||
client_conn: connection.Client,
|
||||
server_conn: connection.Server,
|
||||
live: bool = None
|
||||
) -> None:
|
||||
self.type = type
|
||||
self.id = str(uuid.uuid4())
|
||||
@ -85,8 +83,8 @@ class Flow(stateobject.StateObject):
|
||||
_stateobject_attributes = dict(
|
||||
id=str,
|
||||
error=Error,
|
||||
client_conn=context.Client,
|
||||
server_conn=context.Server,
|
||||
client_conn=connection.Client,
|
||||
server_conn=connection.Server,
|
||||
type=str,
|
||||
intercepted=bool,
|
||||
is_replay=str,
|
||||
|
@ -1,5 +1,4 @@
|
||||
import re
|
||||
import re
|
||||
import time
|
||||
import urllib.parse
|
||||
from dataclasses import dataclass
|
||||
@ -13,7 +12,7 @@ from typing import Optional
|
||||
from typing import Tuple
|
||||
from typing import Union
|
||||
|
||||
from mitmproxy import flow
|
||||
from mitmproxy import flow, connection
|
||||
from mitmproxy.coretypes import multidict
|
||||
from mitmproxy.coretypes import serializable
|
||||
from mitmproxy.net import encoding
|
||||
@ -21,7 +20,6 @@ from mitmproxy.net.http import cookies, multipart
|
||||
from mitmproxy.net.http import status_codes
|
||||
from mitmproxy.net.http import url
|
||||
from mitmproxy.net.http.headers import assemble_content_type, parse_content_type
|
||||
from mitmproxy.proxy import context
|
||||
from mitmproxy.utils import human
|
||||
from mitmproxy.utils import strutils
|
||||
from mitmproxy.utils import typecheck
|
||||
@ -1117,8 +1115,8 @@ class HTTPFlow(flow.Flow):
|
||||
object. This might happen, for instance, when a response was received
|
||||
from the server, but there was an error sending it back to the client.
|
||||
"""
|
||||
server_conn: context.Server
|
||||
client_conn: context.Client
|
||||
server_conn: connection.Server
|
||||
client_conn: connection.Client
|
||||
intercepted: bool = False
|
||||
""" Is this flow currently being intercepted? """
|
||||
mode: str
|
||||
|
@ -9,7 +9,7 @@ The counterpart to commands are events.
|
||||
from typing import Literal, Union, TYPE_CHECKING
|
||||
|
||||
import mitmproxy.hooks
|
||||
from mitmproxy.proxy.context import Connection, Server
|
||||
from mitmproxy.connection import Connection, Server
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import mitmproxy.proxy.layer
|
||||
|
@ -1,394 +1,30 @@
|
||||
import uuid
|
||||
import warnings
|
||||
from abc import ABCMeta
|
||||
from enum import Flag
|
||||
from typing import List, Literal, Optional, Sequence, Tuple, Union, TYPE_CHECKING
|
||||
from typing import List, TYPE_CHECKING
|
||||
|
||||
import mitmproxy
|
||||
from mitmproxy import certs
|
||||
from mitmproxy.coretypes import serializable
|
||||
from mitmproxy.net import server_spec
|
||||
from mitmproxy import connection
|
||||
from mitmproxy.options import Options
|
||||
from mitmproxy.utils import human
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import mitmproxy.proxy.layer
|
||||
|
||||
|
||||
class ConnectionState(Flag):
|
||||
"""The current state of the underlying socket."""
|
||||
CLOSED = 0
|
||||
CAN_READ = 1
|
||||
CAN_WRITE = 2
|
||||
OPEN = CAN_READ | CAN_WRITE
|
||||
|
||||
|
||||
# practically speaking we may have IPv6 addresses with flowinfo and scope_id,
|
||||
# but type checking isn't good enough to properly handle tuple unions.
|
||||
# this version at least provides useful type checking messages.
|
||||
Address = Tuple[str, int]
|
||||
|
||||
|
||||
class Connection(serializable.Serializable, metaclass=ABCMeta):
|
||||
"""
|
||||
Base class for client and server connections.
|
||||
|
||||
The connection object only exposes metadata about the connection, but not the underlying socket object.
|
||||
This is intentional, all I/O should be handled by mitmproxy.proxy.server exclusively.
|
||||
"""
|
||||
# all connections have a unique id. While
|
||||
# f.client_conn == f2.client_conn already holds true for live flows (where we have object identity),
|
||||
# we also want these semantics for recorded flows.
|
||||
id: str
|
||||
"""A unique UUID to identify the connection."""
|
||||
state: ConnectionState
|
||||
"""The current connection state."""
|
||||
peername: Optional[Address]
|
||||
"""The remote's `(ip, port)` tuple for this connection."""
|
||||
sockname: Optional[Address]
|
||||
"""Our local `(ip, port)` tuple for this connection."""
|
||||
error: Optional[str] = None
|
||||
"""A string describing the connection error."""
|
||||
|
||||
tls: bool = False
|
||||
"""
|
||||
`True` if TLS should be established, `False` otherwise.
|
||||
Note that this property only describes if a connection should eventually be protected using TLS.
|
||||
To check if TLS has already been established, use `Connection.tls_established`.
|
||||
"""
|
||||
certificate_list: Sequence[certs.Cert] = ()
|
||||
"""
|
||||
The TLS certificate list as sent by the peer.
|
||||
The first certificate is the end-entity certificate.
|
||||
|
||||
> [RFC 8446] Prior to TLS 1.3, "certificate_list" ordering required each
|
||||
> certificate to certify the one immediately preceding it; however,
|
||||
> some implementations allowed some flexibility. Servers sometimes
|
||||
> send both a current and deprecated intermediate for transitional
|
||||
> purposes, and others are simply configured incorrectly, but these
|
||||
> cases can nonetheless be validated properly. For maximum
|
||||
> compatibility, all implementations SHOULD be prepared to handle
|
||||
> potentially extraneous certificates and arbitrary orderings from any
|
||||
> TLS version, with the exception of the end-entity certificate which
|
||||
> MUST be first.
|
||||
"""
|
||||
alpn: Optional[bytes] = None
|
||||
"""The application-layer protocol as negotiated using
|
||||
[ALPN](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation)."""
|
||||
alpn_offers: Sequence[bytes] = ()
|
||||
"""The ALPN offers as sent in the ClientHello."""
|
||||
# we may want to add SSL_CIPHER_description here, but that's currently not exposed by cryptography
|
||||
cipher: Optional[str] = None
|
||||
"""The active cipher name as returned by OpenSSL's `SSL_CIPHER_get_name`."""
|
||||
cipher_list: Sequence[str] = ()
|
||||
"""Ciphers accepted by the proxy server on this connection."""
|
||||
tls_version: Optional[str] = None
|
||||
"""The active TLS version."""
|
||||
sni: Union[str, Literal[True], None]
|
||||
"""
|
||||
The [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) sent in the ClientHello.
|
||||
For server connections, this value may also be set to `True`, which means "use `Server.address`".
|
||||
"""
|
||||
|
||||
timestamp_end: Optional[float] = None
|
||||
"""*Timestamp:* Connection has been closed."""
|
||||
timestamp_tls_setup: Optional[float] = None
|
||||
"""*Timestamp:* TLS handshake has been completed successfully."""
|
||||
|
||||
@property
|
||||
def connected(self) -> bool:
|
||||
"""`True` if Connection.state is ConnectionState.OPEN, `False` otherwise. Read-only."""
|
||||
return self.state is ConnectionState.OPEN
|
||||
|
||||
@property
|
||||
def tls_established(self) -> bool:
|
||||
"""`True` if TLS has been established, `False` otherwise. Read-only."""
|
||||
return self.timestamp_tls_setup is not None
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Connection):
|
||||
return self.id == other.id
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.id)
|
||||
|
||||
def __repr__(self):
|
||||
attrs = repr({
|
||||
k: {
|
||||
"cipher_list": lambda: f"<{len(v)} ciphers>",
|
||||
"id": lambda: f"…{v[-6:]}"
|
||||
}.get(k, lambda: v)()
|
||||
for k, v in self.__dict__.items()
|
||||
})
|
||||
return f"{type(self).__name__}({attrs})"
|
||||
|
||||
@property
|
||||
def alpn_proto_negotiated(self) -> Optional[bytes]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for Connection.alpn."""
|
||||
warnings.warn("Connection.alpn_proto_negotiated is deprecated, use Connection.alpn instead.",
|
||||
DeprecationWarning)
|
||||
return self.alpn
|
||||
|
||||
|
||||
class Client(Connection):
|
||||
"""A connection between a client and mitmproxy."""
|
||||
peername: Address
|
||||
"""The client's address."""
|
||||
sockname: Address
|
||||
"""The local address we received this connection on."""
|
||||
|
||||
mitmcert: Optional[certs.Cert] = None
|
||||
"""
|
||||
The certificate used by mitmproxy to establish TLS with the client.
|
||||
"""
|
||||
sni: Union[str, None] = None
|
||||
"""The Server Name Indication sent by the client."""
|
||||
|
||||
timestamp_start: float
|
||||
"""*Timestamp:* TCP SYN received"""
|
||||
|
||||
def __init__(self, peername, sockname, timestamp_start):
|
||||
self.id = str(uuid.uuid4())
|
||||
self.peername = peername
|
||||
self.sockname = sockname
|
||||
self.timestamp_start = timestamp_start
|
||||
self.state = ConnectionState.OPEN
|
||||
|
||||
def __str__(self):
|
||||
if self.alpn:
|
||||
tls_state = f", alpn={self.alpn.decode(errors='replace')}"
|
||||
elif self.tls_established:
|
||||
tls_state = ", tls"
|
||||
else:
|
||||
tls_state = ""
|
||||
return f"Client({human.format_address(self.peername)}, state={self.state.name.lower()}{tls_state})"
|
||||
|
||||
def get_state(self):
|
||||
# Important: Retain full compatibility with old proxy core for now!
|
||||
# This means we need to add all new fields to the old implementation.
|
||||
return {
|
||||
'address': self.peername,
|
||||
'alpn': self.alpn,
|
||||
'cipher_name': self.cipher,
|
||||
'id': self.id,
|
||||
'mitmcert': self.mitmcert.get_state() if self.mitmcert is not None else None,
|
||||
'sni': self.sni,
|
||||
'timestamp_end': self.timestamp_end,
|
||||
'timestamp_start': self.timestamp_start,
|
||||
'timestamp_tls_setup': self.timestamp_tls_setup,
|
||||
'tls_established': self.tls_established,
|
||||
'tls_extensions': [],
|
||||
'tls_version': self.tls_version,
|
||||
# only used in sans-io
|
||||
'state': self.state.value,
|
||||
'sockname': self.sockname,
|
||||
'error': self.error,
|
||||
'tls': self.tls,
|
||||
'certificate_list': [x.get_state() for x in self.certificate_list],
|
||||
'alpn_offers': self.alpn_offers,
|
||||
'cipher_list': self.cipher_list,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_state(cls, state) -> "Client":
|
||||
client = Client(
|
||||
state["address"],
|
||||
("mitmproxy", 8080),
|
||||
state["timestamp_start"]
|
||||
)
|
||||
client.set_state(state)
|
||||
return client
|
||||
|
||||
def set_state(self, state):
|
||||
self.peername = tuple(state["address"]) if state["address"] else None
|
||||
self.alpn = state["alpn"]
|
||||
self.cipher = state["cipher_name"]
|
||||
self.id = state["id"]
|
||||
self.sni = state["sni"]
|
||||
self.timestamp_end = state["timestamp_end"]
|
||||
self.timestamp_start = state["timestamp_start"]
|
||||
self.timestamp_tls_setup = state["timestamp_tls_setup"]
|
||||
self.tls_version = state["tls_version"]
|
||||
# only used in sans-io
|
||||
self.state = ConnectionState(state["state"])
|
||||
self.sockname = tuple(state["sockname"]) if state["sockname"] else None
|
||||
self.error = state["error"]
|
||||
self.tls = state["tls"]
|
||||
self.certificate_list = [certs.Cert.from_state(x) for x in state["certificate_list"]]
|
||||
self.mitmcert = certs.Cert.from_state(state["mitmcert"]) if state["mitmcert"] is not None else None
|
||||
self.alpn_offers = state["alpn_offers"]
|
||||
self.cipher_list = state["cipher_list"]
|
||||
|
||||
@property
|
||||
def address(self): # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for Client.peername."""
|
||||
warnings.warn("Client.address is deprecated, use Client.peername instead.", DeprecationWarning, stacklevel=2)
|
||||
return self.peername
|
||||
|
||||
@address.setter
|
||||
def address(self, x): # pragma: no cover
|
||||
warnings.warn("Client.address is deprecated, use Client.peername instead.", DeprecationWarning, stacklevel=2)
|
||||
self.peername = x
|
||||
|
||||
@property
|
||||
def cipher_name(self) -> Optional[str]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for Connection.cipher."""
|
||||
warnings.warn("Client.cipher_name is deprecated, use Client.cipher instead.", DeprecationWarning, stacklevel=2)
|
||||
return self.cipher
|
||||
|
||||
@property
|
||||
def clientcert(self) -> Optional[certs.Cert]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for Connection.certificate_list[0]."""
|
||||
warnings.warn("Client.clientcert is deprecated, use Client.certificate_list instead.", DeprecationWarning,
|
||||
stacklevel=2)
|
||||
if self.certificate_list:
|
||||
return self.certificate_list[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
@clientcert.setter
|
||||
def clientcert(self, val): # pragma: no cover
|
||||
warnings.warn("Client.clientcert is deprecated, use Client.certificate_list instead.", DeprecationWarning)
|
||||
if val:
|
||||
self.certificate_list = [val]
|
||||
else:
|
||||
self.certificate_list = []
|
||||
|
||||
|
||||
class Server(Connection):
|
||||
"""A connection between mitmproxy and an upstream server."""
|
||||
|
||||
peername: Optional[Address] = None
|
||||
"""The server's resolved `(ip, port)` tuple. Will be set during connection establishment."""
|
||||
sockname: Optional[Address] = None
|
||||
address: Optional[Address]
|
||||
"""The server's `(host, port)` address tuple. The host can either be a domain or a plain IP address."""
|
||||
|
||||
timestamp_start: Optional[float] = None
|
||||
"""*Timestamp:* TCP SYN sent."""
|
||||
timestamp_tcp_setup: Optional[float] = None
|
||||
"""*Timestamp:* TCP ACK received."""
|
||||
|
||||
sni: Union[str, Literal[True], None] = True
|
||||
via: Optional[server_spec.ServerSpec] = None
|
||||
"""An optional proxy server specification via which the connection should be established."""
|
||||
|
||||
def __init__(self, address: Optional[Address]):
|
||||
self.id = str(uuid.uuid4())
|
||||
self.address = address
|
||||
self.state = ConnectionState.CLOSED
|
||||
|
||||
def __str__(self):
|
||||
if self.alpn:
|
||||
tls_state = f", alpn={self.alpn.decode(errors='replace')}"
|
||||
elif self.tls_established:
|
||||
tls_state = ", tls"
|
||||
else:
|
||||
tls_state = ""
|
||||
if self.sockname:
|
||||
local_port = f", src_port={self.sockname[1]}"
|
||||
else:
|
||||
local_port = ""
|
||||
return f"Server({human.format_address(self.address)}, state={self.state.name.lower()}{tls_state}{local_port})"
|
||||
|
||||
def get_state(self):
|
||||
return {
|
||||
'address': self.address,
|
||||
'alpn': self.alpn,
|
||||
'id': self.id,
|
||||
'ip_address': self.peername,
|
||||
'sni': self.sni,
|
||||
'source_address': self.sockname,
|
||||
'timestamp_end': self.timestamp_end,
|
||||
'timestamp_start': self.timestamp_start,
|
||||
'timestamp_tcp_setup': self.timestamp_tcp_setup,
|
||||
'timestamp_tls_setup': self.timestamp_tls_setup,
|
||||
'tls_established': self.tls_established,
|
||||
'tls_version': self.tls_version,
|
||||
'via': None,
|
||||
# only used in sans-io
|
||||
'state': self.state.value,
|
||||
'error': self.error,
|
||||
'tls': self.tls,
|
||||
'certificate_list': [x.get_state() for x in self.certificate_list],
|
||||
'alpn_offers': self.alpn_offers,
|
||||
'cipher_name': self.cipher,
|
||||
'cipher_list': self.cipher_list,
|
||||
'via2': self.via,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_state(cls, state) -> "Server":
|
||||
server = Server(None)
|
||||
server.set_state(state)
|
||||
return server
|
||||
|
||||
def set_state(self, state):
|
||||
self.address = tuple(state["address"]) if state["address"] else None
|
||||
self.alpn = state["alpn"]
|
||||
self.id = state["id"]
|
||||
self.peername = tuple(state["ip_address"]) if state["ip_address"] else None
|
||||
self.sni = state["sni"]
|
||||
self.sockname = tuple(state["source_address"]) if state["source_address"] else None
|
||||
self.timestamp_end = state["timestamp_end"]
|
||||
self.timestamp_start = state["timestamp_start"]
|
||||
self.timestamp_tcp_setup = state["timestamp_tcp_setup"]
|
||||
self.timestamp_tls_setup = state["timestamp_tls_setup"]
|
||||
self.tls_version = state["tls_version"]
|
||||
self.state = ConnectionState(state["state"])
|
||||
self.error = state["error"]
|
||||
self.tls = state["tls"]
|
||||
self.certificate_list = [certs.Cert.from_state(x) for x in state["certificate_list"]]
|
||||
self.alpn_offers = state["alpn_offers"]
|
||||
self.cipher = state["cipher_name"]
|
||||
self.cipher_list = state["cipher_list"]
|
||||
self.via = state["via2"]
|
||||
|
||||
@property
|
||||
def ip_address(self) -> Optional[Address]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for `Server.peername`."""
|
||||
warnings.warn("Server.ip_address is deprecated, use Server.peername instead.", DeprecationWarning, stacklevel=2)
|
||||
return self.peername
|
||||
|
||||
@property
|
||||
def cert(self) -> Optional[certs.Cert]: # pragma: no cover
|
||||
"""*Deprecated:* An outdated alias for `Connection.certificate_list[0]`."""
|
||||
warnings.warn("Server.cert is deprecated, use Server.certificate_list instead.", DeprecationWarning,
|
||||
stacklevel=2)
|
||||
if self.certificate_list:
|
||||
return self.certificate_list[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
@cert.setter
|
||||
def cert(self, val): # pragma: no cover
|
||||
warnings.warn("Server.cert is deprecated, use Server.certificate_list instead.", DeprecationWarning,
|
||||
stacklevel=2)
|
||||
if val:
|
||||
self.certificate_list = [val]
|
||||
else:
|
||||
self.certificate_list = []
|
||||
|
||||
|
||||
class Context:
|
||||
"""
|
||||
The context object provided to each `mitmproxy.proxy.layer.Layer` by its parent layer.
|
||||
"""
|
||||
|
||||
client: Client
|
||||
server: Server
|
||||
client: connection.Client
|
||||
server: connection.Server
|
||||
options: Options
|
||||
layers: List["mitmproxy.proxy.layer.Layer"]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
client: Client,
|
||||
options: Options,
|
||||
self,
|
||||
client: connection.Client,
|
||||
options: Options,
|
||||
) -> None:
|
||||
self.client = client
|
||||
self.options = options
|
||||
self.server = Server(None)
|
||||
self.server = connection.Server(None)
|
||||
self.layers = []
|
||||
|
||||
def fork(self) -> "Context":
|
||||
|
@ -9,7 +9,7 @@ import warnings
|
||||
from dataclasses import dataclass, is_dataclass
|
||||
|
||||
from mitmproxy.proxy import commands
|
||||
from mitmproxy.proxy.context import Connection
|
||||
from mitmproxy.connection import Connection
|
||||
|
||||
|
||||
class Event:
|
||||
|
@ -7,9 +7,10 @@ from abc import abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, List, ClassVar, Deque, NamedTuple, Generator, Any, TypeVar
|
||||
|
||||
from mitmproxy.connection import Connection
|
||||
from mitmproxy.proxy import commands, events
|
||||
from mitmproxy.proxy.commands import Command, StartHook
|
||||
from mitmproxy.proxy.context import Connection, Context
|
||||
from mitmproxy.proxy.context import Context
|
||||
|
||||
T = TypeVar('T')
|
||||
CommandGenerator = Generator[Command, Any, T]
|
||||
@ -96,8 +97,8 @@ class Layer:
|
||||
if self._paused:
|
||||
# did we just receive the reply we were waiting for?
|
||||
pause_finished = (
|
||||
isinstance(event, events.CommandCompleted) and
|
||||
event.command is self._paused.command
|
||||
isinstance(event, events.CommandCompleted) and
|
||||
event.command is self._paused.command
|
||||
)
|
||||
if self.debug is not None:
|
||||
yield self.__debug(f"{'>>' if pause_finished else '>!'} {event}")
|
||||
|
@ -5,15 +5,14 @@ from dataclasses import dataclass
|
||||
from typing import Optional, Tuple, Union, Dict, DefaultDict, List
|
||||
|
||||
from mitmproxy import flow, http
|
||||
from mitmproxy.connection import Connection, ConnectionState, Server
|
||||
from mitmproxy.net import server_spec
|
||||
from mitmproxy.net.http import url
|
||||
from mitmproxy.proxy import commands, events, layer, tunnel
|
||||
from mitmproxy.proxy.context import Connection, ConnectionState, Context, Server
|
||||
from mitmproxy.proxy.layers import tls, websocket, tcp
|
||||
from mitmproxy.proxy.layers.http import _upstream_proxy
|
||||
from mitmproxy.proxy.utils import expect
|
||||
from mitmproxy.utils import human
|
||||
|
||||
from ._base import HttpCommand, ReceiveHttp, StreamId, HttpConnection
|
||||
from ._events import HttpEvent, RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolError, ResponseData, \
|
||||
ResponseEndOfMessage, ResponseHeaders, ResponseProtocolError
|
||||
@ -21,6 +20,7 @@ from ._hooks import HttpConnectHook, HttpErrorHook, HttpRequestHeadersHook, Http
|
||||
HttpResponseHook
|
||||
from ._http1 import Http1Client, Http1Server
|
||||
from ._http2 import Http2Client, Http2Server
|
||||
from ...context import Context
|
||||
|
||||
|
||||
class HTTPMode(enum.Enum):
|
||||
@ -55,13 +55,13 @@ class GetHttpConnection(HttpCommand):
|
||||
|
||||
def connection_spec_matches(self, connection: Connection) -> bool:
|
||||
return (
|
||||
isinstance(connection, Server)
|
||||
and
|
||||
self.address == connection.address
|
||||
and
|
||||
self.tls == connection.tls
|
||||
and
|
||||
self.via == connection.via
|
||||
isinstance(connection, Server)
|
||||
and
|
||||
self.address == connection.address
|
||||
and
|
||||
self.tls == connection.tls
|
||||
and
|
||||
self.via == connection.via
|
||||
)
|
||||
|
||||
|
||||
@ -317,9 +317,9 @@ class HttpStream(layer.Layer):
|
||||
|
||||
if self.flow.response.status_code == 101:
|
||||
is_websocket = (
|
||||
self.flow.response.headers.get("upgrade", "").lower() == "websocket"
|
||||
and
|
||||
self.flow.request.headers.get("Sec-WebSocket-Version", "") == "13"
|
||||
self.flow.response.headers.get("upgrade", "").lower() == "websocket"
|
||||
and
|
||||
self.flow.request.headers.get("Sec-WebSocket-Version", "") == "13"
|
||||
)
|
||||
if is_websocket and self.context.options.websocket:
|
||||
self.child_layer = websocket.WebsocketLayer(self.context, self.flow)
|
||||
@ -338,7 +338,7 @@ class HttpStream(layer.Layer):
|
||||
|
||||
def check_killed(self, emit_error_hook: bool) -> layer.CommandGenerator[bool]:
|
||||
killed_by_us = (
|
||||
self.flow.error and self.flow.error.msg == flow.Error.KILLED_MESSAGE
|
||||
self.flow.error and self.flow.error.msg == flow.Error.KILLED_MESSAGE
|
||||
)
|
||||
# The client may have closed the connection while we were waiting for the hook to complete.
|
||||
# We peek into the event queue to see if that is the case.
|
||||
@ -366,18 +366,18 @@ class HttpStream(layer.Layer):
|
||||
return False
|
||||
|
||||
def handle_protocol_error(
|
||||
self,
|
||||
event: Union[RequestProtocolError, ResponseProtocolError]
|
||||
self,
|
||||
event: Union[RequestProtocolError, ResponseProtocolError]
|
||||
) -> layer.CommandGenerator[None]:
|
||||
is_client_error_but_we_already_talk_upstream = (
|
||||
isinstance(event, RequestProtocolError)
|
||||
and self.client_state in (self.state_stream_request_body, self.state_done)
|
||||
and self.server_state != self.state_errored
|
||||
isinstance(event, RequestProtocolError)
|
||||
and self.client_state in (self.state_stream_request_body, self.state_done)
|
||||
and self.server_state != self.state_errored
|
||||
)
|
||||
need_error_hook = not (
|
||||
self.client_state in (self.state_wait_for_request_headers, self.state_errored)
|
||||
or
|
||||
self.server_state in (self.state_done, self.state_errored)
|
||||
self.client_state in (self.state_wait_for_request_headers, self.state_errored)
|
||||
or
|
||||
self.server_state in (self.state_done, self.state_errored)
|
||||
)
|
||||
|
||||
if is_client_error_but_we_already_talk_upstream:
|
||||
@ -579,9 +579,9 @@ class HttpLayer(layer.Layer):
|
||||
raise AssertionError(f"Unexpected event: {event}")
|
||||
|
||||
def event_to_child(
|
||||
self,
|
||||
child: Union[layer.Layer, HttpStream],
|
||||
event: events.Event,
|
||||
self,
|
||||
child: Union[layer.Layer, HttpStream],
|
||||
event: events.Event,
|
||||
) -> layer.CommandGenerator[None]:
|
||||
for command in child.handle_event(event):
|
||||
assert isinstance(command, commands.Command)
|
||||
@ -622,13 +622,13 @@ class HttpLayer(layer.Layer):
|
||||
for connection in self.connections:
|
||||
# see "tricky multiplexing edge case" in make_http_connection for an explanation
|
||||
conn_is_pending_or_h2 = (
|
||||
connection.alpn == b"h2"
|
||||
or connection in self.waiting_for_establishment
|
||||
connection.alpn == b"h2"
|
||||
or connection in self.waiting_for_establishment
|
||||
)
|
||||
h2_to_h1 = self.context.client.alpn == b"h2" and not conn_is_pending_or_h2
|
||||
connection_suitable = (
|
||||
event.connection_spec_matches(connection)
|
||||
and not h2_to_h1
|
||||
event.connection_spec_matches(connection)
|
||||
and not h2_to_h1
|
||||
)
|
||||
if connection_suitable:
|
||||
if connection in self.waiting_for_establishment:
|
||||
@ -639,9 +639,9 @@ class HttpLayer(layer.Layer):
|
||||
return
|
||||
|
||||
can_use_context_connection = (
|
||||
self.context.server not in self.connections and
|
||||
self.context.server.connected and
|
||||
event.connection_spec_matches(self.context.server)
|
||||
self.context.server not in self.connections and
|
||||
self.context.server.connected and
|
||||
event.connection_spec_matches(self.context.server)
|
||||
)
|
||||
context = self.context.fork()
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from mitmproxy.proxy import events, layer, commands
|
||||
from mitmproxy.proxy.context import Connection, Context
|
||||
from mitmproxy.connection import Connection
|
||||
from mitmproxy.proxy.context import Context
|
||||
|
||||
StreamId = int
|
||||
|
||||
|
@ -9,13 +9,14 @@ from h11._receivebuffer import ReceiveBuffer
|
||||
from mitmproxy import http, version
|
||||
from mitmproxy.net.http import http1, status_codes
|
||||
from mitmproxy.proxy import commands, events, layer
|
||||
from mitmproxy.proxy.context import Connection, ConnectionState, Context
|
||||
from mitmproxy.connection import Connection, ConnectionState
|
||||
from mitmproxy.proxy.layers.http._base import ReceiveHttp, StreamId
|
||||
from mitmproxy.proxy.utils import expect
|
||||
from mitmproxy.utils import human
|
||||
from ._base import HttpConnection
|
||||
from ._events import HttpEvent, RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolError, ResponseData, \
|
||||
ResponseEndOfMessage, ResponseHeaders, ResponseProtocolError
|
||||
from ...context import Context
|
||||
|
||||
TBodyReader = Union[ChunkedReader, Http10Reader, ContentLengthReader]
|
||||
|
||||
|
@ -13,6 +13,7 @@ import h2.stream
|
||||
import h2.utilities
|
||||
|
||||
from mitmproxy import http
|
||||
from mitmproxy.connection import Connection
|
||||
from mitmproxy.net.http import url, status_codes
|
||||
from mitmproxy.utils import human
|
||||
from . import RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolError, ResponseData, \
|
||||
@ -20,7 +21,7 @@ from . import RequestData, RequestEndOfMessage, RequestHeaders, RequestProtocolE
|
||||
from ._base import HttpConnection, HttpEvent, ReceiveHttp
|
||||
from ._http_h2 import BufferedH2Connection, H2ConnectionLogger
|
||||
from ...commands import CloseConnection, Log, SendData
|
||||
from ...context import Connection, Context
|
||||
from ...context import Context
|
||||
from ...events import ConnectionClosed, DataReceived, Event, Start
|
||||
from ...layer import CommandGenerator
|
||||
from ...utils import expect
|
||||
|
@ -3,7 +3,7 @@ from typing import Optional, Tuple
|
||||
|
||||
from h11._receivebuffer import ReceiveBuffer
|
||||
|
||||
from mitmproxy import http
|
||||
from mitmproxy import http, connection
|
||||
from mitmproxy.net import server_spec
|
||||
from mitmproxy.net.http import http1
|
||||
from mitmproxy.proxy import commands, context, layer, tunnel
|
||||
@ -13,13 +13,13 @@ from mitmproxy.utils import human
|
||||
class HttpUpstreamProxy(tunnel.TunnelLayer):
|
||||
buf: ReceiveBuffer
|
||||
send_connect: bool
|
||||
conn: context.Server
|
||||
tunnel_connection: context.Server
|
||||
conn: connection.Server
|
||||
tunnel_connection: connection.Server
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ctx: context.Context,
|
||||
tunnel_conn: context.Server,
|
||||
tunnel_conn: connection.Server,
|
||||
send_connect: bool
|
||||
):
|
||||
super().__init__(
|
||||
|
@ -4,7 +4,8 @@ from typing import Optional
|
||||
from mitmproxy import flow, tcp
|
||||
from mitmproxy.proxy import commands, events, layer
|
||||
from mitmproxy.proxy.commands import StartHook
|
||||
from mitmproxy.proxy.context import ConnectionState, Context, Connection
|
||||
from mitmproxy.connection import ConnectionState, Connection
|
||||
from mitmproxy.proxy.context import Context
|
||||
from mitmproxy.proxy.utils import expect
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@ from dataclasses import dataclass
|
||||
from typing import Iterator, Optional, Tuple
|
||||
|
||||
from OpenSSL import SSL
|
||||
from mitmproxy import certs
|
||||
from mitmproxy import certs, connection
|
||||
from mitmproxy.net import tls as net_tls
|
||||
from mitmproxy.proxy import commands, events, layer, tunnel
|
||||
from mitmproxy.proxy import context
|
||||
@ -116,7 +116,7 @@ class TlsClienthelloHook(StartHook):
|
||||
|
||||
@dataclass
|
||||
class TlsStartData:
|
||||
conn: context.Connection
|
||||
conn: connection.Connection
|
||||
context: context.Context
|
||||
ssl_conn: Optional[SSL.Connection] = None
|
||||
|
||||
@ -136,7 +136,7 @@ class _TLSLayer(tunnel.TunnelLayer):
|
||||
tls: SSL.Connection = None
|
||||
"""The OpenSSL connection object"""
|
||||
|
||||
def __init__(self, context: context.Context, conn: context.Connection):
|
||||
def __init__(self, context: context.Context, conn: connection.Connection):
|
||||
super().__init__(
|
||||
context,
|
||||
tunnel_connection=conn,
|
||||
@ -240,7 +240,7 @@ class _TLSLayer(tunnel.TunnelLayer):
|
||||
events.DataReceived(self.conn, bytes(plaintext))
|
||||
)
|
||||
if close:
|
||||
self.conn.state &= ~context.ConnectionState.CAN_READ
|
||||
self.conn.state &= ~connection.ConnectionState.CAN_READ
|
||||
if self.debug:
|
||||
yield commands.Log(f"{self.debug}[tls] close_notify {self.conn}", level="debug")
|
||||
yield from self.event_to_child(
|
||||
@ -268,7 +268,7 @@ class ServerTLSLayer(_TLSLayer):
|
||||
"""
|
||||
command_to_reply_to: Optional[commands.OpenConnection] = None
|
||||
|
||||
def __init__(self, context: context.Context, conn: Optional[context.Server] = None):
|
||||
def __init__(self, context: context.Context, conn: Optional[connection.Server] = None):
|
||||
super().__init__(context, conn or context.server)
|
||||
|
||||
def start_handshake(self) -> layer.CommandGenerator[None]:
|
||||
@ -373,4 +373,4 @@ class MockTLSLayer(_TLSLayer):
|
||||
"""
|
||||
|
||||
def __init__(self, ctx: context.Context):
|
||||
super().__init__(ctx, context.Server(None))
|
||||
super().__init__(ctx, connection.Server(None))
|
||||
|
@ -5,8 +5,8 @@ import wsproto
|
||||
import wsproto.extensions
|
||||
import wsproto.frame_protocol
|
||||
import wsproto.utilities
|
||||
from mitmproxy import flow, websocket, http
|
||||
from mitmproxy.proxy import commands, events, layer, context
|
||||
from mitmproxy import flow, websocket, http, connection
|
||||
from mitmproxy.proxy import commands, events, layer
|
||||
from mitmproxy.proxy.commands import StartHook
|
||||
from mitmproxy.proxy.context import Context
|
||||
from mitmproxy.proxy.utils import expect
|
||||
@ -60,10 +60,10 @@ class WebsocketConnection(wsproto.Connection):
|
||||
- we add a framebuffer for incomplete messages
|
||||
- we wrap .send() so that we can directly yield it.
|
||||
"""
|
||||
conn: context.Connection
|
||||
conn: connection.Connection
|
||||
frame_buf: List[Union[str, bytes]]
|
||||
|
||||
def __init__(self, *args, conn: context.Connection, **kwargs):
|
||||
def __init__(self, *args, conn: connection.Connection, **kwargs):
|
||||
super(WebsocketConnection, self).__init__(*args, **kwargs)
|
||||
self.conn = conn
|
||||
self.frame_buf = []
|
||||
|
@ -17,9 +17,10 @@ from dataclasses import dataclass
|
||||
|
||||
from OpenSSL import SSL
|
||||
from mitmproxy import http, options as moptions
|
||||
from mitmproxy.proxy.context import Context
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy import commands, events, layer, layers, server_hooks
|
||||
from mitmproxy.proxy.context import Address, Client, Connection, ConnectionState, Context
|
||||
from mitmproxy.connection import Address, Client, Connection, ConnectionState
|
||||
from mitmproxy.proxy.layers import tls
|
||||
from mitmproxy.utils import asyncio_utils
|
||||
from mitmproxy.utils import human
|
||||
|
@ -1,6 +1,7 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from . import commands, context
|
||||
from mitmproxy import connection
|
||||
from . import commands
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -11,7 +12,7 @@ class ClientConnectedHook(commands.StartHook):
|
||||
|
||||
Setting client.error kills the connection.
|
||||
"""
|
||||
client: context.Client
|
||||
client: connection.Client
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -20,13 +21,13 @@ class ClientDisconnectedHook(commands.StartHook):
|
||||
A client connection has been closed (either by us or the client).
|
||||
"""
|
||||
blocking = False
|
||||
client: context.Client
|
||||
client: connection.Client
|
||||
|
||||
|
||||
@dataclass
|
||||
class ServerConnectionHookData:
|
||||
server: context.Server
|
||||
client: context.Client
|
||||
server: connection.Server
|
||||
client: connection.Client
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -1,6 +1,7 @@
|
||||
from enum import Enum, auto
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from mitmproxy import connection
|
||||
from mitmproxy.proxy import commands, context, events, layer
|
||||
from mitmproxy.proxy.layer import Layer
|
||||
|
||||
@ -18,9 +19,9 @@ class TunnelLayer(layer.Layer):
|
||||
or TLS.
|
||||
"""
|
||||
child_layer: layer.Layer
|
||||
tunnel_connection: context.Connection
|
||||
tunnel_connection: connection.Connection
|
||||
"""The 'outer' connection which provides the tunnel protocol I/O"""
|
||||
conn: context.Connection
|
||||
conn: connection.Connection
|
||||
"""The 'inner' connection which provides data I/O"""
|
||||
tunnel_state: TunnelState = TunnelState.INACTIVE
|
||||
command_to_reply_to: Optional[commands.OpenConnection] = None
|
||||
@ -33,8 +34,8 @@ class TunnelLayer(layer.Layer):
|
||||
def __init__(
|
||||
self,
|
||||
context: context.Context,
|
||||
tunnel_connection: context.Connection,
|
||||
conn: context.Connection,
|
||||
tunnel_connection: connection.Connection,
|
||||
conn: connection.Connection,
|
||||
):
|
||||
super().__init__(context)
|
||||
self.tunnel_connection = tunnel_connection
|
||||
@ -47,7 +48,7 @@ class TunnelLayer(layer.Layer):
|
||||
|
||||
def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]:
|
||||
if isinstance(event, events.Start):
|
||||
if self.tunnel_connection.state is not context.ConnectionState.CLOSED:
|
||||
if self.tunnel_connection.state is not connection.ConnectionState.CLOSED:
|
||||
# we might be in the interesting state here where the connection is already half-closed,
|
||||
# for example because next_layer buffered events and the client disconnected in the meantime.
|
||||
# we still expect a close event to arrive, so we carry on here as normal for now.
|
||||
@ -60,17 +61,17 @@ class TunnelLayer(layer.Layer):
|
||||
done, err = yield from self.receive_handshake_data(event.data)
|
||||
if done:
|
||||
if self.conn != self.tunnel_connection:
|
||||
self.conn.state = context.ConnectionState.OPEN
|
||||
self.conn.state = connection.ConnectionState.OPEN
|
||||
if err:
|
||||
if self.conn != self.tunnel_connection:
|
||||
self.conn.state = context.ConnectionState.CLOSED
|
||||
self.conn.state = connection.ConnectionState.CLOSED
|
||||
yield from self.on_handshake_error(err)
|
||||
if done or err:
|
||||
yield from self._handshake_finished(err)
|
||||
else:
|
||||
yield from self.receive_data(event.data)
|
||||
elif isinstance(event, events.ConnectionClosed):
|
||||
self.conn.state &= ~context.ConnectionState.CAN_READ
|
||||
self.conn.state &= ~connection.ConnectionState.CAN_READ
|
||||
if self.tunnel_state is TunnelState.OPEN:
|
||||
yield from self.receive_close()
|
||||
elif self.tunnel_state is TunnelState.ESTABLISHING:
|
||||
@ -107,9 +108,9 @@ class TunnelLayer(layer.Layer):
|
||||
elif isinstance(command, commands.CloseConnection):
|
||||
if self.conn != self.tunnel_connection:
|
||||
if command.half_close:
|
||||
self.conn.state &= ~context.ConnectionState.CAN_WRITE
|
||||
self.conn.state &= ~connection.ConnectionState.CAN_WRITE
|
||||
else:
|
||||
self.conn.state = context.ConnectionState.CLOSED
|
||||
self.conn.state = connection.ConnectionState.CLOSED
|
||||
yield from self.send_close(command.half_close)
|
||||
elif isinstance(command, commands.OpenConnection):
|
||||
# create our own OpenConnection command object that blocks here.
|
||||
|
@ -1,12 +1,12 @@
|
||||
import uuid
|
||||
|
||||
from mitmproxy import connection
|
||||
from mitmproxy import controller
|
||||
from mitmproxy import flow
|
||||
from mitmproxy import http
|
||||
from mitmproxy import tcp
|
||||
from mitmproxy import websocket
|
||||
from mitmproxy.net.http import status_codes
|
||||
from mitmproxy.proxy import context
|
||||
from mitmproxy.test import tutils
|
||||
from wsproto.frame_protocol import Opcode
|
||||
|
||||
@ -144,8 +144,8 @@ def tdummyflow(client_conn=True, server_conn=True, err=None):
|
||||
return f
|
||||
|
||||
|
||||
def tclient_conn() -> context.Client:
|
||||
c = context.Client.from_state(dict(
|
||||
def tclient_conn() -> connection.Client:
|
||||
c = connection.Client.from_state(dict(
|
||||
id=str(uuid.uuid4()),
|
||||
address=("127.0.0.1", 22),
|
||||
mitmcert=None,
|
||||
@ -170,8 +170,8 @@ def tclient_conn() -> context.Client:
|
||||
return c
|
||||
|
||||
|
||||
def tserver_conn() -> context.Server:
|
||||
c = context.Server.from_state(dict(
|
||||
def tserver_conn() -> connection.Server:
|
||||
c = connection.Server.from_state(dict(
|
||||
id=str(uuid.uuid4()),
|
||||
address=("address", 22),
|
||||
source_address=("address", 22),
|
||||
|
@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from mitmproxy import connection
|
||||
from mitmproxy.addons import block
|
||||
from mitmproxy.proxy import context
|
||||
from mitmproxy.test import taddons
|
||||
|
||||
|
||||
@ -28,7 +28,6 @@ from mitmproxy.test import taddons
|
||||
(True, False, True, ("2001:4860:4860::8888",)),
|
||||
(True, False, True, (r"2001:4860:4860::8888%scope",)),
|
||||
|
||||
|
||||
# block_private: loopback
|
||||
(False, True, False, ("127.0.0.1",)),
|
||||
(False, True, False, ("::1",)),
|
||||
@ -56,6 +55,6 @@ async def test_block_global(block_global, block_private, should_be_killed, addre
|
||||
ar = block.Block()
|
||||
with taddons.context(ar) as tctx:
|
||||
tctx.configure(ar, block_global=block_global, block_private=block_private)
|
||||
client = context.Client(address, ("127.0.0.1", 8080), 1607699500)
|
||||
client = connection.Client(address, ("127.0.0.1", 8080), 1607699500)
|
||||
ar.client_connected(client)
|
||||
assert bool(client.error) == should_be_killed
|
||||
|
@ -5,7 +5,7 @@ import pytest
|
||||
|
||||
from mitmproxy.addons.clientplayback import ClientPlayback, ReplayHandler
|
||||
from mitmproxy.exceptions import CommandError, OptionsError
|
||||
from mitmproxy.proxy.context import Address
|
||||
from mitmproxy.connection import Address
|
||||
from mitmproxy.test import taddons, tflow
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@ from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from mitmproxy import connection
|
||||
from mitmproxy.addons.next_layer import NextLayer
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy import context, layers
|
||||
@ -10,7 +11,7 @@ from mitmproxy.test import taddons
|
||||
|
||||
@pytest.fixture
|
||||
def tctx():
|
||||
context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
|
||||
|
||||
client_hello_no_extensions = bytes.fromhex(
|
||||
|
@ -6,7 +6,7 @@ import pytest
|
||||
from mitmproxy.addons.proxyserver import Proxyserver
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy import layers
|
||||
from mitmproxy.proxy.context import Address
|
||||
from mitmproxy.connection import Address
|
||||
from mitmproxy.test import taddons
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@ from typing import Union
|
||||
import pytest
|
||||
|
||||
from OpenSSL import SSL
|
||||
from mitmproxy import certs
|
||||
from mitmproxy import certs, connection
|
||||
from mitmproxy.addons import tlsconfig
|
||||
from mitmproxy.proxy import context
|
||||
from mitmproxy.proxy.layers import tls
|
||||
@ -54,7 +54,7 @@ class TestTlsConfig:
|
||||
with taddons.context(ta) as tctx:
|
||||
ta.configure(["confdir"])
|
||||
|
||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
|
||||
# Edge case first: We don't have _any_ idea about the server, so we just return "mitmproxy" as subject.
|
||||
entry = ta.get_cert(ctx)
|
||||
@ -77,7 +77,7 @@ class TestTlsConfig:
|
||||
# only really testing for coverage here, there's no point in mirroring the individual conditions
|
||||
ta = tlsconfig.TlsConfig()
|
||||
with taddons.context(ta) as tctx:
|
||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ch = tls.ClientHelloData(ctx)
|
||||
ta.tls_clienthello(ch)
|
||||
assert not ch.establish_server_tls_first
|
||||
@ -113,7 +113,7 @@ class TestTlsConfig:
|
||||
certs=[tdata.path("mitmproxy/net/data/verificationcerts/trusted-leaf.pem")],
|
||||
ciphers_client="ECDHE-ECDSA-AES128-GCM-SHA256",
|
||||
)
|
||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
|
||||
tls_start = tls.TlsStartData(ctx.client, context=ctx)
|
||||
ta.tls_start(tls_start)
|
||||
@ -125,7 +125,7 @@ class TestTlsConfig:
|
||||
def test_create_proxy_server_ssl_conn_verify_failed(self):
|
||||
ta = tlsconfig.TlsConfig()
|
||||
with taddons.context(ta) as tctx:
|
||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx.client.alpn_offers = [b"h2"]
|
||||
ctx.client.cipher_list = ["TLS_AES_256_GCM_SHA384", "ECDHE-RSA-AES128-SHA"]
|
||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||
@ -140,7 +140,7 @@ class TestTlsConfig:
|
||||
def test_create_proxy_server_ssl_conn_verify_ok(self, tdata):
|
||||
ta = tlsconfig.TlsConfig()
|
||||
with taddons.context(ta) as tctx:
|
||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||
tctx.configure(ta, ssl_verify_upstream_trusted_ca=tdata.path(
|
||||
"mitmproxy/net/data/verificationcerts/trusted-root.crt"))
|
||||
@ -154,7 +154,7 @@ class TestTlsConfig:
|
||||
def test_create_proxy_server_ssl_conn_insecure(self):
|
||||
ta = tlsconfig.TlsConfig()
|
||||
with taddons.context(ta) as tctx:
|
||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||
|
||||
tctx.configure(
|
||||
@ -173,7 +173,7 @@ class TestTlsConfig:
|
||||
def test_alpn_selection(self):
|
||||
ta = tlsconfig.TlsConfig()
|
||||
with taddons.context(ta) as tctx:
|
||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||
tls_start = tls.TlsStartData(ctx.server, context=ctx)
|
||||
|
||||
@ -203,7 +203,7 @@ class TestTlsConfig:
|
||||
def test_client_cert_file(self, tdata, client_certs):
|
||||
ta = tlsconfig.TlsConfig()
|
||||
with taddons.context(ta) as tctx:
|
||||
ctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
|
||||
ctx.server.address = ("example.mitmproxy.org", 443)
|
||||
tctx.configure(
|
||||
ta,
|
||||
|
@ -1,9 +1,11 @@
|
||||
import collections
|
||||
|
||||
import pytest
|
||||
|
||||
from mitmproxy.http import Headers
|
||||
from mitmproxy.net.http.headers import parse_content_type, assemble_content_type
|
||||
|
||||
|
||||
class TestHeaders:
|
||||
def _2host(self):
|
||||
return Headers(
|
||||
@ -79,4 +81,5 @@ def test_assemble_content_type():
|
||||
p = assemble_content_type
|
||||
assert p("text", "html", {}) == "text/html"
|
||||
assert p("text", "html", {"charset": "utf8"}) == "text/html; charset=utf8"
|
||||
assert p("text", "html", collections.OrderedDict([("charset", "utf8"), ("foo", "bar")])) == "text/html; charset=utf8; foo=bar"
|
||||
assert p("text", "html",
|
||||
collections.OrderedDict([("charset", "utf8"), ("foo", "bar")])) == "text/html; charset=utf8; foo=bar"
|
||||
|
@ -3,7 +3,7 @@ import os
|
||||
import pytest
|
||||
from hypothesis import settings
|
||||
|
||||
from mitmproxy import options
|
||||
from mitmproxy import options, connection
|
||||
from mitmproxy.addons.core import Core
|
||||
from mitmproxy.addons.proxyserver import Proxyserver
|
||||
from mitmproxy.addons.termlog import TermLog
|
||||
@ -17,7 +17,7 @@ def tctx() -> context.Context:
|
||||
TermLog().load(opts)
|
||||
Core().load(opts)
|
||||
return context.Context(
|
||||
context.Client(
|
||||
connection.Client(
|
||||
("client", 1234),
|
||||
("127.0.0.1", 8080),
|
||||
1605699329
|
||||
|
@ -6,7 +6,7 @@ from mitmproxy.net.server_spec import ServerSpec
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy import layer
|
||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData, Log
|
||||
from mitmproxy.proxy.context import ConnectionState, Server
|
||||
from mitmproxy.connection import ConnectionState, Server
|
||||
from mitmproxy.proxy.events import ConnectionClosed, DataReceived
|
||||
from mitmproxy.proxy.layers import TCPLayer, http, tls
|
||||
from mitmproxy.proxy.layers.tcp import TcpStartHook
|
||||
|
@ -9,9 +9,10 @@ from h2.errors import ErrorCodes
|
||||
from mitmproxy.flow import Error
|
||||
from mitmproxy.http import HTTPFlow, Headers, Request
|
||||
from mitmproxy.net.http import status_codes
|
||||
from mitmproxy.proxy.context import Context
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData
|
||||
from mitmproxy.proxy.context import Context, Server
|
||||
from mitmproxy.connection import Server
|
||||
from mitmproxy.proxy.events import ConnectionClosed, DataReceived
|
||||
from mitmproxy.proxy.layers import http
|
||||
from mitmproxy.proxy.layers.http._http2 import split_pseudo_headers, Http2Client
|
||||
|
@ -6,13 +6,13 @@ from hypothesis import example, given
|
||||
from hypothesis.strategies import binary, booleans, composite, dictionaries, integers, lists, sampled_from, sets, text, \
|
||||
data
|
||||
|
||||
from mitmproxy import options
|
||||
from mitmproxy import options, connection
|
||||
from mitmproxy.addons.proxyserver import Proxyserver
|
||||
from mitmproxy.connection import Server
|
||||
from mitmproxy.http import HTTPFlow
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy import context, events
|
||||
from mitmproxy.proxy.commands import OpenConnection, SendData
|
||||
from mitmproxy.proxy.context import Server
|
||||
from mitmproxy.proxy.events import DataReceived, Start, ConnectionClosed
|
||||
from mitmproxy.proxy.layers import http
|
||||
from test.mitmproxy.proxy.layers.http.hyper_h2_test_helpers import FrameFactory
|
||||
@ -100,7 +100,7 @@ def h2_responses(draw):
|
||||
|
||||
@given(chunks(mutations(h1_requests())))
|
||||
def test_fuzz_h1_request(data):
|
||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
|
||||
layer = http.HttpLayer(tctx, HTTPMode.regular)
|
||||
for _ in layer.handle_event(Start()):
|
||||
@ -113,8 +113,8 @@ def test_fuzz_h1_request(data):
|
||||
@given(chunks(mutations(h2_responses())))
|
||||
@example([b'0 OK\r\n\r\n', b'\r\n', b'5\r\n12345\r\n0\r\n\r\n'])
|
||||
def test_fuzz_h1_response(data):
|
||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
server = Placeholder(context.Server)
|
||||
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
server = Placeholder(connection.Server)
|
||||
playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)
|
||||
assert (
|
||||
playbook
|
||||
@ -207,7 +207,7 @@ def h2_frames(draw):
|
||||
|
||||
|
||||
def h2_layer(opts):
|
||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
tctx.client.alpn = b"h2"
|
||||
|
||||
layer = http.HttpLayer(tctx, HTTPMode.regular)
|
||||
@ -246,9 +246,9 @@ def test_fuzz_h2_request_mutations(chunks):
|
||||
|
||||
|
||||
def _h2_response(chunks):
|
||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)
|
||||
server = Placeholder(context.Server)
|
||||
server = Placeholder(connection.Server)
|
||||
assert (
|
||||
playbook
|
||||
>> DataReceived(tctx.client, b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n")
|
||||
@ -314,7 +314,7 @@ def _test_cancel(stream_req, stream_resp, draw):
|
||||
"""
|
||||
Test that we don't raise an exception if someone disconnects.
|
||||
"""
|
||||
tctx = context.Context(context.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
|
||||
playbook, cff = start_h2_client(tctx)
|
||||
flow = Placeholder(HTTPFlow)
|
||||
server = Placeholder(Server)
|
||||
|
@ -5,9 +5,10 @@ import h2.connection
|
||||
import h2.events
|
||||
|
||||
from mitmproxy.http import HTTPFlow
|
||||
from mitmproxy.proxy.context import Context
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData
|
||||
from mitmproxy.proxy.context import Context, Server
|
||||
from mitmproxy.connection import Server
|
||||
from mitmproxy.proxy.events import DataReceived
|
||||
from mitmproxy.proxy.layers import http
|
||||
from test.mitmproxy.proxy.layers.http.hyper_h2_test_helpers import FrameFactory
|
||||
|
@ -3,9 +3,10 @@ import copy
|
||||
import pytest
|
||||
|
||||
from mitmproxy import platform
|
||||
from mitmproxy.proxy.context import Context
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData, GetSocket, Log
|
||||
from mitmproxy.proxy.context import Client, Context, Server
|
||||
from mitmproxy.connection import Client, Server
|
||||
from mitmproxy.proxy.events import DataReceived, ConnectionClosed
|
||||
from mitmproxy.proxy.layer import NextLayer, NextLayerHook
|
||||
from mitmproxy.proxy.layers import http, modes, tcp, tls
|
||||
|
@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from mitmproxy.proxy.commands import CloseConnection, OpenConnection, SendData
|
||||
from mitmproxy.proxy.context import ConnectionState
|
||||
from mitmproxy.connection import ConnectionState
|
||||
from mitmproxy.proxy.events import ConnectionClosed, DataReceived
|
||||
from mitmproxy.proxy.layers import tcp
|
||||
from mitmproxy.tcp import TCPFlow
|
||||
|
@ -4,8 +4,9 @@ import typing
|
||||
import pytest
|
||||
|
||||
from OpenSSL import SSL
|
||||
from mitmproxy import connection
|
||||
from mitmproxy.connection import ConnectionState, Server
|
||||
from mitmproxy.proxy import commands, context, events, layer
|
||||
from mitmproxy.proxy.context import ConnectionState
|
||||
from mitmproxy.proxy.layers import tls
|
||||
from mitmproxy.utils import data
|
||||
from test.mitmproxy.proxy import tutils
|
||||
@ -121,7 +122,7 @@ class SSLTest:
|
||||
return self.obj.do_handshake()
|
||||
|
||||
|
||||
def _test_echo(playbook: tutils.Playbook, tssl: SSLTest, conn: context.Connection) -> None:
|
||||
def _test_echo(playbook: tutils.Playbook, tssl: SSLTest, conn: connection.Connection) -> None:
|
||||
tssl.obj.write(b"Hello World")
|
||||
data = tutils.Placeholder(bytes)
|
||||
assert (
|
||||
@ -145,7 +146,7 @@ class TlsEchoLayer(tutils.EchoLayer):
|
||||
yield from super()._handle_event(event)
|
||||
|
||||
|
||||
def interact(playbook: tutils.Playbook, conn: context.Connection, tssl: SSLTest):
|
||||
def interact(playbook: tutils.Playbook, conn: connection.Connection, tssl: SSLTest):
|
||||
data = tutils.Placeholder(bytes)
|
||||
assert (
|
||||
playbook
|
||||
@ -383,7 +384,7 @@ class TestClientTLS:
|
||||
|
||||
# Echo
|
||||
_test_echo(playbook, tssl_client, tctx.client)
|
||||
other_server = context.Server(None)
|
||||
other_server = Server(None)
|
||||
assert (
|
||||
playbook
|
||||
>> events.DataReceived(other_server, b"Plaintext")
|
||||
|
@ -8,7 +8,7 @@ import wsproto.events
|
||||
from mitmproxy.http import HTTPFlow, Request, Response
|
||||
from mitmproxy.proxy.layers.http import HTTPMode
|
||||
from mitmproxy.proxy.commands import SendData, CloseConnection, Log
|
||||
from mitmproxy.proxy.context import ConnectionState
|
||||
from mitmproxy.connection import ConnectionState
|
||||
from mitmproxy.proxy.events import DataReceived, ConnectionClosed
|
||||
from mitmproxy.proxy.layers import http, websocket
|
||||
from mitmproxy.websocket import WebSocketFlow
|
||||
|
@ -2,13 +2,14 @@ from dataclasses import dataclass
|
||||
|
||||
import pytest
|
||||
|
||||
from mitmproxy import connection
|
||||
from mitmproxy.hooks import all_hooks
|
||||
from mitmproxy.proxy import commands, context
|
||||
from mitmproxy.proxy import commands
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def tconn() -> context.Server:
|
||||
return context.Server(None)
|
||||
def tconn() -> connection.Server:
|
||||
return connection.Server(None)
|
||||
|
||||
|
||||
def test_dataclasses(tconn):
|
||||
|
@ -1,10 +1,11 @@
|
||||
from mitmproxy import connection
|
||||
from mitmproxy.proxy import context
|
||||
from mitmproxy.test import tflow, taddons
|
||||
|
||||
|
||||
class TestConnection:
|
||||
def test_basic(self):
|
||||
c = context.Client(
|
||||
c = connection.Client(
|
||||
("127.0.0.1", 52314),
|
||||
("127.0.0.1", 8080),
|
||||
1607780791
|
||||
@ -13,7 +14,7 @@ class TestConnection:
|
||||
c.timestamp_tls_setup = 1607780792
|
||||
assert c.tls_established
|
||||
assert c.connected
|
||||
c.state = context.ConnectionState.CAN_WRITE
|
||||
c.state = connection.ConnectionState.CAN_WRITE
|
||||
assert not c.connected
|
||||
|
||||
def test_eq(self):
|
||||
@ -30,7 +31,7 @@ class TestConnection:
|
||||
|
||||
class TestClient:
|
||||
def test_basic(self):
|
||||
c = context.Client(
|
||||
c = connection.Client(
|
||||
("127.0.0.1", 52314),
|
||||
("127.0.0.1", 8080),
|
||||
1607780791
|
||||
@ -44,7 +45,7 @@ class TestClient:
|
||||
|
||||
def test_state(self):
|
||||
c = tflow.tclient_conn()
|
||||
assert context.Client.from_state(c.get_state()).get_state() == c.get_state()
|
||||
assert connection.Client.from_state(c.get_state()).get_state() == c.get_state()
|
||||
|
||||
c2 = tflow.tclient_conn()
|
||||
assert c != c2
|
||||
@ -61,7 +62,7 @@ class TestClient:
|
||||
|
||||
class TestServer:
|
||||
def test_basic(self):
|
||||
s = context.Server(("address", 22))
|
||||
s = connection.Server(("address", 22))
|
||||
assert repr(s)
|
||||
assert str(s)
|
||||
s.timestamp_tls_setup = 1607780791
|
||||
|
@ -2,12 +2,13 @@ from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from mitmproxy.proxy import events, context, commands
|
||||
from mitmproxy import connection
|
||||
from mitmproxy.proxy import events, commands
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def tconn() -> context.Server:
|
||||
return context.Server(None)
|
||||
def tconn() -> connection.Server:
|
||||
return connection.Server(None)
|
||||
|
||||
|
||||
def test_dataclasses(tconn):
|
||||
|
@ -4,7 +4,8 @@ import pytest
|
||||
|
||||
from mitmproxy.proxy import tunnel, layer
|
||||
from mitmproxy.proxy.commands import SendData, Log, CloseConnection, OpenConnection
|
||||
from mitmproxy.proxy.context import Context, Server, ConnectionState
|
||||
from mitmproxy.connection import Server, ConnectionState
|
||||
from mitmproxy.proxy.context import Context
|
||||
from mitmproxy.proxy.events import Event, DataReceived, Start, ConnectionClosed
|
||||
from test.mitmproxy.proxy.tutils import Playbook, reply
|
||||
|
||||
|
@ -7,7 +7,7 @@ import typing
|
||||
|
||||
from mitmproxy.proxy import commands, context, layer
|
||||
from mitmproxy.proxy import events
|
||||
from mitmproxy.proxy.context import ConnectionState
|
||||
from mitmproxy.connection import ConnectionState
|
||||
from mitmproxy.proxy.events import command_reply_subclasses
|
||||
from mitmproxy.proxy.layer import Layer
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user