Added PandocHttpException, trap exceptions in fetching from URLs.

Closes #3646.
This commit is contained in:
John MacFarlane 2017-05-07 13:11:04 +02:00
parent d414b2543a
commit 99be906101
4 changed files with 26 additions and 9 deletions

View file

@ -376,7 +376,7 @@ convertWithOpts opts = do
then 0 then 0
else optTabStop opts) else optTabStop opts)
readSources :: (Functor m, MonadIO m) => [FilePath] -> m String readSources :: [FilePath] -> PandocIO String
readSources srcs = convertTabs . intercalate "\n" <$> readSources srcs = convertTabs . intercalate "\n" <$>
mapM readSource srcs mapM readSource srcs
@ -751,6 +751,11 @@ fillMedia sourceURL d = walkM handleImage d
"replacing image with description" "replacing image with description"
-- emit alt text -- emit alt text
return $ Span ("",["image"],[]) lab return $ Span ("",["image"],[]) lab
PandocHttpError u er -> do
report $ CouldNotFetchResource u
(show er ++ "\rReplacing image with description.")
-- emit alt text
return $ Span ("",["image"],[]) lab
_ -> throwError e) _ -> throwError e)
handleImage x = return x handleImage x = return x
@ -800,7 +805,7 @@ applyFilters mbDatadir filters args d = do
expandedFilters <- mapM (expandFilterPath mbDatadir) filters expandedFilters <- mapM (expandFilterPath mbDatadir) filters
foldrM ($) d $ map (flip externalFilter args) expandedFilters foldrM ($) d $ map (flip externalFilter args) expandedFilters
readSource :: MonadIO m => FilePath -> m String readSource :: FilePath -> PandocIO String
readSource "-" = liftIO UTF8.getContents readSource "-" = liftIO UTF8.getContents
readSource src = case parseURI src of readSource src = case parseURI src of
Just u | uriScheme u `elem` ["http:","https:"] -> Just u | uriScheme u `elem` ["http:","https:"] ->
@ -809,8 +814,12 @@ readSource src = case parseURI src of
liftIO $ UTF8.readFile (uriPath u) liftIO $ UTF8.readFile (uriPath u)
_ -> liftIO $ UTF8.readFile src _ -> liftIO $ UTF8.readFile src
readURI :: MonadIO m => FilePath -> m String readURI :: FilePath -> PandocIO String
readURI src = liftIO $ (UTF8.toString . fst) <$> openURL src readURI src = do
res <- liftIO $ openURL src
case res of
Left e -> throwError $ PandocHttpError src e
Right (contents, _) -> return $ UTF8.toString contents
readFile' :: MonadIO m => FilePath -> m B.ByteString readFile' :: MonadIO m => FilePath -> m B.ByteString
readFile' "-" = liftIO B.getContents readFile' "-" = liftIO B.getContents

View file

@ -242,7 +242,10 @@ instance PandocMonad PandocIO where
newUniqueHash = hashUnique <$> (liftIO IO.newUnique) newUniqueHash = hashUnique <$> (liftIO IO.newUnique)
openURL u = do openURL u = do
report $ Fetching u report $ Fetching u
liftIOError IO.openURL u res <- liftIO (IO.openURL u)
case res of
Right r -> return r
Left e -> throwError $ PandocHttpError u e
readFileLazy s = liftIOError BL.readFile s readFileLazy s = liftIOError BL.readFile s
readFileStrict s = liftIOError B.readFile s readFileStrict s = liftIOError B.readFile s
readDataFile mfp fname = liftIOError (IO.readDataFile mfp) fname readDataFile mfp fname = liftIOError (IO.readDataFile mfp) fname

View file

@ -42,10 +42,12 @@ import Text.Parsec.Pos hiding (Line)
import qualified Text.Pandoc.UTF8 as UTF8 import qualified Text.Pandoc.UTF8 as UTF8
import System.Exit (exitWith, ExitCode(..)) import System.Exit (exitWith, ExitCode(..))
import System.IO (stderr) import System.IO (stderr)
import Network.HTTP.Client (HttpException)
type Input = String type Input = String
data PandocError = PandocIOError String IOError data PandocError = PandocIOError String IOError
| PandocHttpError String HttpException
| PandocShouldNeverHappenError String | PandocShouldNeverHappenError String
| PandocSomeError String | PandocSomeError String
| PandocParseError String | PandocParseError String
@ -70,6 +72,8 @@ handleError (Right r) = return r
handleError (Left e) = handleError (Left e) =
case e of case e of
PandocIOError _ err' -> ioError err' PandocIOError _ err' -> ioError err'
PandocHttpError u err' -> err 61 $
"Could not fetch " ++ u ++ "\n" ++ show err'
PandocShouldNeverHappenError s -> err 62 s PandocShouldNeverHappenError s -> err 62 s
PandocSomeError s -> err 63 s PandocSomeError s -> err 63 s
PandocParseError s -> err 64 s PandocParseError s -> err 64 s

View file

@ -141,7 +141,8 @@ import Text.Pandoc.Data (dataFiles)
import Paths_pandoc (getDataFileName) import Paths_pandoc (getDataFileName)
#endif #endif
import Network.HTTP.Client (httpLbs, responseBody, responseHeaders, import Network.HTTP.Client (httpLbs, responseBody, responseHeaders,
Request(port,host,requestHeaders)) Request(port,host,requestHeaders),
HttpException)
import Network.HTTP.Client (parseRequest) import Network.HTTP.Client (parseRequest)
import Network.HTTP.Client (newManager) import Network.HTTP.Client (newManager)
import Network.HTTP.Client.Internal (addProxy) import Network.HTTP.Client.Internal (addProxy)
@ -702,13 +703,13 @@ readDataFileUTF8 userDir fname =
UTF8.toString `fmap` readDataFile userDir fname UTF8.toString `fmap` readDataFile userDir fname
-- | Read from a URL and return raw data and maybe mime type. -- | Read from a URL and return raw data and maybe mime type.
openURL :: String -> IO (BS.ByteString, Maybe MimeType) openURL :: String -> IO (Either HttpException (BS.ByteString, Maybe MimeType))
openURL u openURL u
| Just u'' <- stripPrefix "data:" u = | Just u'' <- stripPrefix "data:" u =
let mime = takeWhile (/=',') u'' let mime = takeWhile (/=',') u''
contents = B8.pack $ unEscapeString $ drop 1 $ dropWhile (/=',') u'' contents = B8.pack $ unEscapeString $ drop 1 $ dropWhile (/=',') u''
in return (decodeLenient contents, Just mime) in return $ Right (decodeLenient contents, Just mime)
| otherwise = withSocketsDo $ do | otherwise = E.try $ withSocketsDo $ do
let parseReq = parseRequest let parseReq = parseRequest
(proxy :: Either IOError String) <- (proxy :: Either IOError String) <-
tryIOError $ getEnv "http_proxy" tryIOError $ getEnv "http_proxy"