diff options
author | ianb <devnull@localhost> | 2005-04-22 03:18:20 +0000 |
---|---|---|
committer | ianb <devnull@localhost> | 2005-04-22 03:18:20 +0000 |
commit | 36593a8d40cd1417d2927a78cdbe621090b6e8a5 (patch) | |
tree | 74dc42b93bb512593869fd57f8be99c198d8c108 /paste/recursive.py | |
parent | 7752a3102fc8aa68ee7e349495bc2e9345c77c00 (diff) | |
download | paste-36593a8d40cd1417d2927a78cdbe621090b6e8a5.tar.gz |
Renamed package itself
Diffstat (limited to 'paste/recursive.py')
-rw-r--r-- | paste/recursive.py | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/paste/recursive.py b/paste/recursive.py new file mode 100644 index 0000000..bfe8206 --- /dev/null +++ b/paste/recursive.py @@ -0,0 +1,110 @@ +""" +A WSGI middleware that allows for recursive and forwarded calls. +All these calls go to the same 'application', but presumably that +application acts differently with different URLs. The forwarded +URLs must be relative to this container. + +The forwarder is available through +``environ['paste.recursive.forward'](path, extra_environ=None)``, +the second argument is a dictionary of values to be added to the +request, overwriting any keys. The forward will call start_response; +thus you must *not* call it after you have sent any output to the +server. Also, it will return an iterator that must be returned up the +stack. You may need to use exceptions to guarantee that this iterator +will be passed back through the application. + +The includer is available through +``environ['paste.recursive.include'](path, extra_environ=None)``. +It is like forwarder, except it completes the request and returns a +response object. The response object has three public attributes: +status, headers, and body. The status is a string, headers is a list +of (header_name, header_value) tuples, and the body is a string. +""" + +from cStringIO import StringIO + +class RecursiveMiddleware(object): + + def __init__(self, application): + self.application = application + + def __call__(self, environ, start_response): + environ['paste.recursive.forward'] = Forwarder( + self.application, environ, start_response) + environ['paste.recursive.include'] = Includer( + self.application, environ, start_response) + return self.application(environ, start_response) + +class Recursive(object): + + def __init__(self, application, environ, start_response): + self.application = application + self.original_environ = environ.copy() + self.previous_environ = environ + self.start_response = start_response + + def __call__(self, path, new_environ=None): + environ = self.original_environ.copy() + if new_environ: + environ.update(new_environ) + environ['paste.recursive.previous_environ'] = self.previous_environ + base_path = self.original_environ.get('SCRIPT_NAME') + if path.startswith('/'): + assert path.startswith(base_path), "You can only forward requests to resources under the path %r (not %r)" % (base_path, path) + path = path[len(base_path)+1:] + assert not path.startswith('/') + path_info = '/' + path + environ['PATH_INFO'] = path_info + return self.activate(environ) + +class Forwarder(Recursive): + + def activate(self, environ): + environ['wsgi.errors'].write('Forwarding to %r\n' % (environ['SCRIPT_NAME'] + environ['PATH_INFO'])) + return self.application(environ, self.start_response) + +class Includer(Recursive): + + def activate(self, environ): + environ['wsgi.errors'].write('Including %r\n' % (environ['SCRIPT_NAME'] + environ['PATH_INFO'])) + response = IncludedResponse + def start_response(status, headers): + response.status = status + response.headers = headers + return response.write + app_iter = self.application(environ, start_response) + try: + for s in app_iter: + response.write(s) + finally: + if hasattr(app_iter, 'close'): + app_iter.close() + response.close() + return response + +class IncludedResponse(object): + + def __init__(self): + self.headers = None + self.status = None + self.output = StringIO() + self.str = None + + def close(self): + self.str = self.output.getvalue() + self.output.close() + self.output = None + + def write(self): + assert self.output is not None, "This response has already been closed and no further data can be written." + self.output.write() + + def __str__(self): + return self.body + + def body__get(self): + if self.str is None: + return self.output.getvalue() + else: + return self.str + body = property(body__get) |