packages feed

http2-5.4.5: test/HPACK/IntegerSpec.hs

module HPACK.IntegerSpec where

import qualified Data.ByteString as BS
import Data.Maybe (fromMaybe)
import Data.Word (Word8)
import Network.HPACK (DecodeError (..))
import Network.HPACK.Internal
import Test.Hspec
import Test.Hspec.QuickCheck

dual :: Int -> Int -> Expectation
dual n i = do
    let x = abs i
    bs <- encodeInteger n x
    let (w, ws) = fromMaybe (error "dual") $ BS.uncons bs
    x' <- decodeInteger n w ws
    x `shouldBe` x'

roundtrip7 :: BS.ByteString -> IO Int
roundtrip7 bs = do
    let (w, ws) = fromMaybe (error "roundtrip7") $ BS.uncons bs
    decodeInteger 7 w ws

-- | Decode with a 7-bit prefix that is all ones, so that the continuation
-- octets in 'ws' are what decides the value.
decode7 :: [Word8] -> IO Int
decode7 ws = decodeInteger 7 127 (BS.pack ws)

spec :: Spec
spec = do
    describe "decodeInteger" $ do
        it "rejects an encoding that runs past the limit" $ do
            r <- encodeInteger 7 integerLimit >>= roundtrip7
            r `shouldBe` integerLimit
            ws <- BS.unpack . BS.tail <$> encodeInteger 7 (integerLimit + 1)
            decode7 ws `shouldThrow` (== TooLargeInteger)

        it "rejects an encoding in more octets than the limit can take" $
            -- Continuation octets that each add nothing, so only their number
            -- is objectionable.
            decode7 (replicate 8 0x80 ++ [0x00]) `shouldThrow` (== TooLargeInteger)

        it "rejects an encoding that would wrap around" $
            -- This used to come back as 2, by overflowing 'Int' until it
            -- landed there: the same as the single octet 0x82, ":method: GET".
            -- Two byte strings decoding alike is exactly what RFC 7541
            -- section 5.1 asks a decoder to refuse.
            decode7 [0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01]
                `shouldThrow` (== TooLargeInteger)

    describe "encode and decode" $ do
        prop "duality" $ dual 1
        prop "duality" $ dual 2
        prop "duality" $ dual 3
        prop "duality" $ dual 4
        prop "duality" $ dual 5
        prop "duality" $ dual 6
        prop "duality" $ dual 7
        prop "duality" $ dual 8