diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # Revision history for http3
 
+## 0.0.24
+
+* Supporting SSLKEYLOGFILE in h3-server and h3-client.
+* Sending SectionAcknowledgement only when reqInsCnt /= 0.
+
 ## 0.0.23
 
 * Enclosing IPv6 address in :authority
diff --git a/Network/HTTP3/Client.hs b/Network/HTTP3/Client.hs
--- a/Network/HTTP3/Client.hs
+++ b/Network/HTTP3/Client.hs
@@ -32,7 +32,6 @@
 import Imports
 import Network.HTTP3.Config
 import Network.HTTP3.Context
-import Network.HTTP3.Control
 import Network.HTTP3.Error
 import Network.HTTP3.Frame
 import Network.HTTP3.Recv
@@ -48,8 +47,6 @@
 -- | Running an HTTP\/3 client.
 run :: Connection -> ClientConfig -> Config -> Client a -> IO a
 run conn ClientConfig{..} conf client = withContext conn conf $ \ctx -> do
-    forkManaged ctx "H3 client: unidirectional setter" $
-        setupUnidirectional conn conf
     forkManaged ctx "H3 client: readerClient" $ readerClient ctx
     client (sendRequest ctx scheme authority) aux
   where
@@ -83,7 +80,8 @@
             sendBody ctx strm th outobj
             QUIC.shutdownStream strm
         src <- newSource strm
-        mvt <- recvHeader ctx src
+        let sid = QUIC.streamId strm
+        mvt <- recvHeader ctx sid src
         case mvt of
             Nothing -> do
                 QUIC.resetStream strm H3MessageError
@@ -93,7 +91,7 @@
             Just vt -> do
                 refI <- newIORef IInit
                 refH <- newIORef Nothing
-                let readB = recvBody ctx src refI refH
+                let readB = recvBody ctx sid src refI refH
                     rsp = Response $ InpObj vt Nothing readB refH
                 processResponse rsp
   where
diff --git a/Network/HTTP3/Context.hs b/Network/HTTP3/Context.hs
--- a/Network/HTTP3/Context.hs
+++ b/Network/HTTP3/Context.hs
@@ -60,9 +60,10 @@
 
 newContext :: Connection -> Config -> IO Context
 newContext conn conf = do
+    sendDI <- setupUnidirectional conn conf
     ctl <- controlStream conn <$> newIORef IInit
     (enc, handleDI) <- newQEncoder defaultQEncoderConfig
-    (dec, handleEI) <- newQDecoder defaultQDecoderConfig
+    (dec, handleEI) <- newQDecoder defaultQDecoderConfig sendDI
     info <- getConnectionInfo conn
     let handleDI' recv = handleDI recv `E.catch` abortWith QpackDecoderStreamError
         handleEI' recv = handleEI recv `E.catch` abortWith QpackEncoderStreamError
diff --git a/Network/HTTP3/Control.hs b/Network/HTTP3/Control.hs
--- a/Network/HTTP3/Control.hs
+++ b/Network/HTTP3/Control.hs
@@ -20,7 +20,8 @@
 mkType :: H3StreamType -> ByteString
 mkType = BS.singleton . fromIntegral . fromH3StreamType
 
-setupUnidirectional :: Connection -> H3.Config -> IO ()
+setupUnidirectional
+    :: Connection -> H3.Config -> IO (EncodedDecoderInstruction -> IO ())
 setupUnidirectional conn conf = do
     settings <-
         encodeH3Settings
@@ -40,6 +41,7 @@
     H3.onControlStreamCreated hooks sC
     H3.onEncoderStreamCreated hooks sE
     H3.onDecoderStreamCreated hooks sD
+    return $ sendStream sD
   where
     stC = mkType H3ControlStreams
     stE = mkType QPACKEncoderStream
diff --git a/Network/HTTP3/Recv.hs b/Network/HTTP3/Recv.hs
--- a/Network/HTTP3/Recv.hs
+++ b/Network/HTTP3/Recv.hs
@@ -45,8 +45,8 @@
 pushbackSource _ "" = return ()
 pushbackSource Source{..} bs = writeIORef sourcePending $ Just bs
 
