@@ -299,20 +299,21 @@ urlEncodeBuilder' extraUnreserved =
299299 | otherwise = h2 ch
300300
301301 -- The order is optimized from most expected to least expected
302- unreserved ch
303- | ch >= 0x61 && ch <= 0x7A = True -- a-z
304- | ch >= 0x30 && ch <= 0x39 = True -- 0-9
305- | ch >= 0x41 && ch <= 0x5A = True -- A-Z
306- | otherwise = ch `elem` extraUnreserved
302+ unreserved ch =
303+ -- FIXME: could be one index lookup
304+ (ch >= 0x61 && ch <= 0x7A ) -- a-z
305+ || (ch >= 0x30 && ch <= 0x39 ) -- 0-9
306+ || (ch >= 0x41 && ch <= 0x5A ) -- A-Z
307+ || (ch `elem` extraUnreserved)
307308
308309 -- must be upper-case
309310 h2 v = B. word8 _percent `mappend` B. word8 (h a) `mappend` B. word8 (h b)
310311 where
311312 a = v `shiftR` 4
312313 b = v .&. 0x0F
313314 h i
314- | i < 10 = 0x30 + i -- zero (0 )
315- | otherwise = 0x41 + i - 10 -- 0x41: A
315+ | i < 10 = 0x30 + i -- digits (0x30 == '0' )
316+ | otherwise = 0x37 + i -- A-F (0x41 - 10; 0x41 == 'A')
316317
317318-- | Percent-encoding for URLs.
318319--
@@ -369,10 +370,13 @@ urlDecode replacePlus z = fst $ B.unfoldrN (B.length z) go z
369370 Just (a `combine` b, ys)
370371 Just other -> Just other
371372 hexVal w
372- | 0x30 <= w && w <= 0x39 = Just $ w .&. 0x0F -- 0 - 9
373- | 0x41 <= w && w <= 0x46 = Just $ w - 0x37 -- A - F ((w - 0x41) + 10)
374- | 0x61 <= w && w <= 0x66 = Just $ w - 0x57 -- a - f ((w - 0x61) + 10)
373+ -- FIXME: could be one index lookup
374+ | 0x30 <= w && w <= 0x39 = Just result -- 0 - 9
375+ | 0x41 <= w && w <= 0x46 = Just (result + 9 ) -- A - F
376+ | 0x61 <= w && w <= 0x66 = Just (result + 9 ) -- a - f
375377 | otherwise = Nothing
378+ where
379+ result = w .&. 0x0F
376380 combine :: Word8 -> Word8 -> Word8
377381 combine a b = shiftL a 4 .|. b
378382
@@ -475,11 +479,17 @@ decodePathSegment = decodeUtf8With lenientDecode . urlDecode False
475479extractPath :: B. ByteString -> B. ByteString
476480extractPath = ensureNonEmpty . extract
477481 where
478- extract path
479- | " http://" `B.isPrefixOf` path = (snd . breakOnSlash . B. drop 7 ) path
480- | " https://" `B.isPrefixOf` path = (snd . breakOnSlash . B. drop 8 ) path
481- | otherwise = path
482- breakOnSlash = B. break (== _slash)
482+ extract path =
483+ case prefix of
484+ " http://" -> fromSlash rest
485+ " https:/"
486+ -- we need one more _slash for it to be a correct protocol prefix
487+ | Just (0x2F , more) <- B. uncons rest ->
488+ fromSlash more
489+ _ -> path
490+ where
491+ (prefix, rest) = B. splitAt 7 path
492+ fromSlash = B. dropWhile (/= _slash)
483493 ensureNonEmpty " " = " /"
484494 ensureNonEmpty p = p
485495
0 commit comments