module Network.HPACK.HeaderBlock.From (
fromHeaderBlock
, decodeStep
) where
import Control.Applicative ((<$>))
import Network.HPACK.Builder
import Network.HPACK.Context
import Network.HPACK.HeaderBlock.HeaderField
import Network.HPACK.Table
type Ctx = (Context, Builder Header)
type Step = Ctx -> HeaderField -> IO Ctx
fromHeaderBlock :: Context
-> HeaderBlock
-> IO (Context, HeaderSet)
fromHeaderBlock !ctx rs = decodeLoop rs (ctx,empty)
decodeLoop :: HeaderBlock -> Ctx -> IO (Context, HeaderSet)
decodeLoop (r:rs) !ctx = decodeStep ctx r >>= decodeLoop rs
decodeLoop [] !ctx = decodeFinal ctx
decodeStep :: Step
decodeStep (!ctx,!builder) Clear = return (clearRefSets ctx,builder)
decodeStep (!ctx,!builder) (ChangeTableSize siz) = do
ctx' <- changeContextForDecoding ctx siz
return (ctx',builder)
decodeStep (!ctx,!builder) (Indexed idx)
| isPresent = return (removeRef ctx idx, builder)
| otherwise = do
w <- whichTable idx ctx
case w of
(InStaticTable, e) -> do
c <- newEntryForDecoding ctx e
let b = builder << fromEntry e
return (c,b)
(InHeaderTable, e) -> do
let c = pushRef ctx idx
b = builder << fromEntry e
return (c,b)
where
isPresent = idx `isPresentIn` ctx
decodeStep (!ctx,!builder) (Literal NotAdd naming v) = do
k <- fromNaming naming ctx
let b = builder << (k,v)
return (ctx, b)
decodeStep (!ctx,!builder) (Literal Never naming v) = do
k <- fromNaming naming ctx
let b = builder << (k,v)
return (ctx, b)
decodeStep (!ctx,!builder) (Literal Add naming v) = do
k <- fromNaming naming ctx
let h = (k,v)
e = toEntry (k,v)
b = builder << h
c <- newEntryForDecoding ctx e
return (c,b)
decodeFinal :: Ctx -> IO (Context, HeaderSet)
decodeFinal (!ctx, !builder) = do
(hs,!ctx') <- emitNotEmittedForDecoding ctx
let hs' = run builder ++ hs
return (ctx', hs')
fromNaming :: Naming -> Context -> IO HeaderName
fromNaming (Lit k) _ = return k
fromNaming (Idx idx) ctx = entryHeaderName <$> getEntry idx ctx