summaryrefslogtreecommitdiff
path: root/mini-http-server/Network/HTTP/Server/Mini/URI.hs
blob: 13d7c353bde13b269579b9be91372c917b544fdd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{-# LANGUAGE ViewPatterns #-}
module Network.HTTP.Server.Mini.URI where

import Data.ByteString (ByteString)
import Data.ByteString qualified as BS

import Network.HTTP.Server.Mini.Util


-- | (path components, query string)
--
-- TODO: percent-decode
parseURI :: ByteString -> ([ByteString], [(ByteString, ByteString)])
parseURI = \bs ->
  case BS.uncons bs of
    Just ((== ord8 '/') -> True, bs1) -> goPath id bs1
    _ -> ([], [])
  where
    goPath f bs
      | BS.null bs = (f [], [])
      | otherwise =
          let (comp, bs1) = BS.span (\c -> c /= ord8 '/' && c /= ord8 '?') bs
          in case BS.uncons bs1 of
               Just ((== ord8 '/') -> True, bs2) ->
                 goPath (f . (comp:)) bs2
               Just ((== ord8 '?') -> True, bs2) ->
                 (f [comp], goQuery bs2)
               _ -> (f [comp], [])

    goQuery bs
      | BS.null bs = []
      | Just ((== ord8 '&') -> True, bs1) <- BS.uncons bs = goQuery bs1
      | otherwise =
          let (key, bs1) = BS.span (\c -> c /= ord8 '=' && c /= ord8 '&') bs
          in case BS.uncons bs1 of
               Just ((== ord8 '=') -> True, bs2) ->
                 let (val, bs3) = BS.span (\c -> c /= ord8 '&') bs2
                 in case BS.uncons bs3 of
                      Just (_, bs4) -> (key, val) : goQuery bs4
                      Nothing -> [(key, val)]
               Just ((== ord8 '&') -> True, bs2) ->
                 (key, BS.empty) : goQuery bs2
               _ ->
                 [(key, BS.empty)]