Repository: wagtail/wagtail

Issue:
Error when serving images through the URL generator
I posted a comment on https://github.com/torchbox/wagtail/issues/983 but probably better to open a new issue. Looks like the same problem to me though.

Hi guys, I think I'm having the same problem but when serving images using the URL generator. It does work if I'm logged-in in the site (cache not working) but doesn't when I'm not (cache full on).

Cheers,
Jordi

Internal Server Error: /images/2dMQIUOPwS5DlZuprp_E_WFdfhw=/47/width-75/
Traceback (most recent call last):
  File "/var/www/buildability/venvs/buildability.co.nz/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 204, in get_response
    response = middleware_method(request, response)
  File "/var/www/buildability/venvs/buildability.co.nz/local/lib/python2.7/site-packages/django/middleware/cache.py", line 121, in process_response
    self.cache.set(cache_key, response, timeout)
  File "/var/www/buildability/venvs/buildability.co.nz/local/lib/python2.7/site-packages/redis_cache/cache.py", line 239, in set
    result = self._set(key, pickle.dumps(value), timeout, client, _add_only)
  File "/var/www/buildability/venvs/buildability.co.nz/lib/python2.7/copy_reg.py", line 70, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle instancemethod objects

Request repr(): 
<WSGIRequest
path:/images/2dMQIUOPwS5DlZuprp_E_WFdfhw=/47/width-75/,
GET:<QueryDict: {}>,
POST:<QueryDict: {}>,
COOKIES:{'_ga': 'GA1.3.1219121887.1434427204',
 'csrftoken': 'GNhfTEGBu40y8wRAFPa15lQTV66F9WCs'},
META:{'CONTENT_LENGTH': '',
 'CONTENT_TYPE': '',
 u'CSRF_COOKIE': u'GNhfTEGBu40y8wRAFPa15lQTV66F9WCs',
 'DOCUMENT_ROOT': '/usr/share/nginx/html',
 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,_/_;q=0.8',
 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, sdch',
 'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.8',
 'HTTP_CACHE_CONTROL': 'max-age=0',
 'HTTP_CONNECTION': 'keep-alive',
 'HTTP_COOKIE': '_ga=GA1.3.1219121887.1434427204; csrftoken=GNhfTEGBu40y8wRAFPa15lQTV66F9WCs',
 'HTTP_HOST': 'www.buildability.co.nz',
 'HTTP_UPGRADE_INSECURE_REQUESTS': '1',
 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.130 Safari/537.36',
 'PATH_INFO': u'/images/2dMQIUOPwS5DlZuprp_E_WFdfhw=/47/width-75/',
 'QUERY_STRING': '',
 'REMOTE_ADDR': '131.203.137.142',
 'REMOTE_PORT': '51455',
 'REQUEST_METHOD': 'GET',
 'REQUEST_URI': '/images/2dMQIUOPwS5DlZuprp_E_WFdfhw%3D/47/width-75/',
 u'SCRIPT_NAME': u'',
 'SERVER_NAME': 'www.buildability.co.nz',
 'SERVER_PORT': '80',
 'SERVER_PROTOCOL': 'HTTP/1.1',
 'UWSGI_SCHEME': 'http',
 'uwsgi.core': 7,
 'uwsgi.node': 'avinton',
 'uwsgi.version': '1.9.17.1-debian',
 'wsgi.errors': <open file 'wsgi_errors', mode 'w' at 0x7f0548a548a0>,
 'wsgi.file_wrapper': <built-in function uwsgi_sendfile>,
 'wsgi.input': <uwsgi._Input object at 0x7f0548a20a08>,
 'wsgi.multiprocess': True,
 'wsgi.multithread': True,
 'wsgi.run_once': False,
 'wsgi.url_scheme': 'http',
 'wsgi.version': (1, 0)}>



Discussion:
Oops I've realised I was using an old version, will try with 1.0 and post the results here.

Cheers

I can confirm it's happening with 1.0 and redis as cache backend:

