Mercurial > piecrust2
comparison piecrust/serving.py @ 258:7ec06ec14247
serve: Use Etags and 304 responses for assets.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 22 Feb 2015 22:02:59 -0800 |
parents | da5e6e00fb41 |
children | 980bbbd0705e |
comparison
equal
deleted
inserted
replaced
257:e6ae65212c32 | 258:7ec06ec14247 |
---|---|
6 import time | 6 import time |
7 import queue | 7 import queue |
8 import os.path | 8 import os.path |
9 import hashlib | 9 import hashlib |
10 import logging | 10 import logging |
11 import datetime | |
11 import threading | 12 import threading |
12 from werkzeug.exceptions import ( | 13 from werkzeug.exceptions import ( |
13 NotFound, MethodNotAllowed, InternalServerError, HTTPException) | 14 NotFound, MethodNotAllowed, InternalServerError, HTTPException) |
14 from werkzeug.wrappers import Request, Response | 15 from werkzeug.wrappers import Request, Response |
15 from werkzeug.wsgi import ClosingIterator, wrap_file | 16 from werkzeug.wsgi import ClosingIterator, wrap_file |
167 os.path.dirname(__file__), | 168 os.path.dirname(__file__), |
168 'resources', 'server') | 169 'resources', 'server') |
169 full_path = os.path.join(mount, rel_req_path) | 170 full_path = os.path.join(mount, rel_req_path) |
170 try: | 171 try: |
171 response = self._make_wrapped_file_response( | 172 response = self._make_wrapped_file_response( |
172 environ, full_path) | 173 environ, request, full_path) |
173 return response | 174 return response |
174 except OSError: | 175 except OSError: |
175 pass | 176 pass |
176 | 177 |
177 debug_mount = '/__piecrust_debug/' | 178 debug_mount = '/__piecrust_debug/' |
200 else: | 201 else: |
201 full_path = os.path.join(self._out_dir, rel_req_path) | 202 full_path = os.path.join(self._out_dir, rel_req_path) |
202 | 203 |
203 try: | 204 try: |
204 response = self._make_wrapped_file_response( | 205 response = self._make_wrapped_file_response( |
205 environ, full_path) | 206 environ, request, full_path) |
206 return response | 207 return response |
207 except OSError: | 208 except OSError: |
208 pass | 209 pass |
209 return None | 210 return None |
210 | 211 |
214 | 215 |
215 full_path = os.path.join(app.root_dir, request.path[len('/_asset/'):]) | 216 full_path = os.path.join(app.root_dir, request.path[len('/_asset/'):]) |
216 if not os.path.isfile(full_path): | 217 if not os.path.isfile(full_path): |
217 return None | 218 return None |
218 | 219 |
219 return self._make_wrapped_file_response(environ, full_path) | 220 return self._make_wrapped_file_response(environ, request, full_path) |
220 | 221 |
221 def _try_serve_page(self, app, environ, request): | 222 def _try_serve_page(self, app, environ, request): |
222 # Try to find what matches the requested URL. | 223 # Try to find what matches the requested URL. |
223 req_path = request.path | 224 req_path = request.path |
224 page_num = 1 | 225 page_num = 1 |
350 "falling back to uncompressed.") | 351 "falling back to uncompressed.") |
351 response.set_data(rp_content) | 352 response.set_data(rp_content) |
352 | 353 |
353 return response | 354 return response |
354 | 355 |
355 def _make_wrapped_file_response(self, environ, path): | 356 def _make_wrapped_file_response(self, environ, request, path): |
356 logger.debug("Serving %s" % path) | 357 logger.debug("Serving %s" % path) |
358 | |
359 # Check if we can return a 304 status code. | |
360 mtime = os.path.getmtime(path) | |
361 etag_str = '%s$$%s' % (path, mtime) | |
362 etag = hashlib.md5(etag_str.encode('utf8')).hexdigest() | |
363 if etag in request.if_none_match: | |
364 response = Response() | |
365 response.status_code = 304 | |
366 return response | |
367 | |
357 wrapper = wrap_file(environ, open(path, 'rb')) | 368 wrapper = wrap_file(environ, open(path, 'rb')) |
358 response = Response(wrapper) | 369 response = Response(wrapper) |
359 _, ext = os.path.splitext(path) | 370 _, ext = os.path.splitext(path) |
371 response.set_etag(etag) | |
372 response.last_modified = datetime.datetime.fromtimestamp(mtime) | |
360 response.mimetype = self._mimetype_map.get( | 373 response.mimetype = self._mimetype_map.get( |
361 ext.lstrip('.'), 'text/plain') | 374 ext.lstrip('.'), 'text/plain') |
362 return response | 375 return response |
363 | 376 |
364 def _handle_error(self, exception, environ, start_response): | 377 def _handle_error(self, exception, environ, start_response): |