~alcinnz/hurl

ref: a7eb27a9d9ad043c591ee4cabbd643dc6fa4ac71 hurl/src/Network/URI/Fetch.hs -rw-r--r-- 2.4 KiB
a7eb27a9 — Adrian Cochrane Extract URL resolver from Rhapsode 4 years ago
                                                                                
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
module Network.URI.Fetch(fetchURL) where
import qualified Data.Text as Txt
import           Data.Text (Text)
import           Network.URI
import           Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as B

#ifdef WITH_HTTP_URI
import qualified Network.HTTP.Client as HTTP
import           Network.HTTP.Types
import           Network.URI.Charset
#endif

#ifdef WITH_DATA_URI
import qualified Data.ByteString.Char8 as C8
import qualified Data.ByteString.Base64 as B64
#endif

data Session = Session {
#ifdef WITH_HTTP_URI
    managerHTTP :: HTTP.Manager
#endif
}

fetchURL :: Session -> String -> URI -> IO (String, Either Text ByteString)
#ifdef WITH_HTTP_URI
fetchURL session defaultMIME uri | uriScheme uri `elem` ["http:", "https:"] = do
    request <- HTTP.requestFromURI uri
    response <- HTTP.httpLbs request $ managerHTTP session
    return $ case (
            HTTP.responseBody response,
            [val | ("content-type", val) <- HTTP.responseHeaders response]
      ) of
        ("", _) -> ("text/plain", Right $ B.fromStrict $ statusMessage $ HTTP.responseStatus response)
        (response, (mimetype:_)) -> let mime = Txt.toLower $ convertCharset "utf-8" mimetype
            in resolveCharset (map (Txt.unpack . Txt.strip) $ Txt.splitOn ";" $ mime) response
        (response, []) -> (defaultMIME, Right response)
#endif

#ifdef WITH_FILE_URI
fetchURL _ defaultMIME uri@URI {uriScheme = "file:"} = do
    response <- B.readFile $ uriPath uri
    return (defaultMIME, Right response)
#endif

#ifdef WITH_DATA_URI
fetchURL _ defaultMIME uri@URI {uriScheme = "data:"} =
    let request = uriPath uri ++ uriQuery uri ++ uriFragment uri
    in case breakOn ',' $ unEscapeString request of
        ("", response) -> return (defaultMIME, Left $ Txt.pack response)
        (mime', response) | '4':'6':'e':'s':'a':'b':';':mime <- reverse mime' ->
            return $ case B64.decode $ C8.pack response of
                Left str -> ("text/plain", Left $ Txt.pack str)
                Right bytes -> (reverse mime, Right $ B.fromStrict bytes)
        (mime, response) -> return (mime, Left $ Txt.pack response)
#endif

fetchURL _ _ uri = return ("text/plain", Left $ Txt.concat ["Unsupported link type ", Txt.pack $ uriScheme uri])

#ifdef WITH_DATA_URI
breakOn c (a:as) | c == a = ([], as)
    | otherwise = let (x, y) = breakOn c as in (a:x, y)
breakOn _ [] = ([], [])
#endif