class MediaMixin: cache_control = CacheControl(maxage=86400) def serve_file(self, request, fullpath, status_code=None): return file_response(request, fullpath, status_code=status_code, cache_control=self.cache_control) def directory_index(self, request, fullpath): names = [Html('a', '../', href='../', cn='folder')] files = [] for f in sorted(os.listdir(fullpath)): if not f.startswith('.'): if os.path.isdir(os.path.join(fullpath, f)): names.append(Html('a', f, href=f+'/', cn='folder')) else: files.append(Html('a', f, href=f)) names.extend(files) return self.static_index(request, names) def static_index(self, request, links): doc = request.html_document doc.title = 'Index of %s' % request.path title = Html('h2', doc.title) list = Html('ul', *[Html('li', a) for a in links]) doc.body.append(Html('div', title, list)) return doc.http_response(request)
class FileRouter(Router, MediaMixin): '''A Router for a single file ''' response_content_types = RouterParam( ('application/octet-stream', 'text/css', 'application/javascript', 'text/html')) cache_control = CacheControl(maxage=86400) def __init__(self, route, file_path, status_code=None, raise_404=True): super().__init__(route) self._status_code = status_code self._file_path = file_path self._raise_404 = raise_404 def filesystem_path(self, request): return self._file_path def get(self, request): fullpath = self.filesystem_path(request) if os.path.isfile(fullpath): return self.serve_file(request, fullpath, status_code=self._status_code) elif self._raise_404: raise Http404
def test_CacheControl(self): headers = CIMultiDict() c = CacheControl() self.assertFalse(c.private) self.assertFalse(c.maxage) c(headers) self.assertEqual(', '.join(headers.getall('cache-control')), 'no-cache') c = CacheControl(maxage=3600) c(headers) self.assertEqual(', '.join(headers.getall('cache-control')), 'max-age=3600, public') c = CacheControl(maxage=3600, private=True) c(headers) self.assertEqual(', '.join(headers.getall('cache-control')), 'max-age=3600, private') c = CacheControl(maxage=3600, must_revalidate=True) c(headers) self.assertEqual(', '.join(headers.getall('cache-control')), 'max-age=3600, public, must-revalidate') c = CacheControl(maxage=3600, proxy_revalidate=True) c(headers) self.assertEqual(', '.join(headers.getall('cache-control')), 'max-age=3600, public, proxy-revalidate') c = CacheControl(maxage=3600, proxy_revalidate=True, nostore=True) c(headers) self.assertEqual(', '.join(headers.getall('cache-control')), 'no-store, no-cache, must-revalidate, max-age=0')
def test_CacheControl(self): headers = Headers() c = CacheControl() self.assertFalse(c.private) self.assertFalse(c.maxage) c(headers) self.assertEqual(headers['cache-control'], 'no-cache') c = CacheControl(maxage=3600) c(headers) self.assertEqual(headers['cache-control'], 'max-age=3600, public') c = CacheControl(maxage=3600, private=True) c(headers) self.assertEqual(headers['cache-control'], 'max-age=3600, private') c = CacheControl(maxage=3600, must_revalidate=True) c(headers) self.assertEqual(headers['cache-control'], 'max-age=3600, public, must-revalidate') c = CacheControl(maxage=3600, proxy_revalidate=True) c(headers) self.assertEqual(headers['cache-control'], 'max-age=3600, public, proxy-revalidate') c = CacheControl(maxage=3600, proxy_revalidate=True, nostore=True) c(headers) self.assertEqual(headers['cache-control'], 'no-store, no-cache, must-revalidate, max-age=0')
class JsonRouter(Router): model = RouterParam() cache_control = CacheControl() response_content_types = ['application/json'] def head(self, request): if hasattr(self, 'get'): return self.get(request) def json_response(self, request, data): """Return a response as application/json """ response = Json(data).http_response(request) self.cache_control(response) return response def get_model(self, request, model=None): model = request.app.models.get(model or self.model) if not model: raise Http404 return model
class SocketIO(Router): info_cache = CacheControl(nostore=True) home_cache = CacheControl(maxage=60*60*24*30) def __init__(self, route, **kwargs): super().__init__(route, **kwargs) self.handle = LuxWs() self.add_child(WebSocket('/websocket', self.handle, **kwargs)) self.add_child(WebSocket('<server_id>/<session_id>/websocket', self.handle, **kwargs)) def get(self, request): response = request.response self.home_cache(response.headers) response.content_type = 'text/plain' response.content = 'Welcome to SockJS!\n' return response @route(method=('OPTIONS', 'GET'), response_content_types=('application/json',)) def info(self, request): response = request.response self.info_cache(response.headers) self.origin(request) return Json({'websocket': request.config['WEBSOCKET_AVAILABLE'], 'origins': ['*:*'], 'entropy': randint(0, sys.maxsize)} ).http_response(request) @route('iframe[0-9-.a-z_]*.html', re=True, response_content_types=('text/html',)) def iframe(self, request): response = request.response url = request.absolute_uri(self.full_route.path) response.content = IFRAME_TEXT % url hsh = hashlib.md5(response.content[0]).hexdigest() value = request.get('HTTP_IF_NONE_MATCH') if value and value.find(hsh) != -1: raise HttpException(status=304) self.home_cache(response.headers) response['Etag'] = hsh return response def origin(self, request): """Handles request authentication""" response = request.response origin = request.get('HTTP_ORIGIN', '*') # Respond with '*' to 'null' origin if origin == 'null': origin = '*' response['Access-Control-Allow-Origin'] = origin headers = request.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') if headers: response['Access-Control-Allow-Headers'] = headers response['Access-Control-Allow-Credentials'] = 'true'
class MediaRouter(Router, MediaMixin): '''A :class:`Router` for serving static media files from a given directory. :param rute: The top-level url for this router. For example ``/media`` will serve the ``/media/<path:path>`` :class:`Route`. :param path: Check the :attr:`path` attribute. :param show_indexes: Check the :attr:`show_indexes` attribute. .. attribute:: path The file-system path of the media files to serve. .. attribute:: show_indexes If ``True``, the router will serve media file directories as well as media files. .. attribute:: default_file The default file to serve when a directory is requested. ''' cache_control = CacheControl(maxage=86400) def __init__(self, rule, path, show_indexes=False, default_suffix=None, default_file='index.html', raise_404=True, **params): super().__init__('%s/<path:path>' % rule, **params) self._default_suffix = default_suffix self._default_file = default_file self._show_indexes = show_indexes self._file_path = path self._raise_404 = raise_404 def filesystem_path(self, request): path = request.urlargs['path'] bits = [bit for bit in path.split('/') if bit] return os.path.join(self._file_path, *bits) def get(self, request): fullpath = self.filesystem_path(request) if os.path.isdir(fullpath) and self._default_file: file = os.path.join(fullpath, self._default_file) if os.path.isfile(file): if not request.path.endswith('/'): return request.redirect('%s/' % request.path) fullpath = file # if os.path.isdir(fullpath): if self._show_indexes: return self.directory_index(request, fullpath) else: raise Http404 # filename = os.path.basename(fullpath) if '.' not in filename and self._default_suffix: fullpath = '%s.%s' % (fullpath, self._default_suffix) # if os.path.isfile(fullpath): return self.serve_file(request, fullpath) elif self._raise_404: raise Http404
from datetime import datetime from pulsar import Http404 from pulsar.utils.httpurl import CacheControl CACHE_TIME = 31536000 nocache = CacheControl(nostore=True) cache = CacheControl(maxage=CACHE_TIME) APPJSON = 'application/json' PRELUDE = 'h' * 2048 + '\n' class Transport(object): access_methods = 'OPTIONS, POST' __slots__ = ['handshake', 'handle'] def __init__(self, request, handle=None): self.handshake = request self.handle = handle @property def response(self): return self.request.response @property def protocol(self): return self.request.connection._current_consumer def write(self, msg): raise NotImplementedError
class MediaMixin(Router): response_content_types = RouterParam( ('application/octet-stream', 'text/css')) cache_control = CacheControl(maxage=86400) _file_path = '' def serve_file(self, request, fullpath): # Respect the If-Modified-Since header. statobj = os.stat(fullpath) content_type, encoding = mimetypes.guess_type(fullpath) response = request.response if content_type: response.content_type = content_type response.encoding = encoding if not self.was_modified_since( request.environ.get('HTTP_IF_MODIFIED_SINCE'), statobj[stat.ST_MTIME], statobj[stat.ST_SIZE]): response.status_code = 304 else: response.content = open(fullpath, 'rb').read() response.headers["Last-Modified"] = http_date( statobj[stat.ST_MTIME]) return response def was_modified_since(self, header=None, mtime=0, size=0): '''Check if an item was modified since the user last downloaded it :param header: the value of the ``If-Modified-Since`` header. If this is None, simply return ``True``. :param mtime: the modification time of the item in question. :param size: the size of the item. ''' try: if header is None: raise ValueError matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header, re.IGNORECASE) header_mtime = mktime_tz(parsedate_tz(matches.group(1))) header_len = matches.group(3) if header_len and int(header_len) != size: raise ValueError() if mtime > header_mtime: raise ValueError() except (AttributeError, ValueError, OverflowError): return True return False def directory_index(self, request, fullpath): names = [Html('a', '../', href='../', cn='folder')] files = [] for f in sorted(os.listdir(fullpath)): if not f.startswith('.'): if os.path.isdir(os.path.join(fullpath, f)): names.append(Html('a', f, href=f + '/', cn='folder')) else: files.append(Html('a', f, href=f)) names.extend(files) return self.static_index(request, names) def html_title(self, request): return 'Index of %s' % request.path def static_index(self, request, links): title = Html('h2', self.html_title(request)) list = Html('ul', *[Html('li', a) for a in links]) body = Html('div', title, list) doc = request.html_document(title=title, body=body) return doc.http_response(request)