mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 08:11:00 +00:00
Rudimentary support for reflected websocket frames.
This commit is contained in:
parent
9311d60596
commit
0a7da6a9b1
@ -57,6 +57,16 @@ def parse_pathoc(s):
|
|||||||
return expanded
|
return expanded
|
||||||
|
|
||||||
|
|
||||||
|
def parse_websocket_frame(s):
|
||||||
|
try:
|
||||||
|
return websockets.WebsocketFrame.expr().parseString(
|
||||||
|
s,
|
||||||
|
parseAll = True
|
||||||
|
)[0]
|
||||||
|
except pp.ParseException as v:
|
||||||
|
raise exceptions.ParseException(v.msg, v.line, v.col)
|
||||||
|
|
||||||
|
|
||||||
def serve(msg, fp, settings):
|
def serve(msg, fp, settings):
|
||||||
"""
|
"""
|
||||||
fp: The file pointer to write to.
|
fp: The file pointer to write to.
|
||||||
|
@ -3,6 +3,7 @@ import netlib.websockets
|
|||||||
import pyparsing as pp
|
import pyparsing as pp
|
||||||
from . import base, generators, actions, message
|
from . import base, generators, actions, message
|
||||||
|
|
||||||
|
NESTED_LEADER = "pathod!"
|
||||||
|
|
||||||
class WF(base.CaselessLiteral):
|
class WF(base.CaselessLiteral):
|
||||||
TOK = "wf"
|
TOK = "wf"
|
||||||
@ -160,6 +161,10 @@ class WebsocketFrame(message.Message):
|
|||||||
resp = resp.setParseAction(klass)
|
resp = resp.setParseAction(klass)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@property
|
||||||
|
def nested_frame(self):
|
||||||
|
return self.tok(NestedFrame)
|
||||||
|
|
||||||
def resolve(self, settings, msg=None):
|
def resolve(self, settings, msg=None):
|
||||||
tokens = self.tokens[:]
|
tokens = self.tokens[:]
|
||||||
if not self.mask and settings.is_client:
|
if not self.mask and settings.is_client:
|
||||||
@ -181,6 +186,9 @@ class WebsocketFrame(message.Message):
|
|||||||
elif self.rawbody:
|
elif self.rawbody:
|
||||||
bodygen = self.rawbody.value.get_generator(settings)
|
bodygen = self.rawbody.value.get_generator(settings)
|
||||||
length = len(self.rawbody.value.get_generator(settings))
|
length = len(self.rawbody.value.get_generator(settings))
|
||||||
|
elif self.nested_frame:
|
||||||
|
bodygen = NESTED_LEADER + self.nested_frame.parsed.spec()
|
||||||
|
length = len(bodygen)
|
||||||
else:
|
else:
|
||||||
bodygen = None
|
bodygen = None
|
||||||
length = 0
|
length = 0
|
||||||
@ -228,7 +236,3 @@ class WebsocketClientFrame(WebsocketFrame):
|
|||||||
components = COMPONENTS + (
|
components = COMPONENTS + (
|
||||||
NestedFrame,
|
NestedFrame,
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def nested_frame(self):
|
|
||||||
return self.tok(NestedFrame)
|
|
||||||
|
@ -11,6 +11,8 @@ from netlib import tcp, http, wsgi, certutils, websockets
|
|||||||
from . import version, app, language, utils, log
|
from . import version, app, language, utils, log
|
||||||
import language.http
|
import language.http
|
||||||
import language.actions
|
import language.actions
|
||||||
|
import language.exceptions
|
||||||
|
import language.websockets
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_CERT_DOMAIN = "pathod.net"
|
DEFAULT_CERT_DOMAIN = "pathod.net"
|
||||||
@ -102,21 +104,37 @@ class PathodHandler(tcp.BaseHandler):
|
|||||||
def handle_websocket(self):
|
def handle_websocket(self):
|
||||||
lr = self.rfile if self.server.logreq else None
|
lr = self.rfile if self.server.logreq else None
|
||||||
lw = self.wfile if self.server.logresp else None
|
lw = self.wfile if self.server.logresp else None
|
||||||
with log.Log(self.logfp, self.server.hexdump, lr, lw) as lg:
|
while True:
|
||||||
while True:
|
with log.Log(self.logfp, self.server.hexdump, lr, lw) as lg:
|
||||||
try:
|
try:
|
||||||
frm = websockets.Frame.from_file(self.rfile)
|
frm = websockets.Frame.from_file(self.rfile)
|
||||||
retlog = dict(
|
except tcp.NetLibIncomplete, e:
|
||||||
type="wsframe",
|
lg("Error reading websocket frame: %s"%e)
|
||||||
frame=dict(
|
|
||||||
),
|
|
||||||
cipher=None,
|
|
||||||
)
|
|
||||||
self.addlog(retlog)
|
|
||||||
break
|
break
|
||||||
except tcp.NetLibTimeout: # pragma: no cover
|
lg(frm.human_readable())
|
||||||
pass
|
retlog = dict(
|
||||||
lg(frm.human_readable())
|
type="wsframe",
|
||||||
|
frame=dict(
|
||||||
|
),
|
||||||
|
cipher=None,
|
||||||
|
)
|
||||||
|
ld = language.websockets.NESTED_LEADER
|
||||||
|
if frm.payload.startswith(ld):
|
||||||
|
nest = frm.payload[len(ld):]
|
||||||
|
try:
|
||||||
|
wf = language.parse_websocket_frame(nest)
|
||||||
|
except language.exceptions.ParseException, v:
|
||||||
|
lg(
|
||||||
|
"Parse error in reflected frame specifcation:"
|
||||||
|
" %s" % v.msg
|
||||||
|
)
|
||||||
|
break
|
||||||
|
frame_log = language.serve(
|
||||||
|
wf,
|
||||||
|
self.wfile,
|
||||||
|
self.settings
|
||||||
|
)
|
||||||
|
self.addlog(retlog)
|
||||||
return self.handle_websocket, None
|
return self.handle_websocket, None
|
||||||
|
|
||||||
def handle_http_connect(self, connect, lg):
|
def handle_http_connect(self, connect, lg):
|
||||||
|
@ -2,6 +2,7 @@ import cStringIO
|
|||||||
from libpathod import pathod, version
|
from libpathod import pathod, version
|
||||||
from netlib import tcp, http
|
from netlib import tcp, http
|
||||||
import time
|
import time
|
||||||
|
import sys
|
||||||
|
|
||||||
import tutils
|
import tutils
|
||||||
|
|
||||||
@ -211,10 +212,14 @@ class CommonTests(tutils.DaemonTests):
|
|||||||
|
|
||||||
def test_websocket_frame(self):
|
def test_websocket_frame(self):
|
||||||
r = self.pathoc(["ws:/p/", "wf:b@10"], ws_read_limit=0)
|
r = self.pathoc(["ws:/p/", "wf:b@10"], ws_read_limit=0)
|
||||||
print r
|
print >> sys.stderr, r
|
||||||
print self.d.log()
|
print >> sys.stderr, self.d.log()
|
||||||
assert self.d.last_log()["type"] == "wsframe"
|
assert self.d.last_log()["type"] == "wsframe"
|
||||||
|
|
||||||
|
def test_websocket_reflected_frame(self):
|
||||||
|
r = self.pathoc(["ws:/p/", "wf:f'wf'"], ws_read_limit=0)
|
||||||
|
assert r
|
||||||
|
|
||||||
|
|
||||||
class TestDaemon(CommonTests):
|
class TestDaemon(CommonTests):
|
||||||
ssl = False
|
ssl = False
|
||||||
|
Loading…
Reference in New Issue
Block a user