On Thu, Sep 16, 2010 at 09:14:28PM +0200, Jelmer Vernooij wrote:
> Package: python-debian
> Version: 0.1.17~bzr184~launchpad1
> Severity: normal
> 
> 
> The Changes() object (but probably other deb822-style objects as well)
> don't handle the situation very well when a field that contains empty
> lines is followed by another field:
> 
> #!/usr/bin/python
> from debian.deb822 import Changes
> x = Changes()
> x["Changes"] = """Foo
> 
> Bar
> """
> x["Format"] = "1.8"
> y = Changes(x.dump())
> print y["Format"]
> 
> It would be nice if an exception was raised instead of an invalid changes file
> being written.

I actually had a patch out for review about a year ago that would have
fixed this problem at __setitem__ time (it wouldn't have let you set
x["Changes"] to that value).  The patch was part of a cleanup series I
never got around to pushing...  I've reattached it here, but it probably
doesn't quite apply anymore.  I'll work on it over the weekend.

-- 
John Wright <[email protected]>
>From bf321ad6fbdd0541d3b972ab8ec090f4d54d50ef Mon Sep 17 00:00:00 2001
From: John Wright <[email protected]>
Date: Wed, 29 Jul 2009 15:17:27 +0200
Subject: [PATCH] deb822: Validate input in Deb822.__setitem__

Try to catch input that would result in multiple stanzas or unparseable
data when dumping the Deb822 object.

This patch also clarifies a comment related to this, and removes an XXX
comment that it addreses.
---
 debian_bundle/deb822.py |   35 ++++++++++++++++++++++++++++++++---
 1 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/debian_bundle/deb822.py b/debian_bundle/deb822.py
index dd1d201..ca35668 100644
--- a/debian_bundle/deb822.py
+++ b/debian_bundle/deb822.py
@@ -358,10 +358,12 @@ class Deb822(Deb822Dict):
         else:
             return_string = False
         for key, value in self.iteritems():
+            # We want one space between the "Field:" and value, unless
+            # value starts with a newline (i.e. the value itself started on
+            # the line *after* the field name in the control file), or is
+            # empty.  In that case, we avoid trailing whitespace by by not
+            # including a space after the colon.
             if not value or value[0] == '\n':
-                # Avoid trailing whitespace after "Field:" if it's on its own
-                # line or the value is empty
-                # XXX Uh, really print value if value == '\n'?
                 fd.write('%s:%s\n' % (key, value))
             else:
                 fd.write('%s: %s\n' % (key, value))
@@ -538,6 +540,33 @@ class Deb822(Deb822Dict):
 
         return self.gpg_info
 
+    def validate_input(self, key, value):
+        """Raise ValueError if value is not a valid value for key
+
+        Subclasses that do interesting things for different keys may wish to
+        override this method.
+        """
+
+        strvalue = str(value)
+
+        # The value cannot end in a newline (if it did, dumping the object
+        # would result in multiple stanzas)
+        if strvalue.endswith('\n'):
+            raise ValueError("value must not end in '\\n'")
+
+        # Make sure there are no blank lines (actually, the first one is
+        # allowed to be blank, but no others), and each subsequent line starts
+        # with whitespace
+        for line in strvalue.splitlines()[1:]:
+            if not line:
+                raise ValueError("value must not have blank lines")
+            if not line[0] in string.whitespace:
+                raise ValueError("each line must start with whitespace")
+
+    def __setitem__(self, key, value):
+        self.validate_input(key, value)
+        Deb822Dict.__setitem__(self, key, value)
+
 ###
 
 # XXX check what happens if input contains more that one signature
-- 
1.6.3.3

Reply via email to