-recvHeader :: Context -> Source -> IO (Maybe TokenHeaderTable)
-recvHeader ctx src = loop IInit
+recvHeader :: Context -> StreamId -> Source -> IO (Maybe TokenHeaderTable)
+recvHeader ctx sid src = loop IInit
   where
     loop st = do
         bs <- readSource src
@@ -56,7 +56,7 @@
                 IDone typ payload leftover
                     | typ == H3FrameHeaders -> do
                         pushbackSource src leftover
-                        Just <$> qpackDecode ctx payload
+                        Just <$> qpackDecode ctx sid payload
                     | typ == H3FrameData -> do
                         abort ctx H3FrameUnexpected
                         loop IInit -- dummy
@@ -70,11 +70,12 @@
 
 recvBody
     :: Context
+    -> StreamId
     -> Source
     -> IORef IFrame
     -> IORef (Maybe TokenHeaderTable)
     -> IO (ByteString, Bool)
-recvBody ctx src refI refH = do
+recvBody ctx sid src refI refH = do
     st <- readIORef refI
     loop st
   where
@@ -95,7 +96,7 @@
                     | typ == H3FrameHeaders -> do
                         writeIORef refI IInit
                         -- pushbackSource src leftover -- fixme
-                        hdr <- qpackDecode ctx payload
+                        hdr <- qpackDecode ctx sid payload
                         writeIORef refH $ Just hdr
                         return ("", True)
                     | typ == H3FrameData -> do
diff --git a/Network/HTTP3/Send.hs b/Network/HTTP3/Send.hs
--- a/Network/HTTP3/Send.hs
+++ b/Network/HTTP3/Send.hs
@@ -26,7 +26,7 @@
 sendHeader ctx strm th hdrs = do
     -- fixme: fixHeaders
     (ths, _) <- toTokenHeaderTable hdrs
-    (hdr, "") <- qpackEncode ctx ths
+    (hdr, "") <- qpackEncode ctx ths -- FIXME: send 2nd ret value as EI
     let frames = [H3Frame H3FrameHeaders hdr]
         frames' = onHeadersFrameCreated (getHooks ctx) frames
         bss = encodeH3Frames frames'
diff --git a/Network/HTTP3/Server.hs b/Network/HTTP3/Server.hs
--- a/Network/HTTP3/Server.hs
+++ b/Network/HTTP3/Server.hs
@@ -36,7 +36,6 @@
 import Imports
 import Network.HTTP3.Config
 import Network.HTTP3.Context
-import Network.HTTP3.Control
 import Network.HTTP3.Error
 import Network.HTTP3.Frame
 import Network.HTTP3.Recv
@@ -47,8 +46,6 @@
 run :: Connection -> Config -> Server -> IO ()
 run conn conf server = withContext conn conf $ \ctx -> do
     myThreadId >>= \t -> labelThread t "H3 server: run"
-    forkManaged ctx "H3 server: unidirectional setter" $
-        setupUnidirectional conn conf
     readerServer ctx $ \strm ->
         forkManagedTimeoutFinally
             ctx
@@ -58,8 +55,6 @@
 
 runIO :: Connection -> Config -> (ServerIO Stream -> IO (IO ())) -> IO ()
 runIO conn conf action = withContext conn conf $ \ctx -> do
-    forkManaged ctx "H3 server: unidirectional setter" $
-        setupUnidirectional conn conf
     info <- getConnectionInfo conn
     reqq <- newTQueueIO
     let sio =
@@ -97,7 +92,7 @@
     -> IO ()
 processRequest ctx server strm th = E.handle reset $ do
     src <- newSource strm
-    mvt <- recvHeader ctx src
+    mvt <- recvHeader ctx sid src
     case mvt of
         Nothing -> QUIC.resetStream strm H3MessageError
         Just ht -> do
@@ -105,6 +100,7 @@
             let aux = Aux th (getMySockAddr ctx) (getPeerSockAddr ctx)
             server req aux $ sendResponse ctx strm th
   where
+    sid = QUIC.streamId strm
     reset se
         | isAsyncException se = E.throwIO se
         | Just (_ :: DecodeError) <- E.fromException se =
@@ -114,13 +110,14 @@
 processRequestIO :: Context -> ((Stream, Request) -> IO ()) -> Stream -> IO ()
 processRequestIO ctx put strm = E.handle reset $ do
     src <- newSource strm
