1
1
module Functora.Rfc2397
2
- ( encode ,
2
+ ( Media (.. ),
3
+ Encoding (.. ),
4
+ encode ,
3
5
decode ,
4
6
)
5
7
where
6
8
7
9
import qualified Data.ByteString.Base64 as B64
8
10
import Functora.Prelude
11
+ import qualified Network.URI as URI
9
12
import qualified Network.URI.Encode as UE
10
13
import qualified Prelude
11
14
12
- data ENC = BASE64 | URL
13
- deriving stock (Eq )
15
+ data Media = Media
16
+ { mediaMime :: String ,
17
+ mediaBytes :: ByteString ,
18
+ mediaEncoding :: Encoding
19
+ }
20
+ deriving stock (Eq , Ord , Show , Data , Generic )
14
21
15
- encode :: String -> ByteString -> String
16
- encode mime bs =
22
+ data Encoding = B64Encoding | UrlEncoding
23
+ deriving stock (Eq , Ord , Show , Read , Data , Generic , Bounded , Enum )
24
+
25
+ encode :: Media -> String
26
+ encode Media {mediaMime = mime, mediaBytes = bs, mediaEncoding = enc} =
17
27
" data:"
18
28
<> mime
19
- <> " ;base64,"
20
- <> either impureThrow id (decodeUtf8Strict $ B64. encode bs)
29
+ <> ( case enc of
30
+ B64Encoding -> " ;base64"
31
+ UrlEncoding -> mempty
32
+ )
33
+ <> " ,"
34
+ <> ( case enc of
35
+ B64Encoding ->
36
+ either impureThrow id
37
+ . decodeUtf8Strict
38
+ $ B64. encode bs
39
+ UrlEncoding ->
40
+ either impureThrow (UE. encodeWith URI. isAllowedInURI)
41
+ $ decodeUtf8Strict bs
42
+ )
21
43
22
- decode :: String -> Maybe ( String , ByteString )
44
+ decode :: String -> Maybe Media
23
45
decode url =
24
46
let (scheme, rest) = break (== ' :' ) url
25
47
in case rest of
26
48
' :' : contents | scheme == " data" -> decodeContents contents
27
49
_ -> Nothing
28
50
29
- decodeContents :: String -> Maybe ( String , ByteString )
51
+ decodeContents :: String -> Maybe Media
30
52
decodeContents xs =
31
53
let (prefix, restdata) = break (== ' ,' ) xs
32
54
in case restdata of
33
55
' ,' : thedata -> decodePrefix prefix thedata
34
56
_ -> Nothing
35
57
36
- decodePrefix :: String -> String -> Maybe ( String , ByteString )
58
+ decodePrefix :: String -> String -> Maybe Media
37
59
decodePrefix prefix thedata =
38
60
let fragments = breakList (== ' ;' ) prefix
39
61
enc = case reverse fragments of
40
- (" base64" : _) -> BASE64
41
- _ -> URL
62
+ (" base64" : _) -> B64Encoding
63
+ _ -> UrlEncoding
42
64
mediapart
43
- | enc == BASE64 = Prelude. init fragments
65
+ | enc == B64Encoding = Prelude. init fragments
44
66
| otherwise = fragments
45
67
in case mediapart of
46
68
(xs : _) ->
@@ -49,14 +71,20 @@ decodePrefix prefix thedata =
49
71
_ -> decodeData mediapart enc thedata
50
72
_ -> decodeData [" text/plain" , " charset=US-ASCII" ] enc thedata
51
73
52
- decodeData :: [String ] -> ENC -> String -> Maybe (String , ByteString )
53
- decodeData mediatype enc thedata =
54
- Just
55
- ( unparse mediatype,
56
- case enc of
57
- URL -> encodeUtf8 $ UE. decode thedata
58
- BASE64 -> either Prelude. error id . B64. decode $ encodeUtf8 thedata
59
- )
74
+ decodeData :: [String ] -> Encoding -> String -> Maybe Media
75
+ decodeData mediatype enc thedata = do
76
+ bs <-
77
+ case enc of
78
+ UrlEncoding ->
79
+ pure . encodeUtf8 $ UE. decode thedata
80
+ B64Encoding ->
81
+ either (const Nothing ) Just . B64. decode $ encodeUtf8 thedata
82
+ pure
83
+ Media
84
+ { mediaMime = unparse mediatype,
85
+ mediaBytes = bs,
86
+ mediaEncoding = enc
87
+ }
60
88
61
89
breakList :: (x -> Bool ) -> [x ] -> [[x ]]
62
90
breakList p xs =
0 commit comments