Add `replacePlus` to `parseUrlencoded` and drop `FromForm` and `ToFor… · purescript-hyper/hyper@76e2d9f · GitHub
Skip to content

Commit 76e2d9f

Browse files
committed
Add replacePlus to parseUrlencoded and drop FromForm and ToForm classes
1 parent 2b19c1d commit 76e2d9f

8 files changed

Lines changed: 57 additions & 58 deletions

File tree

‎src/Hyper/Form.purs‎

Lines changed: 8 additions & 34 deletions

‎src/Hyper/Form/Urlencoded.purs‎

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,48 @@
11
-- | Parser for the `application/x-www-form-urlencoded` format, commonly used
22
-- | for query strings and POST request bodies.
33
module Hyper.Form.Urlencoded
4-
( parseUrlencoded
4+
( defaultOptions
5+
, Options
6+
, parseUrlencoded
57
) where
68

79
import Prelude
10+
811
import Control.Monad.Error.Class (throwError)
912
import Data.Array as Array
1013
import Data.Either (Either)
1114
import Data.Maybe (Maybe(Just, Nothing))
12-
import Data.String (split, joinWith, Pattern(Pattern))
15+
import Data.String (Pattern(..), Replacement(..), joinWith, replaceAll, split)
1316
import Data.Traversable (sequence)
1417
import Data.Tuple (Tuple(Tuple))
1518
import Global (decodeURIComponent)
1619

17-
toTuple :: Array String -> Either String (Tuple String (Maybe String))
18-
toTuple kv =
20+
toTuple :: Options -> Array String -> Either String (Tuple String (Maybe String))
21+
toTuple opts kv =
1922
case kv of
2023
[key] ->
2124
pure (Tuple (decodeURIComponent key) Nothing)
2225
[key, value] ->
23-
pure (Tuple (decodeURIComponent key) (Just (decodeURIComponent value)))
26+
let
27+
value' =
28+
if opts.replacePlus
29+
then
30+
replaceAll (Pattern "+") (Replacement " ") value
31+
else
32+
value
33+
in
34+
pure (Tuple (decodeURIComponent key) (Just (decodeURIComponent value')))
2435
parts ->
2536
throwError ("Invalid form key-value pair: " <> joinWith " " parts)
2637

38+
type Options = { replacePlus :: Boolean }
39+
40+
defaultOptions :: Options
41+
defaultOptions = { replacePlus: true }
2742

28-
parseUrlencoded :: String → Either String (Array (Tuple String (Maybe String)))
29-
parseUrlencoded = split (Pattern "&")
43+
parseUrlencoded :: Options -> String -> Either String (Array (Tuple String (Maybe String)))
44+
parseUrlencoded opts = split (Pattern "&")
3045
>>> Array.filter (_ /= "")
3146
>>> map (split (Pattern "="))
32-
>>> map toTuple
47+
>>> map (toTuple opts)
3348
>>> sequence

‎src/Hyper/Node/Server.purs‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import Data.Newtype (unwrap)
2828
import Data.StrMap as StrMap
2929
import Data.Tuple (Tuple(..))
3030
import Hyper.Conn (Conn)
31+
import Hyper.Form.Urlencoded (Options) as Urlencoded
3132
import Hyper.Middleware (Middleware, evalMiddleware, lift')
3233
import Hyper.Middleware.Class (getConn, modifyConn)
3334
import Hyper.Node.Server.Options (Options)
@@ -210,14 +211,14 @@ instance responseWriterHttpResponse :: MonadAff (http ∷ HTTP | e) m
210211
:*> modifyConn (_ { response = HttpResponse r })
211212

212213

213-
mkHttpRequest :: HTTP.Request -> HttpRequest
214-
mkHttpRequest request =
214+
mkHttpRequest :: Urlencoded.Options -> HTTP.Request -> HttpRequest
215+
mkHttpRequest opts request =
215216
HttpRequest request requestData
216217
where
217218
headers = HTTP.requestHeaders request
218219
requestData =
219220
{ url: HTTP.requestURL request
220-
, parsedUrl: defer \_ -> parseUrl (HTTP.requestURL request)
221+
, parsedUrl: defer \_ -> parseUrl opts (HTTP.requestURL request)
221222
, headers: headers
222223
, method: Method.fromString (HTTP.requestMethod request)
223224
, contentLength: StrMap.lookup "content-length" headers
@@ -247,7 +248,7 @@ runServer' options components runM middleware = do
247248
where
248249
onRequest ∷ HTTP.Request → HTTP.Response → Eff (http :: HTTP | e) Unit
249250
onRequest request response =
250-
let conn = { request: mkHttpRequest request
251+
let conn = { request: mkHttpRequest {replacePlus: options.replacePlus} request
251252
, response: HttpResponse response
252253
, components: components
253254
}

‎src/Hyper/Node/Server/Options.purs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Options e =
2424
, port :: Port
2525
, onListening :: Hostname -> Port -> Eff (http :: HTTP | e) Unit
2626
, onRequestError :: Error -> Eff (http :: HTTP | e) Unit
27+
, replacePlus :: Boolean
2728
}
2829

2930

@@ -33,6 +34,7 @@ defaultOptions =
3334
, port: Port 3000
3435
, onListening: const (const (pure unit))
3536
, onRequestError: const (pure unit)
37+
, replacePlus: true
3638
}
3739

3840

‎src/Hyper/Request.purs‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,18 @@ module Hyper.Request
1212
) where
1313

1414
import Prelude
15+
1516
import Data.Array as Array
16-
import Data.String as String
1717
import Data.Bifunctor (lmap)
1818
import Data.Either (Either)
1919
import Data.HTTP.Method (CustomMethod, Method)
2020
import Data.Lazy (Lazy)
2121
import Data.Maybe (Maybe, fromMaybe)
2222
import Data.StrMap (StrMap)
23+
import Data.String as String
2324
import Data.Tuple (Tuple)
2425
import Hyper.Conn (Conn)
26+
import Hyper.Form.Urlencoded (Options) as Urlencoded
2527
import Hyper.Form.Urlencoded (parseUrlencoded)
2628
import Hyper.Middleware (Middleware)
2729

@@ -38,14 +40,14 @@ type ParsedUrl =
3840
, query :: Either String (Array (Tuple String (Maybe String)))
3941
}
4042

41-
parseUrl :: String -> ParsedUrl
42-
parseUrl url =
43+
parseUrl :: Urlencoded.Options -> String -> ParsedUrl
44+
parseUrl opts url =
4345
let
4446
idx = fromMaybe (String.length url) $ String.indexOf (String.Pattern "?") url
4547
rawPath = String.take idx url
4648
rawQuery = String.drop (idx + 1) url
4749
path = Array.filter (_ /= "") $ String.split (String.Pattern "/") rawPath
48-
query = lmap (const rawQuery) $ parseUrlencoded rawQuery
50+
query = lmap (const rawQuery) $ parseUrlencoded opts rawQuery
4951
in
5052
{path, query}
5153

‎src/Hyper/Test/TestServer.purs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
module Hyper.Test.TestServer where
22

3-
import Data.String as String
4-
import Data.StrMap as StrMap
53
import Control.Alt ((<|>))
64
import Control.Applicative (pure)
75
import Control.IxMonad (ipure, (:*>), (:>>=))
@@ -19,7 +17,10 @@ import Data.Monoid (mempty, class Monoid)
1917
import Data.Newtype (class Newtype, unwrap)
2018
import Data.Semigroup (class Semigroup, (<>))
2119
import Data.StrMap (StrMap)
20+
import Data.StrMap as StrMap
21+
import Data.String as String
2222
import Hyper.Conn (Conn)
23+
import Hyper.Form.Urlencoded (defaultOptions) as Urlencoded
2324
import Hyper.Header (Header)
2425
import Hyper.Middleware (lift')
2526
import Hyper.Middleware.Class (getConn, modifyConn)
@@ -56,7 +57,7 @@ instance requestTestRequest :: Monad m => Request TestRequest m where
5657
getRequestData =
5758
getConn :>>= \{ request: TestRequest r } ->
5859
ipure { url: r.url
59-
, parsedUrl: defer \_ -> parseUrl r.url
60+
, parsedUrl: defer \_ -> parseUrl Urlencoded.defaultOptions r.url
6061
, contentLength: Just (String.length r.body)
6162
, method: r.method
6263
, headers: r.headers

‎test/Hyper/FormSpec.purs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Hyper.FormSpec where
22

33
import Prelude
4+
45
import Control.Monad.Aff (Aff)
56
import Control.Monad.Eff.Exception (error)
67
import Control.Monad.Error.Class (throwError)
@@ -10,6 +11,7 @@ import Data.Maybe (Maybe(..), fromMaybe)
1011
import Data.StrMap (singleton)
1112
import Data.Tuple (Tuple(Tuple), fst)
1213
import Hyper.Form (Form(Form), parseForm)
14+
import Hyper.Form.Urlencoded (defaultOptions) as Urlencoded
1315
import Hyper.Middleware (runMiddleware)
1416
import Hyper.Test.TestServer (TestRequest(TestRequest))
1517
import Test.Spec (Spec, it, describe)
@@ -59,7 +61,7 @@ spec =
5961
where
6062
runParseForm body contentType =
6163
runMiddleware
62-
parseForm
64+
(parseForm Urlencoded.defaultOptions)
6365
{ request: TestRequest { method: Left GET
6466
, body: body
6567
, url: ""

‎test/Hyper/RequestSpec.purs‎

Lines changed: 6 additions & 4 deletions

0 commit comments

Comments
 (0)