-    mvt <- recvHeader ctx src
+    mvt <- recvHeader ctx sid src
     case mvt of
         Nothing -> QUIC.resetStream strm H3MessageError
         Just ht -> do
             req <- mkRequest ctx strm src ht
             put (strm, req)
   where
+    sid = QUIC.streamId strm
     reset se
         | isAsyncException se = E.throwIO se
         | Just (_ :: DecodeError) <- E.fromException se =
@@ -145,7 +142,8 @@
     -- fixme: Content-Length
     refI <- newIORef IInit
     refH <- newIORef Nothing
-    let readB = recvBody ctx src refI refH
+    let sid = QUIC.streamId strm
+    let readB = recvBody ctx sid src refI refH
         req = Request $ InpObj ht Nothing readB refH
     return req
 
diff --git a/Network/HTTP3/Settings.hs b/Network/HTTP3/Settings.hs
--- a/Network/HTTP3/Settings.hs
+++ b/Network/HTTP3/Settings.hs
@@ -7,7 +7,7 @@
 
 type H3Settings = [(H3SettingsKey, Int)]
 
-newtype H3SettingsKey = H3SettingsKey Int deriving (Eq, Show)
+newtype H3SettingsKey = H3SettingsKey Int deriving (Eq)
 
 {- FOURMOLU_DISABLE -}
 pattern SettingsQpackMaxTableCapacity :: H3SettingsKey
@@ -18,6 +18,14 @@
 
 pattern SettingsQpackBlockedStreams   :: H3SettingsKey
 pattern SettingsQpackBlockedStreams    = H3SettingsKey 0x7
+{- FOURMOLU_ENABLE -}
+
+{- FOURMOLU_DISABLE -}
+instance Show H3SettingsKey where
+  show SettingsQpackMaxTableCapacity = "SettingsQpackMaxTableCapacity"
+  show SettingsMaxFieldSectionSize   = "SettingsMaxFieldSectionSize"
+  show SettingsQpackBlockedStreams   = "SettingsQpackBlockedStreams"
+  show (H3SettingsKey n)             = "H3SettingsKey " ++ show n
 {- FOURMOLU_ENABLE -}
 
 encodeH3Settings :: H3Settings -> IO ByteString
diff --git a/Network/QPACK.hs b/Network/QPACK.hs
--- a/Network/QPACK.hs
+++ b/Network/QPACK.hs
@@ -58,7 +58,7 @@
     toTokenHeaderTable,
  )
 import Network.HTTP.Types
-import Network.QUIC.Internal (stdoutLogger)
+import Network.QUIC.Internal (StreamId, stdoutLogger)
 
 import Imports
 import Network.QPACK.Error
@@ -74,10 +74,10 @@
     TokenHeaderList -> IO (EncodedFieldSection, EncodedEncoderInstruction)
 
 -- | QPACK decoder.
-type QDecoder = EncodedFieldSection -> IO TokenHeaderTable
+type QDecoder = StreamId -> EncodedFieldSection -> IO TokenHeaderTable
 
 -- | QPACK simple decoder.
-type QDecoderS = EncodedFieldSection -> IO [Header]
+type QDecoderS = StreamId -> EncodedFieldSection -> IO [Header]
 
 -- | Encoder instruction handler.
 type EncoderInstructionHandler = (Int -> IO EncodedEncoderInstruction) -> IO ()
@@ -174,8 +174,7 @@
                     let hb = prefix `B.append` hb0
                     return (hb, ins)
 
-decoderInstructionHandler
-    :: DynamicTable -> (Int -> IO EncodedDecoderInstruction) -> IO ()
+decoderInstructionHandler :: DynamicTable -> DecoderInstructionHandler
 decoderInstructionHandler dyntbl recv = loop
   where
     loop = do
@@ -191,7 +190,7 @@
     handle (StreamCancellation _n) = return ()
     handle (InsertCountIncrement n)
         | n == 0 = E.throwIO DecoderInstructionError
-        | otherwise = return ()
+        | otherwise = return () -- FIXME: Known Received Count
 
 ----------------------------------------------------------------
 
@@ -214,31 +213,47 @@
         }
 
 -- | Creating a new QPACK decoder.
