aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libpathod/language/__init__.py10
-rw-r--r--libpathod/language/websockets.py12
-rw-r--r--libpathod/pathod.py42
-rw-r--r--test/test_pathod.py9
4 files changed, 55 insertions, 18 deletions
diff --git a/libpathod/language/__init__.py b/libpathod/language/__init__.py
index 12378607..52ccf61c 100644
--- a/libpathod/language/__init__.py
+++ b/libpathod/language/__init__.py
@@ -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.
diff --git a/libpathod/language/websockets.py b/libpathod/language/websockets.py
index 44c12f64..96dbce53 100644
--- a/libpathod/language/websockets.py
+++ b/libpathod/language/websockets.py
@@ -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)
diff --git a/libpathod/pathod.py b/libpathod/pathod.py
index 6b385a47..abce15fe 100644
--- a/libpathod/pathod.py
+++ b/libpathod/pathod.py
@@ -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:
+ while True:
+ with log.Log(self.logfp, self.server.hexdump, lr, lw) as lg:
try:
frm = websockets.Frame.from_file(self.rfile)
- retlog = dict(
- type="wsframe",
- frame=dict(
- ),
- cipher=None,
- )
- self.addlog(retlog)
+ except tcp.NetLibIncomplete, e:
+ lg("Error reading websocket frame: %s"%e)
break
- except tcp.NetLibTimeout: # pragma: no cover
- pass
- lg(frm.human_readable())
+ lg(frm.human_readable())
+ retlog = dict(
+ 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
def handle_http_connect(self, connect, lg):
diff --git a/test/test_pathod.py b/test/test_pathod.py
index 43fb8368..c7ea47e3 100644
--- a/test/test_pathod.py
+++ b/test/test_pathod.py
@@ -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