diff options
| author | Chris McDonough <chrism@plope.com> | 2011-09-06 21:11:42 -0400 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2011-09-06 21:11:42 -0400 |
| commit | 1455baef486d063432d326ff8fc0f37509813179 (patch) | |
| tree | 3cf49cf99723d076af04ff00deb7db9d8e634150 | |
| parent | a829814915b7bfa25e3a70c11ed6fd96da465b4e (diff) | |
| download | pyramid-1455baef486d063432d326ff8fc0f37509813179.tar.gz pyramid-1455baef486d063432d326ff8fc0f37509813179.tar.bz2 pyramid-1455baef486d063432d326ff8fc0f37509813179.zip | |
introduce a _FileIter
| -rw-r--r-- | TODO.txt | 11 | ||||
| -rw-r--r-- | pyramid/static.py | 40 |
2 files changed, 38 insertions, 13 deletions
@@ -83,13 +83,12 @@ Future - 1.3: - Eliminate non-deployment-non-scaffold-related Paste dependency: ``paste.urlparser.StaticURLParser`` (cutnpaste or reimplement, possibly - using chrisrossi's happy stuff as a base). Still need: + using chrisrossi's happy stuff as a base). - handling file permission exceptions (FileApp.get). - - Features we won't support: ETAG and if-none-match support (DataApp.get); - replace with if-modified-since handling, ``wsgi.file_wrapper`` support - (FileApp.get). + Features we no longer support: ETAG and if-none-match support + (DataApp.get); replace with if-modified-since handling, + ``wsgi.file_wrapper`` support (FileApp.get), returning 403 when handling + file permission exceptions (FileApp.get). - 1.3: use zope.registry rather than zope.component. diff --git a/pyramid/static.py b/pyramid/static.py index 5d1bfbcfa..357fe8014 100644 --- a/pyramid/static.py +++ b/pyramid/static.py @@ -24,22 +24,48 @@ def init_mimetypes(mimetypes): # has been applied on the Python 2 trunk). init_mimetypes(mimetypes) -class FileResponse(Response): +class _FileResponse(Response): """ Serves a static filelike object. """ def __init__(self, path, cache_max_age): - super(FileResponse, self).__init__(conditional_response=True) + super(_FileResponse, self).__init__(conditional_response=True) self.last_modified = getmtime(path) - self.app_iter = open(path, 'rb') content_type = mimetypes.guess_type(path, strict=False)[0] if content_type is None: content_type = 'application/octet-stream' self.content_type = content_type - self.content_length = getsize(path) + content_length = getsize(path) + self.app_iter = _FileIter(open(path, 'rb'), content_length) + # assignment of content_length must come after assignment of app_iter + self.content_length = content_length if cache_max_age is not None: self.cache_expires = cache_max_age +class _FileIter(object): + block_size = 4096 * 64 # (256K) + + def __init__(self, file, size=None): + self.file = file + self.size = size + + def __iter__(self): + return self + + def next(self): + chunk_size = self.block_size + if self.size is not None: + if chunk_size > self.size: + chunk_size = self.size + self.size -= chunk_size + data = self.file.read(chunk_size) + if not data: + raise StopIteration + return data + + def close(self): + self.file.close() + class static_view(object): """ An instance of this class is a callable which can act as a :app:`Pyramid` :term:`view callable`; this view will serve @@ -104,7 +130,7 @@ class static_view(object): else: path_tuple = traversal_path(request.path_info) - path = secure_path(path_tuple) + path = _secure_path(path_tuple) if path is None: # belt-and-suspenders security; this should never be true @@ -134,7 +160,7 @@ class static_view(object): if not exists(filepath): return HTTPNotFound(request.url) - return FileResponse(filepath ,self.cache_max_age) + return _FileResponse(filepath ,self.cache_max_age) def add_slash_redirect(self, request): url = request.path_url + '/' @@ -144,7 +170,7 @@ class static_view(object): return HTTPMovedPermanently(url) @lru_cache(1000) -def secure_path(path_tuple): +def _secure_path(path_tuple): if '' in path_tuple: return None for item in path_tuple: |