-newQDecoder :: QDecoderConfig -> IO (QDecoder, EncoderInstructionHandler)
-newQDecoder QDecoderConfig{..} = do
-    dyntbl <- newDynamicTableForDecoding dcDynamicTableSize dcHuffmanBufferSize
+newQDecoder
+    :: QDecoderConfig
+    -> (EncodedDecoderInstruction -> IO ())
+    -> IO (QDecoder, EncoderInstructionHandler)
+newQDecoder QDecoderConfig{..} sendDI = do
+    dyntbl <-
+        newDynamicTableForDecoding dcDynamicTableSize dcHuffmanBufferSize sendDI
     let dec = qpackDecoder dyntbl
         handler = encoderInstructionHandler dyntbl
     return (dec, handler)
 
 -- | Creating a new simple QPACK decoder.
 newQDecoderS
-    :: QDecoderConfig -> Bool -> IO (QDecoderS, EncoderInstructionHandlerS)
-newQDecoderS QDecoderConfig{..} debug = do
-    dyntbl <- newDynamicTableForDecoding dcDynamicTableSize dcHuffmanBufferSize
+    :: QDecoderConfig
+    -> (EncodedDecoderInstruction -> IO ())
+    -> Bool
+    -> IO (QDecoderS, EncoderInstructionHandlerS)
+newQDecoderS QDecoderConfig{..} sendDI debug = do
+    dyntbl <-
+        newDynamicTableForDecoding dcDynamicTableSize dcHuffmanBufferSize sendDI
     when debug $ setDebugQPACK dyntbl
     let dec = qpackDecoderS dyntbl
         handler = encoderInstructionHandlerS dyntbl
     return (dec, handler)
 
-qpackDecoder :: DynamicTable -> EncodedFieldSection -> IO TokenHeaderTable
-qpackDecoder dyntbl bs = withReadBuffer bs $ \rbuf -> decodeTokenHeader dyntbl rbuf
+qpackDecoder
+    :: DynamicTable -> StreamId -> EncodedFieldSection -> IO TokenHeaderTable
+qpackDecoder dyntbl sid bs = do
+    (tbl, needAck) <- withReadBuffer bs $ \rbuf -> decodeTokenHeader dyntbl rbuf
+    when needAck $
+        encodeDecoderInstructions [SectionAcknowledgement sid] >>= getSendDI dyntbl
+    return tbl
 
-qpackDecoderS :: DynamicTable -> EncodedFieldSection -> IO [Header]
-qpackDecoderS dyntbl bs = withReadBuffer bs $ \rbuf -> decodeTokenHeaderS dyntbl rbuf
+qpackDecoderS :: DynamicTable -> StreamId -> EncodedFieldSection -> IO [Header]
+qpackDecoderS dyntbl sid bs = do
+    (hs, needAck) <- withReadBuffer bs $ \rbuf -> decodeTokenHeaderS dyntbl rbuf
+    when needAck $
+        encodeDecoderInstructions [SectionAcknowledgement sid] >>= getSendDI dyntbl
+    return hs
 
-encoderInstructionHandler
-    :: DynamicTable -> (Int -> IO EncodedEncoderInstruction) -> IO ()
+encoderInstructionHandler :: DynamicTable -> EncoderInstructionHandler
 encoderInstructionHandler dyntbl recv = loop
   where
     loop = do
@@ -247,8 +262,9 @@
             encoderInstructionHandlerS dyntbl bs
             loop
 
-encoderInstructionHandlerS :: DynamicTable -> EncodedEncoderInstruction -> IO ()
-encoderInstructionHandlerS dyntbl bs = when (bs /= "") $ do
+encoderInstructionHandlerS :: DynamicTable -> EncoderInstructionHandlerS
+encoderInstructionHandlerS _dyntbl "" = return ()
+encoderInstructionHandlerS dyntbl bs = do
     (ins, leftover) <- decodeEncoderInstructions hufdec bs -- fixme: saving leftover
     when (leftover /= "") $ stdoutLogger "encoderInstructionHandler: leftover"
 
@@ -258,21 +274,27 @@
     hufdec = getHuffmanDecoder dyntbl
     handle (SetDynamicTableCapacity n)
         | n > 4096 = E.throwIO EncoderInstructionError
