add back support for following http to ftp redirects
Did not test build with http-client < 0.5 and while I tried to support it, the ifdefed parts may needs some fixes.
This commit is contained in:
parent
67c06f5121
commit
6136e299a2
3 changed files with 68 additions and 16 deletions
|
@ -55,6 +55,7 @@ import Control.Exception (throwIO)
|
||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource
|
||||||
import Network.HTTP.Conduit
|
import Network.HTTP.Conduit
|
||||||
import Network.HTTP.Client
|
import Network.HTTP.Client
|
||||||
|
import Network.HTTP.Simple (getResponseHeader)
|
||||||
import Network.Socket
|
import Network.Socket
|
||||||
import Network.BSD (getProtocolNumber)
|
import Network.BSD (getProtocolNumber)
|
||||||
import Data.Either
|
import Data.Either
|
||||||
|
@ -208,19 +209,25 @@ getUrlInfo :: URLString -> UrlOptions -> IO UrlInfo
|
||||||
getUrlInfo url uo = case parseURIRelaxed url of
|
getUrlInfo url uo = case parseURIRelaxed url of
|
||||||
Just u -> checkPolicy uo u dne warnError $
|
Just u -> checkPolicy uo u dne warnError $
|
||||||
case (urlDownloader uo, parseUrlRequest (show u)) of
|
case (urlDownloader uo, parseUrlRequest (show u)) of
|
||||||
(DownloadWithConduit _, Just req) ->
|
(DownloadWithConduit (DownloadWithCurlRestricted r), Just req) -> catchJust
|
||||||
existsconduit req
|
-- When http redirects to a protocol which
|
||||||
|
-- conduit does not support, it will throw
|
||||||
|
-- a StatusCodeException with found302
|
||||||
|
-- and a Response with the redir Location.
|
||||||
|
(matchStatusCodeException (== found302))
|
||||||
|
(existsconduit req)
|
||||||
|
(followredir r)
|
||||||
`catchNonAsync` (const $ return dne)
|
`catchNonAsync` (const $ return dne)
|
||||||
(DownloadWithConduit (DownloadWithCurlRestricted r), Nothing)
|
(DownloadWithConduit (DownloadWithCurlRestricted r), Nothing)
|
||||||
| isfileurl u -> existsfile u
|
| isfileurl u -> existsfile u
|
||||||
| isftpurl u -> existscurlrestricted r u 21
|
| isftpurl u -> existscurlrestricted r u url ftpport
|
||||||
`catchNonAsync` (const $ return dne)
|
`catchNonAsync` (const $ return dne)
|
||||||
| otherwise -> do
|
| otherwise -> do
|
||||||
unsupportedUrlScheme u warnError
|
unsupportedUrlScheme u warnError
|
||||||
return dne
|
return dne
|
||||||
(DownloadWithCurl _, _)
|
(DownloadWithCurl _, _)
|
||||||
| isfileurl u -> existsfile u
|
| isfileurl u -> existsfile u
|
||||||
| otherwise -> existscurl u basecurlparams
|
| otherwise -> existscurl u (basecurlparams url)
|
||||||
Nothing -> return dne
|
Nothing -> return dne
|
||||||
where
|
where
|
||||||
dne = UrlInfo False Nothing Nothing
|
dne = UrlInfo False Nothing Nothing
|
||||||
|
@ -229,10 +236,12 @@ getUrlInfo url uo = case parseURIRelaxed url of
|
||||||
isfileurl u = uriScheme u == "file:"
|
isfileurl u = uriScheme u == "file:"
|
||||||
isftpurl u = uriScheme u == "ftp:"
|
isftpurl u = uriScheme u == "ftp:"
|
||||||
|
|
||||||
basecurlparams = curlParams uo $
|
ftpport = 21
|
||||||
|
|
||||||
|
basecurlparams u = curlParams uo $
|
||||||
[ Param "-s"
|
[ Param "-s"
|
||||||
, Param "--head"
|
, Param "--head"
|
||||||
, Param "-L", Param url
|
, Param "-L", Param u
|
||||||
, Param "-w", Param "%{http_code}"
|
, Param "-w", Param "%{http_code}"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -278,8 +287,8 @@ getUrlInfo url uo = case parseURIRelaxed url of
|
||||||
_ | isftp && isJust len -> good
|
_ | isftp && isJust len -> good
|
||||||
_ -> return dne
|
_ -> return dne
|
||||||
|
|
||||||
existscurlrestricted r u defport = existscurl u
|
existscurlrestricted r u url defport = existscurl u
|
||||||
=<< curlRestrictedParams r u defport basecurlparams
|
=<< curlRestrictedParams r u defport (basecurlparams url)
|
||||||
|
|
||||||
existsfile u = do
|
existsfile u = do
|
||||||
let f = unEscapeString (uriPath u)
|
let f = unEscapeString (uriPath u)
|
||||||
|
@ -289,6 +298,22 @@ getUrlInfo url uo = case parseURIRelaxed url of
|
||||||
sz <- getFileSize' f stat
|
sz <- getFileSize' f stat
|
||||||
found (Just sz) Nothing
|
found (Just sz) Nothing
|
||||||
Nothing -> return dne
|
Nothing -> return dne
|
||||||
|
#if MIN_VERSION_http_client(0,5,0)
|
||||||
|
followredir r (HttpExceptionRequest _ (StatusCodeException resp _)) =
|
||||||
|
case headMaybe $ map decodeBS $ getResponseHeader hLocation resp of
|
||||||
|
#else
|
||||||
|
followredir r (StatusCodeException _ respheaders _) =
|
||||||
|
case headMaybe $ map (decodeBS . snd) $ filter (\(h, _) -> h == hLocation) respheaders
|
||||||
|
#endif
|
||||||
|
Just url' -> case parseURIRelaxed url' of
|
||||||
|
-- only follow http to ftp redirects;
|
||||||
|
-- http to file redirect would not be secure,
|
||||||
|
-- and http-conduit follows http to http.
|
||||||
|
Just u' | isftpurl u' ->
|
||||||
|
checkPolicy uo u' dne warnError $
|
||||||
|
existscurlrestricted r u' url' ftpport
|
||||||
|
_ -> return dne
|
||||||
|
Nothing -> return dne
|
||||||
|
|
||||||
-- Parse eg: attachment; filename="fname.ext"
|
-- Parse eg: attachment; filename="fname.ext"
|
||||||
-- per RFC 2616
|
-- per RFC 2616
|
||||||
|
@ -327,16 +352,18 @@ download' noerror meterupdate url file uo =
|
||||||
go = case parseURIRelaxed url of
|
go = case parseURIRelaxed url of
|
||||||
Just u -> checkPolicy uo u False dlfailed $
|
Just u -> checkPolicy uo u False dlfailed $
|
||||||
case (urlDownloader uo, parseUrlRequest (show u)) of
|
case (urlDownloader uo, parseUrlRequest (show u)) of
|
||||||
(DownloadWithConduit _, Just req) ->
|
(DownloadWithConduit (DownloadWithCurlRestricted r), Just req) -> catchJust
|
||||||
downloadconduit req
|
(matchStatusCodeException (== found302))
|
||||||
|
(downloadconduit req)
|
||||||
|
(followredir r)
|
||||||
(DownloadWithConduit (DownloadWithCurlRestricted r), Nothing)
|
(DownloadWithConduit (DownloadWithCurlRestricted r), Nothing)
|
||||||
| isfileurl u -> downloadfile u
|
| isfileurl u -> downloadfile u
|
||||||
| isftpurl u -> downloadcurlrestricted r u 21
|
| isftpurl u -> downloadcurlrestricted r u url ftpport
|
||||||
`catchNonAsync` (dlfailed . show)
|
`catchNonAsync` (dlfailed . show)
|
||||||
| otherwise -> unsupportedUrlScheme u dlfailed
|
| otherwise -> unsupportedUrlScheme u dlfailed
|
||||||
(DownloadWithCurl _, _)
|
(DownloadWithCurl _, _)
|
||||||
| isfileurl u -> downloadfile u
|
| isfileurl u -> downloadfile u
|
||||||
| otherwise -> downloadcurl basecurlparams
|
| otherwise -> downloadcurl url basecurlparams
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
liftIO $ debugM "url" url
|
liftIO $ debugM "url" url
|
||||||
dlfailed "invalid url"
|
dlfailed "invalid url"
|
||||||
|
@ -344,6 +371,8 @@ download' noerror meterupdate url file uo =
|
||||||
isfileurl u = uriScheme u == "file:"
|
isfileurl u = uriScheme u == "file:"
|
||||||
isftpurl u = uriScheme u == "ftp:"
|
isftpurl u = uriScheme u == "ftp:"
|
||||||
|
|
||||||
|
ftpport = 21
|
||||||
|
|
||||||
downloadconduit req = catchMaybeIO (getFileSize file) >>= \case
|
downloadconduit req = catchMaybeIO (getFileSize file) >>= \case
|
||||||
Nothing -> runResourceT $ do
|
Nothing -> runResourceT $ do
|
||||||
liftIO $ debugM "url" (show req')
|
liftIO $ debugM "url" (show req')
|
||||||
|
@ -434,15 +463,15 @@ download' noerror meterupdate url file uo =
|
||||||
, Param "-C", Param "-"
|
, Param "-C", Param "-"
|
||||||
]
|
]
|
||||||
|
|
||||||
downloadcurl curlparams = do
|
downloadcurl rawurl curlparams = do
|
||||||
-- curl does not create destination file
|
-- curl does not create destination file
|
||||||
-- if the url happens to be empty, so pre-create.
|
-- if the url happens to be empty, so pre-create.
|
||||||
unlessM (doesFileExist file) $
|
unlessM (doesFileExist file) $
|
||||||
writeFile file ""
|
writeFile file ""
|
||||||
boolSystem "curl" (curlparams ++ [Param "-o", File file, File url])
|
boolSystem "curl" (curlparams ++ [Param "-o", File file, File rawurl])
|
||||||
|
|
||||||
downloadcurlrestricted r u defport =
|
downloadcurlrestricted r u rawurl defport =
|
||||||
downloadcurl =<< curlRestrictedParams r u defport basecurlparams
|
downloadcurl rawurl =<< curlRestrictedParams r u defport basecurlparams
|
||||||
|
|
||||||
downloadfile u = do
|
downloadfile u = do
|
||||||
let src = unEscapeString (uriPath u)
|
let src = unEscapeString (uriPath u)
|
||||||
|
@ -450,6 +479,20 @@ download' noerror meterupdate url file uo =
|
||||||
L.writeFile file
|
L.writeFile file
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
#if MIN_VERSION_http_client(0,5,0)
|
||||||
|
followredir r ex@(HttpExceptionRequest _ (StatusCodeException resp _)) =
|
||||||
|
case headMaybe $ map decodeBS $ getResponseHeader hLocation resp of
|
||||||
|
#else
|
||||||
|
followredir r ex@(StatusCodeException _ respheaders _) =
|
||||||
|
case headMaybe $ map (decodeBS . snd) $ filter (\(h, _) -> h == hLocation) respheaders
|
||||||
|
#endif
|
||||||
|
Just url' -> case parseURIRelaxed url' of
|
||||||
|
Just u' | isftpurl u' ->
|
||||||
|
checkPolicy uo u' False dlfailed $
|
||||||
|
downloadcurlrestricted r u' url' ftpport
|
||||||
|
_ -> throwIO ex
|
||||||
|
Nothing -> throwIO ex
|
||||||
|
|
||||||
{- Sinks a Response's body to a file. The file can either be opened in
|
{- Sinks a Response's body to a file. The file can either be opened in
|
||||||
- WriteMode or AppendMode. Updates the meter as data is received.
|
- WriteMode or AppendMode. Updates the meter as data is received.
|
||||||
-
|
-
|
||||||
|
|
|
@ -66,3 +66,5 @@ local repository version: 5
|
||||||
Originally [reported in DataLad #3321](https://github.com/datalad/datalad/issues/3321) with workarounds to force `curl` downloads
|
Originally [reported in DataLad #3321](https://github.com/datalad/datalad/issues/3321) with workarounds to force `curl` downloads
|
||||||
|
|
||||||
[[!meta author=yoh]]
|
[[!meta author=yoh]]
|
||||||
|
|
||||||
|
> [[fixed|done]] --[[Joey]]
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
[[!comment format=mdwn
|
||||||
|
username="joey"
|
||||||
|
subject="""comment 7"""
|
||||||
|
date="2019-05-30T20:03:28Z"
|
||||||
|
content="""
|
||||||
|
All fixed now.
|
||||||
|
"""]]
|
Loading…
Reference in a new issue