diff options
-rw-r--r-- | src/Network/BitTorrent/Core/Fingerprint.hs | 7 | ||||
-rw-r--r-- | src/Network/BitTorrent/Tracker/RPC.hs | 1 | ||||
-rw-r--r-- | src/Network/BitTorrent/Tracker/RPC/HTTP.hs | 34 |
3 files changed, 31 insertions, 11 deletions
diff --git a/src/Network/BitTorrent/Core/Fingerprint.hs b/src/Network/BitTorrent/Core/Fingerprint.hs index a81edd8b..d743acd0 100644 --- a/src/Network/BitTorrent/Core/Fingerprint.hs +++ b/src/Network/BitTorrent/Core/Fingerprint.hs | |||
@@ -25,11 +25,13 @@ module Network.BitTorrent.Core.Fingerprint | |||
25 | ( ClientImpl (..) | 25 | ( ClientImpl (..) |
26 | , Fingerprint (..) | 26 | , Fingerprint (..) |
27 | , libFingerprint | 27 | , libFingerprint |
28 | , libUserAgent | ||
28 | ) where | 29 | ) where |
29 | 30 | ||
30 | import Data.Default | 31 | import Data.Default |
31 | import Data.List as L | 32 | import Data.List as L |
32 | import Data.List.Split as L | 33 | import Data.List.Split as L |
34 | import Data.Monoid | ||
33 | import Data.String | 35 | import Data.String |
34 | import Data.Version | 36 | import Data.Version |
35 | import Text.PrettyPrint hiding ((<>)) | 37 | import Text.PrettyPrint hiding ((<>)) |
@@ -190,6 +192,11 @@ instance Pretty Fingerprint where | |||
190 | libFingerprint :: Fingerprint | 192 | libFingerprint :: Fingerprint |
191 | libFingerprint = Fingerprint IlibHSbittorrent version | 193 | libFingerprint = Fingerprint IlibHSbittorrent version |
192 | 194 | ||
195 | -- | HTTP user agent of this (the bittorrent library) package. Can be | ||
196 | -- used in HTTP tracker requests. | ||
197 | libUserAgent :: String | ||
198 | libUserAgent = render (pretty IlibHSbittorrent <> "/" <> pretty version) | ||
199 | |||
193 | {----------------------------------------------------------------------- | 200 | {----------------------------------------------------------------------- |
194 | -- For torrent file | 201 | -- For torrent file |
195 | -----------------------------------------------------------------------} | 202 | -----------------------------------------------------------------------} |
diff --git a/src/Network/BitTorrent/Tracker/RPC.hs b/src/Network/BitTorrent/Tracker/RPC.hs index 3fe5157c..45bd62d8 100644 --- a/src/Network/BitTorrent/Tracker/RPC.hs +++ b/src/Network/BitTorrent/Tracker/RPC.hs | |||
@@ -18,6 +18,7 @@ module Network.BitTorrent.Tracker.RPC | |||
18 | , withManager | 18 | , withManager |
19 | 19 | ||
20 | -- * RPC | 20 | -- * RPC |
21 | , SAnnounceQuery (..) | ||
21 | , announce | 22 | , announce |
22 | , scrape | 23 | , scrape |
23 | ) where | 24 | ) where |
diff --git a/src/Network/BitTorrent/Tracker/RPC/HTTP.hs b/src/Network/BitTorrent/Tracker/RPC/HTTP.hs index d30c0e9d..7d69df1a 100644 --- a/src/Network/BitTorrent/Tracker/RPC/HTTP.hs +++ b/src/Network/BitTorrent/Tracker/RPC/HTTP.hs | |||
@@ -31,7 +31,7 @@ import Control.Applicative | |||
31 | import Control.Exception | 31 | import Control.Exception |
32 | import Control.Monad.Trans.Resource | 32 | import Control.Monad.Trans.Resource |
33 | import Data.BEncode as BE | 33 | import Data.BEncode as BE |
34 | import Data.ByteString as B | 34 | import Data.ByteString as BS |
35 | import Data.ByteString.Char8 as BC | 35 | import Data.ByteString.Char8 as BC |
36 | import Data.ByteString.Lazy as BL | 36 | import Data.ByteString.Lazy as BL |
37 | import Data.Default | 37 | import Data.Default |
@@ -42,9 +42,11 @@ import Network.HTTP.Conduit hiding | |||
42 | (Manager, newManager, closeManager, withManager) | 42 | (Manager, newManager, closeManager, withManager) |
43 | import qualified Network.HTTP.Conduit as HTTP | 43 | import qualified Network.HTTP.Conduit as HTTP |
44 | import Network.HTTP.Conduit.Internal (setUri) | 44 | import Network.HTTP.Conduit.Internal (setUri) |
45 | import Network.HTTP.Types.URI | 45 | import Network.HTTP.Types.Header (hUserAgent) |
46 | import Network.HTTP.Types.URI (SimpleQuery, renderSimpleQuery) | ||
46 | 47 | ||
47 | import Data.Torrent.InfoHash | 48 | import Data.Torrent.InfoHash (InfoHash) |
49 | import Network.BitTorrent.Core.Fingerprint (libUserAgent) | ||
48 | import Network.BitTorrent.Tracker.Message | 50 | import Network.BitTorrent.Tracker.Message |
49 | 51 | ||
50 | {----------------------------------------------------------------------- | 52 | {----------------------------------------------------------------------- |
@@ -59,6 +61,9 @@ data Options = Options | |||
59 | -- | Whether to use HTTP proxy for HTTP tracker requests. | 61 | -- | Whether to use HTTP proxy for HTTP tracker requests. |
60 | , optHttpProxy :: !(Maybe Proxy) | 62 | , optHttpProxy :: !(Maybe Proxy) |
61 | 63 | ||
64 | -- | Value to put in HTTP user agent header. | ||
65 | , optUserAgent :: !BS.ByteString | ||
66 | |||
62 | -- | HTTP manager options. | 67 | -- | HTTP manager options. |
63 | , optHttpOptions :: !ManagerSettings | 68 | , optHttpOptions :: !ManagerSettings |
64 | } | 69 | } |
@@ -67,6 +72,7 @@ instance Default Options where | |||
67 | def = Options | 72 | def = Options |
68 | { optAnnounceExt = def | 73 | { optAnnounceExt = def |
69 | , optHttpProxy = Nothing | 74 | , optHttpProxy = Nothing |
75 | , optUserAgent = BC.pack libUserAgent | ||
70 | , optHttpOptions = def | 76 | , optHttpOptions = def |
71 | } | 77 | } |
72 | 78 | ||
@@ -89,15 +95,21 @@ withManager opts = bracket (newManager opts) closeManager | |||
89 | -- Queries | 95 | -- Queries |
90 | -----------------------------------------------------------------------} | 96 | -----------------------------------------------------------------------} |
91 | 97 | ||
92 | setSimpleQuery :: SimpleQuery -> Request m -> Request m | 98 | fillRequest :: Options -> SimpleQuery -> Request m -> Request m |
93 | setSimpleQuery q r = r | 99 | fillRequest Options {..} q r = r |
94 | { queryString = renderSimpleQuery False q | 100 | { queryString = joinQuery (queryString r) (renderSimpleQuery False q) |
101 | , requestHeaders = (hUserAgent, optUserAgent) : requestHeaders r | ||
102 | , proxy = optHttpProxy | ||
95 | } | 103 | } |
104 | where | ||
105 | joinQuery a b | ||
106 | | BS.null a = b | ||
107 | | otherwise = a <> "&" <> b | ||
96 | 108 | ||
97 | httpTracker :: BEncode a => Manager -> URI -> SimpleQuery -> ResourceT IO a | 109 | httpTracker :: BEncode a => Manager -> URI -> SimpleQuery -> ResourceT IO a |
98 | httpTracker Manager {..} uri q = do | 110 | httpTracker Manager {..} uri q = do |
99 | request <- setSimpleQuery q <$> setUri def uri | 111 | request <- fillRequest options q <$> setUri def uri |
100 | response <- httpLbs request { proxy = optHttpProxy options } httpMgr | 112 | response <- httpLbs request httpMgr |
101 | case BE.decode $ BL.toStrict $ responseBody response of | 113 | case BE.decode $ BL.toStrict $ responseBody response of |
102 | Left msg -> error $ "httpTracker: " ++ msg | 114 | Left msg -> error $ "httpTracker: " ++ msg |
103 | Right info -> return info | 115 | Right info -> return info |
@@ -127,9 +139,9 @@ scrapeURL uri = do | |||
127 | where | 139 | where |
128 | replace p | 140 | replace p |
129 | | ps <- BC.splitWith (== '/') p | 141 | | ps <- BC.splitWith (== '/') p |
130 | , "announce" `B.isPrefixOf` L.last ps | 142 | , "announce" `BS.isPrefixOf` L.last ps |
131 | = let newSuff = "scrape" <> B.drop (B.length "announce") (L.last ps) | 143 | = let newSuff = "scrape" <> BS.drop (BS.length "announce") (L.last ps) |
132 | in Just (B.intercalate "/" (L.init ps ++ [newSuff])) | 144 | in Just (BS.intercalate "/" (L.init ps ++ [newSuff])) |
133 | | otherwise = Nothing | 145 | | otherwise = Nothing |
134 | 146 | ||
135 | -- | For each 'InfoHash' of torrents request scrape info from the tracker. | 147 | -- | For each 'InfoHash' of torrents request scrape info from the tracker. |