diff options
-rw-r--r-- | bittorrent.cabal | 2 | ||||
-rw-r--r-- | src/Network/BitTorrent/Core/PeerAddr.hs | 41 | ||||
-rw-r--r-- | src/Network/BitTorrent/Exchange/Wire.hs | 2 | ||||
-rw-r--r-- | src/Network/BitTorrent/Tracker/Message.hs | 67 | ||||
m--------- | sub/bencoding | 0 | ||||
-rw-r--r-- | tests/Network/BitTorrent/Tracker/MessageSpec.hs | 62 | ||||
-rw-r--r-- | tests/Network/BitTorrent/Tracker/RPC/HTTPSpec.hs | 1 |
7 files changed, 136 insertions, 39 deletions
diff --git a/bittorrent.cabal b/bittorrent.cabal index 8e7fda46..faf72c75 100644 --- a/bittorrent.cabal +++ b/bittorrent.cabal | |||
@@ -124,7 +124,7 @@ library | |||
124 | , base16-bytestring >= 0.1 | 124 | , base16-bytestring >= 0.1 |
125 | , base32-bytestring >= 0.2 | 125 | , base32-bytestring >= 0.2 |
126 | , base64-bytestring >= 1.0 | 126 | , base64-bytestring >= 1.0 |
127 | , bencoding >= 0.4.2 | 127 | , bencoding >= 0.4.2.1 |
128 | , cereal >= 0.3.5 | 128 | , cereal >= 0.3.5 |
129 | 129 | ||
130 | -- Time | 130 | -- Time |
diff --git a/src/Network/BitTorrent/Core/PeerAddr.hs b/src/Network/BitTorrent/Core/PeerAddr.hs index 6c6056c9..88239d0b 100644 --- a/src/Network/BitTorrent/Core/PeerAddr.hs +++ b/src/Network/BitTorrent/Core/PeerAddr.hs | |||
@@ -21,11 +21,6 @@ module Network.BitTorrent.Core.PeerAddr | |||
21 | PeerAddr(..) | 21 | PeerAddr(..) |
22 | , defaultPorts | 22 | , defaultPorts |
23 | , peerSockAddr | 23 | , peerSockAddr |
24 | |||
25 | -- * IP | ||
26 | , mergeIPLists | ||
27 | , splitIPList | ||
28 | , IPAddress () | ||
29 | ) where | 24 | ) where |
30 | 25 | ||
31 | import Control.Applicative | 26 | import Control.Applicative |
@@ -36,8 +31,6 @@ import Data.BEncode.BDict (BKey) | |||
36 | import Data.ByteString.Char8 as BS8 | 31 | import Data.ByteString.Char8 as BS8 |
37 | import Data.Char | 32 | import Data.Char |
38 | import Data.Default | 33 | import Data.Default |
39 | import Data.Either | ||
40 | import Data.Foldable | ||
41 | import Data.IP | 34 | import Data.IP |
42 | import Data.List as L | 35 | import Data.List as L |
43 | import Data.List.Split | 36 | import Data.List.Split |
@@ -86,13 +79,16 @@ class IPAddress i where | |||
86 | 79 | ||
87 | instance IPAddress IPv4 where | 80 | instance IPAddress IPv4 where |
88 | toHostAddr = Left . toHostAddress | 81 | toHostAddr = Left . toHostAddress |
82 | {-# INLINE toHostAddr #-} | ||
89 | 83 | ||
90 | instance IPAddress IPv6 where | 84 | instance IPAddress IPv6 where |
91 | toHostAddr = Right . toHostAddress6 | 85 | toHostAddr = Right . toHostAddress6 |
86 | {-# INLINE toHostAddr #-} | ||
92 | 87 | ||
93 | instance IPAddress IP where | 88 | instance IPAddress IP where |
94 | toHostAddr (IPv4 ip) = toHostAddr ip | 89 | toHostAddr (IPv4 ip) = toHostAddr ip |
95 | toHostAddr (IPv6 ip) = toHostAddr ip | 90 | toHostAddr (IPv6 ip) = toHostAddr ip |
91 | {-# INLINE toHostAddr #-} | ||
96 | 92 | ||
97 | deriving instance Typeable IP | 93 | deriving instance Typeable IP |
98 | deriving instance Typeable IPv4 | 94 | deriving instance Typeable IPv4 |
@@ -100,6 +96,7 @@ deriving instance Typeable IPv6 | |||
100 | 96 | ||
101 | ipToBEncode :: Show i => i -> BValue | 97 | ipToBEncode :: Show i => i -> BValue |
102 | ipToBEncode ip = BString $ BS8.pack $ show ip | 98 | ipToBEncode ip = BString $ BS8.pack $ show ip |
99 | {-# INLINE ipToBEncode #-} | ||
103 | 100 | ||
104 | ipFromBEncode :: Read a => BValue -> BS.Result a | 101 | ipFromBEncode :: Read a => BValue -> BS.Result a |
105 | ipFromBEncode (BString (BS8.unpack -> ipStr)) | 102 | ipFromBEncode (BString (BS8.unpack -> ipStr)) |
@@ -107,17 +104,25 @@ ipFromBEncode (BString (BS8.unpack -> ipStr)) | |||
107 | | otherwise = decodingError $ "IP: " ++ ipStr | 104 | | otherwise = decodingError $ "IP: " ++ ipStr |
108 | ipFromBEncode _ = decodingError $ "IP: addr should be a bstring" | 105 | ipFromBEncode _ = decodingError $ "IP: addr should be a bstring" |
109 | 106 | ||
107 | instance Ord IP where | ||
108 | |||
110 | instance BEncode IP where | 109 | instance BEncode IP where |
111 | toBEncode = ipToBEncode | 110 | toBEncode = ipToBEncode |
111 | {-# INLINE toBEncode #-} | ||
112 | fromBEncode = ipFromBEncode | 112 | fromBEncode = ipFromBEncode |
113 | {-# INLINE fromBEncode #-} | ||
113 | 114 | ||
114 | instance BEncode IPv4 where | 115 | instance BEncode IPv4 where |
115 | toBEncode = ipToBEncode | 116 | toBEncode = ipToBEncode |
117 | {-# INLINE toBEncode #-} | ||
116 | fromBEncode = ipFromBEncode | 118 | fromBEncode = ipFromBEncode |
119 | {-# INLINE fromBEncode #-} | ||
117 | 120 | ||
118 | instance BEncode IPv6 where | 121 | instance BEncode IPv6 where |
119 | toBEncode = ipToBEncode | 122 | toBEncode = ipToBEncode |
123 | {-# INLINE toBEncode #-} | ||
120 | fromBEncode = ipFromBEncode | 124 | fromBEncode = ipFromBEncode |
125 | {-# INLINE fromBEncode #-} | ||
121 | 126 | ||
122 | instance Serialize IPv4 where | 127 | instance Serialize IPv4 where |
123 | put = putWord32host . toHostAddress | 128 | put = putWord32host . toHostAddress |
@@ -136,9 +141,14 @@ instance Serialize IPv6 where | |||
136 | -- compact list encoding. | 141 | -- compact list encoding. |
137 | data PeerAddr a = PeerAddr | 142 | data PeerAddr a = PeerAddr |
138 | { peerId :: !(Maybe PeerId) | 143 | { peerId :: !(Maybe PeerId) |
144 | |||
145 | -- | This is usually 'IPv4', 'IPv6', 'IP' or unresolved | ||
146 | -- 'HostName'. | ||
139 | , peerHost :: !a | 147 | , peerHost :: !a |
148 | |||
149 | -- | The port the peer listenning for incoming P2P sessions. | ||
140 | , peerPort :: {-# UNPACK #-} !PortNumber | 150 | , peerPort :: {-# UNPACK #-} !PortNumber |
141 | } deriving (Show, Eq, Typeable, Functor) | 151 | } deriving (Show, Eq, Ord, Typeable, Functor) |
142 | 152 | ||
143 | peer_ip_key, peer_id_key, peer_port_key :: BKey | 153 | peer_ip_key, peer_id_key, peer_port_key :: BKey |
144 | peer_ip_key = "ip" | 154 | peer_ip_key = "ip" |
@@ -160,17 +170,6 @@ instance (Typeable a, BEncode a) => BEncode (PeerAddr a) where | |||
160 | where | 170 | where |
161 | peerAddr = flip PeerAddr | 171 | peerAddr = flip PeerAddr |
162 | 172 | ||
163 | mergeIPLists :: [PeerAddr IPv4] -> Maybe [PeerAddr IPv6] -> [PeerAddr IP] | ||
164 | mergeIPLists v4 v6 = (fmap IPv4 `L.map` v4) | ||
165 | ++ (fmap IPv6 `L.map` Data.Foldable.concat v6) | ||
166 | |||
167 | splitIPList :: [PeerAddr IP] -> ([PeerAddr IPv4],[PeerAddr IPv6]) | ||
168 | splitIPList xs = partitionEithers $ toEither <$> xs | ||
169 | where | ||
170 | toEither :: PeerAddr IP -> Either (PeerAddr IPv4) (PeerAddr IPv6) | ||
171 | toEither pa@(PeerAddr _ (IPv4 _) _) = Left (ipv4 <$> pa) | ||
172 | toEither pa@(PeerAddr _ (IPv6 _) _) = Right (ipv6 <$> pa) | ||
173 | |||
174 | -- | The tracker's 'compact peer list' compatible encoding. The | 173 | -- | The tracker's 'compact peer list' compatible encoding. The |
175 | -- 'peerId' is always 'Nothing'. | 174 | -- 'peerId' is always 'Nothing'. |
176 | -- | 175 | -- |
@@ -231,8 +230,8 @@ defaultPorts = [6881..6889] | |||
231 | _resolvePeerAddr :: (IPAddress i) => PeerAddr HostName -> PeerAddr i | 230 | _resolvePeerAddr :: (IPAddress i) => PeerAddr HostName -> PeerAddr i |
232 | _resolvePeerAddr = undefined | 231 | _resolvePeerAddr = undefined |
233 | 232 | ||
234 | -- | Convert peer info from tracker response to socket address. Used | 233 | -- | Convert peer info from tracker or DHT announce query response to |
235 | -- for establish connection between peers. | 234 | -- socket address. Usually used to intiate connection between peers. |
236 | -- | 235 | -- |
237 | peerSockAddr :: PeerAddr IP -> SockAddr | 236 | peerSockAddr :: PeerAddr IP -> SockAddr |
238 | peerSockAddr PeerAddr {..} = | 237 | peerSockAddr PeerAddr {..} = |
diff --git a/src/Network/BitTorrent/Exchange/Wire.hs b/src/Network/BitTorrent/Exchange/Wire.hs index 2a7d2aeb..5f7b0ebe 100644 --- a/src/Network/BitTorrent/Exchange/Wire.hs +++ b/src/Network/BitTorrent/Exchange/Wire.hs | |||
@@ -673,7 +673,7 @@ connectWire hs addr extCaps wire = | |||
673 | -- | 673 | -- |
674 | -- This function can throw 'WireFailure' exception. | 674 | -- This function can throw 'WireFailure' exception. |
675 | -- | 675 | -- |
676 | acceptWire :: (IPAddress i) => Socket -> PeerAddr i -> Wire () -> IO () | 676 | acceptWire :: Socket -> PeerAddr IP -> Wire () -> IO () |
677 | acceptWire sock peerAddr wire = do | 677 | acceptWire sock peerAddr wire = do |
678 | bracket (return sock) close $ \ _ -> do | 678 | bracket (return sock) close $ \ _ -> do |
679 | error "acceptWire: not implemented" | 679 | error "acceptWire: not implemented" |
diff --git a/src/Network/BitTorrent/Tracker/Message.hs b/src/Network/BitTorrent/Tracker/Message.hs index d0be1c36..da46628b 100644 --- a/src/Network/BitTorrent/Tracker/Message.hs +++ b/src/Network/BitTorrent/Tracker/Message.hs | |||
@@ -70,7 +70,6 @@ module Network.BitTorrent.Tracker.Message | |||
70 | 70 | ||
71 | import Control.Applicative | 71 | import Control.Applicative |
72 | import Control.Monad | 72 | import Control.Monad |
73 | import Data.Aeson (ToJSON(..), FromJSON(..)) | ||
74 | import Data.Aeson.TH | 73 | import Data.Aeson.TH |
75 | import Data.BEncode as BE hiding (Result) | 74 | import Data.BEncode as BE hiding (Result) |
76 | import Data.BEncode.BDict as BE | 75 | import Data.BEncode.BDict as BE |
@@ -79,8 +78,10 @@ import Data.ByteString.Char8 as BC | |||
79 | import Data.Char as Char | 78 | import Data.Char as Char |
80 | import Data.Convertible | 79 | import Data.Convertible |
81 | import Data.Default | 80 | import Data.Default |
81 | import Data.Either | ||
82 | import Data.List as L | 82 | import Data.List as L |
83 | import Data.Maybe | 83 | import Data.Maybe |
84 | import Data.Monoid | ||
84 | import Data.Serialize as S hiding (Result) | 85 | import Data.Serialize as S hiding (Result) |
85 | import Data.String | 86 | import Data.String |
86 | import Data.Text (Text) | 87 | import Data.Text (Text) |
@@ -193,9 +194,9 @@ instance Serialize AnnounceQuery where | |||
193 | put reqPeerId | 194 | put reqPeerId |
194 | put reqProgress | 195 | put reqProgress |
195 | putEvent reqEvent | 196 | putEvent reqEvent |
196 | putWord32be $ fromMaybe 0 reqIP | 197 | putWord32host $ fromMaybe 0 reqIP |
197 | putWord32be $ 0 -- TODO what the fuck is "key"? | 198 | putWord32be $ 0 -- TODO what the fuck is "key"? |
198 | putWord32be $ fromIntegral $ fromMaybe (-1) reqNumWant | 199 | putWord32be $ fromIntegral $ fromMaybe (-1) reqNumWant |
199 | 200 | ||
200 | put reqPort | 201 | put reqPort |
201 | 202 | ||
@@ -415,7 +416,9 @@ data AnnounceRequest = AnnounceRequest | |||
415 | } deriving (Show, Eq, Typeable) | 416 | } deriving (Show, Eq, Typeable) |
416 | 417 | ||
417 | instance QueryLike AnnounceRequest where | 418 | instance QueryLike AnnounceRequest where |
418 | toQuery AnnounceRequest{..} = toQuery announceAdvises ++ toQuery announceQuery | 419 | toQuery AnnounceRequest{..} = |
420 | toQuery announceAdvises <> | ||
421 | toQuery announceQuery | ||
419 | 422 | ||
420 | -- | Parse announce request from query string. | 423 | -- | Parse announce request from query string. |
421 | parseAnnounceRequest :: SimpleQuery -> ParseResult AnnounceRequest | 424 | parseAnnounceRequest :: SimpleQuery -> ParseResult AnnounceRequest |
@@ -441,6 +444,11 @@ data PeerList ip | |||
441 | | CompactPeerList [PeerAddr ip] | 444 | | CompactPeerList [PeerAddr ip] |
442 | deriving (Show, Eq, Typeable, Functor) | 445 | deriving (Show, Eq, Typeable, Functor) |
443 | 446 | ||
447 | -- | The empty non-compact peer list. | ||
448 | instance Default (PeerList IP) where | ||
449 | def = PeerList [] | ||
450 | {-# INLINE def #-} | ||
451 | |||
444 | getPeerList :: PeerList IP -> [PeerAddr IP] | 452 | getPeerList :: PeerList IP -> [PeerAddr IP] |
445 | getPeerList (PeerList xs) = xs | 453 | getPeerList (PeerList xs) = xs |
446 | getPeerList (CompactPeerList xs) = xs | 454 | getPeerList (CompactPeerList xs) = xs |
@@ -482,6 +490,17 @@ data AnnounceInfo = | |||
482 | , respWarning :: !(Maybe Text) | 490 | , respWarning :: !(Maybe Text) |
483 | } deriving (Show, Eq, Typeable) | 491 | } deriving (Show, Eq, Typeable) |
484 | 492 | ||
493 | -- | Empty peer list with default reannounce interval. | ||
494 | instance Default AnnounceInfo where | ||
495 | def = AnnounceInfo | ||
496 | { respComplete = Nothing | ||
497 | , respIncomplete = Nothing | ||
498 | , respInterval = defaultReannounceInterval | ||
499 | , respMinInterval = Nothing | ||
500 | , respPeers = def | ||
501 | , respWarning = Nothing | ||
502 | } | ||
503 | |||
485 | -- | HTTP tracker protocol compatible encoding. | 504 | -- | HTTP tracker protocol compatible encoding. |
486 | instance BEncode AnnounceInfo where | 505 | instance BEncode AnnounceInfo where |
487 | toBEncode (Failure t) = toDict $ | 506 | toBEncode (Failure t) = toDict $ |
@@ -494,10 +513,24 @@ instance BEncode AnnounceInfo where | |||
494 | .: "interval" .=! respInterval | 513 | .: "interval" .=! respInterval |
495 | .: "min interval" .=? respMinInterval | 514 | .: "min interval" .=? respMinInterval |
496 | .: "peers" .=! peers | 515 | .: "peers" .=! peers |
497 | .: "peers6" .=! peers6 | 516 | .: "peers6" .=? peers6 |
498 | .: "warning message" .=? respWarning | 517 | .: "warning message" .=? respWarning |
499 | .: endDict | 518 | .: endDict |
500 | where (peers,peers6) = splitIPList $ getPeerList respPeers | 519 | where |
520 | (peers, peers6) = prttn respPeers | ||
521 | |||
522 | prttn :: PeerList IP -> (PeerList IPv4, Maybe (PeerList IPv6)) | ||
523 | prttn (PeerList xs) = (PeerList xs, Nothing) | ||
524 | prttn (CompactPeerList xs) = mk $ partitionEithers $ toEither <$> xs | ||
525 | where | ||
526 | mk (v4s, v6s) | ||
527 | | L.null v6s = (CompactPeerList v4s, Nothing) | ||
528 | | otherwise = (CompactPeerList v4s, Just (CompactPeerList v6s)) | ||
529 | |||
530 | toEither :: PeerAddr IP -> Either (PeerAddr IPv4) (PeerAddr IPv6) | ||
531 | toEither PeerAddr {..} = case peerHost of | ||
532 | IPv4 ipv4 -> Left $ PeerAddr peerId ipv4 peerPort | ||
533 | IPv6 ipv6 -> Right $ PeerAddr peerId ipv6 peerPort | ||
501 | 534 | ||
502 | fromBEncode (BDict d) | 535 | fromBEncode (BDict d) |
503 | | Just t <- BE.lookup "failure reason" d = Failure <$> fromBEncode t | 536 | | Just t <- BE.lookup "failure reason" d = Failure <$> fromBEncode t |
@@ -507,8 +540,26 @@ instance BEncode AnnounceInfo where | |||
507 | <*>? "incomplete" | 540 | <*>? "incomplete" |
508 | <*>! "interval" | 541 | <*>! "interval" |
509 | <*>? "min interval" | 542 | <*>? "min interval" |
510 | <*> (PeerList <$> (mergeIPLists <$>! "peers" <*>? "peers6")) | 543 | <*> (uncurry merge =<< (,) <$>! "peers" <*>? "peers6") |
511 | <*>? "warning message" | 544 | <*>? "warning message" |
545 | where | ||
546 | merge :: PeerList IPv4 -> Maybe (PeerList IPv6) -> BE.Get (PeerList IP) | ||
547 | merge (PeerList ips) Nothing = pure (PeerList ips) | ||
548 | merge (PeerList _ ) (Just _) | ||
549 | = fail "PeerList: non-compact peer list provided, \ | ||
550 | \but the `peers6' field present" | ||
551 | |||
552 | merge (CompactPeerList ipv4s) Nothing | ||
553 | = pure $ CompactPeerList (fmap IPv4 <$> ipv4s) | ||
554 | |||
555 | merge (CompactPeerList _ ) (Just (PeerList _)) | ||
556 | = fail "PeerList: the `peers6' field value \ | ||
557 | \should contain *compact* peer list" | ||
558 | |||
559 | merge (CompactPeerList ipv4s) (Just (CompactPeerList ipv6s)) | ||
560 | = pure $ CompactPeerList $ | ||
561 | (fmap IPv4 <$> ipv4s) <> (fmap IPv6 <$> ipv6s) | ||
562 | |||
512 | fromBEncode _ = decodingError "Announce info" | 563 | fromBEncode _ = decodingError "Announce info" |
513 | 564 | ||
514 | -- | UDP tracker protocol compatible encoding. | 565 | -- | UDP tracker protocol compatible encoding. |
diff --git a/sub/bencoding b/sub/bencoding | |||
Subproject fa7861cc092fb3d423d6e3c05df36d3651068de | Subproject d80b4fbe1ffe8478a1c72b1e96bbc5b44991d96 | ||
diff --git a/tests/Network/BitTorrent/Tracker/MessageSpec.hs b/tests/Network/BitTorrent/Tracker/MessageSpec.hs index c3de7b30..5949de7a 100644 --- a/tests/Network/BitTorrent/Tracker/MessageSpec.hs +++ b/tests/Network/BitTorrent/Tracker/MessageSpec.hs | |||
@@ -1,6 +1,7 @@ | |||
1 | {-# LANGUAGE RecordWildCards #-} | 1 | {-# LANGUAGE RecordWildCards #-} |
2 | {-# LANGUAGE ViewPatterns #-} | 2 | {-# LANGUAGE ViewPatterns #-} |
3 | {-# OPTIONS -fno-warn-orphans #-} | 3 | {-# LANGUAGE FlexibleInstances #-} |
4 | {-# OPTIONS -fno-warn-orphans #-} | ||
4 | module Network.BitTorrent.Tracker.MessageSpec | 5 | module Network.BitTorrent.Tracker.MessageSpec |
5 | ( spec | 6 | ( spec |
6 | , validateInfo | 7 | , validateInfo |
@@ -39,6 +40,20 @@ instance Arbitrary AnnounceQuery where | |||
39 | <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary | 40 | <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary |
40 | <*> arbitrary <*> arbitrary <*> arbitrary | 41 | <*> arbitrary <*> arbitrary <*> arbitrary |
41 | 42 | ||
43 | instance Arbitrary (PeerList IP) where | ||
44 | arbitrary = frequency | ||
45 | [ (1, (PeerList . maybeToList) <$> arbitrary) | ||
46 | , (1, (CompactPeerList . maybeToList . fmap zeroPeerId) <$> arbitrary) | ||
47 | ] | ||
48 | |||
49 | shrink ( PeerList xs) = PeerList <$> shrink xs | ||
50 | shrink (CompactPeerList xs) = CompactPeerList <$> shrink xs | ||
51 | |||
52 | instance Arbitrary AnnounceInfo where | ||
53 | arbitrary = AnnounceInfo | ||
54 | <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary | ||
55 | <*> arbitrary <*> arbitrary | ||
56 | |||
42 | validateInfo :: AnnounceQuery -> AnnounceInfo -> Expectation | 57 | validateInfo :: AnnounceQuery -> AnnounceInfo -> Expectation |
43 | validateInfo _ Message.Failure {..} = error "validateInfo: failure" | 58 | validateInfo _ Message.Failure {..} = error "validateInfo: failure" |
44 | validateInfo AnnounceQuery {..} AnnounceInfo {..} = do | 59 | validateInfo AnnounceQuery {..} AnnounceInfo {..} = do |
@@ -47,7 +62,8 @@ validateInfo AnnounceQuery {..} AnnounceInfo {..} = do | |||
47 | respMinInterval `shouldSatisfy` isNothing | 62 | respMinInterval `shouldSatisfy` isNothing |
48 | respWarning `shouldSatisfy` isNothing | 63 | respWarning `shouldSatisfy` isNothing |
49 | peerList `shouldSatisfy` L.all (isNothing . peerId) | 64 | peerList `shouldSatisfy` L.all (isNothing . peerId) |
50 | fromJust respComplete + fromJust respIncomplete `shouldBe` L.length peerList | 65 | fromJust respComplete + fromJust respIncomplete |
66 | `shouldBe` L.length peerList | ||
51 | where | 67 | where |
52 | peerList = getPeerList respPeers | 68 | peerList = getPeerList respPeers |
53 | 69 | ||
@@ -125,15 +141,47 @@ spec = do | |||
125 | errorCall "fromString: unable to decode AnnounceInfo: \ | 141 | errorCall "fromString: unable to decode AnnounceInfo: \ |
126 | \required field `peers' not found" | 142 | \required field `peers' not found" |
127 | 143 | ||
128 | it "parses peer list" $ do -- TODO | 144 | it "parses `peer' list" $ do -- TODO |
129 | "d8:intervali0e\ | 145 | "d8:intervali0e\ |
130 | \5:peersl\ | 146 | \5:peersl\ |
131 | \d2:ip7:1.2.3.4\ | 147 | \d2:ip7:1.2.3.4\ |
132 | \4:porti80e\ | 148 | \4:porti80e\ |
149 | \e\ | ||
150 | \d2:ip3:::1\ | ||
151 | \4:porti80e\ | ||
133 | \e\ | 152 | \e\ |
134 | \e\ | 153 | \e\ |
135 | \e" `shouldBe` | 154 | \e" `shouldBe` |
136 | AnnounceInfo Nothing Nothing 0 Nothing (PeerList ["1.2.3.4:80"]) Nothing | 155 | let xs = PeerList ["1.2.3.4:80", "[::1]:80"] in |
156 | AnnounceInfo Nothing Nothing 0 Nothing xs Nothing | ||
157 | |||
158 | it "parses `peers6' list" $ do | ||
159 | "d8:intervali0e\ | ||
160 | \5:peers0:\ | ||
161 | \6:peers60:\ | ||
162 | \e" `shouldBe` | ||
163 | AnnounceInfo Nothing Nothing 0 Nothing (CompactPeerList []) Nothing | ||
164 | |||
165 | it "fails on invalid combinations of the peer lists" $ do | ||
166 | BE.decode "d8:intervali0e\ | ||
167 | \5:peers0:\ | ||
168 | \6:peers6le\ | ||
169 | \e" | ||
170 | `shouldBe` (Left | ||
171 | "PeerList: the `peers6' field value should contain \ | ||
172 | \*compact* peer list" :: BE.Result AnnounceInfo) | ||
173 | |||
174 | BE.decode "d8:intervali0e\ | ||
175 | \5:peersle\ | ||
176 | \6:peers60:\ | ||
177 | \e" | ||
178 | `shouldBe` (Left | ||
179 | "PeerList: non-compact peer list provided, \ | ||
180 | \but the `peers6' field present" :: BE.Result AnnounceInfo) | ||
181 | |||
182 | it "properly bencoded (iso)" $ property $ \ info -> | ||
183 | BE.decode (BL.toStrict (BE.encode info)) | ||
184 | `shouldBe` Right (info :: AnnounceInfo) | ||
137 | 185 | ||
138 | describe "Scrape" $ do | 186 | describe "Scrape" $ do |
139 | return () | 187 | return () |
diff --git a/tests/Network/BitTorrent/Tracker/RPC/HTTPSpec.hs b/tests/Network/BitTorrent/Tracker/RPC/HTTPSpec.hs index 37029b75..eb549516 100644 --- a/tests/Network/BitTorrent/Tracker/RPC/HTTPSpec.hs +++ b/tests/Network/BitTorrent/Tracker/RPC/HTTPSpec.hs | |||
@@ -1,7 +1,6 @@ | |||
1 | module Network.BitTorrent.Tracker.RPC.HTTPSpec (spec, trackerURIs) where | 1 | module Network.BitTorrent.Tracker.RPC.HTTPSpec (spec, trackerURIs) where |
2 | 2 | ||
3 | import Control.Monad | 3 | import Control.Monad |
4 | import Control.Monad.Trans | ||
5 | import Control.Monad.Trans.Resource | 4 | import Control.Monad.Trans.Resource |
6 | import Data.Default | 5 | import Data.Default |
7 | import Data.List as L | 6 | import Data.List as L |