OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 Google Inc. All Rights Reserved. |
| 2 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with the License. |
| 5 # You may obtain a copy of the License at |
| 6 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # |
| 9 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 # See the License for the specific language governing permissions and |
| 13 # limitations under the License. |
| 14 |
| 15 """Endpoints-specific implementation of ProtoRPC's ProtoJson class.""" |
| 16 |
| 17 import base64 |
| 18 |
| 19 from protorpc import messages |
| 20 from protorpc import protojson |
| 21 |
| 22 # pylint: disable=g-bad-name |
| 23 |
| 24 |
| 25 __all__ = ['EndpointsProtoJson'] |
| 26 |
| 27 |
| 28 class EndpointsProtoJson(protojson.ProtoJson): |
| 29 """Endpoints-specific implementation of ProtoRPC's ProtoJson class. |
| 30 |
| 31 We need to adjust the way some types of data are encoded to ensure they're |
| 32 consistent with the existing API pipeline. This class adjusts the JSON |
| 33 encoding as needed. |
| 34 |
| 35 This may be used in a multithreaded environment, so take care to ensure |
| 36 that this class (and its parent, protojson.ProtoJson) remain thread-safe. |
| 37 """ |
| 38 |
| 39 def encode_field(self, field, value): |
| 40 """Encode a python field value to a JSON value. |
| 41 |
| 42 Args: |
| 43 field: A ProtoRPC field instance. |
| 44 value: A python value supported by field. |
| 45 |
| 46 Returns: |
| 47 A JSON serializable value appropriate for field. |
| 48 """ |
| 49 # Override the handling of 64-bit integers, so they're always encoded |
| 50 # as strings. |
| 51 if (isinstance(field, messages.IntegerField) and |
| 52 field.variant in (messages.Variant.INT64, |
| 53 messages.Variant.UINT64, |
| 54 messages.Variant.SINT64)): |
| 55 if value not in (None, [], ()): |
| 56 # Convert and replace the value. |
| 57 if isinstance(value, list): |
| 58 value = [str(subvalue) for subvalue in value] |
| 59 else: |
| 60 value = str(value) |
| 61 return value |
| 62 |
| 63 return super(EndpointsProtoJson, self).encode_field(field, value) |
| 64 |
| 65 @staticmethod |
| 66 def __pad_value(value, pad_len_multiple, pad_char): |
| 67 """Add padding characters to the value if needed. |
| 68 |
| 69 Args: |
| 70 value: The string value to be padded. |
| 71 pad_len_multiple: Pad the result so its length is a multiple |
| 72 of pad_len_multiple. |
| 73 pad_char: The character to use for padding. |
| 74 |
| 75 Returns: |
| 76 The string value with padding characters added. |
| 77 """ |
| 78 assert pad_len_multiple > 0 |
| 79 assert len(pad_char) == 1 |
| 80 padding_length = (pad_len_multiple - |
| 81 (len(value) % pad_len_multiple)) % pad_len_multiple |
| 82 return value + pad_char * padding_length |
| 83 |
| 84 def decode_field(self, field, value): |
| 85 """Decode a JSON value to a python value. |
| 86 |
| 87 Args: |
| 88 field: A ProtoRPC field instance. |
| 89 value: A serialized JSON value. |
| 90 |
| 91 Returns: |
| 92 A Python value compatible with field. |
| 93 """ |
| 94 # Override BytesField handling. Client libraries typically use a url-safe |
| 95 # encoding. b64decode doesn't handle these gracefully. urlsafe_b64decode |
| 96 # handles both cases safely. Also add padding if the padding is incorrect. |
| 97 if isinstance(field, messages.BytesField): |
| 98 try: |
| 99 # Need to call str(value) because ProtoRPC likes to pass values |
| 100 # as unicode, and urlsafe_b64decode can only handle bytes. |
| 101 padded_value = self.__pad_value(str(value), 4, '=') |
| 102 return base64.urlsafe_b64decode(padded_value) |
| 103 except (TypeError, UnicodeEncodeError), err: |
| 104 raise messages.DecodeError('Base64 decoding error: %s' % err) |
| 105 |
| 106 return super(EndpointsProtoJson, self).decode_field(field, value) |
OLD | NEW |