[Checkins] SVN: hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/ split resource publisher from the delegator functionality "middleware"
Jan-Wijbrand Kolman
janwijbrand at gmail.com
Tue Nov 23 11:16:57 EST 2010
Log message for revision 118537:
split resource publisher from the delegator functionality "middleware"
Changed:
U hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/README.txt
U hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/__init__.py
U hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/core.py
U hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/publisher.py
-=-
Modified: hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/README.txt
===================================================================
--- hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/README.txt 2010-11-23 16:14:07 UTC (rev 118536)
+++ hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/README.txt 2010-11-23 16:16:56 UTC (rev 118537)
@@ -753,9 +753,9 @@
for instance)::
>>> print needed.render()
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
Let's set this a currently needed inclusions::
@@ -766,9 +766,9 @@
>>> from hurry import resource
>>> print resource.render()
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
Hashing resources
=================
@@ -786,12 +786,12 @@
To make browsers update their caches of resources immediately when the
resource changes, the absolute URLs of resources can now be made to contain a
hash of the resource's contents, so it will look like
-/foo/:hash:12345/myresource instead of /foo/myresource.
+/foo/fanstatic/:hash:12345/myresource instead of /foo/myresource.
>>> print resource.render()
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
More about the devmode in a minute::
@@ -871,9 +871,9 @@
>>> print needed.render_into_html(html)
<html><head>
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
something more</head></html>
The top-level convenience function does this for the currently needed
@@ -881,9 +881,9 @@
>>> print resource.render_into_html(html)
<html><head>
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
something more</head></html>
See below for a way to insert into HTML when bottom fragments are
@@ -904,9 +904,9 @@
>>> top, bottom = needed.render_topbottom()
>>> print top
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
>>> print bottom
<BLANKLINE>
@@ -921,9 +921,9 @@
>>> top, bottom = needed.render_topbottom()
>>> print top
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
>>> print bottom
<BLANKLINE>
@@ -933,10 +933,10 @@
>>> needed.bottom(force=True)
>>> top, bottom = needed.render_topbottom()
>>> print top
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
>>> print bottom
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
Let's now introduce a javascript resource that says it is safe to be
included on the bottom::
@@ -953,10 +953,10 @@
>>> top, bottom = needed.render_topbottom()
>>> print top
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/y2.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/y2.js"></script>
>>> print bottom
<BLANKLINE>
@@ -968,22 +968,22 @@
>>> top, bottom = needed.render_topbottom()
>>> print top
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
>>> print bottom
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/y2.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/y2.js"></script>
There's also a convenience function for the currently needed inclusion::
>>> request.needed = needed
>>> top, bottom = resource.render_topbottom()
>>> print top
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
>>> print bottom
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/y2.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/y2.js"></script>
When we force bottom rendering of Javascript, there is no effect of
making a resource bottom-safe: all ``.js`` resources will be rendered
@@ -992,11 +992,11 @@
>>> needed.bottom(force=True)
>>> top, bottom = needed.render_topbottom()
>>> print top
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
>>> print bottom
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/y2.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/y2.js"></script>
Note that if ``bottom`` is enabled, it makes no sense to have a
resource inclusion ``b`` that depends on a resource inclusion ``a``
@@ -1027,20 +1027,20 @@
>>> print needed.render_topbottom_into_html(html)
<html><head>
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- rest of head</head><body>rest of body<script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/y2.js"></script></body></html>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ rest of head</head><body>rest of body<script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/y2.js"></script></body></html>
There's also a function available to do this for the currently needed
resources::
>>> print resource.render_topbottom_into_html(html)
<html><head>
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- rest of head</head><body>rest of body<script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/y2.js"></script></body></html>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ rest of head</head><body>rest of body<script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/y2.js"></script></body></html>
Using WSGI middleware to insert into HTML
=========================================
@@ -1075,9 +1075,9 @@
>>> print res.body
<html><head>
- <link rel="stylesheet" type="text/css" href="http://localhost/static/:hash:.../foo/b.css" />
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/a.js"></script>
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/c.js"></script>
+ <link rel="stylesheet" type="text/css" href="http://localhost/static/fanstatic/:hash:.../foo/b.css" />
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/a.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/c.js"></script>
</head><body</body></html>
When we set the response Content-Type to non-HTML, the middleware
@@ -1111,7 +1111,7 @@
>>> c.base_url = 'http://localhost/static'
>>> top, bottom = c.render_topbottom()
>>> print top
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/l1.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/l1.js"></script>
>>> print bottom
<BLANKLINE>
@@ -1127,7 +1127,7 @@
>>> print top
<BLANKLINE>
>>> print bottom
- <script type="text/javascript" src="http://localhost/static/:hash:.../foo/l1.js"></script>
+ <script type="text/javascript" src="http://localhost/static/fanstatic/:hash:.../foo/l1.js"></script>
Generating resource code
========================
@@ -1250,7 +1250,7 @@
... return '<link rel="unknown" href="%s" />' % url
>>> inclusion_renderers['.unknown'] = render_unknown
>>> needed.render()
- '<link rel="unknown" href="http://localhost/static/:hash:.../foo/nothing.unknown" />'
+ '<link rel="unknown" href="http://localhost/static/fanstatic/:hash:.../foo/nothing.unknown" />'
Resource publisher
==================
@@ -1261,10 +1261,7 @@
>>> from hurry.resource.publisher import Publisher
>>> from paste.fixture import TestApp
>>> from paste.httpexceptions import HTTPNotFound
- >>> class NoFindNoResource(object):
- ... def __call__(self, environ, start_response):
- ... return HTTPNotFound()(environ, start_response)
- >>> app = TestApp(Publisher(NoFindNoResource()))
+ >>> app = TestApp(Publisher())
We don't do anything fancy if the resource can not be found, but raise 404.
@@ -1284,6 +1281,15 @@
>>> 'ETag' in headers
True
+ >>> res = app.get('/foo/style.css')
+ >>> print res.body
+ body {
+ color: #f00;
+ }
+ >>> headers = dict(res.headers)
+ >>> 'ETag' in headers
+ True
+
When we find the 'hash' marker in the requested URL, we send headers that let
the user agent cache the resources for a long time.
@@ -1294,7 +1300,7 @@
We don't set cache-control headers on non-successful responses::
- >>> res = app.get('/:hash:12345/foo/notfound.css', expect_errors=True)
+ >>> res = app.get('/fanstatic/:hash:12345/foo/notfound.css', expect_errors=True)
>>> headers = dict(res.headers)
>>> 'Expires' in headers
False
@@ -1303,13 +1309,13 @@
Hidden files and directories are not served:
- >>> res = app.get('/:hash:foo/sub/.svn/test', expect_errors=True)
+ >>> res = app.get('/fanstatic/:hash:foo/sub/.svn/test', expect_errors=True)
>>> print res.status
404
The publisher_signature can be found arbitrarily deep in the path_info:
- >>> res = app.get('/++skin++foo/++etc++bar/foo/:hash:12345/foo/style.css')
+ >>> res = app.get('/++skin++foo/++etc++bar/foo/fanstatic/:hash:12345/foo/style.css')
>>> res.status
200
>>> print res.body
Modified: hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/__init__.py
===================================================================
--- hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/__init__.py 2010-11-23 16:14:07 UTC (rev 118536)
+++ hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/__init__.py 2010-11-23 16:16:56 UTC (rev 118537)
@@ -15,7 +15,7 @@
from hurry.resource.core import (register_plugin,
get_current_needed_inclusions)
-publisher_signature = ':hash:'
+publisher_signature = 'fanstatic'
devmode = False
Modified: hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/core.py
===================================================================
--- hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/core.py 2010-11-23 16:14:07 UTC (rev 118536)
+++ hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/core.py 2010-11-23 16:16:56 UTC (rev 118537)
@@ -24,7 +24,8 @@
# before or (2) we are in development mode.
if self._signature is None or hurry.resource.devmode:
self._signature = hurry.resource.hash.checksum(self.path)
- return hurry.resource.publisher_signature + str(self._signature)
+ return '%s/:hash:%s' % (
+ hurry.resource.publisher_signature, str(self._signature))
# total hack to be able to get the dir the resources will be in
def caller_dir():
Modified: hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/publisher.py
===================================================================
--- hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/publisher.py 2010-11-23 16:14:07 UTC (rev 118536)
+++ hurry.resource/branches/janjaapdriessen-resource-publisher/src/hurry/resource/publisher.py 2010-11-23 16:16:56 UTC (rev 118537)
@@ -7,7 +7,6 @@
import hurry.resource
-
class FilterHiddenDirectoryApp(DirectoryApp):
def __call__(self, environ, start_response):
path_info = environ['PATH_INFO']
@@ -16,43 +15,60 @@
return HTTPNotFound()(environ, start_response)
return DirectoryApp.__call__(self, environ, start_response)
-
class Publisher(object):
- def __init__(self, app):
- self._wrapped_app = app
+ def __init__(self):
self.directory_apps = {}
for library in hurry.resource.libraries():
app = FilterHiddenDirectoryApp(library.path)
self.directory_apps[library.name] = app
def __call__(self, environ, start_response):
+ # Pop the hash, if it exists.
path_info = environ['PATH_INFO']
+ if path_info.startswith('/:hash:'):
+ path_info_pop(environ)
+ # Overwrite the start_response callable with one that will
+ # apply expiry headers for 20* responses.
+ _start_response = start_response
+ def start_response(status, headers, exc_info=None):
+ # Only set the cache control for succesful requests
+ # (200, 206).
+ if status.startswith('20'):
+ expires = CACHE_CONTROL.apply(
+ headers, max_age=10*CACHE_CONTROL.ONE_YEAR)
+ EXPIRES.update(headers, delta=expires)
+ return _start_response(status, headers, exc_info)
+
+ # Pop first name, being library name.
+ library_name = path_info_pop(environ)
+ directory_app = self.directory_apps.get(library_name)
+ if directory_app is None:
+ return HTTPNotFound()(environ, start_response)
+ return directory_app(environ, start_response)
- path_segments = [s for s in path_info.split('/') if s.strip() != '']
+class Delegator(object):
+
+ def __init__(self, app):
+ self.application = app
+ self.resource_publisher = Publisher()
- def hash_find(segment):
- return not segment.startswith(hurry.resource.publisher_signature)
+ def __call__(self, environ, start_response):
+ path_info = environ['PATH_INFO']
+ trigger = '/%s/' % hurry.resource.publisher_signature
+ chunks = path_info.split(trigger, 1)
+ if len(chunks) == 1:
+ # The trigger is not in the URL at all, we delegate to the
+ # original application.
+ return self.application(environ, start_response)
+ environ = environ.copy()
+ environ['PATH_INFO'] = '/%s' % chunks[1]
+ return self.resource_publisher(environ, start_response)
- new_path = list(dropwhile(hash_find, path_segments))
+def make_delegator(app, global_conf):
+ return Delegator(app)
- if len(new_path) == 0:
- # There's no hash signature found in the path, so we
- # cannot publish it from here. Leave the response to the
- # wrapped app.
- return self._wrapped_app(environ, start_response)
-
- try:
- hash = new_path.pop(0)
- library_name = new_path.pop(0)
- except IndexError:
- return HTTPNotFound()(environ, start_response)
-
- try:
- directory_app = self.directory_apps[library_name]
- except KeyError:
- return HTTPNotFound()(environ, start_response)
-
+"""
def cache_header_start_response(status, headers, exc_info=None):
# Only set the cache control for succesful requests (200, 206).
if status.startswith('20'):
@@ -60,10 +76,4 @@
headers, max_age=10*CACHE_CONTROL.ONE_YEAR)
EXPIRES.update(headers, delta=expires)
return start_response(status, headers, exc_info)
-
- # Reconstruct information for the directory_app to work with.
- environ['PATH_INFO'] = '/' + '/'.join(new_path)
- return directory_app(environ, cache_header_start_response)
-
-def make_publisher(app, global_conf):
- return Publisher(app)
+"""
More information about the checkins
mailing list