Index: third_party/google-endpoints/endpoints/protojson.py |
diff --git a/third_party/google-endpoints/endpoints/protojson.py b/third_party/google-endpoints/endpoints/protojson.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3a8b635ea64172b264f27fe9f1b4bd89e297d875 |
--- /dev/null |
+++ b/third_party/google-endpoints/endpoints/protojson.py |
@@ -0,0 +1,106 @@ |
+# Copyright 2016 Google Inc. All Rights Reserved. |
+# |
+# Licensed under the Apache License, Version 2.0 (the "License"); |
+# you may not use this file except in compliance with the License. |
+# You may obtain a copy of the License at |
+# |
+# http://www.apache.org/licenses/LICENSE-2.0 |
+# |
+# Unless required by applicable law or agreed to in writing, software |
+# distributed under the License is distributed on an "AS IS" BASIS, |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+# See the License for the specific language governing permissions and |
+# limitations under the License. |
+ |
+"""Endpoints-specific implementation of ProtoRPC's ProtoJson class.""" |
+ |
+import base64 |
+ |
+from protorpc import messages |
+from protorpc import protojson |
+ |
+# pylint: disable=g-bad-name |
+ |
+ |
+__all__ = ['EndpointsProtoJson'] |
+ |
+ |
+class EndpointsProtoJson(protojson.ProtoJson): |
+ """Endpoints-specific implementation of ProtoRPC's ProtoJson class. |
+ |
+ We need to adjust the way some types of data are encoded to ensure they're |
+ consistent with the existing API pipeline. This class adjusts the JSON |
+ encoding as needed. |
+ |
+ This may be used in a multithreaded environment, so take care to ensure |
+ that this class (and its parent, protojson.ProtoJson) remain thread-safe. |
+ """ |
+ |
+ def encode_field(self, field, value): |
+ """Encode a python field value to a JSON value. |
+ |
+ Args: |
+ field: A ProtoRPC field instance. |
+ value: A python value supported by field. |
+ |
+ Returns: |
+ A JSON serializable value appropriate for field. |
+ """ |
+ # Override the handling of 64-bit integers, so they're always encoded |
+ # as strings. |
+ if (isinstance(field, messages.IntegerField) and |
+ field.variant in (messages.Variant.INT64, |
+ messages.Variant.UINT64, |
+ messages.Variant.SINT64)): |
+ if value not in (None, [], ()): |
+ # Convert and replace the value. |
+ if isinstance(value, list): |
+ value = [str(subvalue) for subvalue in value] |
+ else: |
+ value = str(value) |
+ return value |
+ |
+ return super(EndpointsProtoJson, self).encode_field(field, value) |
+ |
+ @staticmethod |
+ def __pad_value(value, pad_len_multiple, pad_char): |
+ """Add padding characters to the value if needed. |
+ |
+ Args: |
+ value: The string value to be padded. |
+ pad_len_multiple: Pad the result so its length is a multiple |
+ of pad_len_multiple. |
+ pad_char: The character to use for padding. |
+ |
+ Returns: |
+ The string value with padding characters added. |
+ """ |
+ assert pad_len_multiple > 0 |
+ assert len(pad_char) == 1 |
+ padding_length = (pad_len_multiple - |
+ (len(value) % pad_len_multiple)) % pad_len_multiple |
+ return value + pad_char * padding_length |
+ |
+ def decode_field(self, field, value): |
+ """Decode a JSON value to a python value. |
+ |
+ Args: |
+ field: A ProtoRPC field instance. |
+ value: A serialized JSON value. |
+ |
+ Returns: |
+ A Python value compatible with field. |
+ """ |
+ # Override BytesField handling. Client libraries typically use a url-safe |
+ # encoding. b64decode doesn't handle these gracefully. urlsafe_b64decode |
+ # handles both cases safely. Also add padding if the padding is incorrect. |
+ if isinstance(field, messages.BytesField): |
+ try: |
+ # Need to call str(value) because ProtoRPC likes to pass values |
+ # as unicode, and urlsafe_b64decode can only handle bytes. |
+ padded_value = self.__pad_value(str(value), 4, '=') |
+ return base64.urlsafe_b64decode(padded_value) |
+ except (TypeError, UnicodeEncodeError), err: |
+ raise messages.DecodeError('Base64 decoding error: %s' % err) |
+ |
+ return super(EndpointsProtoJson, self).decode_field(field, value) |