Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clone a new RendererHelper per request #1575

Merged
merged 4 commits into from
Mar 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ Bug Fixes
- Prevent "parameters to load are deprecated" ``DeprecationWarning``
from setuptools>=11.3. See https://github.com/Pylons/pyramid/pull/1541

- Avoiding sharing the ``IRenderer`` objects across threads when attached to
a view using the `renderer=` argument. These renderers were instantiated
at time of first render and shared between requests, causing potentially
subtle effects like `pyramid.reload_templates = true` failing to work
in `pyramid_mako`. See https://github.com/Pylons/pyramid/pull/1575
and https://github.com/Pylons/pyramid/issues/1268

- Avoiding timing attacks against CSRF tokens.
See https://github.com/Pylons/pyramid/pull/1574

Expand Down
3 changes: 2 additions & 1 deletion pyramid/config/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,6 @@ def rendered_view(self, view):

def _rendered_view(self, view, view_renderer):
def rendered_view(context, request):
renderer = view_renderer
result = view(context, request)
if result.__class__ is Response: # potential common case
response = result
Expand All @@ -367,6 +366,8 @@ def rendered_view(context, request):
name=renderer_name,
package=self.kw.get('package'),
registry = registry)
else:
renderer = view_renderer.clone()
if '__view__' in attrs:
view_inst = attrs.pop('__view__')
else:
Expand Down
3 changes: 3 additions & 0 deletions pyramid/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,9 @@ class IRendererInfo(Interface):
settings = Attribute('The deployment settings dictionary related '
'to the current application')

def clone():
""" Return a shallow copy that does not share any mutable state."""

class IRendererFactory(Interface):
def __call__(info):
""" Return an object that implements
Expand Down
16 changes: 16 additions & 0 deletions pyramid/tests/test_config/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2548,6 +2548,8 @@ def render_view(inself, req, resp, view_inst, ctx):
self.assertEqual(view_inst, view)
self.assertEqual(ctx, context)
return response
def clone(self):
return self
def view(request):
return 'OK'
deriver = self._makeOne(renderer=moo())
Expand Down Expand Up @@ -2585,6 +2587,8 @@ def render_view(inself, req, resp, view_inst, ctx):
self.assertEqual(view_inst, 'view')
self.assertEqual(ctx, context)
return response
def clone(self):
return self
def view(request):
return 'OK'
deriver = self._makeOne(renderer=moo())
Expand Down Expand Up @@ -3179,6 +3183,8 @@ def render_view(inself, req, resp, view_inst, ctx):
self.assertEqual(view_inst.__class__, View)
self.assertEqual(ctx, context)
return response
def clone(self):
return self
class View(object):
def __init__(self, context, request):
pass
Expand All @@ -3203,6 +3209,8 @@ def render_view(inself, req, resp, view_inst, ctx):
self.assertEqual(view_inst.__class__, View)
self.assertEqual(ctx, context)
return response
def clone(self):
return self
class View(object):
def __init__(self, request):
pass
Expand All @@ -3227,6 +3235,8 @@ def render_view(inself, req, resp, view_inst, ctx):
self.assertEqual(view_inst.__class__, View)
self.assertEqual(ctx, context)
return response
def clone(self):
return self
class View:
def __init__(self, context, request):
pass
Expand All @@ -3251,6 +3261,8 @@ def render_view(inself, req, resp, view_inst, ctx):
self.assertEqual(view_inst.__class__, View)
self.assertEqual(ctx, context)
return response
def clone(self):
return self
class View:
def __init__(self, request):
pass
Expand All @@ -3275,6 +3287,8 @@ def render_view(inself, req, resp, view_inst, ctx):
self.assertEqual(view_inst, view)
self.assertEqual(ctx, context)
return response
def clone(self):
return self
class View:
def index(self, context, request):
return {'a':'1'}
Expand All @@ -3297,6 +3311,8 @@ def render_view(inself, req, resp, view_inst, ctx):
self.assertEqual(view_inst, view)
self.assertEqual(ctx, context)
return response
def clone(self):
return self
class View:
def index(self, request):
return {'a':'1'}
Expand Down