[#4988] gracefully handle attachments that are partial images
diff --git a/Allura/allura/model/attachments.py b/Allura/allura/model/attachments.py
index 99d43ab..d0869c9 100644
--- a/Allura/allura/model/attachments.py
+++ b/Allura/allura/model/attachments.py
@@ -56,8 +56,9 @@
original_meta=original_meta)
if orig is not None:
return orig, thumbnail
-
- # No, generic attachment
- return cls.from_stream(
- filename, fp, content_type=content_type,
- **original_meta)
+ else:
+ # No, generic attachment
+ fp.seek(0) # stream may have been partially consumed in a failed save_image attempt
+ return cls.from_stream(
+ filename, fp, content_type=content_type,
+ **original_meta)
diff --git a/Allura/allura/model/filesystem.py b/Allura/allura/model/filesystem.py
index e98aea1..36269e4 100644
--- a/Allura/allura/model/filesystem.py
+++ b/Allura/allura/model/filesystem.py
@@ -161,10 +161,15 @@
original = cls(
filename=filename, content_type=content_type, **original_meta)
with original.wfile() as fp_w:
- if 'transparency' in image.info:
- image.save(fp_w, format, transparency=image.info['transparency'])
- else:
- image.save(fp_w, format)
+ try:
+ if 'transparency' in image.info:
+ image.save(fp_w, format, transparency=image.info['transparency'])
+ else:
+ image.save(fp_w, format)
+ except Exception as e:
+ session(original).expunge(original)
+ log.error('Error saving image %s %s', filename, e)
+ return None, None
else:
original = None
diff --git a/Allura/allura/tests/model/test_filesystem.py b/Allura/allura/tests/model/test_filesystem.py
index ca988bc..7ab99b5 100644
--- a/Allura/allura/tests/model/test_filesystem.py
+++ b/Allura/allura/tests/model/test_filesystem.py
@@ -2,10 +2,12 @@
import os
from unittest import TestCase
from cStringIO import StringIO
+from io import BytesIO
from pylons import response
+from pylons import tmpl_context as c
from ming.orm import session, Mapper
-
+from nose.tools import assert_equal
from allura import model as M
from alluratest.controller import setup_unit_test
@@ -150,6 +152,17 @@
assert f == None
assert t == None
+ def test_partial_image_as_attachment(self):
+ path = os.path.join(os.path.dirname(__file__), '..', 'data', 'user.png')
+ fp = BytesIO(open(path, 'rb').read(500))
+ c.app.config._id = None
+ attachment = M.BaseAttachment.save_attachment('user.png', fp,
+ save_original=True)
+ assert type(attachment) != tuple # tuple is for (img, thumb) pairs
+ assert_equal(attachment.length, 500)
+ assert_equal(attachment.filename, 'user.png')
+
+
def _assert_content(self, f, content):
result = f.rfile().read()
assert result == content, result