-        | otherwise = return ()
-    handle (InsertWithNameReference ii val) = atomically $ do
-        idx <- case ii of
-            Left ai -> return $ SIndex ai
-            Right ri -> do
-                ip <- getInsertionPointSTM dyntbl
-                return $ DIndex $ fromInsRelativeIndex ri ip
-        ent0 <- toIndexedEntry dyntbl idx
-        let ent = toEntryToken (entryToken ent0) val
-        insertEntryToDecoder ent dyntbl
-    handle (InsertWithoutNameReference t val) = atomically $ do
-        let ent = toEntryToken t val
-        insertEntryToDecoder ent dyntbl
-    handle (Duplicate ri) = atomically $ do
-        ip <- getInsertionPointSTM dyntbl
-        let idx = DIndex $ fromInsRelativeIndex ri ip
-        ent <- toIndexedEntry dyntbl idx
-        insertEntryToDecoder ent dyntbl
+        | otherwise = return () -- FIXME: set cap
+    handle (InsertWithNameReference ii val) = do
+        atomically $ do
+            idx <- case ii of
+                Left ai -> return $ SIndex ai
+                Right ri -> do
+                    ip <- getInsertionPointSTM dyntbl
+                    return $ DIndex $ fromInsRelativeIndex ri ip
+            ent0 <- toIndexedEntry dyntbl idx
+            let ent = toEntryToken (entryToken ent0) val
+            insertEntryToDecoder ent dyntbl
+        encodeDecoderInstructions [InsertCountIncrement 1] >>= getSendDI dyntbl
+    handle (InsertWithLiteralName t val) = do
+        atomically $ do
+            let ent = toEntryToken t val
+            insertEntryToDecoder ent dyntbl
+        encodeDecoderInstructions [InsertCountIncrement 1] >>= getSendDI dyntbl
+    handle (Duplicate ri) = do
+        atomically $ do
+            ip <- getInsertionPointSTM dyntbl
+            let idx = DIndex $ fromInsRelativeIndex ri ip
+            ent <- toIndexedEntry dyntbl idx
+            insertEntryToDecoder ent dyntbl
+        encodeDecoderInstructions [InsertCountIncrement 1] >>= getSendDI dyntbl
diff --git a/Network/QPACK/HeaderBlock/Decode.hs b/Network/QPACK/HeaderBlock/Decode.hs
--- a/Network/QPACK/HeaderBlock/Decode.hs
+++ b/Network/QPACK/HeaderBlock/Decode.hs
@@ -24,21 +24,23 @@
 decodeTokenHeader
     :: DynamicTable
     -> ReadBuffer
-    -> IO TokenHeaderTable
+    -> IO (TokenHeaderTable, Bool)
 decodeTokenHeader dyntbl rbuf = do
-    (reqip, bp) <- decodePrefix rbuf dyntbl
+    (reqip, bp, needAck) <- decodePrefix rbuf dyntbl
     checkInsertionPoint dyntbl reqip
-    decodeSophisticated (toTokenHeader dyntbl bp) rbuf
+    tbl <- decodeSophisticated (toTokenHeader dyntbl bp) rbuf
+    return (tbl, needAck)
 
 decodeTokenHeaderS
     :: DynamicTable
     -> ReadBuffer
-    -> IO [Header]
+    -> IO ([Header], Bool)
 decodeTokenHeaderS dyntbl rbuf = do
-    (reqip, bp) <- decodePrefix rbuf dyntbl
+    (reqip, bp, needAck) <- decodePrefix rbuf dyntbl
     debug <- getDebugQPACK dyntbl
     unless debug $ checkInsertionPoint dyntbl reqip
-    decodeSimple (toTokenHeader dyntbl bp) rbuf
+    hs <- decodeSimple (toTokenHeader dyntbl bp) rbuf
+    return (hs, needAck)
 
 toTokenHeader
     :: DynamicTable -> BasePoint -> Word8 -> ReadBuffer -> IO TokenHeader
diff --git a/Network/QPACK/HeaderBlock/Encode.hs b/Network/QPACK/HeaderBlock/Encode.hs
--- a/Network/QPACK/HeaderBlock/Encode.hs
+++ b/Network/QPACK/HeaderBlock/Encode.hs
@@ -147,7 +147,7 @@
                     encodeLiteralFieldLineWithNameReference wbuf1 dyntbl hi val huff
             N
                 | shouldBeIndexed t -> do
