{-# LANGUAGE CPP #-}------------------------------------------------------------------------------- |-- Module : Network.HTTP.Proxy-- Copyright : See LICENSE file-- License : BSD---- Maintainer : Ganesh Sittampalam <ganesh@earth.li>-- Stability : experimental-- Portability : non-portable (not tested)---- Handling proxy server settings and their resolution.-------------------------------------------------------------------------------moduleNetwork.HTTP.Proxy(Proxy (..),noProxy -- :: Proxy,fetchProxy -- :: Bool -> IO Proxy,parseProxy -- :: String -> Maybe Proxy)where{-
#if !defined(WIN32) && defined(mingw32_HOST_OS)
#define WIN32 1
#endif
-}importControl.Monad(when,mplus,join,liftM2)
#if defined(WIN32)
importNetwork.HTTP.Base(catchIO)importControl.Monad(liftM)importData.List(isPrefixOf)
#endif
importNetwork.HTTP.Utils (dropWhileTail ,chopAtDelim )importNetwork.HTTP.Auth importNetwork.URI(URI(..),URIAuth(..),parseAbsoluteURI,unEscapeString)importSystem.IO(hPutStrLn,stderr)importSystem.Environment{-
#if !defined(WIN32) && defined(mingw32_HOST_OS)
#define WIN32 1
#endif
-}
#if defined(WIN32)
importSystem.Win32.Types(DWORD,HKEY)importSystem.Win32.Registry(hKEY_CURRENT_USER,regOpenKey,regCloseKey,regQueryValueEx)importControl.Exception(bracket)importForeign(toBool,Storable(peek,sizeOf),castPtr,alloca)
#if MIN_VERSION_Win32(2,8,0)
importSystem.Win32.Registry(regQueryDefaultValue)
#else
importSystem.Win32.Registry(regQueryValue)
#endif
#endif
-- | HTTP proxies (or not) are represented via 'Proxy', specifying if a-- proxy should be used for the request (see 'Network.Browser.setProxy')dataProxy =NoProxy -- ^ Don't use a proxy.|Proxy String(MaybeAuthority )-- ^ Use the proxy given. Should be of the-- form "http:\/\/host:port", "host", "host:port", or "http:\/\/host".-- Additionally, an optional 'Authority' for authentication with the proxy.noProxy ::Proxy noProxy :: Proxy
noProxy =Proxy
NoProxy -- | @envProxyString@ locates proxy server settings by looking-- up env variable @HTTP_PROXY@ (or its lower-case equivalent.)-- If no mapping found, returns @Nothing@.envProxyString ::IO(MaybeString)envProxyString :: IO (Maybe String)
envProxyString =do[(String, String)]
env <-IO [(String, String)]
getEnvironmentMaybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return(String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookupString
"http_proxy"[(String, String)]
env Maybe String -> Maybe String -> Maybe String
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus`String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookupString
"HTTP_PROXY"[(String, String)]
env )-- | @proxyString@ tries to locate the user's proxy server setting.-- Consults environment variable, and in case of Windows, by querying-- the Registry (cf. @registryProxyString@.)proxyString ::IO(MaybeString)proxyString :: IO (Maybe String)
proxyString =(Maybe String -> Maybe String -> Maybe String)
-> IO (Maybe String) -> IO (Maybe String) -> IO (Maybe String)
forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2Maybe String -> Maybe String -> Maybe String
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
mplusIO (Maybe String)
envProxyString IO (Maybe String)
windowsProxyString windowsProxyString ::IO(MaybeString)
#if !defined(WIN32)
windowsProxyString :: IO (Maybe String)
windowsProxyString =Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
returnMaybe String
forall a. Maybe a
Nothing
#else
windowsProxyString=liftM(>>=parseWindowsProxy)registryProxyStringregistryProxyLoc::(HKEY,String)registryProxyLoc=(hive,path)where-- some sources say proxy settings should be at-- HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows-- \CurrentVersion\Internet Settings\ProxyServer-- but if the user sets them with IE connection panel they seem to-- end up in the following place:hive=hKEY_CURRENT_USERpath="Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"-- read proxy settings from the windows registry; this is just a best-- effort and may not work on all setups.registryProxyString::IO(MaybeString)registryProxyString=catchIO(bracket(uncurryregOpenKeyregistryProxyLoc)regCloseKey$\hkey->doenable<-fmaptoBool$regQueryValueDWORDhkey"ProxyEnable"ifenable
#if MIN_VERSION_Win32(2,8,0)
thenfmapJust$regQueryDefaultValuehkey"ProxyServer"
#elif MIN_VERSION_Win32(2,6,0)
thenfmapJust$regQueryValuehkey"ProxyServer"
#else
thenfmapJust$regQueryValuehkey(Just"ProxyServer")
#endif
elsereturnNothing)(\_->returnNothing)-- the proxy string is in the format "http=x.x.x.x:yyyy;https=...;ftp=...;socks=..."-- even though the following article indicates otherwise-- https://support.microsoft.com/en-us/kb/819961---- to be sure, parse strings where each entry in the ';'-separated list above is-- either in the format "protocol=..." or "protocol://..."---- only return the first "http" of them, if it existsparseWindowsProxy::String->MaybeStringparseWindowsProxys=caseproxiesofx:_->Justx_->Nothingwhereparts=split';'sprx=casebreak(=='=')xof(p,[])->p-- might be in format http://(p,u)->p++"://"++drop1uproxies=filter(isPrefixOf"http://").mappr$partssplit::Eqa=>a->[a]->[[a]]split_[]=[]splitaxs=casebreak(a==)xsof(ys,[])->[ys](ys,_:zs)->ys:splitazs
#endif
-- | @fetchProxy flg@ gets the local proxy settings and parse the string-- into a @Proxy@ value. If you want to be informed of ill-formed proxy-- configuration strings, supply @True@ for @flg@.-- Proxy settings are sourced from the @HTTP_PROXY@ environment variable,-- and in the case of Windows platforms, by consulting IE/WinInet's proxy-- setting in the Registry.fetchProxy ::Bool->IOProxy fetchProxy :: Bool -> IO Proxy
fetchProxy Bool
warnIfIllformed =doMaybe String
mstr <-IO (Maybe String)
proxyString caseMaybe String
mstr ofMaybe String
Nothing->Proxy -> IO Proxy
forall (m :: * -> *) a. Monad m => a -> m a
returnProxy
NoProxy JustString
str ->caseString -> Maybe Proxy
parseProxy String
str ofJustProxy
p ->Proxy -> IO Proxy
forall (m :: * -> *) a. Monad m => a -> m a
returnProxy
p Maybe Proxy
Nothing->doBool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenBool
warnIfIllformed (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$Handle -> String -> IO ()
System.IO.hPutStrLnHandle
System.IO.stderr(String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$[String] -> String
unlines[String
"invalid http proxy uri: "String -> String -> String
forall a. [a] -> [a] -> [a]
++String -> String
forall a. Show a => a -> String
showString
str ,String
"proxy uri must be http with a hostname",String
"ignoring http proxy, trying a direct connection"]Proxy -> IO Proxy
forall (m :: * -> *) a. Monad m => a -> m a
returnProxy
NoProxy -- | @parseProxy str@ translates a proxy server string into a @Proxy@ value;-- returns @Nothing@ if not well-formed.parseProxy ::String->MaybeProxy parseProxy :: String -> Maybe Proxy
parseProxy String
""=Maybe Proxy
forall a. Maybe a
NothingparseProxy String
str =Maybe (Maybe Proxy) -> Maybe Proxy
forall (m :: * -> *) a. Monad m => m (m a) -> m a
join(Maybe (Maybe Proxy) -> Maybe Proxy)
-> (Maybe URI -> Maybe (Maybe Proxy)) -> Maybe URI -> Maybe Proxy
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(URI -> Maybe Proxy) -> Maybe URI -> Maybe (Maybe Proxy)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmapURI -> Maybe Proxy
uri2proxy (Maybe URI -> Maybe Proxy) -> Maybe URI -> Maybe Proxy
forall a b. (a -> b) -> a -> b
$String -> Maybe URI
parseHttpURI String
str Maybe URI -> Maybe URI -> Maybe URI
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus`String -> Maybe URI
parseHttpURI (String
"http://"String -> String -> String
forall a. [a] -> [a] -> [a]
++String
str )whereparseHttpURI :: String -> Maybe URI
parseHttpURI String
str' =caseString -> Maybe URI
parseAbsoluteURIString
str' ofJusturi :: URI
uri @URI{uriAuthority :: URI -> Maybe URIAuth
uriAuthority=Just{}}->URI -> Maybe URI
forall a. a -> Maybe a
Just(URI -> URI
fixUserInfo URI
uri )Maybe URI
_->Maybe URI
forall a. Maybe a
Nothing-- Note: we need to be able to parse non-URIs like @\"wwwcache.example.com:80\"@-- which lack the @\"http://\"@ URI scheme. The problem is that-- @\"wwwcache.example.com:80\"@ is in fact a valid URI but with scheme-- @\"wwwcache.example.com:\"@, no authority part and a path of @\"80\"@.---- So our strategy is to try parsing as normal uri first and if it lacks the-- 'uriAuthority' then we try parsing again with a @\"http://\"@ prefix.---- | tidy up user portion, don't want the trailing "\@".fixUserInfo ::URI->URIfixUserInfo :: URI -> URI
fixUserInfo URI
uri =URI
uri {uriAuthority :: Maybe URIAuth
uriAuthority=URIAuth -> URIAuth
f (URIAuth -> URIAuth) -> Maybe URIAuth -> Maybe URIAuth
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap`URI -> Maybe URIAuth
uriAuthorityURI
uri }wheref :: URIAuth -> URIAuth
f a :: URIAuth
a @URIAuth{uriUserInfo :: URIAuth -> String
uriUserInfo=String
s }=URIAuth
a {uriUserInfo :: String
uriUserInfo=(Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhileTail (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
'@')String
s }--uri2proxy ::URI->MaybeProxy uri2proxy :: URI -> Maybe Proxy
uri2proxy uri :: URI
uri @URI{uriScheme :: URI -> String
uriScheme=String
"http:",uriAuthority :: URI -> Maybe URIAuth
uriAuthority=Just(URIAuthString
auth' String
hst String
prt )}=Proxy -> Maybe Proxy
forall a. a -> Maybe a
Just(String -> Maybe Authority -> Proxy
Proxy (String
hst String -> String -> String
forall a. [a] -> [a] -> [a]
++String
prt )Maybe Authority
auth )whereauth :: Maybe Authority
auth =caseString
auth' of[]->Maybe Authority
forall a. Maybe a
NothingString
as ->Authority -> Maybe Authority
forall a. a -> Maybe a
Just(String -> String -> String -> URI -> Authority
AuthBasic String
""(String -> String
unEscapeStringString
usr )(String -> String
unEscapeStringString
pwd )URI
uri )where(String
usr ,String
pwd )=Char -> String -> (String, String)
forall a. Eq a => a -> [a] -> ([a], [a])
chopAtDelim Char
':'String
as uri2proxy URI
_=Maybe Proxy
forall a. Maybe a
Nothing-- utilities
#if defined(WIN32)
regQueryValueDWORD::HKEY->String->IODWORDregQueryValueDWORDhkeyname=alloca$\ptr->do-- TODO: this throws away the key type returned by regQueryValueEx-- we should check it's what we expect instead_<-regQueryValueExhkeyname(castPtrptr)(sizeOf(undefined::DWORD))peekptr
#endif

AltStyle によって変換されたページ (->オリジナル) /