anchor.diff:     response,% active response
   
      iolen,   % expected length of data
  +   pckt,    % number of processed payload chunks
   
      opts,    % http protocol options
      buffer   % I/O buffer
  
positive.code: %%%
  %%%------------------------------------------------------------------ 
  'REQUESTED'({_Prot, _Peer, {recv, Chunk}}, #fsm{buffer=Buf}=S) ->
     'REQUESTED'(io, S#fsm{buffer = <<Buf/binary, Chunk/binary>>});
  
  'REQUESTED'(io, #fsm{buffer=Buf}=S) ->   
     % TODO: error handling policy
     % TODO: {ok, {http_error, ...}}
     case erlang:decode_packet(http_bin, Buf, []) of
        {more, _}       -> {next_state, 'REQUESTED', S, ?T_SERVER};
        {error, Reason} -> {error, Reason};
        {ok, Req, Chunk}-> 'REQUESTED'(Req, S#fsm{buffer=Chunk})
     end;
  
  'REQUESTED'({http_response, _Vsn, Code, Msg}, #fsm{request={{Method, _}, Uri}}=S) ->
     lager:debug("http ~p ~p ~p ~p", [Method, Uri, Code, Msg]), 
     'RESPONSE'(io, S#fsm{response={Code, []}}).
  
  %%%------------------------------------------------------------------
  %%%
  %%% RESPONSE: status line is received, waiting for headers
  %%%
  %%%------------------------------------------------------------------ 
  'RESPONSE'({_Prot, _Peer, {recv, Chunk}}, #fsm{buffer=Buf}=S) ->
     'RESPONSE'(io, S#fsm{buffer = <<Buf/binary, Chunk/binary>>});
  
  'RESPONSE'(io, #fsm{buffer=Buf}=S) -> 
     % TODO: error handling policy
     % TODO: {ok, {http_error, ...}}  
     case erlang:decode_packet(httph_bin, Buf, []) of
        {more, _}       -> {next_state, 'RESPONSE', S};
        {error, Reason} -> {error, Reason};
        {ok, Req, Rest} -> 'RESPONSE'(Req, S#fsm{buffer=Rest})
     end;
  
  'RESPONSE'({http_header, _I, 'Content-Length'=Head, _R, Val}, 
             #fsm{response={Code, Heads}}=S) ->
     Len = list_to_integer(binary_to_list(Val)),
     'RESPONSE'(io, S#fsm{response={Code, [{Head, Len} | Heads]}, iolen=Len});
  
  'RESPONSE'({http_header, _I, Head, _R, Val},
             #fsm{response={Code, Heads}}=S) ->
     'RESPONSE'(io, S#fsm{response={Code, [{Head, Val} | Heads]}});
  
  'RESPONSE'(http_eoh, #fsm{request={_, Uri}, response=Rsp, iolen=0}=S) ->
     % expected length of response is not known, stream it
     {send, 
        nil,               %% Reply
        {http, Uri, Rsp},  %% Next
        io,                %% Self
        'STREAM',
        S
     };
  
  'RESPONSE'(http_eoh, #fsm{request={_, Uri}, response=Rsp}=S) ->
     % exprected length of response is know, receive it
     {send,
        nil,               %% Reply
        {http, Uri, Rsp},  %% Next
        io,                %% Self 
        'RECV', 
        S
     }.
  
  
  %%%------------------------------------------------------------------
  %%%
  %%% RECV: receive response payload
  %%%
  %%%------------------------------------------------------------------ 
  'RECV'({_Prot, _Peer, {recv, Data}}, #fsm{buffer=Buf}=S) ->
     'RECV'(io, S#fsm{buffer = <<Buf/binary, Data/binary>>});
  
  'RECV'(io, #fsm{buffer = <<>>}=S) ->
     {next_state, 'RECV', S};
  'RECV'(io, #fsm{request={_, Uri}, response=Rsp, iolen=Len, buffer=Chunk}=S) ->
     case size(Chunk) of
        Size when Size >= Len ->
           <<Chnk:Len/binary, _/binary>> = Chunk,
           {emit, 
              [{http, Uri, {recv, Chnk}}, {http, Uri, eof}],
              'CONNECTED', 
              S#fsm{buffer= <<>>}
           };
        Size when Size < Len ->
           {emit, 
              {http, Uri, {recv, Chunk}},
              'RECV',
              S#fsm{
                 iolen = Len - size(Chunk), 
                 buffer= <<>>
              }
           }
     end.
  
  
  %%%------------------------------------------------------------------
  %%%
  %%% STREAM
  %%%
  %%%------------------------------------------------------------------ 
  'STREAM'({_Prot, _Peer, {recv, Data}}, #fsm{buffer=Buf}=S) ->
     'STREAM'(io, S#fsm{buffer = <<Buf/binary, Data/binary>>});
  
  'STREAM'(io, #fsm{buffer = <<>>}=S) ->
     {next_state, 'STREAM', S};
  'STREAM'(io, #fsm{request={_, Uri}, buffer=Buf}=S) ->
     case binary:split(Buf, <<"\r\n">>) of  
        [_]          -> 
           {next_state, 'STREAM', S};
        [Head, Data] -> 
           [L |_] = binary:split(Head, [<<" ">>, <<";">>]),
           Len    = list_to_integer(binary_to_list(L), 16),
           if
              Len =:= 0 ->
                 {emit, {http, Uri, eof}, 'CONNECTED', S};
              true      ->
                 'CHUNK'(io, S#fsm{iolen=Len, buffer=Data})
           end
     end.
  
  
  'CHUNK'({_Prot, _Peer, {recv, Data}}, #fsm{buffer=Buf}=S) ->
     'CHUNK'(io, S#fsm{buffer = <<Buf/binary, Data/binary>>});
  
  'CHUNK'(io, #fsm{buffer = <<>>}=S) ->
     {next_state, 'CHUNK', S};
  'CHUNK'(io, #fsm{request={_, Uri}, response=Rsp, iolen=Len, buffer=Chunk}=S) ->
     case size(Chunk) of
        Size when Size >= Len ->
           <<Chnk:Len/binary, $\r, $\n, Rest/binary>> = Chunk,
           {send,
              nil,                       %% Reply
              {http, Uri, {recv, Chnk}}, %% Next
              io,                        %% Self
              'STREAM',
              S#fsm{buffer = Rest}
           };
        Size when Size < Len ->
           {emit, 
              {http, Uri, {recv, Chunk}}, 
              'CHUNK', 
              S#fsm{
                 iolen=Len - size(Chunk), 
                 buffer= <<>>
              }
           }
     end.
   
  
  %%%------------------------------------------------------------------
  %%%
  