-                    let ins = InsertWithoutNameReference t val
+                    let ins = InsertWithLiteralName t val
                     encodeEI wbuf2 True ins
                     dai <- insertEntryToEncoder (toEntryToken t val) dyntbl
                     encodeIndexedFieldLineWithPostBaseIndex wbuf1 dyntbl dai
diff --git a/Network/QPACK/HeaderBlock/Prefix.hs b/Network/QPACK/HeaderBlock/Prefix.hs
--- a/Network/QPACK/HeaderBlock/Prefix.hs
+++ b/Network/QPACK/HeaderBlock/Prefix.hs
@@ -95,7 +95,8 @@
     encodeI wbuf set 7 base
 
 -- | Decoding the prefix part of header block.
-decodePrefix :: ReadBuffer -> DynamicTable -> IO (InsertionPoint, BasePoint)
+decodePrefix
+    :: ReadBuffer -> DynamicTable -> IO (InsertionPoint, BasePoint, Bool)
 decodePrefix rbuf dyntbl = do
     maxEntries <- getMaxNumOfEntries dyntbl
     totalNumberOfInserts <- getInsertionPoint dyntbl
@@ -110,4 +111,5 @@
     qpackDebug dyntbl $
         putStrLn $
             "Required" ++ show reqInsCnt ++ ", " ++ show baseIndex
-    return (reqInsCnt, baseIndex)
+    let needAck = reqInsCnt /= 0
+    return (reqInsCnt, baseIndex, needAck)
diff --git a/Network/QPACK/Instruction.hs b/Network/QPACK/Instruction.hs
--- a/Network/QPACK/Instruction.hs
+++ b/Network/QPACK/Instruction.hs
@@ -33,6 +33,7 @@
     encodeS,
     entryHeaderName,
  )
+import Network.QUIC (StreamId)
 
 import Imports
 import Network.QPACK.Table.Static
@@ -45,7 +46,7 @@
 data EncoderInstruction
     = SetDynamicTableCapacity Int
     | InsertWithNameReference InsIndex FieldValue
-    | InsertWithoutNameReference Token FieldValue
+    | InsertWithLiteralName Token FieldValue
     | Duplicate InsRelativeIndex
     deriving (Eq)
 
@@ -59,8 +60,8 @@
             ++ "\""
     show (InsertWithNameReference (Right (InsRelativeIndex idx)) v) =
         "InsertWithNameReference (DynRel " ++ show idx ++ ") \"" ++ BS8.unpack v ++ "\""
-    show (InsertWithoutNameReference t v) =
-        "InsertWithoutNameReference \""
+    show (InsertWithLiteralName t v) =
+        "InsertWithLiteralName \""
             ++ BS8.unpack (foldedCase (tokenKey t))
             ++ "\" \""
             ++ BS8.unpack v
@@ -81,7 +82,7 @@
             Right (InsRelativeIndex i) -> (set1, i)
     encodeI wbuf set 6 idx
     encodeS wbuf huff id set1 7 v
-encodeEI wbuf huff (InsertWithoutNameReference k v) = do
+encodeEI wbuf huff (InsertWithLiteralName k v) = do
     encodeS wbuf huff set01 set001 5 $ foldedCase $ tokenKey k
     encodeS wbuf huff id set1 7 v
 encodeEI wbuf _ (Duplicate (InsRelativeIndex idx)) = encodeI wbuf set000 5 idx
@@ -124,7 +125,7 @@
         then decodeInsertWithNameReference rbuf w8 hufdec
         else
             if w8 `testBit` 6
-                then decodeInsertWithoutNameReference rbuf hufdec
+                then decodeInsertWithLiteralName rbuf hufdec
                 else
                     if w8 `testBit` 5
                         then decodeSetDynamicTableCapacity rbuf w8
@@ -140,13 +141,13 @@
     v <- decodeS (.&. 0b01111111) (`testBit` 7) 7 hufdec rbuf
     return $ InsertWithNameReference hidx v
 
-decodeInsertWithoutNameReference
+decodeInsertWithLiteralName
     :: ReadBuffer -> HuffmanDecoder -> IO EncoderInstruction
-decodeInsertWithoutNameReference rbuf hufdec = do
+decodeInsertWithLiteralName rbuf hufdec = do
     ff rbuf (-1)
     k <- decodeS (.&. 0b00011111) (`testBit` 5) 5 hufdec rbuf
     v <- decodeS (.&. 0b01111111) (`testBit` 7) 7 hufdec rbuf
