def __call__(self, environ, start_response): """Main WSGI callable. """ # Translate the request to the filesystem. # ======================================== fspath = translate(self.config.paths.root, environ['PATH_INFO']) if self.config.paths.__ is not None: if fspath.startswith(self.config.paths.__): raise Response(404) # protect magic directory environ['PATH_TRANSLATED'] = fspath # Dispatch to a WSGI app or an aspen handler. # =========================================== app = self.get_app(environ) # 301 if app is not None: # app response = app(environ, start_response) # WSGI else: # handler if not exists(fspath): raise Response(404) check_trailing_slash(environ) fspath = find_default(self.config.defaults, fspath) # 403 environ['PATH_TRANSLATED'] = fspath environ['aspen.website'] = self fp = environ['aspen.fp'] = open(fspath) handler = self.get_handler(fp) fp.seek(0) response = handler.handle(environ, start_response) # WSGI return response
def check_trailing_slash(environ): """Given a WSGI environ, return None or raise 301. environ must have PATH_TRANSLATED set in addition to PATH_INFO, which latter is required by the spec. """ fs = environ['PATH_TRANSLATED'] url = environ['PATH_INFO'] if isdir(fs) and not url.endswith('/'): environ['PATH_INFO'] += '/' response = Response(301) response.headers['Location'] = full_url(environ) raise response
def pyscript(environ, start_response): """Execute the script pseudo-CGI-style. """ context = dict(request=environ) context['response'] = Response() context['__file__'] = environ['aspen.fp'].name fp = environ['aspen.fp'] del environ['aspen.fp'] try: exec fp in context except SystemExit: pass return environ['response']
def find_default(defaults, path): """Given a list of defaults and a path, return a filepath or raise 403. If the path isn't a directory, simply return it. """ default = None if isdir(path): for name in defaults: _path = join(path, name) if isfile(_path): default = _path break if default is None: raise Response(403) path = default return path
def get_app(self, environ): """Given a WSGI environ, return the first matching app. """ app = None test_path = environ['PATH_INFO'] if not test_path.endswith('/'): test_path += '/' for app_urlpath, _app in self.config.apps: if test_path.startswith(app_urlpath): environ['PATH_TRANSLATED'] = translate(self.config.paths.root, app_urlpath) if not isdir(environ['PATH_TRANSLATED']): raise Response(404) if app_urlpath.endswith('/'): check_trailing_slash(environ) app = _app break if app is None: log.debug("No app found for '%s'" % environ['PATH_INFO']) return app
def static(environ, start_response): """Serve a static file off of the filesystem. In staging and deployment modes, we honor any 'If-Modified-Since' header, an HTTP header used for caching. """ path = environ['PATH_TRANSLATED'] ims = environ.get('HTTP_IF_MODIFIED_SINCE', '') # Get basic info from the filesystem and start building a response. # ================================================================= stats = os.stat(path) mtime = stats[stat.ST_MTIME] size = stats[stat.ST_SIZE] content_type = mimetypes.guess_type(path)[0] or 'text/plain' response = Response(200) # Support 304s, but only in deployment mode. # ========================================== if mode.stprod: if ims: mod_since = rfc822.parsedate(ims) last_modified = time.gmtime(mtime) if last_modified[:6] <= mod_since[:6]: response.code = 304 # Finish building the response and return it. # =========================================== response.headers['Last-Modified'] = rfc822.formatdate(mtime) response.headers['Content-Type'] = content_type response.headers['Content-Length'] = size if response.code != 304: response.body = open(path).read() return response
def HTTP404(environ, start_response): raise Response(404)