diff options
| author | Nick Mathewson <nickm@torproject.org> | 2008-10-14 21:07:57 +0000 | 
|---|---|---|
| committer | Nick Mathewson <nickm@torproject.org> | 2008-10-14 21:07:57 +0000 | 
| commit | 64f1d761b930aa6103229b3f78ed60dacbc1763d (patch) | |
| tree | 383e19b27b1f172ba75e784caae79abd834b72ca /lib | |
| parent | 8681c8b39fe4477f0647db79db83acfa19bc587a (diff) | |
Stop trying to monkeypatch simplejson to support canonical encoding, and just use our own internal canonical encoder when we want that.  It is actually less code this way.
git-svn-id: file:///home/or/svnrepo/updater/trunk@17104 55e972cd-5a19-0410-ae62-a4d7a52db4cd
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/thandy/formats.py | 109 | 
1 files changed, 51 insertions, 58 deletions
diff --git a/lib/thandy/formats.py b/lib/thandy/formats.py index c65d390..08d7a7f 100644 --- a/lib/thandy/formats.py +++ b/lib/thandy/formats.py @@ -153,59 +153,52 @@ def checkSignatures(signed, keyDB, role=None, path=None):      return SignatureStatus(goodSigs, badSigs, unknownSigs, tangentialSigs) -def _encodeCanonical_makeiter(obj): -    """Return an iterator to encode 'obj' canonically, and a nil -       cleanup function.  Works with newer versions of simplejson that -       have a _make_iterencode method. -    """ -    def default(o): -        raise TypeError("Can't encode %r", o) -    def floatstr(o): -        raise TypeError("Floats not allowed.") -    def canonical_str_encoder(s): -        return '"%s"' % re.sub(r'(["\\])', r'\\\1', s) - -    # XXX This is, alas, a hack.  I'll submit a canonical JSon patch to -    # the simplejson folks. -    iterator = simplejson.encoder._make_iterencode( -        None, default, canonical_str_encoder, None, floatstr, -        ":", ",", True, False, True)(obj, 0) - -    return iterator, lambda:None - -def _encodeCanonical_monkeypatch(obj): -    """Return an iterator to encode 'obj' canonically, and a cleanup -       function to un-monkeypatch simplejson.  Works with older -       versions of simplejson.  This is not threadsafe wrt other -       invocations of simplejson, so until we're all upgraded, no -       doing canonical encodings outside of the main thread. -    """ -    def default(o): -        raise TypeError("Can't encode %r", o) -    save_floatstr = simplejson.encoder.floatstr -    save_encode_basestring = simplejson.encoder.encode_basestring -    def floatstr(o): -        raise TypeError("Floats not allowed.") +def _encodeCanonical(obj, outf): +    # Helper for encodeCanonical.  Older versions of simplejson.encoder don't +    # even let us replace the separators. +      def canonical_str_encoder(s): -        return '"%s"' % re.sub(r'(["\\])', r'\\\1', s) -    simplejson.encoder.floatstr = floatstr -    simplejson.encoder.encode_basestring = canonical_str_encoder -    def unpatch(): -        simplejson.encoder.floatstr = save_floatstr -        simplejson.encoder.encode_basestring = save_encode_basestring - -    encoder = simplejson.encoder.JSONEncoder(ensure_ascii=False, -                                             check_circular=False, -                                             allow_nan=False, -                                             sort_keys=True, -                                             separators=(",",":"), -                                             default=default) -    return encoder.iterencode(obj), unpatch - -if hasattr(simplejson.encoder, "_make_iterencode"): -    _encodeCanonical = _encodeCanonical_makeiter -else: -    _encodeCanonical = _encodeCanonical_monkeypatch +        s = '"%s"' % re.sub(r'(["\\])', r'\\\1', s) +        if isinstance(s, unicode): +            return s.encode("utf-8") +        else: +            return s + +    if isinstance(obj, basestring): +        outf(canonical_str_encoder(obj)) +    elif obj is True: +        outf("true") +    elif obj is False: +            outf("false") +    elif obj is None: +        outf("null") +    elif isinstance(obj, (int,long)): +        outf(str(obj)) +    elif isinstance(obj, (tuple, list)): +        outf("[") +        if len(obj): +            for item in obj[:-1]: +                _encodeCanonical(item, outf) +                outf(",") +            _encodeCanonical(obj[-1], outf) +        outf("]") +    elif isinstance(obj, dict): +        outf("{") +        if len(obj): +            items = obj.items() +            items.sort() +            for k,v in items[:-1]: +                outf(canonical_str_encoder(k)) +                outf(":") +                _encodeCanonical(v, outf) +                outf(",") +            k, v = items[-1] +            outf(canonical_str_encoder(k)) +            outf(":") +            _encodeCanonical(v, outf) +        outf("}") +    else: +        raise thandy.FormatException("I can't encode %r"%obj)  def encodeCanonical(obj, outf=None):      """Encode the object obj in canoncial JSon form, as specified at @@ -220,6 +213,10 @@ def encodeCanonical(obj, outf=None):         '""'         >>> encodeCanonical([1, 2, 3])         '[1,2,3]' +       >>> encodeCanonical([]) +       '[]' +       >>> encodeCanonical({"A": [99]}) +       '{"A":[99]}'         >>> encodeCanonical({"x" : 3, "y" : 2})         '{"x":3,"y":2}'      """ @@ -229,16 +226,12 @@ def encodeCanonical(obj, outf=None):          result = [ ]          outf = result.append -    iterator, cleanup = _encodeCanonical(obj) +    _encodeCanonical(obj, outf) -    try: -        for u in iterator: -            outf(u.encode("utf-8")) -    finally: -        cleanup()      if result is not None:          return "".join(result) +  def getDigest(obj, digestObj=None):      """Update 'digestObj' (typically a SHA256 object) with the digest of         the canonical json encoding of obj.  If digestObj is none,  | 