-    return $ InsertWithoutNameReference (toToken k) v
+    return $ InsertWithLiteralName (toToken k) v
 
 decodeSetDynamicTableCapacity :: ReadBuffer -> Word8 -> IO EncoderInstruction
 decodeSetDynamicTableCapacity rbuf w8 =
@@ -159,8 +160,8 @@
 ----------------------------------------------------------------
 
 data DecoderInstruction
-    = SectionAcknowledgement Int
-    | StreamCancellation Int
+    = SectionAcknowledgement StreamId
+    | StreamCancellation StreamId
     | InsertCountIncrement Int
     deriving (Eq, Show)
 
diff --git a/Network/QPACK/Table.hs b/Network/QPACK/Table.hs
--- a/Network/QPACK/Table.hs
+++ b/Network/QPACK/Table.hs
@@ -27,6 +27,7 @@
 
     -- * Misc
     getHuffmanDecoder,
+    getSendDI,
     setDebugQPACK,
     getDebugQPACK,
     qpackDebug,
diff --git a/Network/QPACK/Table/Dynamic.hs b/Network/QPACK/Table/Dynamic.hs
--- a/Network/QPACK/Table/Dynamic.hs
+++ b/Network/QPACK/Table/Dynamic.hs
@@ -28,7 +28,7 @@
     = EncodeInfo
         RevIndex -- Reverse index
         (IORef InsertionPoint)
-    | DecodeInfo HuffmanDecoder
+    | DecodeInfo HuffmanDecoder (ByteString -> IO ())
 
 -- | Dynamic table for QPACK.
 data DynamicTable = DynamicTable
@@ -42,6 +42,8 @@
     , debugQPACK :: IORef Bool
     }
 
+-- knownReceivedCount :: TVar Int
+
 type Table = TArray Index Entry
 
 ----------------------------------------------------------------
@@ -84,12 +86,13 @@
     -- ^ The dynamic table size
     -> Size
     -- ^ The size of temporary buffer for Huffman decoding
+    -> (ByteString -> IO ())
     -> IO DynamicTable
-newDynamicTableForDecoding maxsiz huftmpsiz = do
+newDynamicTableForDecoding maxsiz huftmpsiz sendDI = do
     gcbuf <- mallocPlainForeignPtrBytes huftmpsiz
     tvar <- newTVarIO $ Just (gcbuf, huftmpsiz)
     let decoder = decodeHLock tvar
-        info = DecodeInfo decoder
+        info = DecodeInfo decoder sendDI
     newDynamicTable maxsiz info
 
 decodeHLock
@@ -153,7 +156,12 @@
 getHuffmanDecoder :: DynamicTable -> HuffmanDecoder
 getHuffmanDecoder DynamicTable{..} = huf
   where
-    DecodeInfo huf = codeInfo
+    DecodeInfo huf _ = codeInfo
+
+getSendDI :: DynamicTable -> (ByteString -> IO ())
+getSendDI DynamicTable{..} = sendDI
+  where
+    DecodeInfo _ sendDI = codeInfo
 
 ----------------------------------------------------------------
 
diff --git a/http3.cabal b/http3.cabal
--- a/http3.cabal
+++ b/http3.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               http3
-version:            0.0.23
+version:            0.0.24
 license:            BSD-3-Clause
 license-file:       LICENSE
 maintainer:         Kazu Yamamoto <kazu@iij.ad.jp>
@@ -114,7 +114,7 @@
         http2,
         http3,
         quic,
-        tls < 2.2,
+        tls >=2.1.10 && <2.2,
         tls-session-manager
 
     if flag(devel)
@@ -141,7 +141,7 @@
         http-types,
         http3,
         quic,
-        tls,
+        tls >=2.1.10 && <2.2,
         unix-time
 
     if flag(devel)
diff --git a/test/QPACK/InstructionSpec.hs b/test/QPACK/InstructionSpec.hs
--- a/test/QPACK/InstructionSpec.hs
+++ b/test/QPACK/InstructionSpec.hs
@@ -14,7 +14,7 @@
             let eis0 =
                     [ SetDynamicTableCapacity 4096
                     , InsertWithNameReference (Left 92) "Warp/4.3.2.1"
-                    , InsertWithoutNameReference tokenContentType "text/plain"
+                    , InsertWithLiteralName tokenContentType "text/plain"
                     , Duplicate 40
                     ]
             bs1 <- encodeEncoderInstructions eis0 True
