Better internal error pages.

This commit is contained in:
Aldo Cortesi 2012-04-28 14:43:57 +12:00
parent 2c8f17eae7
commit 5fc2a63781
5 changed files with 55 additions and 32 deletions

View File

@ -16,7 +16,6 @@ def application(**settings):
(r"/preview", handlers.Preview),
(r"/p/.*", handlers.Pathod, settings),
],
debug=True,
static_path = utils.data.path("static"),
template_path = utils.data.path("templates"),
)

View File

@ -36,9 +36,9 @@ class Pathod(object):
try:
self.response = rparse.parse(self.settings, spec)
except rparse.ParseException, v:
self.response = rparse.StubResponse(
self.response = rparse.InternalResponse(
800,
"Error parsing response spec:" + str(v)
"Error parsing response spec: %s\n"%v.msg + v.marked()
)
def _execute(self, transforms, *args, **kwargs):

View File

@ -5,7 +5,17 @@ import tornado.ioloop
TESTING = False
class ParseException(Exception): pass
class ParseException(Exception):
def __init__(self, msg, s, col):
Exception.__init__(self)
self.msg = msg
self.s = s
self.col = col
def marked(self):
return "%s\n%s"%(self.s, " "*(self.col-1) + "^")
class ServerError(Exception): pass
@ -304,19 +314,9 @@ class Response:
code = 200
msg = LiteralGenerator(http.RESPONSES[code])
body = LiteralGenerator("OK")
def __init__(self, settings, tokens):
self.tokens = tokens
def __init__(self):
self.headers = []
self.pauses = []
for i in tokens:
i.mod_response(settings, self)
if self.body and not self.get_header("Content-Length"):
self.headers.append(
(
LiteralGenerator("Content-Length"),
LiteralGenerator(str(len(self.body))),
)
)
def get_header(self, hdr):
for k, v in self.headers:
@ -393,6 +393,14 @@ class Response:
fp.finish()
def render(self, fp):
if self.body and not self.get_header("Content-Length"):
self.headers.append(
(
LiteralGenerator("Content-Length"),
LiteralGenerator(str(len(self.body))),
)
)
hdrs = []
for k, v in self.headers:
hdrs.extend([
@ -423,8 +431,17 @@ class Response:
return "\n".join(parts)
class StubResponse:
class CraftedResponse(Response):
def __init__(self, settings, tokens):
Response.__init__(self)
self.tokens = tokens
for i in tokens:
i.mod_response(settings, self)
class InternalResponse(Response):
def __init__(self, code, body):
Response.__init__(self)
self.code = code
self.msg = LiteralGenerator(http.RESPONSES.get(code, "Unknown error"))
self.body = LiteralGenerator(body)
@ -442,6 +459,6 @@ class StubResponse:
def parse(settings, s):
try:
return Response(settings, Response.expr().parseString(s, parseAll=True))
return CraftedResponse(settings, Response.expr().parseString(s, parseAll=True))
except pp.ParseException, v:
raise ParseException(v)
raise ParseException(v.msg, v.line, v.col)

View File

@ -4,6 +4,17 @@ from libpathod import rparse
rparse.TESTING = True
class DummyRequest(StringIO.StringIO):
def write(self, d, callback=None):
StringIO.StringIO.write(self, d)
if callback:
callback()
def finish(self):
return
class uMisc(libpry.AutoTree):
def test_generators(self):
v = rparse.Value.parseString("val")[0]
@ -130,8 +141,10 @@ class uMisc(libpry.AutoTree):
r = e.parseString('10')[0]
assert r.msg.val == "Unknown code"
def test_stub_response(self):
s = rparse.StubResponse(400, "foo")
def test_internal_response(self):
d = DummyRequest()
s = rparse.InternalResponse(400, "foo")
s.render(d)
class uDisconnects(libpry.AutoTree):
@ -175,6 +188,10 @@ class uPauses(libpry.AutoTree):
class uparse(libpry.AutoTree):
def test_parse_err(self):
libpry.raises(rparse.ParseException, rparse.parse, {}, "400:msg,b:")
try:
rparse.parse({}, "400:msg,b:")
except rparse.ParseException, v:
print v.marked()
def test_parse_header(self):
r = rparse.parse({}, "400,h:foo:bar")
@ -193,16 +210,6 @@ class uparse(libpry.AutoTree):
assert ("random", 10) in r.pauses
class DummyRequest(StringIO.StringIO):
def write(self, d, callback=None):
StringIO.StringIO.write(self, d)
if callback:
callback()
def finish(self):
return
class uResponse(libpry.AutoTree):
def dummy_response(self):
return rparse.parse({}, "400:msg")

4
todo
View File

@ -1,6 +1,6 @@
- Files
- Shortcuts
- HTTPS
- Sequences
- Anchors
- Sequences