def testBuildRequest_DecodeError(self): """Test building a request generating a decode error.""" expected_request = Request1() self.protocol.decode_message(Request1, 'my body').AndRaise( messages.DecodeError('xyz')) self.mox.ReplayAll() mapper = service_handlers.RPCMapper(['POST'], 'my-content-type', self.protocol) self.assertRaisesWithRegexpMatch( service_handlers.RequestError, 'Unable to parse request content: xyz', mapper.build_request, self.handler, Request1)
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. """ if isinstance(field, messages.BytesField): try: return base64.urlsafe_b64decode(value) except TypeError, err: raise messages.DecodeError('Base64 decoding error: %s' % err)
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. """ if isinstance(field, messages.BytesField): try: padded_value = self.__pad_value(str(value), 4, '=') return base64.urlsafe_b64decode(padded_value) except (TypeError, UnicodeEncodeError) as err: raise messages.DecodeError('Base64 decoding error: %s' % err) return super(EndpointsProtoJson, self).decode_field(field, value)
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)
def build_request(handler, request): raise messages.DecodeError('This is a decode error')
def add_parameter(self, parameter, values): """Add a single parameter. Adds a single parameter and its value to the request message. Args: parameter: Query string parameter to map to request. values: List of values to assign to request message. Returns: True if parameter was valid and added to the message, else False. Raises: DecodeError if the parameter refers to a valid field, and the values parameter does not have one and only one value. Non-valid query parameters may have multiple values and should not cause an error. """ path = self.make_path(parameter) if not path: return False # Must check that all indexes of all items in the path are correct before # instantiating any of them. For example, consider: # # class Repeated(object): # ... # # class Inner(object): # # repeated = messages.MessageField(Repeated, 1, repeated=True) # # class Outer(object): # # inner = messages.MessageField(Inner, 1) # # instance = Outer() # builder = URLEncodedRequestBuilder(instance) # builder.add_parameter('inner.repeated') # # assert not hasattr(instance, 'inner') # # The check is done relative to the instance of Outer pass in to the # constructor of the builder. This instance is not referred to at all # because all names are assumed to be relative to it. # # The 'repeated' part of the path is not correct because it is missing an # index. Because it is missing an index, it should not create an instance # of Repeated. In this case add_parameter will return False and have no # side effects. # # A correct path that would cause a new Inner instance to be inserted at # instance.inner and a new Repeated instance to be appended to the # instance.inner.repeated list would be 'inner.repeated-0'. if not self.__check_indexes(path): return False # Ok to build objects. parent_path = path[:-1] parent = self.__get_or_create_path(parent_path) name, index = path[-1] field = parent.field_by_name(name) if len(values) != 1: raise messages.DecodeError( 'Found repeated values for field %s.' % field.name) value = values[0] if isinstance(field, messages.IntegerField): converted_value = int(value) elif isinstance(field, messages.MessageField): # Just make sure it's instantiated. Assignment to field or # appending to list is done in __get_or_create_path. self.__get_or_create_path(path) return True elif isinstance(field, messages.StringField): converted_value = value.decode('utf-8') elif isinstance(field, messages.BooleanField): converted_value = value.lower() == 'true' and True or False else: converted_value = field.type(value) if field.repeated: value_list = getattr(parent, field.name, None) if value_list is None: setattr(parent, field.name, [converted_value]) else: if index == len(value_list): value_list.append(converted_value) else: # Index should never be above len(value_list) because it was # verified during the index check above. value_list[index] = converted_value else: setattr(parent, field.name, converted_value) return True
def decode_message(message_type, encoded_message): """Decode protocol buffer to Message instance. Args: message_type: Message type to decode data to. encoded_message: Encoded version of message as string. Returns: Decoded instance of message_type. Raises: DecodeError if an error occurs during decoding, such as incompatible wire format for a field. messages.ValidationError if merged message is not initialized. """ message = message_type() message_array = array.array('B') message_array.fromstring(encoded_message) try: decoder = _Decoder(message_array, 0, len(message_array)) while decoder.avail() > 0: # Decode tag and variant information. encoded_tag = decoder.getVarInt32() tag = encoded_tag >> _WIRE_TYPE_BITS wire_type = encoded_tag & _WIRE_TYPE_MASK try: found_wire_type_decoder = _WIRE_TYPE_TO_DECODER_MAP[wire_type] except: raise messages.DecodeError('No such wire type %d' % wire_type) if tag < 1: raise messages.DecodeError('Invalid tag value %d' % tag) try: field = message.field_by_number(tag) except KeyError: # Unexpected tags are ok, just ignored unless below 0. field = None wire_type_decoder = found_wire_type_decoder else: expected_wire_type = _VARIANT_TO_WIRE_TYPE[field.variant] if expected_wire_type != wire_type: raise messages.DecodeError('Expected wire type %s but found %s' % ( _WIRE_TYPE_NAME[expected_wire_type], _WIRE_TYPE_NAME[wire_type])) wire_type_decoder = _VARIANT_TO_DECODER_MAP[field.variant] value = wire_type_decoder(decoder) # Skip additional processing if unknown field. if not field: continue # Special case Enum and Message types. if isinstance(field, messages.EnumField): value = field.type(value) elif isinstance(field, messages.MessageField): nested_message = decode_message(field.type, value) value = nested_message # Merge value in to message. if field.repeated: values = getattr(message, field.name) if values is None: setattr(message, field.name, [value]) else: values.append(value) else: setattr(message, field.name, value) except ProtocolBuffer.ProtocolBufferDecodeError, err: raise messages.DecodeError('Decoding error: %s' % str(err))