diff --git a/test/QPACK/QIFSpec.hs b/test/QPACK/QIFSpec.hs
--- a/test/QPACK/QIFSpec.hs
+++ b/test/QPACK/QIFSpec.hs
@@ -14,6 +14,7 @@
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Char8 as BS8
 import Data.Conduit.Attoparsec
+import Network.QUIC (StreamId)
 import System.IO
 import Test.Hspec
 
@@ -36,7 +37,7 @@
 
 test :: FilePath -> FilePath -> IO ()
 test efile qfile = do
-    (dec, insthdr) <- newQDecoderS defaultQDecoderConfig False
+    (dec, insthdr) <- newQDecoderS defaultQDecoderConfig (\_ -> return ()) False
     q <- newTQueueIO
     let recv = atomically $ readTQueue q
         send x = atomically $ writeTQueue q x
@@ -60,7 +61,7 @@
     | otherwise = send blk
 
 decode
-    :: (ByteString -> IO [Header])
+    :: (StreamId -> ByteString -> IO [Header])
     -> Handle
     -> IO Block
     -> MVar ()
@@ -73,8 +74,8 @@
             then
                 putMVar mvar ()
             else do
-                Block _ bs <- recv
-                hdr <- dec bs
+                Block n bs <- recv
+                hdr <- dec n bs
                 hdr `shouldBe` hdr'
                 loop
 
diff --git a/util/Common.hs b/util/Common.hs
--- a/util/Common.hs
+++ b/util/Common.hs
@@ -41,7 +41,7 @@
     (s', r) -> s' : split c (drop 1 r)
 
 getLogger :: Maybe FilePath -> (String -> IO ())
-getLogger Nothing = \_ -> return ()
+getLogger Nothing = defaultKeyLogger
 getLogger (Just file) = \msg -> appendFile file (msg ++ "\n")
 
 makeProtos :: Version -> (ByteString, ByteString)
diff --git a/util/qif.hs b/util/qif.hs
--- a/util/qif.hs
+++ b/util/qif.hs
@@ -14,6 +14,7 @@
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Char8 as BS8
 import Data.Conduit.Attoparsec
+import Network.QUIC (StreamId)
 import System.Environment
 import System.IO
 
@@ -36,7 +37,10 @@
 dump :: Int -> FilePath -> IO ()
 dump size efile = do
     (dec, insthdr) <-
-        newQDecoderS defaultQDecoderConfig{dcDynamicTableSize = size} True
+        newQDecoderS
+            defaultQDecoderConfig{dcDynamicTableSize = size}
+            (\_ -> return ())
+            True
     runConduitRes
         ( sourceFile efile
             .| conduitParser block
@@ -44,17 +48,17 @@
         )
 
 dumpSwitch
-    :: (ByteString -> IO [Header])
+    :: (StreamId -> ByteString -> IO [Header])
     -> EncoderInstructionHandlerS
     -> (a, Block)
     -> IO ()
 dumpSwitch dec insthdr (_, Block n bs)
     | n == 0 = do
-        putStrLn "---- Stream 0"
+        putStrLn "---- Encoder Stream"
         insthdr bs
     | otherwise = do
         putStrLn $ "---- Stream " ++ show n
-        _ <- dec bs
+        _ <- dec n bs
         return ()
 
 ----------------------------------------------------------------
@@ -62,7 +66,10 @@
 test :: Int -> FilePath -> FilePath -> IO ()
 test size efile qfile = do
     (dec, insthdr') <-
-        newQDecoderS defaultQDecoderConfig{dcDynamicTableSize = size} False
+        newQDecoderS
+            defaultQDecoderConfig{dcDynamicTableSize = size}
+            (\_ -> return ())
+            False
     q <- newTQueueIO
     let recv = atomically $ readTQueue q
         send x = atomically $ writeTQueue q x
@@ -100,7 +107,7 @@
             then putMVar mvar ()
             else do
                 Block n bs <- recv
-                hdr <- dec bs
+                hdr <- dec n bs
                 if hdr == hdr'
                     then loop
                     else do