```
[13/Aug/2015 22:37:18] ERROR [django.request:231] Internal Server Error: /images/eG6p_vHhTMhSV-fROD_AbEYPDXQ=/129/width-400/
Traceback (most recent call last):
  File "/var/www/madewithwagtail/venvs/madewithwagtail/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 204, in get_response
    response = middleware_method(request, response)
  File "/var/www/madewithwagtail/venvs/madewithwagtail/local/lib/python2.7/site-packages/django/middleware/cache.py", line 121, in process_response
    self.cache.set(cache_key, response, timeout)
  File "/var/www/madewithwagtail/venvs/madewithwagtail/local/lib/python2.7/site-packages/redis_cache/cache.py", line 239, in set
    result = self._set(key, pickle.dumps(value), timeout, client, _add_only)
  File "/var/www/madewithwagtail/venvs/madewithwagtail/lib/python2.7/copy_reg.py", line 70, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle instancemethod objects
```


Resolving patch:
diff --git a/wagtail/wagtailimages/views/frontend.py b/wagtail/wagtailimages/views/frontend.py
--- a/wagtail/wagtailimages/views/frontend.py
+++ b/wagtail/wagtailimages/views/frontend.py
@@ -2,7 +2,7 @@
 import imghdr
 
 from django.shortcuts import get_object_or_404
-from django.http import HttpResponse
+from django.http import HttpResponse, StreamingHttpResponse
 from django.core.exceptions import PermissionDenied
 
 from wagtail.wagtailimages.models import get_image_model
@@ -20,6 +20,6 @@ def serve(request, signature, image_id, filter_spec):
         rendition = image.get_rendition(filter_spec)
         rendition.file.open('rb')
         image_format = imghdr.what(rendition.file)
-        return HttpResponse(FileWrapper(rendition.file), content_type='image/' + image_format)
+        return StreamingHttpResponse(FileWrapper(rendition.file), content_type='image/' + image_format)
     except InvalidFilterSpecError:
         return HttpResponse("Invalid filter spec: " + filter_spec, content_type='text/plain', status=400)


Test patch:
diff --git a/wagtail/wagtailimages/tests/tests.py b/wagtail/wagtailimages/tests/tests.py
--- a/wagtail/wagtailimages/tests/tests.py
+++ b/wagtail/wagtailimages/tests/tests.py
@@ -182,6 +182,7 @@ def test_get(self):
 
         # Check response
         self.assertEqual(response.status_code, 200)
+        self.assertTrue(response.streaming)
         self.assertEqual(response['Content-Type'], 'image/png')
 
     def test_get_invalid_signature(self):
@@ -291,13 +292,20 @@ def test_admin_form_fields_attribute(self):
 
     def test_custom_image_model_without_admin_form_fields_raises_warning(self):
         self.reset_warning_registry()
-        with warnings.catch_warnings(record=True) as w:
+        with warnings.catch_warnings(record=True) as raw_warnings:
             form = get_image_form(CustomImageWithoutAdminFormFields)
 
             # Check that a RemovedInWagtail12Warning has been triggered
-            self.assertEqual(len(w), 1)
-            self.assertTrue(issubclass(w[-1].category, RemovedInWagtail12Warning))
-            self.assertTrue("Add admin_form_fields = (tuple of field names) to CustomImageWithoutAdminFormFields" in str(w[-1].message))
+
+            # Ignore any ResourceWarnings. TODO: remove this when we've stopped ResourceWarnings from happening...
+            try:
+                clean_warnings = [w for w in raw_warnings if not issubclass(w.category, ResourceWarning)]
+            except NameError:  # ResourceWarning only exists on Python >= 3.2
+                clean_warnings = raw_warnings
+
+            self.assertEqual(len(clean_warnings), 1)
+            self.assertTrue(issubclass(clean_warnings[-1].category, RemovedInWagtail12Warning))
+            self.assertTrue("Add admin_form_fields = (tuple of field names) to CustomImageWithoutAdminFormFields" in str(clean_warnings[-1].message))
 
         # All fields, including the not editable one should be on the form
         self.assertEqual(list(form.base_fields.keys()), [