mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2025-01-30 14:58:38 +00:00
rename WebSocket{s,} protocol
This commit is contained in:
parent
a6c608e085
commit
ffb3988dc9
@ -3,7 +3,7 @@
|
||||
TCP Proxy
|
||||
=========
|
||||
|
||||
WebSockets or other non-HTTP protocols are not supported by mitmproxy yet. However, you can exempt
|
||||
Non-HTTP protocols are not supported by mitmproxy yet. However, you can exempt
|
||||
hostnames from processing, so that mitmproxy acts as a generic TCP forwarder.
|
||||
This feature is closely related to the :ref:`passthrough` functionality,
|
||||
but differs in two important aspects:
|
||||
|
@ -162,15 +162,15 @@ WebSocket Events
|
||||
:widths: 40 60
|
||||
:header-rows: 0
|
||||
|
||||
* - .. py:function:: websockets_handshake(flow)
|
||||
* - .. py:function:: websocket_handshake(flow)
|
||||
|
||||
- Called when a client wants to establish a WebSockets connection. The
|
||||
WebSockets-specific headers can be manipulated to manipulate the
|
||||
- Called when a client wants to establish a WebSocket connection. The
|
||||
WebSocket-specific headers can be manipulated to manipulate the
|
||||
handshake. The ``flow`` object is guaranteed to have a non-None
|
||||
``request`` attribute.
|
||||
|
||||
*flow*
|
||||
The flow containing the HTTP websocket handshake request. The
|
||||
The flow containing the HTTP WebSocket handshake request. The
|
||||
object is guaranteed to have a non-None ``request`` attribute.
|
||||
|
||||
|
||||
|
@ -90,7 +90,7 @@ class FrameHeader:
|
||||
@classmethod
|
||||
def _make_length_code(self, length):
|
||||
"""
|
||||
A websockets frame contains an initial length_code, and an optional
|
||||
A WebSocket frame contains an initial length_code, and an optional
|
||||
extended length code to represent the actual length if length code is
|
||||
larger than 125
|
||||
"""
|
||||
@ -149,7 +149,7 @@ class FrameHeader:
|
||||
@classmethod
|
||||
def from_file(cls, fp):
|
||||
"""
|
||||
read a websockets frame header
|
||||
read a WebSocket frame header
|
||||
"""
|
||||
first_byte, second_byte = fp.safe_read(2)
|
||||
fin = bits.getbit(first_byte, 7)
|
||||
@ -195,11 +195,11 @@ class FrameHeader:
|
||||
|
||||
class Frame:
|
||||
"""
|
||||
Represents a single WebSockets frame.
|
||||
Represents a single WebSocket frame.
|
||||
Constructor takes human readable forms of the frame components.
|
||||
from_bytes() reads from a file-like object to create a new Frame.
|
||||
|
||||
WebSockets Frame as defined in RFC6455
|
||||
WebSocket frame as defined in RFC6455
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-------+-+-------------+-------------------------------+
|
||||
@ -253,7 +253,7 @@ class Frame:
|
||||
@classmethod
|
||||
def from_file(cls, fp):
|
||||
"""
|
||||
read a websockets frame sent by a server or client
|
||||
read a WebSocket frame sent by a server or client
|
||||
|
||||
fp is a "file like" object that could be backed by a network
|
||||
stream or a disk or an in memory stream reader
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""
|
||||
Collection of WebSockets Protocol utility functions (RFC6455)
|
||||
Collection of WebSocket protocol utility functions (RFC6455)
|
||||
Spec: https://tools.ietf.org/html/rfc6455
|
||||
"""
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
In mitmproxy, protocols are implemented as a set of layers, which are composed
|
||||
on top each other. The first layer is usually the proxy mode, e.g. transparent
|
||||
proxy or normal HTTP proxy. Next, various protocol layers are stacked on top of
|
||||
each other - imagine WebSockets on top of an HTTP Upgrade request. An actual
|
||||
each other - imagine WebSocket on top of an HTTP Upgrade request. An actual
|
||||
mitmproxy connection may look as follows (outermost layer first):
|
||||
|
||||
Transparent HTTP proxy, no TLS:
|
||||
@ -10,7 +10,7 @@ mitmproxy connection may look as follows (outermost layer first):
|
||||
- Http1Layer
|
||||
- HttpLayer
|
||||
|
||||
Regular proxy, CONNECT request with WebSockets over SSL:
|
||||
Regular proxy, CONNECT request with WebSocket over SSL:
|
||||
- ReverseProxy
|
||||
- Http1Layer
|
||||
- HttpLayer
|
||||
@ -34,7 +34,7 @@ from .http import UpstreamConnectLayer
|
||||
from .http import HttpLayer
|
||||
from .http1 import Http1Layer
|
||||
from .http2 import Http2Layer
|
||||
from .websockets import WebSocketsLayer
|
||||
from .websocket import WebSocketLayer
|
||||
from .rawtcp import RawTCPLayer
|
||||
from .tls import TlsClientHello
|
||||
from .tls import TlsLayer
|
||||
@ -47,6 +47,6 @@ __all__ = [
|
||||
"HttpLayer",
|
||||
"Http1Layer",
|
||||
"Http2Layer",
|
||||
"WebSocketsLayer",
|
||||
"WebSocketLayer",
|
||||
"RawTCPLayer",
|
||||
]
|
||||
|
@ -8,7 +8,8 @@ from mitmproxy import exceptions
|
||||
from mitmproxy import http
|
||||
from mitmproxy import flow
|
||||
from mitmproxy.proxy.protocol import base
|
||||
from mitmproxy.proxy.protocol import websockets as pwebsockets
|
||||
from mitmproxy.proxy.protocol.websocket import WebSocketLayer
|
||||
import mitmproxy.net.http
|
||||
from mitmproxy.net import tcp
|
||||
from mitmproxy.net import websockets
|
||||
|
||||
@ -300,7 +301,7 @@ class HttpLayer(base.Layer):
|
||||
|
||||
try:
|
||||
if websockets.check_handshake(request.headers) and websockets.check_client_version(request.headers):
|
||||
# We only support RFC6455 with WebSockets version 13
|
||||
# We only support RFC6455 with WebSocket version 13
|
||||
# allow inline scripts to manipulate the client handshake
|
||||
self.channel.ask("websocket_handshake", f)
|
||||
|
||||
@ -392,19 +393,19 @@ class HttpLayer(base.Layer):
|
||||
if f.response.status_code == 101:
|
||||
# Handle a successful HTTP 101 Switching Protocols Response,
|
||||
# received after e.g. a WebSocket upgrade request.
|
||||
# Check for WebSockets handshake
|
||||
is_websockets = (
|
||||
# Check for WebSocket handshake
|
||||
is_websocket = (
|
||||
websockets.check_handshake(f.request.headers) and
|
||||
websockets.check_handshake(f.response.headers)
|
||||
)
|
||||
if is_websockets and not self.config.options.websockets:
|
||||
if is_websocket and not self.config.options.websockets:
|
||||
self.log(
|
||||
"Client requested WebSocket connection, but the protocol is disabled.",
|
||||
"info"
|
||||
)
|
||||
|
||||
if is_websockets and self.config.options.websockets:
|
||||
layer = pwebsockets.WebSocketsLayer(self, f)
|
||||
if is_websocket and self.config.options.websockets:
|
||||
layer = WebSocketLayer(self, f)
|
||||
else:
|
||||
layer = self.ctx.next_layer(self)
|
||||
layer()
|
||||
|
@ -121,7 +121,7 @@ class Http2Layer(base.Layer):
|
||||
self.client_conn.send(self.connections[self.client_conn].data_to_send())
|
||||
|
||||
def next_layer(self): # pragma: no cover
|
||||
# WebSockets over HTTP/2?
|
||||
# WebSocket over HTTP/2?
|
||||
# CONNECT for proxying?
|
||||
raise NotImplementedError()
|
||||
|
||||
|
@ -8,9 +8,9 @@ from mitmproxy.net import tcp
|
||||
from mitmproxy.net import websockets
|
||||
|
||||
|
||||
class WebSocketsLayer(base.Layer):
|
||||
class WebSocketLayer(base.Layer):
|
||||
"""
|
||||
WebSockets layer to intercept, modify, and forward WebSockets connections
|
||||
WebSocket layer to intercept, modify, and forward WebSocket connections
|
||||
|
||||
Only version 13 is supported (as specified in RFC6455)
|
||||
Only HTTP/1.1-initiated connections are supported.
|
||||
@ -20,11 +20,11 @@ class WebSocketsLayer(base.Layer):
|
||||
and extensions, the Upgrade-request is forwarded to the server.
|
||||
The response from the server is then parsed and negotiated settings are extracted.
|
||||
Finally the handshake is completed by forwarding the server-response to the client.
|
||||
After that, only WebSockets frames are exchanged.
|
||||
After that, only WebSocket frames are exchanged.
|
||||
|
||||
PING/PONG frames pass through and must be answered by the other endpoint.
|
||||
|
||||
CLOSE frames are forwarded before this WebSocketsLayer terminates.
|
||||
CLOSE frames are forwarded before this WebSocketLayer terminates.
|
||||
|
||||
This layer is transparent to any negotiated extensions.
|
||||
This layer is transparent to any negotiated subprotocols.
|
||||
@ -46,7 +46,7 @@ class WebSocketsLayer(base.Layer):
|
||||
def _handle_frame(self, frame, source_conn, other_conn, is_server):
|
||||
sender = "server" if is_server else "client"
|
||||
self.log(
|
||||
"WebSockets Frame received from {}".format(sender),
|
||||
"WebSocket frame received from {}".format(sender),
|
||||
"debug",
|
||||
[repr(frame)]
|
||||
)
|
||||
@ -74,13 +74,13 @@ class WebSocketsLayer(base.Layer):
|
||||
msg = websockets.CLOSE_REASON.get_name(code, default='unknown status code')
|
||||
if len(frame.payload) > 2:
|
||||
reason = frame.payload[2:]
|
||||
self.log("WebSockets connection closed by {}: {} {}, {}".format(sender, code, msg, reason), "info")
|
||||
self.log("WebSocket connection closed by {}: {} {}, {}".format(sender, code, msg, reason), "info")
|
||||
|
||||
other_conn.send(bytes(frame))
|
||||
# close the connection
|
||||
return False
|
||||
else:
|
||||
self.log("Unknown WebSockets frame received from {}".format(sender), "info", [repr(frame)])
|
||||
self.log("Unknown WebSocket frame received from {}".format(sender), "info", [repr(frame)])
|
||||
# unknown frame - just forward it
|
||||
other_conn.send(bytes(frame))
|
||||
|
||||
@ -105,7 +105,7 @@ class WebSocketsLayer(base.Layer):
|
||||
if not self._handle_frame(frame, source_conn, other_conn, is_server):
|
||||
return
|
||||
except (socket.error, exceptions.TcpException, SSL.Error) as e:
|
||||
self.log("WebSockets connection closed unexpectedly by {}: {}".format(
|
||||
self.log("WebSocket connection closed unexpectedly by {}: {}".format(
|
||||
"server" if is_server else "client", repr(e)), "info")
|
||||
except Exception as e: # pragma: no cover
|
||||
raise exceptions.ProtocolException("Error in WebSockets connection: {}".format(repr(e)))
|
||||
raise exceptions.ProtocolException("Error in WebSocket connection: {}".format(repr(e)))
|
@ -15,7 +15,7 @@ from .. import tservers
|
||||
from mitmproxy.net import websockets
|
||||
|
||||
|
||||
class _WebSocketsServerBase(net_tservers.ServerTestBase):
|
||||
class _WebSocketServerBase(net_tservers.ServerTestBase):
|
||||
|
||||
class handler(mitmproxy.net.tcp.BaseHandler):
|
||||
|
||||
@ -43,7 +43,7 @@ class _WebSocketsServerBase(net_tservers.ServerTestBase):
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
class _WebSocketsTestBase:
|
||||
class _WebSocketTestBase:
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
@ -123,20 +123,20 @@ class _WebSocketsTestBase:
|
||||
return client
|
||||
|
||||
|
||||
class _WebSocketsTest(_WebSocketsTestBase, _WebSocketsServerBase):
|
||||
class _WebSocketTest(_WebSocketTestBase, _WebSocketServerBase):
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
_WebSocketsTestBase.setup_class()
|
||||
_WebSocketsServerBase.setup_class(ssl=cls.ssl)
|
||||
_WebSocketTestBase.setup_class()
|
||||
_WebSocketServerBase.setup_class(ssl=cls.ssl)
|
||||
|
||||
@classmethod
|
||||
def teardown_class(cls):
|
||||
_WebSocketsTestBase.teardown_class()
|
||||
_WebSocketsServerBase.teardown_class()
|
||||
_WebSocketTestBase.teardown_class()
|
||||
_WebSocketServerBase.teardown_class()
|
||||
|
||||
|
||||
class TestSimple(_WebSocketsTest):
|
||||
class TestSimple(_WebSocketTest):
|
||||
|
||||
@classmethod
|
||||
def handle_websockets(cls, rfile, wfile):
|
||||
@ -163,7 +163,7 @@ class TestSimple(_WebSocketsTest):
|
||||
client.wfile.flush()
|
||||
|
||||
|
||||
class TestSimpleTLS(_WebSocketsTest):
|
||||
class TestSimpleTLS(_WebSocketTest):
|
||||
ssl = True
|
||||
|
||||
@classmethod
|
||||
@ -191,7 +191,7 @@ class TestSimpleTLS(_WebSocketsTest):
|
||||
client.wfile.flush()
|
||||
|
||||
|
||||
class TestPing(_WebSocketsTest):
|
||||
class TestPing(_WebSocketTest):
|
||||
|
||||
@classmethod
|
||||
def handle_websockets(cls, rfile, wfile):
|
||||
@ -220,7 +220,7 @@ class TestPing(_WebSocketsTest):
|
||||
assert frame.payload == b'pong-received'
|
||||
|
||||
|
||||
class TestPong(_WebSocketsTest):
|
||||
class TestPong(_WebSocketTest):
|
||||
|
||||
@classmethod
|
||||
def handle_websockets(cls, rfile, wfile):
|
||||
@ -242,7 +242,7 @@ class TestPong(_WebSocketsTest):
|
||||
assert frame.payload == b'foobar'
|
||||
|
||||
|
||||
class TestClose(_WebSocketsTest):
|
||||
class TestClose(_WebSocketTest):
|
||||
|
||||
@classmethod
|
||||
def handle_websockets(cls, rfile, wfile):
|
||||
@ -281,7 +281,7 @@ class TestClose(_WebSocketsTest):
|
||||
websockets.Frame.from_file(client.rfile)
|
||||
|
||||
|
||||
class TestInvalidFrame(_WebSocketsTest):
|
||||
class TestInvalidFrame(_WebSocketTest):
|
||||
|
||||
@classmethod
|
||||
def handle_websockets(cls, rfile, wfile):
|
Loading…
Reference in New Issue
Block a user