From: Fredrik Tolf Date: Wed, 5 Jun 2013 10:59:12 +0000 (+0200) Subject: Merge branch 'master' of git.dolda2000.com:/srv/git/r/wrw X-Git-Url: http://dolda2000.com/gitweb/?p=wrw.git;a=commitdiff_plain;h=7756066bff7ee01d615cbce0d5ddd58441108bd6;hp=a7b35f84508eb5ab8a890065275e5a0f3bc5bef5 Merge branch 'master' of git.dolda2000.com:/srv/git/r/wrw --- diff --git a/wrw/__init__.py b/wrw/__init__.py index 8fcb72e..95ff4cd 100644 --- a/wrw/__init__.py +++ b/wrw/__init__.py @@ -1,7 +1,7 @@ __all__ = ["wsgiwrap", "restart", "cookie", "formdata"] import proto -from util import wsgiwrap, formparams, persession, sessiondata, autodirty, manudirty, specdirty +from util import wsgiwrap, formparams, funplex, persession, sessiondata, autodirty, manudirty, specdirty from dispatch import restart import cookie from form import formdata diff --git a/wrw/dispatch.py b/wrw/dispatch.py index 4d22b72..1dedbe6 100644 --- a/wrw/dispatch.py +++ b/wrw/dispatch.py @@ -24,6 +24,7 @@ def defaulterror(req, excinfo): def wraphandler(handler, excinfo): def wrapped(req): return handler(req, excinfo) + wrapped.__wrapped__ = handler return wrapped errorhandler = env.var(defaulterror) diff --git a/wrw/resp.py b/wrw/resp.py index a27a143..50ac6b1 100644 --- a/wrw/resp.py +++ b/wrw/resp.py @@ -42,7 +42,7 @@ class message(dispatch.restart): self.detail = detail def handle(self, req): - return skelfor(req).error(req, self.message, *self.detail) + return skelfor(req).message(req, self.message, *self.detail) class httperror(usererror): def __init__(self, status, message = None, detail = None): @@ -72,3 +72,9 @@ class redirect(dispatch.restart): req.ohead["Location"] = proto.appendurl(proto.requrl(req), self.url) req.ohead["Content-Length"] = 0 return [] + +class unmodified(dispatch.restart): + def handle(self, req): + req.status(304, "Not Modified") + req.ohead["Content-Length"] = "0" + return [] diff --git a/wrw/sp/util.py b/wrw/sp/util.py index 50fbd90..3ea7a8a 100644 --- a/wrw/sp/util.py +++ b/wrw/sp/util.py @@ -1,3 +1,5 @@ +import StringIO +from wrw import dispatch import cons def findnsnames(el): @@ -144,6 +146,12 @@ class formatter(object): def fragment(cls, out, el, *args, **kw): cls(out=out, root=el, *args, **kw).node(el) + @classmethod + def format(cls, el, *args, **kw): + buf = StringIO.StringIO() + cls.output(buf, el, *args, **kw) + return buf.getvalue() + def update(self, **ch): ret = type(self).__new__(type(self)) ret.__dict__.update(self.__dict__) @@ -211,3 +219,20 @@ class indenter(formatter): def start(self): super(indenter, self).start() self.write('\n') + +class response(dispatch.restart): + charset = "utf-8" + doctype = None + formatter = indenter + + def __init__(self, root): + super(response, self).__init__() + self.root = root + + @property + def ctype(self): + raise Exception("a subclass of wrw.sp.util.response must override ctype") + + def handle(self, req): + req.ohead["Content-Type"] = self.ctype + return [self.formatter.format(self.root, doctype=self.doctype, charset=self.charset)] diff --git a/wrw/sp/xhtml.py b/wrw/sp/xhtml.py index d19fc99..e78d197 100644 --- a/wrw/sp/xhtml.py +++ b/wrw/sp/xhtml.py @@ -60,4 +60,5 @@ def forreq(req, tree): def xhtmlresp(callable): def wrapper(req): return forreq(req, callable(req)) + wrapper.__wrapped__ = callable return wrapper diff --git a/wrw/util.py b/wrw/util.py index 64b820f..759c295 100644 --- a/wrw/util.py +++ b/wrw/util.py @@ -1,9 +1,10 @@ -import inspect -import req, dispatch, session, form, resp +import inspect, math +import req, dispatch, session, form, resp, proto def wsgiwrap(callable): def wrapper(env, startreq): return dispatch.handleenv(env, startreq, callable) + wrapper.__wrapped__ = callable return wrapper def formparams(callable): @@ -20,8 +21,47 @@ def formparams(callable): if spec.args[i] not in args: raise resp.httperror(400, "Missing parameter", ("The query parameter `", resp.h.code(spec.args[i]), "' is required but not supplied.")) return callable(**args) + wrapper.__wrapped__ = callable return wrapper +class funplex(object): + def __init__(self, *funs, **nfuns): + self.dir = {} + self.dir.update(((self.unwrap(fun).__name__, fun) for fun in funs)) + self.dir.update(nfuns) + + @staticmethod + def unwrap(fun): + while hasattr(fun, "__wrapped__"): + fun = fun.__wrapped__ + return fun + + def __call__(self, req): + if req.pathinfo == "": + raise resp.redirect(req.uriname + "/") + if req.pathinfo[:1] != "/": + raise resp.notfound() + p = req.pathinfo[1:] + if p == "": + p = "__index__" + bi = 1 + else: + p = p.partition("/")[0] + bi = len(p) + 1 + if p in self.dir: + return self.dir[p](req.shift(bi)) + raise resp.notfound() + + def add(self, fun): + self.dir[self.unwrap(fun).__name__] = fun + return fun + + def name(self, name): + def dec(fun): + self.dir[name] = fun + return fun + return dec + def persession(data = None): def dec(callable): def wrapper(req): @@ -34,6 +74,7 @@ def persession(data = None): sess[data] = data() sess[callable] = callable(data) return sess[callable].handle(req) + wrapper.__wrapped__ = callable return wrapper return dec @@ -66,6 +107,7 @@ class preiter(object): def pregen(callable): def wrapper(*args, **kwargs): return preiter(callable(*args, **kwargs)) + wrapper.__wrapped__ = callable return wrapper class sessiondata(object): @@ -212,3 +254,10 @@ class specdirty(sessiondata): ss[i] = specslot.unbound else: ss[i] = val + +def datecheck(req, mtime): + if "If-Modified-Since" in req.ihead: + rtime = proto.phttpdate(req.ihead["If-Modified-Since"]) + if rtime >= math.floor(mtime): + raise resp.unmodified() + req.ohead["Last-Modified"] = proto.httpdate(mtime)