Skip to content

Commit 4ee7076

Browse files
committed
Rfc2397 wip
1 parent d7e173e commit 4ee7076

File tree

6 files changed

+97
-0
lines changed

6 files changed

+97
-0
lines changed

ghcjs/miso-functora/test/Functora/Miso/TypesSpec.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import qualified Optics.Setter as Ops
88
import Test.Hspec
99
import Test.Hspec.QuickCheck
1010
import Test.QuickCheck.Instances ()
11+
import qualified Text.URI as URI
1112

1213
data Expr
1314
= Lit Int

pub/functora/functora.cabal

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,11 @@ common pkg-web
176176
hs-source-dirs: src/web
177177
build-depends:
178178
, base
179+
, base64-bytestring
179180
, http-types
180181
, modern-uri
181182
, network-uri
183+
, uri-encode
182184

183185
if impl(ghcjs)
184186
build-depends: ghcjs-base
@@ -311,6 +313,7 @@ library web
311313
exposed: True
312314
visibility: public
313315
exposed-modules:
316+
Functora.Rfc2397
314317
Functora.Web
315318
Functora.WebOrphan
316319

@@ -407,6 +410,7 @@ test-suite functora-test
407410
Functora.Tags.TestFgpt
408411
Functora.Tags.TestSing
409412
Functora.TagsSpec
413+
Functora.WebSpec
410414

411415
if flag(ghcid)
412416
import:
@@ -430,6 +434,7 @@ test-suite functora-test
430434
Functora.Qr
431435
Functora.QrOrphan
432436
Functora.Rates
437+
Functora.Rfc2397
433438
Functora.Soplate
434439
Functora.Sql
435440
Functora.SqlOrphan

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{-# LANGUAGE QuasiQuotes #-}
2+
13
module Functora.CfgSpec (spec) where
24

35
import Functora.Cfg

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{-# LANGUAGE QuasiQuotes #-}
2+
13
module Functora.Elm2MisoSpec (spec) where
24

35
import Data.String.QQ
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module Functora.WebSpec (spec) where
2+
3+
import Functora.Prelude
4+
import qualified Functora.Rfc2397 as Rfc2397
5+
import Test.Hspec
6+
import Test.QuickCheck.Instances ()
7+
8+
dot :: String
9+
dot =
10+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
11+
12+
spec :: Spec
13+
spec = do
14+
it "encode/decode" $
15+
fmap (uncurry Rfc2397.encode) (Rfc2397.decode dot)
16+
`shouldBe` Just dot
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
module Functora.Rfc2397
2+
( encode,
3+
decode,
4+
)
5+
where
6+
7+
import qualified Data.ByteString.Base64 as B64
8+
import Functora.Prelude
9+
import qualified Network.URI.Encode as UE
10+
import qualified Prelude
11+
12+
data ENC = BASE64 | URL
13+
deriving stock (Eq)
14+
15+
encode :: String -> ByteString -> String
16+
encode mime bs =
17+
"data:"
18+
<> mime
19+
<> ";base64,"
20+
<> either impureThrow id (decodeUtf8Strict $ B64.encode bs)
21+
22+
decode :: String -> Maybe (String, ByteString)
23+
decode url =
24+
let (scheme, rest) = break (== ':') url
25+
in case rest of
26+
':' : contents | scheme == "data" -> decodeContents contents
27+
_ -> Nothing
28+
29+
decodeContents :: String -> Maybe (String, ByteString)
30+
decodeContents xs =
31+
let (prefix, restdata) = break (== ',') xs
32+
in case restdata of
33+
',' : thedata -> decodePrefix prefix thedata
34+
_ -> Nothing
35+
36+
decodePrefix :: String -> String -> Maybe (String, ByteString)
37+
decodePrefix prefix thedata =
38+
let fragments = breakList (== ';') prefix
39+
enc = case reverse fragments of
40+
("base64" : _) -> BASE64
41+
_ -> URL
42+
mediapart
43+
| enc == BASE64 = Prelude.init fragments
44+
| otherwise = fragments
45+
in case mediapart of
46+
(xs : _) ->
47+
case break (== '/') xs of
48+
(_, []) -> decodeData ("text/plain" : mediapart) enc thedata
49+
_ -> decodeData mediapart enc thedata
50+
_ -> decodeData ["text/plain", "charset=US-ASCII"] enc thedata
51+
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+
)
60+
61+
breakList :: (x -> Bool) -> [x] -> [[x]]
62+
breakList p xs =
63+
let (pre, post) = break p xs
64+
in case post of
65+
[] -> [pre]
66+
_ : ys -> pre : breakList p ys
67+
68+
unparse :: [String] -> String
69+
unparse [] = ""
70+
unparse [xs] = xs
71+
unparse (xs : xss) = xs ++ ';' : unparse xss

0 commit comments

Comments
 (0)