[Note: same patch as earlier but rebased]
Traverse the objects passed to JSON for encoding and decoding.
When binary data is seen during encode replace the binary
data with a dict {'__base64__' : base64_encoding_of_binary_value}.
On decode if a dict is seen whose single key is '__base64__' replace
that dict with the base64 decoded value of the key's value.
--
John Dennis
Looking to carve out IT costs?
www.redhat.com/carveoutcosts/
>From d3627d87ff2b26b380a4a4d0a349ad2d432c1ca3 Mon Sep 17 00:00:00 2001
From: John Dennis
Date: Mon, 1 Mar 2010 18:55:39 -0500
Subject: [PATCH] Fix JSON binary encode and decode errors
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="1.6.6.1"
This is a multi-part message in MIME format.
--1.6.6.1
Content-Type: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding: 8bit
Traverse the objects passed to JSON for encoding and decoding.
When binary data is seen during encode replace the binary
data with a dict {'__base64__' : base64_encoding_of_binary_value}.
On decode if a dict is seen whose single key is '__base64__' replace
that dict with the base64 decoded value of the key's value.
---
ipaserver/rpcserver.py | 101 +++-
1 files changed, 99 insertions(+), 2 deletions(-)
--1.6.6.1
Content-Type: text/x-patch; name="0003-Fix-JSON-binary-encode-and-decode-errors.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="0003-Fix-JSON-binary-encode-and-decode-errors.patch"
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index ad402cd..967ee33 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -33,7 +33,7 @@ from ipalib.rpc import xml_dumps, xml_loads
from ipalib.util import make_repr
from ipalib.compat import json
from wsgiref.util import shift_path_info
-
+import base64
_not_found_template = """
@@ -60,7 +60,6 @@ def not_found(environ, start_response):
)
return [output]
-
def read_input(environ):
"""
Read the request body from environ['wsgi.input'].
@@ -300,6 +299,102 @@ class xmlserver(WSGIExecutioner):
return xml_dumps(response, methodresponse=True)
+def json_encode_binary(val):
+'''
+ JSON cannot encode binary values. We encode binary values in Python str
+ objects and text in Python unicode objects. In order to allow a binary
+ object to be passed through JSON we base64 encode it thus converting it to
+ text which JSON can transport. To assure we recognize the value is a base64
+ encoded representation of the original binary value and not confuse it with
+ other text we convert the binary value to a dict in this form:
+
+ {'__base64__' : base64_encoding_of_binary_value}
+
+ This modification of the original input value cannot be done "in place" as
+ one might first assume (e.g. replacing any binary items in a container
+ (e.g. list, tuple, dict) with the base64 dict because the container might be
+ an immutable object (i.e. a tuple). Therefore this function returns a copy
+ of any container objects it encounters with tuples replaced by lists. This
+ is O.K. because the JSON encoding will map both lists and tuples to JSON
+ arrays.
+ '''
+
+if isinstance(val, dict):
+new_dict = {}
+for k,v in val.items():
+if isinstance(v, str):
+new_dict[k] = {'__base64__' : base64.b64encode(v)}
+else:
+new_dict[k] = json_encode_binary(v)
+del val
+return new_dict
+elif isinstance(val, (list, tuple)):
+new_list = []
+n = len(val)
+i = 0
+while i < n:
+v = val[i]
+if isinstance(v, str):
+new_list.append({'__base64__' : base64.b64encode(v)})
+else:
+new_list.append(json_encode_binary(v))
+i += 1
+del val
+return new_list
+elif isinstance(val, str):
+return {'__base64__' : base64.b64encode(val)}
+else:
+return val
+
+def json_decode_binary(val):
+'''
+JSON cannot transport binary data. In order to transport binary data we
+convert binary data to a form like this:
+
+ {'__base64__' : base64_encoding_of_binary_value}
+
+ see json_encode_binary()
+
+After JSON had decoded the JSON stream back into a Python object we must
+recursively scan the object looking for any dicts which might represent
+binary values and replace the dict containing the base64 encoding of the
+binary value with the decoded binary value. Unlike the encoding problem
+where the input might consist of immutable object, all JSON decoded
+container are mutable so the conversion could be done in place. However we
+don't modify objects in place because of side effects which may be
+dangerous. Thus we elect to spend a few more cycles