@@ -7,7 +7,7 @@ defmodule Mint.WebSocket.Frame do
77 shared = [ { :reserved , << 0 :: size ( 3 ) >> } , :mask , :data ]
88
99 import Record
10- alias Mint.WebSocket . { Utils , Frame.Fragment }
10+ alias Mint.WebSocket.Utils
1111
1212 defrecord :continuation , shared ++ [ :fin? ]
1313 defrecord :text , shared ++ [ :fin? ]
@@ -125,11 +125,11 @@ defmodule Mint.WebSocket.Frame do
125125 def decode ( websocket , data ) do
126126 case websocket . buffer |> Utils . maybe_concat ( data ) |> decode_raw ( websocket , [ ] ) do
127127 { :ok , frames } ->
128- { websocket , frames } = Fragment . resolve ( websocket , frames )
128+ { websocket , frames } = resolve_fragments ( websocket , frames )
129129 { :ok , put_in ( websocket . buffer , << >> ) , frames }
130130
131131 { :buffer , partial , frames } ->
132- { websocket , frames } = Fragment . resolve ( websocket , frames )
132+ { websocket , frames } = resolve_fragments ( websocket , frames )
133133 { :ok , put_in ( websocket . buffer , partial ) , frames }
134134 end
135135 catch
@@ -355,4 +355,46 @@ defmodule Mint.WebSocket.Frame do
355355 unquote ( type ) ( frame , data: frame_data <> continuation_data , fin?: fin? )
356356 end
357357 end
358+
359+ @ doc """
360+ Emits frames for any finalized fragments and stores any unfinalized fragments
361+ in the `:fragments` key in the websocket
362+ """
363+ def resolve_fragments ( websocket , frames , acc \\ [ ] )
364+
365+ def resolve_fragments ( websocket , [ ] , acc ) do
366+ { websocket , :lists . reverse ( acc ) }
367+ end
368+
369+ def resolve_fragments ( websocket , [ frame | rest ] , acc ) when is_control ( frame ) do
370+ resolve_fragments ( websocket , rest , [ translate ( frame ) | acc ] )
371+ end
372+
373+ def resolve_fragments ( websocket , [ frame | rest ] , acc ) when is_fin ( frame ) do
374+ frame = combine_frames ( [ frame | websocket . fragments ] )
375+
376+ put_in ( websocket . fragments , [ ] )
377+ |> resolve_fragments ( rest , [ frame | acc ] )
378+ end
379+
380+ def resolve_fragments ( websocket , [ frame | rest ] , acc ) do
381+ update_in ( websocket . fragments , & [ frame | & 1 ] )
382+ |> resolve_fragments ( rest , acc )
383+ end
384+
385+ defp combine_frames ( [ continuation ( ) ] ) do
386+ throw ( { :mint , :uninitiated_continuation } )
387+ end
388+
389+ defp combine_frames ( [ full_frame ] ) do
390+ translate ( full_frame )
391+ end
392+
393+ defp combine_frames ( [ continuation ( ) = continuation , prior_fragment | rest ] ) do
394+ combine_frames ( [ combine ( prior_fragment , continuation ) | rest ] )
395+ end
396+
397+ defp combine_frames ( _out_of_order_fragments ) do
398+ throw ( { :mint , :out_of_order_fragments } )
399+ end
358400end
0 commit comments