[python-bugzilla/f18] Don't upload scrambled attachments (bz #915318)
Cole Robinson
crobinso at fedoraproject.org
Mon Mar 4 21:07:43 UTC 2013
commit 843f8f31732d5505ab90b82e6c0669e940f70389
Author: Cole Robinson <crobinso at redhat.com>
Date: Mon Mar 4 16:07:40 2013 -0500
Don't upload scrambled attachments (bz #915318)
...loading-attachments-as-base64-and-test-it.patch | 205 ++++++++++++++++++++
python-bugzilla.spec | 11 +-
2 files changed, 215 insertions(+), 1 deletions(-)
---
diff --git a/0001-Fix-uploading-attachments-as-base64-and-test-it.patch b/0001-Fix-uploading-attachments-as-base64-and-test-it.patch
new file mode 100644
index 0000000..3f83c09
--- /dev/null
+++ b/0001-Fix-uploading-attachments-as-base64-and-test-it.patch
@@ -0,0 +1,205 @@
+From 23b5b373ec18974bde6ce4dba006e81b8af1169f Mon Sep 17 00:00:00 2001
+Message-Id: <23b5b373ec18974bde6ce4dba006e81b8af1169f.1362430417.git.crobinso at redhat.com>
+From: Cole Robinson <crobinso at redhat.com>
+Date: Tue, 26 Feb 2013 17:47:37 -0500
+Subject: [PATCH] Fix uploading attachments as base64, and test it
+
+Use xmlrpclib's base64 support, rather than a hand rolled one.
+---
+ bugzilla/base.py | 47 +++++++++++++----------------------------
+ tests/rw_functional.py | 57 +++++++++++++++++++++++++-------------------------
+ 2 files changed, 43 insertions(+), 61 deletions(-)
+
+diff --git a/bugzilla/base.py b/bugzilla/base.py
+index 60480dc..faddd0a 100644
+--- a/bugzilla/base.py
++++ b/bugzilla/base.py
+@@ -9,7 +9,6 @@
+ # option) any later version. See http://www.gnu.org/copyleft/gpl.html for
+ # the full text of the license.
+
+-import base64
+ import cookielib
+ import os
+ import tempfile
+@@ -834,14 +833,22 @@ class BugzillaBase(object):
+ # Methods for working with attachments #
+ ########################################
+
++ def _attachment_uri(self, attachid):
++ '''Returns the URI for the given attachment ID.'''
++ att_uri = self.url.replace('xmlrpc.cgi', 'attachment.cgi')
++ att_uri = att_uri + '?id=%s' % attachid
++ return att_uri
++
+ def attachfile(self, idlist, attachfile, description, **kwargs):
+ '''
+ Attach a file to the given bug IDs. Returns the ID of the attachment
+ or raises xmlrpclib.Fault if something goes wrong.
++
+ attachfile may be a filename (which will be opened) or a file-like
+ object, which must provide a 'read' method. If it's not one of these,
+ this method will raise a TypeError.
+ description is the short description of this attachment.
++
+ Optional keyword args are as follows:
+ file_name: this will be used as the filename for the attachment.
+ REQUIRED if attachfile is a file-like object with no
+@@ -851,9 +858,9 @@ class BugzillaBase(object):
+ is_private: Set to True if the attachment should be marked private.
+ is_patch: Set to True if the attachment is a patch.
+ content_type: The mime-type of the attached file. Defaults to
+- application/octet-stream if not set. NOTE that text
+- files will *not* be viewable in bugzilla unless you
+- remember to set this to text/plain. So remember that!
++ application/octet-stream if not set. NOTE that text
++ files will *not* be viewable in bugzilla unless you
++ remember to set this to text/plain. So remember that!
+
+ Returns the list of attachment ids that were added. If only one
+ attachment was added, we return the single int ID for back compat
+@@ -876,15 +883,14 @@ class BugzillaBase(object):
+ kwargs["file_name"] = kwargs.pop("filename")
+
+ kwargs['summary'] = description
++ kwargs['data'] = xmlrpclib.Binary(f.read())
++ kwargs['ids'] = self._listify(idlist)
++
+ if 'file_name' not in kwargs:
+ kwargs['file_name'] = os.path.basename(f.name)
+-
+ if 'content_type' not in kwargs:
+ kwargs['content_type'] = 'application/octet-stream'
+
+- kwargs['data'] = self._attachment_encode(f)
+- kwargs['ids'] = self._listify(idlist)
+-
+ ret = self._proxy.Bug.add_attachment(kwargs)
+
+ if "attachments" in ret:
+@@ -916,31 +922,6 @@ class BugzillaBase(object):
+ # Hooray, now we have a file-like object with .read() and .name
+ return att
+
+- def _attachment_uri(self, attachid):
+- '''Returns the URI for the given attachment ID.'''
+- att_uri = self.url.replace('xmlrpc.cgi', 'attachment.cgi')
+- att_uri = att_uri + '?id=%s' % attachid
+- return att_uri
+-
+- def _attachment_encode(self, fh):
+- '''Return the contents of the file-like object fh in a form
+- appropriate for attaching to a bug in bugzilla. This is the default
+- encoding method, base64.'''
+- # Read data in chunks so we don't end up with two copies of the file
+- # in RAM.
+-
+- # base64 encoding wants input in multiples of 3
+- chunksize = 3072
+- data = ''
+- chunk = fh.read(chunksize)
+- while chunk:
+- # we could use chunk.encode('base64') but that throws a newline
+- # at the end of every output chunk, which increases the size of
+- # the output.
+- data = data + base64.b64encode(chunk)
+- chunk = fh.read(chunksize)
+- return data
+-
+ def updateattachmentflags(self, bugid, attachid, flagname, **kwargs):
+ '''
+ Updates a flag for the given attachment ID.
+diff --git a/tests/rw_functional.py b/tests/rw_functional.py
+index 1b8997d..82e444f 100644
+--- a/tests/rw_functional.py
++++ b/tests/rw_functional.py
+@@ -357,43 +357,16 @@ class RHPartnerTest(BaseTest):
+ os.chdir("..")
+ os.system("rm -r %s" % tmpdir)
+
+-
+ def _test8Attachments(self):
+ """
+ Get and set attachments for a bug
+ """
+ bz = self.bzclass(url=self.url, cookiefile=cf)
+- getbugid = "663674"
++ getallbugid = "663674"
+ setbugid = "461686"
+- attachid = "469147"
+ cmd = "bugzilla attach "
+ testfile = "../tests/data/bz-attach-get1.txt"
+
+- # Get first attachment
+- out = tests.clicomm(cmd + "--get %s" % attachid, bz).splitlines()
+-
+- # Expect format:
+- # Wrote <filename>
+- fname = out[2].split()[1].strip()
+-
+- self.assertEquals(len(out), 3)
+- self.assertEquals(fname, "bugzilla-filename.patch")
+- self.assertEquals(file(fname).read(),
+- file(testfile).read())
+-
+- # Get all attachments
+- getbug = bz.getbug(getbugid)
+- numattach = len(getbug.attachments)
+- out = tests.clicomm(cmd + "--getall %s" % getbugid, bz).splitlines()
+-
+- self.assertEquals(len(out), numattach + 2)
+- fnames = [l.split(" ", 1)[1].strip() for l in out[2:]]
+- self.assertEquals(len(fnames), numattach)
+- for f in fnames:
+- if not os.path.exists(f):
+- raise AssertionError("filename '%s' not found" % f)
+- os.unlink(f)
+-
+ # Add attachment as CLI option
+ setbug = bz.getbug(setbugid)
+ orignumattach = len(setbug.attachments)
+@@ -418,6 +391,7 @@ class RHPartnerTest(BaseTest):
+ self.assertEquals(setbug.attachments[-1]["description"], desc2)
+ self.assertEquals(setbug.attachments[-1]["id"],
+ int(out2.splitlines()[2].split()[2]))
++ attachid = setbug.attachments[-2]["id"]
+
+ # Set attachment flags
+ self.assertEquals(setbug.attachments[-1]["flags"], [])
+@@ -435,6 +409,33 @@ class RHPartnerTest(BaseTest):
+ self.assertEquals(setbug.attachments[-1]["flags"], [])
+
+
++ # Get attachment, verify content
++ out = tests.clicomm(cmd + "--get %s" % attachid, bz).splitlines()
++
++ # Expect format:
++ # Wrote <filename>
++ fname = out[2].split()[1].strip()
++
++ self.assertEquals(len(out), 3)
++ self.assertEquals(fname, "bz-attach-get1.txt")
++ self.assertEquals(file(fname).read(),
++ file(testfile).read())
++ os.unlink(fname)
++
++ # Get all attachments
++ getbug = bz.getbug(getallbugid)
++ numattach = len(getbug.attachments)
++ out = tests.clicomm(cmd + "--getall %s" % getallbugid, bz).splitlines()
++
++ self.assertEquals(len(out), numattach + 2)
++ fnames = [l.split(" ", 1)[1].strip() for l in out[2:]]
++ self.assertEquals(len(fnames), numattach)
++ for f in fnames:
++ if not os.path.exists(f):
++ raise AssertionError("filename '%s' not found" % f)
++ os.unlink(f)
++
++
+ def test9Whiteboards(self):
+ bz = self.bzclass(url=self.url, cookiefile=cf)
+ bug_id = "663674"
+--
+1.8.1.4
+
diff --git a/python-bugzilla.spec b/python-bugzilla.spec
index deb4455..d1b1654 100644
--- a/python-bugzilla.spec
+++ b/python-bugzilla.spec
@@ -2,7 +2,7 @@
Name: python-bugzilla
Version: 0.8.0
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: A python library for interacting with Bugzilla
Group: Development/Languages
@@ -10,6 +10,9 @@ License: GPLv2+
URL: https://fedorahosted.org/python-bugzilla
Source0: https://fedorahosted.org/releases/p/y/%{name}/%{name}-%{version}.tar.gz
+# Don't upload scrambled attachments (bz #915318)
+Patch0001: 0001-Fix-uploading-attachments-as-base64-and-test-it.patch
+
BuildArch: noarch
BuildRequires: python-devel
@@ -27,6 +30,9 @@ for interacting with bugzilla from shell scripts.
%prep
%setup -q
+# Don't upload scrambled attachments (bz #915318)
+%patch0001 -p1
+
%build
%{__python} setup.py build
@@ -45,6 +51,9 @@ for interacting with bugzilla from shell scripts.
%changelog
+* Mon Mar 04 2013 Cole Robinson <crobinso at redhat.com> - 0.8.0-2
+- Don't upload scrambled attachments (bz #915318)
+
* Fri Feb 15 2013 Cole Robinson <crobinso at redhat.com> - 0.8.0-1
- Rebased to version 0.8.0
- Drop most usage of non-upstream RH Bugzilla API
More information about the scm-commits
mailing list