Skip to content

Commit

Permalink
Merge 7e77717 into b3ec59a
Browse files Browse the repository at this point in the history
  • Loading branch information
pguillory committed Dec 5, 2016
2 parents b3ec59a + 7e77717 commit 07b67b4
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 16 deletions.
81 changes: 65 additions & 16 deletions lib/thrift/generator/struct_binary_protocol.ex
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ defmodule Thrift.Generator.StructBinaryProtocol do
{acc, rest}
end
unquote_splicing(field_deserializers)
defp deserialize(_, _), do: :error
end
end

Expand Down Expand Up @@ -154,17 +155,25 @@ defmodule Thrift.Generator.StructBinaryProtocol do
def field_deserializer(:string, field, name, _file_group) do
quote do
defp unquote(name)(<<11, unquote(field.id)::16-signed, string_size::32-signed, rest::binary>>, acc) do
<<value::binary-size(string_size), rest::binary>> = rest
unquote(name)(rest, %{acc | unquote(field.name) => value})
case rest do
<<value::binary-size(string_size), rest::binary>> ->
unquote(name)(rest, %{acc | unquote(field.name) => value})
_ ->
:error
end
end
end
end
def field_deserializer(struct=%Struct{}, field, name, file_group) do
dest_module = FileGroup.dest_module(file_group, struct)
quote do
defp unquote(name)(<<12, unquote(field.id)::16-signed, rest::binary>>, acc) do
{value, rest} = unquote(dest_module).BinaryProtocol.deserialize(rest)
unquote(name)(rest, %{acc | unquote(field.name) => value})
case unquote(dest_module).BinaryProtocol.deserialize(rest) do
{value, rest} ->
unquote(name)(rest, %{acc | unquote(field.name) => value})
:error ->
:error
end
end
end
end
Expand All @@ -185,6 +194,8 @@ defmodule Thrift.Generator.StructBinaryProtocol do
end
unquote(map_key_deserializer(key_type, key_name, value_name, file_group))
unquote(map_value_deserializer(value_type, key_name, value_name, file_group))
defp unquote(key_name)(_, _), do: :error
defp unquote(value_name)(_, _, _), do: :error
end
end
def field_deserializer({:set, element_type}, field, name, file_group) do
Expand All @@ -197,6 +208,7 @@ defmodule Thrift.Generator.StructBinaryProtocol do
unquote(name)(rest, %{struct | unquote(field.name) => MapSet.new(Enum.reverse(list))})
end
unquote(list_deserializer(element_type, sub_name, file_group))
defp unquote(sub_name)(_, _), do: :error
end
end
def field_deserializer({:list, element_type}, field, name, file_group) do
Expand All @@ -209,6 +221,7 @@ defmodule Thrift.Generator.StructBinaryProtocol do
unquote(name)(rest, %{struct | unquote(field.name) => Enum.reverse(list)})
end
unquote(list_deserializer(element_type, sub_name, file_group))
defp unquote(sub_name)(_, _), do: :error
end
end
def field_deserializer(%StructRef{referenced_type: type}, field, name, file_group) do
Expand Down Expand Up @@ -271,17 +284,25 @@ defmodule Thrift.Generator.StructBinaryProtocol do
def map_key_deserializer(:string, key_name, value_name, _file_group) do
quote do
defp unquote(key_name)(<<string_size::32-signed, rest::binary>>, stack) do
<<key::binary-size(string_size), rest::binary>> = rest
unquote(value_name)(rest, key, stack)
case rest do
<<key::binary-size(string_size), rest::binary>> ->
unquote(value_name)(rest, key, stack)
_ ->
:error
end
end
end
end
def map_key_deserializer(struct=%Struct{}, key_name, value_name, file_group) do
dest_module = FileGroup.dest_module(file_group, struct)
quote do
defp unquote(key_name)(<<rest::binary>>, stack) do
{key, rest} = unquote(dest_module).BinaryProtocol.deserialize(rest)
unquote(value_name)(rest, key, stack)
case unquote(dest_module).BinaryProtocol.deserialize(rest) do
{key, rest} ->
unquote(value_name)(rest, key, stack)
:error ->
:error
end
end
end
end
Expand All @@ -297,6 +318,8 @@ defmodule Thrift.Generator.StructBinaryProtocol do
end
unquote(map_key_deserializer(key_type, child_key_name, child_value_name, file_group))
unquote(map_value_deserializer(value_type, child_key_name, child_value_name, file_group))
defp unquote(child_key_name)(_, _), do: :error
defp unquote(child_value_name)(_, _, _), do: :error
end
end
def map_key_deserializer({:set, element_type}, key_name, value_name, file_group) do
Expand All @@ -309,6 +332,7 @@ defmodule Thrift.Generator.StructBinaryProtocol do
unquote(value_name)(rest, MapSet.new(Enum.reverse(key)), stack)
end
unquote(list_deserializer(element_type, sub_name, file_group))
defp unquote(sub_name)(_, _), do: :error
end
end
def map_key_deserializer({:list, element_type}, key_name, value_name, file_group) do
Expand All @@ -321,6 +345,7 @@ defmodule Thrift.Generator.StructBinaryProtocol do
unquote(value_name)(rest, Enum.reverse(key), stack)
end
unquote(list_deserializer(element_type, sub_name, file_group))
defp unquote(sub_name)(_, _), do: :error
end
end
def map_key_deserializer(%StructRef{referenced_type: type}, key_name, value_name, file_group) do
Expand Down Expand Up @@ -383,17 +408,25 @@ defmodule Thrift.Generator.StructBinaryProtocol do
def map_value_deserializer(:string, key_name, value_name, _file_group) do
quote do
defp unquote(value_name)(<<string_size::32-signed, rest::binary>>, key, [map, remaining | stack]) do
<<value::binary-size(string_size), rest::binary>> = rest
unquote(key_name)(rest, [Map.put(map, key, value), remaining - 1 | stack])
case rest do
<<value::binary-size(string_size), rest::binary>> ->
unquote(key_name)(rest, [Map.put(map, key, value), remaining - 1 | stack])
_ ->
:error
end
end
end
end
def map_value_deserializer(struct=%Struct{}, key_name, value_name, file_group) do
dest_module = FileGroup.dest_module(file_group, struct)
quote do
defp unquote(value_name)(<<rest::binary>>, key, [map, remaining | stack]) do
{value, rest} = unquote(dest_module).BinaryProtocol.deserialize(rest)
unquote(key_name)(rest, [Map.put(map, key, value), remaining - 1 | stack])
case unquote(dest_module).BinaryProtocol.deserialize(rest) do
{value, rest} ->
unquote(key_name)(rest, [Map.put(map, key, value), remaining - 1 | stack])
:error ->
:error
end
end
end
end
Expand All @@ -409,6 +442,8 @@ defmodule Thrift.Generator.StructBinaryProtocol do
end
unquote(map_key_deserializer(key_type, child_key_name, child_value_name, file_group))
unquote(map_value_deserializer(value_type, child_key_name, child_value_name, file_group))
defp unquote(child_key_name)(_, _), do: :error
defp unquote(child_value_name)(_, _, _), do: :error
end
end
def map_value_deserializer({:set, element_type}, key_name, value_name, file_group) do
Expand All @@ -421,6 +456,7 @@ defmodule Thrift.Generator.StructBinaryProtocol do
unquote(key_name)(rest, [Map.put(map, key, MapSet.new(Enum.reverse(value))), remaining - 1 | stack])
end
unquote(list_deserializer(element_type, sub_name, file_group))
defp unquote(sub_name)(_, _), do: :error
end
end
def map_value_deserializer({:list, element_type}, key_name, value_name, file_group) do
Expand All @@ -433,6 +469,7 @@ defmodule Thrift.Generator.StructBinaryProtocol do
unquote(key_name)(rest, [Map.put(map, key, Enum.reverse(value)), remaining - 1 | stack])
end
unquote(list_deserializer(element_type, sub_name, file_group))
defp unquote(sub_name)(_, _), do: :error
end
end
def map_value_deserializer(%StructRef{referenced_type: type}, key_name, value_name, file_group) do
Expand Down Expand Up @@ -495,17 +532,25 @@ defmodule Thrift.Generator.StructBinaryProtocol do
def list_deserializer(:string, name, _file_group) do
quote do
defp unquote(name)(<<string_size::32-signed, rest::binary>>, [list, remaining | stack]) do
<<element::binary-size(string_size), rest::binary>> = rest
unquote(name)(rest, [[element | list], remaining - 1 | stack])
case rest do
<<element::binary-size(string_size), rest::binary>> ->
unquote(name)(rest, [[element | list], remaining - 1 | stack])
_ ->
:error
end
end
end
end
def list_deserializer(struct=%Struct{}, name, file_group) do
dest_module = FileGroup.dest_module(file_group, struct)
quote do
defp unquote(name)(<<rest::binary>>, [list, remaining | stack]) do
{element, rest} = unquote(dest_module).BinaryProtocol.deserialize(rest)
unquote(name)(rest, [[element | list], remaining - 1 | stack])
case unquote(dest_module).BinaryProtocol.deserialize(rest) do
{element, rest} ->
unquote(name)(rest, [[element | list], remaining - 1 | stack])
:error ->
:error
end
end
end
end
Expand All @@ -525,6 +570,8 @@ defmodule Thrift.Generator.StructBinaryProtocol do
end
unquote(map_key_deserializer(key_type, key_name, value_name, file_group))
unquote(map_value_deserializer(value_type, key_name, value_name, file_group))
defp unquote(key_name)(_, _), do: :error
defp unquote(value_name)(_, _, _), do: :error
end
end
def list_deserializer({:set, element_type}, name, file_group) do
Expand All @@ -537,6 +584,7 @@ defmodule Thrift.Generator.StructBinaryProtocol do
unquote(name)(rest, [[MapSet.new(Enum.reverse(inner_list)) | list], remaining - 1 | stack])
end
unquote(list_deserializer(element_type, sub_name, file_group))
defp unquote(sub_name)(_, _), do: :error
end
end
def list_deserializer({:list, element_type}, name, file_group) do
Expand All @@ -549,6 +597,7 @@ defmodule Thrift.Generator.StructBinaryProtocol do
unquote(name)(rest, [[Enum.reverse(inner_list) | list], remaining - 1 | stack])
end
unquote(list_deserializer(element_type, sub_name, file_group))
defp unquote(sub_name)(_, _), do: :error
end
end
def list_deserializer(%StructRef{referenced_type: type}, name, file_group) do
Expand Down
15 changes: 15 additions & 0 deletions test/generator/binary_protocol_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ defmodule Thrift.Generator.BinaryProtocolTest do
def assert_serializes(struct=%{__struct__: mod}, binary) do
assert binary == Binary.serialize(:struct, struct) |> IO.iodata_to_binary
assert {^struct, ""} = mod.deserialize(binary)

# If we randomly mutate any byte in the binary, it may deserialize to a
# struct of the proper type, or it may return :error. But it should never
# raise.
for i <- 1..byte_size(binary) do
mutated_binary = binary
|> :binary.bin_to_list
|> List.replace_at(i - 1, :rand.uniform(256) - 1)
|> :binary.list_to_bin

case mod.deserialize(mutated_binary) do
{%{__struct__: ^mod}, _} -> :ok
:error -> :ok
end
end
end

def assert_serializes(struct=%{__struct__: mod}, binary, deserialized_struct=%{__struct__: mod}) do
Expand Down

0 comments on commit 07b67b4

Please sign in to comment.