Skip to content

Commit 71f8210

Browse files
committed
refactor rfc2397
1 parent e22f85f commit 71f8210

File tree

3 files changed

+78
-74
lines changed

3 files changed

+78
-74
lines changed

pub/functora/src/prelude/Functora/Prelude.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,7 @@ import qualified Data.Semigroup as Semigroup
209209
import Data.Sequences as X hiding
210210
( Textual,
211211
Utf8 (..),
212-
break,
213212
catMaybes,
214-
drop,
215213
dropWhile,
216214
filter,
217215
filterM,
@@ -285,9 +283,11 @@ import Universum as X hiding
285283
Traversal',
286284
atomically,
287285
bracket,
286+
break,
288287
catch,
289288
catchAny,
290289
decodeUtf8',
290+
drop,
291291
finally,
292292
fromInteger,
293293
fromIntegral,

pub/functora/src/test/Functora/WebSpec.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import qualified Functora.Rfc2397 as Rfc2397
55
import Test.Hspec
66
import Test.QuickCheck.Instances ()
77

8-
smaples :: [String]
8+
smaples :: [Unicode]
99
smaples =
1010
[ "data:text/vnd-example+xyz;foo=bar;base64,R0lGODdh",
1111
"data:text/plain;charset=UTF-8;page=21,the%20data:1234,5678",
Lines changed: 75 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module Functora.Rfc2397
2-
( Media (..),
3-
Encoding (..),
2+
( Rfc2397 (..),
3+
Rfc2397Encoding (..),
44
encodeRfc2397,
55
decodeRfc2397,
66
)
@@ -12,92 +12,96 @@ import qualified Network.URI as URI
1212
import qualified Network.URI.Encode as UE
1313
import qualified Prelude
1414

15-
data Media = Media
16-
{ mediaMime :: String,
17-
mediaBytes :: ByteString,
18-
mediaEncoding :: Encoding
15+
data Rfc2397 = Rfc2397
16+
{ rfc2397Mime :: Unicode,
17+
rfc2397Bytes :: ByteString,
18+
rfc2397Encoding :: Rfc2397Encoding
1919
}
2020
deriving stock (Eq, Ord, Show, Data, Generic)
2121

22-
instance Binary Media
22+
instance Binary Rfc2397
2323

24-
data Encoding = B64Encoding | UrlEncoding
24+
data Rfc2397Encoding
25+
= Rfc2397EncodingB64
26+
| Rfc2397EncodingUrl
2527
deriving stock (Eq, Ord, Show, Read, Data, Generic, Bounded, Enum)
2628

27-
instance Binary Encoding
29+
instance Binary Rfc2397Encoding
2830

29-
encodeRfc2397 :: Media -> String
30-
encodeRfc2397 Media {mediaMime = mime, mediaBytes = bs, mediaEncoding = enc} =
31-
"data:"
32-
<> mime
33-
<> ( case enc of
34-
B64Encoding -> ";base64"
35-
UrlEncoding -> mempty
36-
)
37-
<> ","
38-
<> ( case enc of
39-
B64Encoding ->
40-
either impureThrow id
41-
. decodeUtf8Strict
42-
$ B64.encode bs
43-
UrlEncoding ->
44-
either impureThrow (UE.encodeWith URI.isAllowedInURI)
45-
$ decodeUtf8Strict bs
46-
)
31+
encodeRfc2397 :: Rfc2397 -> Unicode
32+
encodeRfc2397
33+
Rfc2397
34+
{ rfc2397Mime = mime,
35+
rfc2397Bytes = bs,
36+
rfc2397Encoding = enc
37+
} =
38+
"data:"
39+
<> mime
40+
<> ( case enc of
41+
Rfc2397EncodingB64 -> ";base64"
42+
Rfc2397EncodingUrl -> mempty
43+
)
44+
<> ","
45+
<> ( case enc of
46+
Rfc2397EncodingB64 ->
47+
either impureThrow id
48+
. decodeUtf8Strict
49+
$ B64.encode bs
50+
Rfc2397EncodingUrl ->
51+
either
52+
impureThrow
53+
( from @String @Unicode
54+
. UE.encodeWith URI.isAllowedInURI
55+
)
56+
$ decodeUtf8Strict bs
57+
)
4758

48-
decodeRfc2397 :: String -> Maybe Media
49-
decodeRfc2397 url =
50-
let (scheme, rest) = break (== ':') url
51-
in case rest of
52-
':' : contents | scheme == "data" -> decodeContents contents
53-
_ -> Nothing
59+
decodeRfc2397 :: Unicode -> Maybe Rfc2397
60+
decodeRfc2397 xs =
61+
case break (== ':') xs of
62+
("data", rhs) | not (null rhs) -> decodeContents $ drop 1 rhs
63+
_ -> Nothing
5464

55-
decodeContents :: String -> Maybe Media
65+
decodeContents :: Unicode -> Maybe Rfc2397
5666
decodeContents xs =
57-
let (prefix, restdata) = break (== ',') xs
58-
in case restdata of
59-
',' : thedata -> decodePrefix prefix thedata
60-
_ -> Nothing
67+
case break (== ',') xs of
68+
(lhs, rhs) | not (null rhs) -> decodePrefix lhs $ drop 1 rhs
69+
_ -> Nothing
6170

62-
decodePrefix :: String -> String -> Maybe Media
71+
decodePrefix :: Unicode -> Unicode -> Maybe Rfc2397
6372
decodePrefix prefix thedata =
64-
let fragments = breakList (== ';') prefix
65-
enc = case reverse fragments of
66-
("base64" : _) -> B64Encoding
67-
_ -> UrlEncoding
68-
mediapart
69-
| enc == B64Encoding = Prelude.init fragments
70-
| otherwise = fragments
71-
in case mediapart of
72-
(xs : _) ->
73-
case break (== '/') xs of
74-
(_, []) -> decodeData ("text/plain" : mediapart) enc thedata
75-
_ -> decodeData mediapart enc thedata
76-
_ -> decodeData ["text/plain", "charset=US-ASCII"] enc thedata
73+
case mediapart of
74+
[] -> decodeData ["text/plain", "charset=US-ASCII"] enc thedata
75+
(xs : _) ->
76+
case break (== '/') xs of
77+
(_, []) -> decodeData ("text/plain" : mediapart) enc thedata
78+
_ -> decodeData mediapart enc thedata
79+
where
80+
fragments = breakList (== ';') prefix
81+
enc = case reverse fragments of
82+
("base64" : _) -> Rfc2397EncodingB64
83+
_ -> Rfc2397EncodingUrl
84+
mediapart
85+
| enc == Rfc2397EncodingB64 = Prelude.init fragments
86+
| otherwise = fragments
7787

78-
decodeData :: [String] -> Encoding -> String -> Maybe Media
88+
decodeData :: [Unicode] -> Rfc2397Encoding -> Unicode -> Maybe Rfc2397
7989
decodeData mediatype enc thedata = do
8090
bs <-
8191
case enc of
82-
UrlEncoding ->
83-
pure . encodeUtf8 $ UE.decode thedata
84-
B64Encoding ->
92+
Rfc2397EncodingUrl ->
93+
pure . encodeUtf8 . UE.decode $ from @Unicode @String thedata
94+
Rfc2397EncodingB64 ->
8595
either (const Nothing) Just . B64.decode $ encodeUtf8 thedata
8696
pure
87-
Media
88-
{ mediaMime = unparse mediatype,
89-
mediaBytes = bs,
90-
mediaEncoding = enc
97+
Rfc2397
98+
{ rfc2397Mime = intercalate ";" mediatype,
99+
rfc2397Bytes = bs,
100+
rfc2397Encoding = enc
91101
}
92102

93-
breakList :: (x -> Bool) -> [x] -> [[x]]
94-
breakList p xs =
95-
let (pre, post) = break p xs
96-
in case post of
97-
[] -> [pre]
98-
_ : ys -> pre : breakList p ys
99-
100-
unparse :: [String] -> String
101-
unparse [] = ""
102-
unparse [xs] = xs
103-
unparse (xs : xss) = xs ++ ';' : unparse xss
103+
breakList :: (Char -> Bool) -> Unicode -> [Unicode]
104+
breakList f xs =
105+
case break f xs of
106+
(lhs, rhs) | null rhs -> [lhs]
107+
(lhs, rhs) -> lhs : breakList f (drop 1 rhs)

0 commit comments

Comments
 (0)