我正在尝试使用Network.HTTP.Client调用API,并试图找出如何正确处理TlsNotSupported
异常并通过SSL调用API。 documentation中没有示例,也没有(令人惊讶的)我可以在网络上找到的任何示例。
这是我现有的代码:
module Main where
import Network.URL
import qualified Network.URI as URI
import qualified Network.HTTP as HTTP
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Base64 as B64
import qualified Network.HTTP.Client as HTTPClient
import qualified Network.HTTP.Types.Header as HTTPHeaders
import qualified Data.ByteString.Char8 as C
import qualified Network.HTTP.Types.Status as HTTPStatus
import qualified Data.Text as T
import qualified Control.Exception as E
import qualified Data.Text.Encoding as TE
import Data.Aeson
import Control.Applicative ((<*>), (<$>), pure)
import Control.Monad (mzero)
data Bookmark = Bookmark {
url :: T.Text,
title :: Maybe T.Text
} deriving Show
data Note = Note {
author :: T.Text,
text :: T.Text
} deriving Show
instance FromJSON Bookmark where
parseJSON (Object v) = Bookmark <$>
v .: T.pack "href" <*>
v .: T.pack "description"
parseJSON _ = mzero
b64Encode :: String -> String
b64Encode = T.unpack . TE.decodeUtf8 . B64.encode . TE.encodeUtf8 . T.pack
basicAuthHeader :: String -> String -> String
basicAuthHeader username password = "Authorization: " ++
b64Encode (username ++ ":" ++ username)
postsURL token = "https://api.pinboard.in/posts/all?format=json&auth_token=" ++ token
parse :: BS.ByteString -> Maybe [Bookmark]
parse response = decode (LBS.fromStrict response)
transform = LBS.fromStrict . C.pack
errorHandler :: HTTPClient.HttpException -> IO (Maybe a)
errorHandler (HTTPClient.StatusCodeException status _ _) = return Nothing
errorHandler (HTTPClient.InvalidUrlException _ _) = return Nothing
errorHandler (HTTPClient.HttpParserException _) = return Nothing
errorHandler e = do
case e of
HTTPClient.TlsNotSupported -> (putStrLn $ "Bummer. " ++ show e) >> return Nothing
main = do
putStrLn "Enter auth token: "
token <- getLine
manager <- HTTPClient.newManager HTTPClient.defaultManagerSettings
request <- HTTPClient.parseUrl $ postsURL token
putStrLn $ "Calling " ++ postsURL token
response <- (Just <$> HTTPClient.httpLbs request manager) `E.catch` errorHandler
return ()
这是一个示例会话:
$ runhaskell Pinboard.hs
Enter auth token:
blah
Calling https://api.pinboard.in/posts/all?format=json&auth_token=asd
Bummer. TlsNotSupported
提前致谢!
答案 0 :(得分:7)
您需要使用http-client-tls。请特别将defaultManagerSettings
的使用情况替换为tlsManagerSettings。
答案 1 :(得分:0)
Calling https://api.pinboard.in/posts/all?format=json&auth_token=asd Bummer. TlsNotSupported
我得到了不同的结果。似乎支持TLS。
您使用 Gandi标准SSL CA 或 UTN-USERFirst-Hardware 作为信任锚吗?
$ echo -e "GET /posts/all?format=json&auth_token=asd HTTP/1.1\r\nHost:api.pinboard.in\r\n\r\n" | \
openssl s_client -tls1 -connect api.pinboard.in:443 -servername api.pinboard.in -ign_eof
CONNECTED(00000003)
depth=1 C = FR, O = GANDI SAS, CN = Gandi Standard SSL CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
0 s:/OU=Domain Control Validated/OU=Gandi Standard Wildcard SSL/CN=*.pinboard.in
i:/C=FR/O=GANDI SAS/CN=Gandi Standard SSL CA
1 s:/C=FR/O=GANDI SAS/CN=Gandi Standard SSL CA
i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIE4zCCA8ugAwIBAgIRAJhTQpn18jrbs6EACUBuCEEwDQYJKoZIhvcNAQEFBQAw
QTELMAkGA1UEBhMCRlIxEjAQBgNVBAoTCUdBTkRJIFNBUzEeMBwGA1UEAxMVR2Fu
ZGkgU3RhbmRhcmQgU1NMIENBMB4XDTEzMDgwNTAwMDAwMFoXDTE1MDkwMzIzNTk1
OVowYTEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMSQwIgYDVQQL
ExtHYW5kaSBTdGFuZGFyZCBXaWxkY2FyZCBTU0wxFjAUBgNVBAMUDSoucGluYm9h
cmQuaW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmwELG8RLaC+PD
YRSORwf5dZ+OGDFNnot9It+nEJh3Y9e95y2xxfQQnMfGcrj4UdMNx6Vie2Baz3yD
hU6hweT5ZlpWA43u7xoF2DP5NsgktcTZzQ+IZ124uVvDs+Q5LAH6/aHUplzmdZDz
xDM9JSz8pxXmS9HSJmR1tamYi9B+d30/yxHPibe62Ku6FQ4yoa+f2GVGdvqqvvpZ
7gbwBgu6PKLVNRQPrhUdjdgEj0h44/4DZ/sUw3Jw2cti0yELh4eDLgXonvqCUrOQ
79NJTEzqBBHBUER0ltdUbCXczAm5IQk4pTzSUaI5rML/fcphBaWh0t0XSg9cMFAl
biNqpr9tAgMBAAGjggG0MIIBsDAfBgNVHSMEGDAWgBS2qP+iqC/Qps1LsWjz51AQ
Mad5ITAdBgNVHQ4EFgQUzuFnVq27SbN342v9mBiEc7tygJIwDgYDVR0PAQH/BAQD
AgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MGAGA1UdIARZMFcwSwYLKwYBBAGyMQECAhowPDA6BggrBgEFBQcCARYuaHR0cDov
L3d3dy5nYW5kaS5uZXQvY29udHJhY3RzL2ZyL3NzbC9jcHMvcGRmLzAIBgZngQwB
AgEwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5nYW5kaS5uZXQvR2FuZGlT
dGFuZGFyZFNTTENBLmNybDBqBggrBgEFBQcBAQReMFwwNwYIKwYBBQUHMAKGK2h0
dHA6Ly9jcnQuZ2FuZGkubmV0L0dhbmRpU3RhbmRhcmRTU0xDQS5jcnQwIQYIKwYB
BQUHMAGGFWh0dHA6Ly9vY3NwLmdhbmRpLm5ldDAlBgNVHREEHjAcgg0qLnBpbmJv
YXJkLmluggtwaW5ib2FyZC5pbjANBgkqhkiG9w0BAQUFAAOCAQEAn9i7ilujiOhL
QKMAAuS7xWTvERddqjnnOPBwUw7FCd+VaEnpNCCjqxwrTdWjm4MkjtN2HfDesw1c
IqpLVAMNn35m3aqu7fvyCbBKCkjXLnj1TuKsd/IIFJuqgHNjqyvfe6IIW/Mss+Qq
2TUmVF0HLF2+fyihsdYTlqcv5bR/X7dwbFi1xecoMaDf6K8TTiEKjmr2wNWuKRGy
TsWTqMPBPkyHBJPL589/ETBvqvx1cu/CU81hiadlVino/Buha0cDjNYZra2gOfRR
U2+vK9tsN9Ct0lfOYAamHSiIwGD1HfzdV8xItmZSNsLm3jBZQ1bsqN82+9n2CKWG
IS0WjmfyaA==
-----END CERTIFICATE-----
subject=/OU=Domain Control Validated/OU=Gandi Standard Wildcard SSL/CN=*.pinboard.in
issuer=/C=FR/O=GANDI SAS/CN=Gandi Standard SSL CA
---
No client certificate CA names sent
---
SSL handshake has read 3332 bytes and written 438 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : DHE-RSA-AES256-SHA
Session-ID: C4D0B1D4C4DA50734AFA09A3675A9A6828053B022A516F53E6C2BEA303C49AFC
Session-ID-ctx:
Master-Key: 34A2E6C6B1D17AE7214380462438E9C670CA1E8F9E719D0DEFB7EDE1EC87D847D1DF317523BAAE05278A10E1EDAE51C5
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 300 (seconds)
TLS session ticket:
0000 - 15 99 b9 ce d4 d9 bc 6f-d5 4b 12 83 cd 6f eb b0 .......o.K...o..
0010 - f6 37 a3 66 21 ea ff d1-cf 73 56 fa 25 99 61 1c .7.f!....sV.%.a.
0020 - 38 15 a6 e9 e8 47 cc f8-2b df 8d 64 68 13 1c be 8....G..+..dh...
0030 - 8d 8a 32 a5 ca dd 79 d7-f6 d0 0c 1e e4 50 01 64 ..2...y......P.d
0040 - 73 3e 9f 34 42 3d 4d 56-a3 cc 09 d8 aa 7b 2a 82 s>.4B=MV.....{*.
0050 - 5d 96 c3 1f 3e 19 48 c7-90 c6 4c 07 75 15 e5 42 ]...>.H...L.u..B
0060 - 13 31 c1 fc b4 cc 5f 8e-0b a1 cd 5f bc 7a 16 9c .1...._...._.z..
0070 - 24 3c 5b e7 52 97 ce 15-4f b1 01 44 dc 72 35 82 $<[.R...O..D.r5.
0080 - 4e c9 f9 19 69 26 1c 82-44 f5 c0 6a 57 99 54 da N...i&..D..jW.T.
0090 - cf a8 f4 6f 6b ab c6 ec-98 c6 91 31 d1 20 5c 5c ...ok......1. \\
00a0 - 0f 94 42 5a 8f f5 f7 0d-cd 31 71 04 66 89 5f c1 ..BZ.....1q.f._.
00b0 - 00 84 cd 9e c1 99 52 4f-c0 1e 43 25 f2 36 b9 28 ......RO..C%.6.(
Start Time: 1408986495
Timeout : 7200 (sec)
Verify return code: 20 (unable to get local issuer certificate)
---
HTTP/1.1 403 Forbidden
Date: Mon, 25 Aug 2014 17:07:55 GMT
Server: Apache/2.2.22 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 292
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /posts/all
on this server.</p>
<hr>
<address>Apache/2.2.22 (Ubuntu) Server at api.pinboard.in Port 80</address>
</body></html>
read:errno=0
riemann::~$