mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-29 11:03:13 +00:00
add WebSocketMessage.text
This commit is contained in:
parent
f135be8e65
commit
1858564b91
@ -55,6 +55,10 @@ To document all event hooks, we do a bit of hackery:
|
|||||||
{% if doc.qualname.startswith("ServerConnectionHookData") and doc.name != "__init__" %}
|
{% if doc.qualname.startswith("ServerConnectionHookData") and doc.name != "__init__" %}
|
||||||
{{ default_is_public(doc) }}
|
{{ default_is_public(doc) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% elif doc.modulename == "mitmproxy.websocket" %}
|
||||||
|
{% if doc.qualname != "WebSocketMessage.type" %}
|
||||||
|
{{ default_is_public(doc) }}
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ default_is_public(doc) }}
|
{{ default_is_public(doc) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -20,18 +20,16 @@ class WebSocketMessage(serializable.Serializable):
|
|||||||
"""
|
"""
|
||||||
A single WebSocket message sent from one peer to the other.
|
A single WebSocket message sent from one peer to the other.
|
||||||
|
|
||||||
Fragmented WebSocket messages are reassembled by mitmproxy and the
|
Fragmented WebSocket messages are reassembled by mitmproxy and then
|
||||||
represented as a single instance of this class.
|
represented as a single instance of this class.
|
||||||
|
|
||||||
The [WebSocket RFC](https://tools.ietf.org/html/rfc6455) specifies both
|
The [WebSocket RFC](https://tools.ietf.org/html/rfc6455) specifies both
|
||||||
text and binary messages. To avoid a whole class of nasty type confusion bugs,
|
text and binary messages. To avoid a whole class of nasty type confusion bugs,
|
||||||
mitmproxy stores all message contents as binary. If you need text, you can decode the `content` property:
|
mitmproxy stores all message contents as `bytes`. If you need a `str`, you can access the `text` property
|
||||||
|
on text messages:
|
||||||
|
|
||||||
>>> from wsproto.frame_protocol import Opcode
|
>>> if message.is_text:
|
||||||
>>> if message.type == Opcode.TEXT:
|
>>> text = message.text
|
||||||
>>> text = message.content.decode()
|
|
||||||
|
|
||||||
Per the WebSocket spec, text messages always use UTF-8 encoding.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from_client: bool
|
from_client: bool
|
||||||
@ -40,8 +38,7 @@ class WebSocketMessage(serializable.Serializable):
|
|||||||
"""
|
"""
|
||||||
The message type, as per RFC 6455's [opcode](https://tools.ietf.org/html/rfc6455#section-5.2).
|
The message type, as per RFC 6455's [opcode](https://tools.ietf.org/html/rfc6455#section-5.2).
|
||||||
|
|
||||||
Note that mitmproxy will always store the message contents as *bytes*.
|
Mitmproxy currently only exposes messages assembled from `TEXT` and `BINARY` frames.
|
||||||
A dedicated `.text` property for text messages is planned, see https://github.com/mitmproxy/mitmproxy/pull/4486.
|
|
||||||
"""
|
"""
|
||||||
content: bytes
|
content: bytes
|
||||||
"""A byte-string representing the content of this message."""
|
"""A byte-string representing the content of this message."""
|
||||||
@ -81,10 +78,39 @@ class WebSocketMessage(serializable.Serializable):
|
|||||||
else:
|
else:
|
||||||
return repr(self.content)
|
return repr(self.content)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_text(self) -> bool:
|
||||||
|
"""
|
||||||
|
`True` if this message is assembled from WebSocket `TEXT` frames,
|
||||||
|
`False` if it is assembled from `BINARY` frames.
|
||||||
|
"""
|
||||||
|
return self.type == Opcode.TEXT
|
||||||
|
|
||||||
def kill(self):
|
def kill(self):
|
||||||
# Likely to be replaced with .drop() in the future, see https://github.com/mitmproxy/mitmproxy/pull/4486
|
# Likely to be replaced with .drop() in the future, see https://github.com/mitmproxy/mitmproxy/pull/4486
|
||||||
self.killed = True
|
self.killed = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self) -> str:
|
||||||
|
"""
|
||||||
|
The message content as text.
|
||||||
|
|
||||||
|
This attribute is only available if `WebSocketMessage.is_text` is `True`.
|
||||||
|
|
||||||
|
*See also:* `WebSocketMessage.content`
|
||||||
|
"""
|
||||||
|
if self.type != Opcode.TEXT:
|
||||||
|
raise AttributeError(f"{self.type.name.title()} WebSocket frames do not have a 'text' attribute.")
|
||||||
|
|
||||||
|
return self.content.decode()
|
||||||
|
|
||||||
|
@text.setter
|
||||||
|
def text(self, value: str) -> None:
|
||||||
|
if self.type != Opcode.TEXT:
|
||||||
|
raise AttributeError(f"{self.type.name.title()} WebSocket frames do not have a 'text' attribute.")
|
||||||
|
|
||||||
|
self.content = value.encode()
|
||||||
|
|
||||||
|
|
||||||
class WebSocketData(stateobject.StateObject):
|
class WebSocketData(stateobject.StateObject):
|
||||||
"""
|
"""
|
||||||
@ -97,9 +123,9 @@ class WebSocketData(stateobject.StateObject):
|
|||||||
|
|
||||||
closed_by_client: Optional[bool] = None
|
closed_by_client: Optional[bool] = None
|
||||||
"""
|
"""
|
||||||
True if the client closed the connection,
|
`True` if the client closed the connection,
|
||||||
False if the server closed the connection,
|
`False` if the server closed the connection,
|
||||||
None if the connection is active.
|
`None` if the connection is active.
|
||||||
"""
|
"""
|
||||||
close_code: Optional[int] = None
|
close_code: Optional[int] = None
|
||||||
"""[Close Code](https://tools.ietf.org/html/rfc6455#section-7.1.5)"""
|
"""[Close Code](https://tools.ietf.org/html/rfc6455#section-7.1.5)"""
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
from mitmproxy import http
|
from mitmproxy import http
|
||||||
from mitmproxy import websocket
|
from mitmproxy import websocket
|
||||||
from mitmproxy.test import tflow
|
from mitmproxy.test import tflow
|
||||||
@ -26,3 +28,18 @@ class TestWebSocketMessage:
|
|||||||
assert not m.killed
|
assert not m.killed
|
||||||
m.kill()
|
m.kill()
|
||||||
assert m.killed
|
assert m.killed
|
||||||
|
|
||||||
|
def test_text(self):
|
||||||
|
txt = websocket.WebSocketMessage(Opcode.TEXT, True, b"foo")
|
||||||
|
bin = websocket.WebSocketMessage(Opcode.BINARY, True, b"foo")
|
||||||
|
|
||||||
|
assert txt.is_text
|
||||||
|
assert txt.text
|
||||||
|
txt.text = "bar"
|
||||||
|
assert txt.content == b"bar"
|
||||||
|
|
||||||
|
assert not bin.is_text
|
||||||
|
with pytest.raises(AttributeError, match="do not have a 'text' attribute."):
|
||||||
|
_ = bin.text
|
||||||
|
with pytest.raises(AttributeError, match="do not have a 'text' attribute."):
|
||||||
|
bin.text = "bar"
|
||||||
|
Loading…
Reference in New Issue
Block a user