2 %% Licensed to the Apache Software Foundation (ASF) under one
3 %% or more contributor license agreements. See the NOTICE file
4 %% distributed with this work for additional information
5 %% regarding copyright ownership. The ASF licenses this file
6 %% to you under the Apache License, Version 2.0 (the
7 %% "License"); you may not use this file except in compliance
8 %% with the License. You may obtain a copy of the License at
10 %% http://www.apache.org/licenses/LICENSE-2.0
12 %% Unless required by applicable law or agreed to in writing,
13 %% software distributed under the License is distributed on an
14 %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 %% KIND, either express or implied. See the License for the
16 %% specific language governing permissions and limitations
20 -module(thrift_framed_transport).
22 -behaviour(thrift_transport).
27 -export([read/2, read_exact/2, write/2, flush/1, close/1]).
36 -type state() :: #t_framed{}.
39 -spec new(Transport::thrift_transport:t_transport()) ->
40 thrift_transport:t_transport().
48 thrift_transport:new(?MODULE, State).
51 -include("thrift_transport_behaviour.hrl").
54 read(State = #t_framed{wrapped = Wrapped, read_buffer = Buffer}, Len)
55 when is_integer(Len), Len >= 0 ->
56 Binary = iolist_to_binary(Buffer),
59 case next_frame(Wrapped) of
60 {NewState, {ok, Frame}} ->
61 NewBinary = iolist_to_binary([Binary, Frame]),
62 Give = min(iolist_size(NewBinary), Len),
63 {Result, Remaining} = split_binary(NewBinary, Give),
64 {State#t_framed{wrapped = NewState, read_buffer = Remaining}, {ok, Result}};
66 {State#t_framed{wrapped = NewState}, Error}
69 <<>> -> {State, {ok, <<>>}};
70 %% read buffer is nonempty
72 Give = min(iolist_size(Binary), Len),
73 {Result, Remaining} = split_binary(Binary, Give),
74 {State#t_framed{read_buffer = Remaining}, {ok, Result}}
78 read_exact(State = #t_framed{wrapped = Wrapped, read_buffer = Buffer}, Len)
79 when is_integer(Len), Len >= 0 ->
80 Binary = iolist_to_binary(Buffer),
81 case iolist_size(Binary) of
82 %% read buffer is larger than requested read size
84 {Result, Remaining} = split_binary(Binary, Len),
85 {State#t_framed{read_buffer = Remaining}, {ok, Result}};
86 %% read buffer is insufficient for requested read size
88 case next_frame(Wrapped) of
89 {NewState, {ok, Frame}} ->
91 State#t_framed{wrapped = NewState, read_buffer = [Buffer, Frame]},
95 {State#t_framed{wrapped = NewState}, Error}
99 next_frame(Transport) ->
100 case thrift_transport:read_exact(Transport, 4) of
101 {NewState, {ok, <<FrameLength:32/integer-signed-big>>}} ->
102 thrift_transport:read_exact(NewState, FrameLength);
107 write(State = #t_framed{write_buffer = Buffer}, Data) ->
108 {State#t_framed{write_buffer = [Buffer, Data]}, ok}.
111 flush(State = #t_framed{write_buffer = Buffer, wrapped = Wrapped}) ->
112 case iolist_size(Buffer) of
113 %% if write buffer is empty, do nothing
116 Data = [<<FrameLen:32/integer-signed-big>>, Buffer],
117 {Written, Response} = thrift_transport:write(Wrapped, Data),
118 {Flushed, ok} = thrift_transport:flush(Written),
119 {State#t_framed{wrapped = Flushed, write_buffer = []}, Response}
123 close(State = #t_framed{wrapped = Wrapped}) ->
124 {Closed, Result} = thrift_transport:close(Wrapped),
125 {State#t_framed{wrapped = Closed}, Result}.