Erlang: add framed_transport and non-strict binary_protocol
- thrift_client now takes as its fourth parameter Options: framed, strict_{read,write}, connect_timeout (P.S. fourth param used to be Timeout)
- binary protocol now takes options: strict_{read,write}
- buffers in framed and buffered transport are now iolists and not reversed lists of binaries
- rename buffer in buffered transport "write_buffer" to match framed transport
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@666447 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/alterl/src/thrift_binary_protocol.erl b/lib/alterl/src/thrift_binary_protocol.erl
index f115b2f..da43d14 100644
--- a/lib/alterl/src/thrift_binary_protocol.erl
+++ b/lib/alterl/src/thrift_binary_protocol.erl
@@ -11,22 +11,37 @@
-include("thrift_constants.hrl").
-include("thrift_protocol.hrl").
--export([new/1,
+-export([new/1, new/2,
read/2,
write/2,
flush_transport/1,
close_transport/1
-]).
+ ]).
--record(binary_protocol, {transport}).
-
+-record(binary_protocol, {transport,
+ strict_read=true,
+ strict_write=true
+ }).
-define(VERSION_MASK, 16#FFFF0000).
-define(VERSION_1, 16#80010000).
-
+-define(TYPE_MASK, 16#000000ff).
new(Transport) ->
- thrift_protocol:new(?MODULE, #binary_protocol{transport = Transport}).
+ new(Transport, _Options = []).
+
+new(Transport, Options) ->
+ State = #binary_protocol{transport = Transport},
+ State1 = parse_options(Options, State),
+ thrift_protocol:new(?MODULE, State1).
+
+parse_options([], State) ->
+ State;
+parse_options([{strict_read, Bool} | Rest], State) when is_boolean(Bool) ->
+ parse_options(Rest, State#binary_protocol{strict_read=Bool});
+parse_options([{strict_write, Bool} | Rest], State) when is_boolean(Bool) ->
+ parse_options(Rest, State#binary_protocol{strict_write=Bool}).
+
flush_transport(#binary_protocol{transport = Transport}) ->
thrift_transport:flush(Transport).
@@ -42,9 +57,16 @@
name = Name,
type = Type,
seqid = Seqid}) ->
- write(This, {i32, ?VERSION_1 bor Type}),
- write(This, {string, Name}),
- write(This, {i32, Seqid}),
+ case This#binary_protocol.strict_write of
+ true ->
+ write(This, {i32, ?VERSION_1 bor Type}),
+ write(This, {string, Name}),
+ write(This, {i32, Seqid});
+ false ->
+ write(This, {string, Name}),
+ write(This, {byte, Type}),
+ write(This, {i32, Seqid})
+ end,
ok;
write(This, message_end) -> ok;
@@ -121,20 +143,40 @@
write(This, {i32, size(Bin)}),
write(This, Bin);
-write(This, Binary) when is_binary(Binary) ->
- thrift_transport:write(This#binary_protocol.transport, Binary).
+%% Data :: iolist()
+write(This, Data) ->
+ thrift_transport:write(This#binary_protocol.transport, Data).
%%
read(This, message_begin) ->
case read(This, i32) of
- {ok, Version} when Version band ?VERSION_MASK == ?VERSION_1 ->
- Type = Version band 16#000000ff,
+ {ok, Sz} when Sz band ?VERSION_MASK =:= ?VERSION_1 ->
+ %% we're at version 1
{ok, Name} = read(This, string),
+ Type = Sz band ?TYPE_MASK,
{ok, SeqId} = read(This, i32),
#protocol_message_begin{name = binary_to_list(Name),
type = Type,
seqid = SeqId};
+
+ {ok, Sz} when Sz < 0 ->
+ %% there's a version number but it's unexpected
+ {error, {bad_binary_protocol_version, Sz}};
+
+ {ok, Sz} when This#binary_protocol.strict_read =:= true ->
+ %% strict_read is true and there's no version header; that's an error
+ {error, no_binary_protocol_version};
+
+ {ok, Sz} when This#binary_protocol.strict_read =:= false ->
+ %% strict_read is false, so just read the old way
+ {ok, Name} = read(This, Sz),
+ {ok, Type} = read(This, byte),
+ {ok, SeqId} = read(This, i32),
+ #protocol_message_begin{name = binary_to_list(Name),
+ type = Type,
+ seqid = SeqId};
+
Err = {error, closed} -> Err;
Err = {error, ebadf} -> Err
end;