Skip to content

Commit

Permalink
parseRequest/parseRequest_/defaultRequest, deprecate parseUrl #193
Browse files Browse the repository at this point in the history
  • Loading branch information
snoyberg committed Jun 21, 2016
1 parent b2cdd0a commit 573a28a
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 70 deletions.
6 changes: 6 additions & 0 deletions http-client/ChangeLog.md
@@ -1,3 +1,9 @@
## 0.4.30

* Initial implementation of [#193](https://github.com/snoyberg/http-client/issues/193)
* Deprecate `parseUrl`
* Add `parseUrlThrow`, `parseRequest`, and `parseRequest_`

## 0.4.29

* Changed the order of connecting a socket and tweaking a socket, such that the socket tweaking callback now happen before connecting.
Expand Down
13 changes: 9 additions & 4 deletions http-client/Network/HTTP/Client.hs
Expand Up @@ -49,7 +49,7 @@
-- The next core component is a 'Request', which represents a single HTTP
-- request to be sent to a specific server. 'Request's allow for many settings
-- to control exact how they function, but usually the simplest approach for
-- creating a 'Request' is to use 'parseUrl'.
-- creating a 'Request' is to use 'parseRequest'.
--
-- Finally, a 'Response' is the result of sending a single 'Request' to a
-- server, over a connection which was acquired from a 'Manager'. Note that you
Expand All @@ -70,7 +70,7 @@
-- 'applyBasicAuth' are guaranteed to be total (or there\'s a bug in the
-- library).
--
-- One thing to be cautioned about: the type of 'parseUrl' allows it to work in
-- One thing to be cautioned about: the type of 'parseRequest' allows it to work in
-- different monads. If used in the 'IO' monad, it will throw an exception in
-- the case of an invalid URI. In addition, if you leverage the @IsString@
-- instance of the 'Request' value via @OverloadedStrings@, an invalid URI will
Expand Down Expand Up @@ -129,6 +129,11 @@ module Network.HTTP.Client
, rawConnectionModifySocket
-- * Request
, parseUrl
, parseUrlThrow
, parseRequest
, parseRequest_
, defaultRequest

, applyBasicAuth
, urlEncodedBody
, getUri
Expand Down Expand Up @@ -296,7 +301,7 @@ managerSetProxy po = managerSetInsecureProxy po . managerSetSecureProxy po
-- > main = do
-- > manager <- newManager defaultManagerSettings
-- >
-- > request <- parseUrl "http://httpbin.org/post"
-- > request <- parseRequest "http://httpbin.org/post"
-- > response <- httpLbs request manager
-- >
-- > putStrLn $ "The status code was: " ++ (show $ statusCode $ responseStatus response)
Expand All @@ -316,7 +321,7 @@ managerSetProxy po = managerSetInsecureProxy po . managerSetSecureProxy po
-- >
-- > -- Create the request
-- > let requestObject = object ["name" .= "Michael", "age" .= 30]
-- > initialRequest <- parseUrl "http://httpbin.org/post"
-- > initialRequest <- parseRequest "http://httpbin.org/post"
-- > let request = initialRequest { method = "POST", requestBody = RequestBodyLBS $ encode requestObject }
-- >
-- > response <- httpLbs request manager
Expand Down
4 changes: 2 additions & 2 deletions http-client/Network/HTTP/Client/MultipartFormData.hs
Expand Up @@ -11,9 +11,9 @@
-- > import Control.Monad
-- >
-- > main = withSocketsDo $ void $ withManager defaultManagerSettings $ \m -> do
-- > req1 <- parseUrl "http://random-cat-photo.net/cat.jpg"
-- > req1 <- parseRequest "http://random-cat-photo.net/cat.jpg"
-- > res <- httpLbs req1 m
-- > req2 <- parseUrl "http://example.org/~friedrich/blog/addPost.hs"
-- > req2 <- parseRequest "http://example.org/~friedrich/blog/addPost.hs"
-- > flip httpLbs m =<<
-- > (formDataBody [partBS "title" "Bleaurgh"
-- > ,partBS "text" $ TE.encodeUtf8 "矢田矢田矢田矢田矢田"
Expand Down
71 changes: 53 additions & 18 deletions http-client/Network/HTTP/Client/Request.hs
Expand Up @@ -8,6 +8,10 @@

module Network.HTTP.Client.Request
( parseUrl
, parseUrlThrow
, parseRequest
, parseRequest_
, defaultRequest
, setUriRelative
, getUri
, setUri
Expand Down Expand Up @@ -67,6 +71,36 @@ import Data.IORef
import System.IO (withBinaryFile, hTell, hFileSize, Handle, IOMode (ReadMode))
import Control.Monad (liftM)

-- | Deprecated synonym for 'parseUrlThrow'. You probably want
-- 'parseRequest' or 'parseRequest_' instead.
--
-- @since 0.1.0
parseUrl :: MonadThrow m => String -> m Request
parseUrl = parseUrlThrow
{-# DEPRECATED parseUrl "Please use parseUrlThrow, parseRequest, or parseRequest_ instead" #-}

-- | Same as 'parseRequest', except will throw an 'HttpException' in
-- the event of a non-2XX response.
--
-- @since 0.4.30
parseUrlThrow :: MonadThrow m => String -> m Request
parseUrlThrow s' =
case parseURI (encode s) of
Just uri -> liftM setMethod (setUri def uri)
Nothing -> throwM $ InvalidUrlException s "Invalid URL"
where
encode = escapeURIString isAllowedInURI
(mmethod, s) =
case break (== ' ') s' of
(x, ' ':y) | all (\c -> 'A' <= c && c <= 'Z') x -> (Just x, y)
_ -> (Nothing, s')

setMethod req =
case mmethod of
Nothing -> req
Just m -> req { method = S8.pack m }


-- | Convert a URL into a 'Request'.
--
-- This defaults some of the values in 'Request', such as setting 'method' to
Expand All @@ -79,28 +113,23 @@ import Control.Monad (liftM)
-- space, e.g.:
--
-- @@@
-- parseUrl "POST http://httpbin.org/post"
-- parseRequeset "POST http://httpbin.org/post"
-- @@@
--
-- Note that the request method must be provided as all capital letters.
--
-- Since 0.1.0
parseUrl :: MonadThrow m => String -> m Request
parseUrl s' =
case parseURI (encode s) of
Just uri -> liftM setMethod (setUri def uri)
Nothing -> throwM $ InvalidUrlException s "Invalid URL"
-- @since 0.4.30
parseRequest :: MonadThrow m => String -> m Request
parseRequest =
liftM noThrow . parseUrlThrow
where
encode = escapeURIString isAllowedInURI
(mmethod, s) =
case break (== ' ') s' of
(x, ' ':y) | all (\c -> 'A' <= c && c <= 'Z') x -> (Just x, y)
_ -> (Nothing, s')
noThrow req = req { checkStatus = \_ _ _ -> Nothing }

setMethod req =
case mmethod of
Nothing -> req
Just m -> req { method = S8.pack m }
-- | Same as 'parseRequest', but in the cases of a parse error
-- generates an impure exception. Mostly useful for static strings which
-- are known to be correctly formatted.
parseRequest_ :: String -> Request
parseRequest_ = either throw id . parseRequest

-- | Add a 'URI' to the request. If it is absolute (includes a host name), add
-- it as per 'setUri'; if it is relative, merge it with the existing request.
Expand Down Expand Up @@ -219,6 +248,12 @@ instance Show Request where
useDefaultTimeout :: Maybe Int
useDefaultTimeout = Just (-3425)

-- | A default request value
--
-- @since 0.4.30
defaultRequest :: Request
defaultRequest = def { checkStatus = \_ _ _ -> Nothing }

instance Default Request where
def = Request
{ host = "localhost"
Expand Down Expand Up @@ -280,7 +315,7 @@ browserDecompress = (/= "application/x-tar")
-- | Add a Basic Auth header (with the specified user name and password) to the
-- given Request. Ignore error handling:
--
-- > applyBasicAuth "user" "pass" $ fromJust $ parseUrl url
-- > applyBasicAuth "user" "pass" $ parseRequest_ url
--
-- Since 0.1.0
applyBasicAuth :: S.ByteString -> S.ByteString -> Request -> Request
Expand All @@ -301,7 +336,7 @@ addProxy hst prt req =
-- | Add a Proxy-Authorization header (with the specified username and
-- password) to the given 'Request'. Ignore error handling:
--
-- > applyBasicProxyAuth "user" "pass" <$> parseUrl "http://example.org"
-- > applyBasicProxyAuth "user" "pass" <$> parseRequest "http://example.org"
--
-- Since 0.3.4

Expand Down
2 changes: 1 addition & 1 deletion http-client/Network/HTTP/Client/Response.hs
Expand Up @@ -33,7 +33,7 @@ import Network.HTTP.Client.Headers
-- a new request from the old request, the server headers returned with the
-- redirection, and the redirection code itself. This function returns 'Nothing'
-- if the code is not a 3xx, there is no 'location' header included, or if the
-- redirected response couldn't be parsed with 'parseUrl'.
-- redirected response couldn't be parsed with 'parseRequest'.
--
-- If a user of this library wants to know the url chain that results from a
-- specific request, that user has to re-implement the redirect-following logic
Expand Down
6 changes: 3 additions & 3 deletions http-client/Network/HTTP/Client/Types.hs
Expand Up @@ -307,17 +307,17 @@ type GivesPopper a = NeedsPopper a -> IO a
-- | All information on how to connect to a host and what should be sent in the
-- HTTP request.
--
-- If you simply wish to download from a URL, see 'parseUrl'.
-- If you simply wish to download from a URL, see 'parseRequest'.
--
-- The constructor for this data type is not exposed. Instead, you should use
-- either the 'def' method to retrieve a default instance, or 'parseUrl' to
-- either the 'defaultRequest' value, or 'parseRequest' to
-- construct from a URL, and then use the records below to make modifications.
-- This approach allows http-client to add configuration options without
-- breaking backwards compatibility.
--
-- For example, to construct a POST request, you could do something like:
--
-- > initReq <- parseUrl "http://www.example.com/path"
-- > initReq <- parseRequest "http://www.example.com/path"
-- > let req = initReq
-- > { method = "POST"
-- > }
Expand Down
5 changes: 1 addition & 4 deletions http-client/bench/threaded-stress.hs
Expand Up @@ -40,10 +40,7 @@ app gen _ = do
return $ W.responseLBS status200 headers body

req :: HC.Request
req =
case HC.parseUrl "http://localhost:4567" of
Nothing -> error "bad request"
Just x -> x
req = HC.parseRequest_ "http://localhost:4567"

client :: HC.Manager -> MWC.GenIO -> Int -> IO String
client man gen threadid = do
Expand Down
2 changes: 1 addition & 1 deletion http-client/http-client.cabal
@@ -1,5 +1,5 @@
name: http-client
version: 0.4.29
version: 0.4.30
synopsis: An HTTP client engine, intended as a base layer for more user-friendly packages.
description: Hackage documentation generation is not reliable. For up to date documentation, please see: <http://www.stackage.org/package/http-client>.
homepage: https://github.com/snoyberg/http-client
Expand Down
2 changes: 1 addition & 1 deletion http-client/publicsuffixlist/Create.hs
Expand Up @@ -23,7 +23,7 @@ import Network.PublicSuffixList.Serialize

generateDataStructure :: String -> IO (DataStructure, UTCTime)
generateDataStructure url = do
req <- HC.parseUrl url
req <- HC.parseRequest url
out <- HC.withManager $ \ manager -> do
res <- HC.http req manager
HC.responseBody res C.$$+- conduitFile "effective_tld_names.dat" C.=$ sink
Expand Down
2 changes: 1 addition & 1 deletion http-client/publicsuffixlist/CreateTest.hs
Expand Up @@ -105,7 +105,7 @@ populateFile url filename = withFile filename WriteMode $ \ h -> do
mapM_ (hPutStrLn h) header
hPutStrLn h $ "-- DO NOT MODIFY! This file has been automatically generated from the CreateTest.hs script at " ++ show current_time
mapM_ (hPutStrLn h) header2
req <- HC.parseUrl url
req <- HC.parseRequest url
HC.withManager $ \ manager -> do
res <- HC.http req manager
HC.responseBody res C.$$+-
Expand Down
4 changes: 4 additions & 0 deletions http-conduit/ChangeLog.md
@@ -1,3 +1,7 @@
## 2.1.11

* Switch to non-throwing behavior in `Network.HTTP.Simple` [#193](https://github.com/snoyberg/http-client/issues/193)

## 2.1.10.1

* Fix mistaken `@since` comments
Expand Down
19 changes: 12 additions & 7 deletions http-conduit/Network/HTTP/Conduit.hs
Expand Up @@ -36,7 +36,7 @@
-- >
-- > main :: IO ()
-- > main = do
-- > request <- parseUrl "http://google.com/"
-- > request <- parseRequest "http://google.com/"
-- > manager <- newManager tlsManagerSettings
-- > runResourceT $ do
-- > response <- http request manager
Expand Down Expand Up @@ -88,7 +88,7 @@
-- > }
-- >
-- > main = withSocketsDo $ do
-- > request' <- parseUrl "http://example.com/secret-page"
-- > request' <- parseRequest "http://example.com/secret-page"
-- > manager <- newManager tlsManagerSettings
-- > let request = request' { cookieJar = Just $ createCookieJar [cookie] }
-- > (fmap Just (httpLbs request manager)) `E.catch`
Expand Down Expand Up @@ -121,7 +121,7 @@
-- >
-- > main :: IO ()
-- > main = withSocketsDo $ do
-- > request' <- parseUrl "http://www.yesodweb.com/does-not-exist"
-- > request' <- parseRequest "http://www.yesodweb.com/does-not-exist"
-- > let request = request' { checkStatus = \_ _ _ -> Nothing }
-- > manager <- newManager tlsManagerSettings
-- > res <- httpLbs request manager
Expand All @@ -137,7 +137,7 @@
-- >
-- > main :: IO ()
-- > main = do
-- > request <- parseUrl "https://github.com/"
-- > request <- parseRequest "https://github.com/"
-- > let settings = mkManagerSettings (TLSSettingsSimple True False False) Nothing
-- > manager <- newManager settings
-- > res <- httpLbs request manager
Expand Down Expand Up @@ -208,6 +208,10 @@ module Network.HTTP.Conduit
, destroyCookieJar
-- * Utility functions
, parseUrl
, parseUrlThrow
, parseRequest
, parseRequest_
, defaultRequest
, applyBasicAuth
, addProxy
, lbsResponse
Expand Down Expand Up @@ -243,7 +247,8 @@ import Network.HTTP.Client.Internal (Manager, ManagerSettings,
closeManager, managerConnCount,
managerResponseTimeout,
managerTlsConnection, newManager)
import Network.HTTP.Client (parseUrl, urlEncodedBody, applyBasicAuth)
import Network.HTTP.Client (parseUrl, parseUrlThrow, urlEncodedBody, applyBasicAuth,
defaultRequest, parseRequest, parseRequest_)
import Network.HTTP.Client.Internal (addProxy, alwaysDecompress,
browserDecompress)
import Network.HTTP.Client.Internal (getRedirectedRequest)
Expand Down Expand Up @@ -284,7 +289,7 @@ httpLbs r m = liftIO $ Client.httpLbs r m
--
-- This function will 'throwIO' an 'HttpException' for any
-- response with a non-2xx status code (besides 3xx redirects up
-- to a limit of 10 redirects). It uses 'parseUrl' to parse the
-- to a limit of 10 redirects). It uses 'parseUrlThrow' to parse the
-- input. This function essentially wraps 'httpLbs'.
--
-- Note: Even though this function returns a lazy bytestring, it
Expand All @@ -297,7 +302,7 @@ httpLbs r m = liftIO $ Client.httpLbs r m
simpleHttp :: MonadIO m => String -> m L.ByteString
simpleHttp url = liftIO $ do
man <- newManager tlsManagerSettings
req <- liftIO $ parseUrl url
req <- liftIO $ parseUrlThrow url
responseBody <$> httpLbs (setConnectionClose req) man

conduitManagerSettings :: ManagerSettings
Expand Down
29 changes: 3 additions & 26 deletions http-conduit/Network/HTTP/Simple.hs
Expand Up @@ -30,8 +30,9 @@ module Network.HTTP.Simple
, H.HttpException (..)
, H.Proxy (..)
-- * Request constructions
, defaultRequest
, parseRequest
, H.defaultRequest
, H.parseRequest
, H.parseRequest_
-- * Request lenses
-- ** Basics
, setRequestMethod
Expand Down Expand Up @@ -135,30 +136,6 @@ data JSONException
deriving (Show, Typeable)
instance Exception JSONException

-- | The default request value. You'll almost certainly want to set the
-- 'requestHost', and likely the 'requestPath' as well.
--
-- See also 'parseRequest'
--
-- @since 2.1.10
defaultRequest :: H.Request
defaultRequest = def

-- | Parse a 'H.Request' from a 'String'. This is given as a URL, with an
-- optional leading request method, e.g.:
--
-- * @http://example.com@
-- * @https://example.com:1234/foo/bar?baz=bin@
-- * @PUT http://example.com/some-resource@
--
-- If parsing fails, 'Catch.throwM' will be called. The behavior of this
-- function is also used for the @IsString@ instance for use with
-- @OverloadedStrings@.
--
-- @since 2.1.10
parseRequest :: Catch.MonadThrow m => String -> m H.Request
parseRequest = H.parseUrl

-- | Perform an HTTP request and consume the body with the given 'C.Sink'
--
-- @since 2.1.10
Expand Down
4 changes: 2 additions & 2 deletions http-conduit/http-conduit.cabal
@@ -1,5 +1,5 @@
name: http-conduit
version: 2.1.10.1
version: 2.1.11
license: BSD3
license-file: LICENSE
author: Michael Snoyman <michael@snoyman.com>
Expand Down Expand Up @@ -30,7 +30,7 @@ library
, conduit-extra >= 1.1.5
, http-types >= 0.7
, lifted-base >= 0.1
, http-client >= 0.4.28 && < 0.5
, http-client >= 0.4.30 && < 0.5
, http-client-tls >= 0.2.4
, monad-control
, mtl
Expand Down

0 comments on commit 573a28a

Please sign in to comment.