Rudimentary support for reflected websocket frames.

This commit is contained in:
Aldo Cortesi 2015-06-04 23:57:23 +12:00
parent 9311d60596
commit 0a7da6a9b1
4 changed files with 55 additions and 18 deletions

View File

@ -57,6 +57,16 @@ def parse_pathoc(s):
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):
"""
fp: The file pointer to write to.

View File

@ -3,6 +3,7 @@ import netlib.websockets
import pyparsing as pp
from . import base, generators, actions, message
NESTED_LEADER = "pathod!"
class WF(base.CaselessLiteral):
TOK = "wf"
@ -160,6 +161,10 @@ class WebsocketFrame(message.Message):
resp = resp.setParseAction(klass)
return resp
@property
def nested_frame(self):
return self.tok(NestedFrame)
def resolve(self, settings, msg=None):
tokens = self.tokens[:]
if not self.mask and settings.is_client:
@ -181,6 +186,9 @@ class WebsocketFrame(message.Message):
elif self.rawbody:
bodygen = 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:
bodygen = None
length = 0
@ -228,7 +236,3 @@ class WebsocketClientFrame(WebsocketFrame):
components = COMPONENTS + (
NestedFrame,
)
@property
def nested_frame(self):
return self.tok(NestedFrame)

View File

@ -11,6 +11,8 @@ from netlib import tcp, http, wsgi, certutils, websockets
from . import version, app, language, utils, log
import language.http
import language.actions
import language.exceptions
import language.websockets
DEFAULT_CERT_DOMAIN = "pathod.net"
@ -102,21 +104,37 @@ class PathodHandler(tcp.BaseHandler):
def handle_websocket(self):
lr = self.rfile if self.server.logreq 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:
with log.Log(self.logfp, self.server.hexdump, lr, lw) as lg:
try:
frm = websockets.Frame.from_file(self.rfile)
except tcp.NetLibIncomplete, e:
lg("Error reading websocket frame: %s"%e)
break
lg(frm.human_readable())
retlog = dict(
type="wsframe",
frame=dict(
),
cipher=None,
)
self.addlog(retlog)
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
except tcp.NetLibTimeout: # pragma: no cover
pass
lg(frm.human_readable())
frame_log = language.serve(
wf,
self.wfile,
self.settings
)
self.addlog(retlog)
return self.handle_websocket, None
def handle_http_connect(self, connect, lg):

View File

@ -2,6 +2,7 @@ import cStringIO
from libpathod import pathod, version
from netlib import tcp, http
import time
import sys
import tutils
@ -211,10 +212,14 @@ class CommonTests(tutils.DaemonTests):
def test_websocket_frame(self):
r = self.pathoc(["ws:/p/", "wf:b@10"], ws_read_limit=0)
print r
print self.d.log()
print >> sys.stderr, r
print >> sys.stderr, self.d.log()
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):
ssl = False