Skip to content

changes for 0.12 #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
"url": "git://github.com/purescript-node/purescript-node-http.git"
},
"devDependencies": {
"purescript-console": "^3.0.0"
"purescript-console": "#compiler/0.12"
},
"dependencies": {
"purescript-maps": "^3.0.0",
"purescript-node-streams": "^3.0.0",
"purescript-node-url": "^3.0.0",
"purescript-options": "^3.0.0",
"purescript-unsafe-coerce": "^3.0.0",
"purescript-node-buffer": "^3.0.1",
"purescript-arraybuffer-types": "^2.0.0"
"purescript-node-streams": "#compiler/0.12",
"purescript-node-url": "#compiler/0.12",
"purescript-options": "#compiler/0.12",
"purescript-node-buffer": "#compiler/0.12",
"purescript-arraybuffer-types": "^2.0.0",
"purescript-foreign-object": "#compiler/0.12",
"purescript-unsafe-coerce": "#compiler/0.12"
}
}
37 changes: 15 additions & 22 deletions src/Node/HTTP.purs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ module Node.HTTP
( Server
, Request
, Response
, HTTP

, createServer
, listen
Expand All @@ -27,14 +26,11 @@ module Node.HTTP

import Prelude

import Control.Monad.Eff (Eff, kind Effect)

import Data.Maybe (Maybe)
import Data.Nullable (Nullable, toNullable)
import Data.StrMap (StrMap)

import Effect (Effect)
import Foreign.Object (Object)
import Node.Stream (Writable, Readable)

import Unsafe.Coerce (unsafeCoerce)

-- | The type of a HTTP server object
Expand All @@ -46,22 +42,19 @@ foreign import data Request :: Type
-- | A HTTP response object
foreign import data Response :: Type

-- | The effect associated with using the HTTP module.
foreign import data HTTP :: Effect

-- | Create a HTTP server, given a function to be executed when a request is received.
foreign import createServer :: forall eff. (Request -> Response -> Eff (http :: HTTP | eff) Unit) -> Eff (http :: HTTP | eff) Server
foreign import createServer :: (Request -> Response -> Effect Unit) -> Effect Server

foreign import listenImpl :: forall eff. Server -> Int -> String -> Nullable Int -> Eff (http :: HTTP | eff) Unit -> Eff (http :: HTTP | eff) Unit
foreign import listenImpl :: Server -> Int -> String -> Nullable Int -> Effect Unit -> Effect Unit

foreign import closeImpl :: forall eff. Server -> Eff (http :: HTTP | eff) Unit -> Eff (http :: HTTP | eff) Unit
foreign import closeImpl :: Server -> Effect Unit -> Effect Unit

-- | Listen on a port in order to start accepting HTTP requests. The specified callback will be run when setup is complete.
listen :: forall eff. Server -> ListenOptions -> Eff (http :: HTTP | eff) Unit -> Eff (http :: HTTP | eff) Unit
listen :: Server -> ListenOptions -> Effect Unit -> Effect Unit
listen server opts done = listenImpl server opts.port opts.hostname (toNullable opts.backlog) done

-- | Close a listening HTTP server. The specified callback will be run the server closing is complete.
close :: forall eff. Server -> Eff (http :: HTTP | eff) Unit -> Eff (http :: HTTP | eff) Unit
close :: Server -> Effect Unit -> Effect Unit
close server done = closeImpl server done

-- | Options to be supplied to `listen`. See the [Node API](https://nodejs.org/dist/latest-v6.x/docs/api/http.html#http_server_listen_handle_callback) for detailed information about these.
Expand All @@ -72,14 +65,14 @@ type ListenOptions =
}

-- | Listen on a unix socket. The specified callback will be run when setup is complete.
foreign import listenSocket :: forall eff. Server -> String -> Eff (http :: HTTP | eff) Unit -> Eff (http :: HTTP | eff) Unit
foreign import listenSocket :: Server -> String -> Effect Unit -> Effect Unit

-- | Get the request HTTP version
httpVersion :: Request -> String
httpVersion = _.httpVersion <<< unsafeCoerce

-- | Get the request headers as a hash
requestHeaders :: Request -> StrMap String
requestHeaders :: Request -> Object String
requestHeaders = _.headers <<< unsafeCoerce

-- | Get the request method (GET, POST, etc.)
Expand All @@ -91,21 +84,21 @@ requestURL :: Request -> String
requestURL = _.url <<< unsafeCoerce

-- | Coerce the request object into a readable stream.
requestAsStream :: forall eff. Request -> Readable () (http :: HTTP | eff)
requestAsStream :: Request -> Readable ()
requestAsStream = unsafeCoerce

-- | Set a header with a single value.
foreign import setHeader :: forall eff. Response -> String -> String -> Eff (http :: HTTP | eff) Unit
foreign import setHeader :: Response -> String -> String -> Effect Unit

-- | Set a header with multiple values.
foreign import setHeaders :: forall eff. Response -> String -> Array String -> Eff (http :: HTTP | eff) Unit
foreign import setHeaders :: Response -> String -> Array String -> Effect Unit

-- | Set the status code.
foreign import setStatusCode :: forall eff. Response -> Int -> Eff (http :: HTTP | eff) Unit
foreign import setStatusCode :: Response -> Int -> Effect Unit

-- | Set the status message.
foreign import setStatusMessage :: forall eff. Response -> String -> Eff (http :: HTTP | eff) Unit
foreign import setStatusMessage :: Response -> String -> Effect Unit

-- | Coerce the response object into a writable stream.
responseAsStream :: forall eff. Response -> Writable () (http :: HTTP | eff)
responseAsStream :: Response -> Writable ()
responseAsStream = unsafeCoerce
35 changes: 16 additions & 19 deletions src/Node/HTTP/Client.purs
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,15 @@ module Node.HTTP.Client

import Prelude

import Control.Monad.Eff (Eff)

import Data.Foreign (Foreign, toForeign)
import Data.Functor.Contravariant ((>$<))
import Data.Maybe (Maybe)
import Data.Options (Options, Option, options, opt)
import Data.StrMap (StrMap, delete, lookup)

import Node.HTTP (HTTP)
import Data.Options (Option, Options, opt, options)
import Effect (Effect)
import Foreign (Foreign, toForeign)
import Foreign.Object (Object)
import Foreign.Object as Object
import Node.Stream (Readable, Writable)
import Node.URL as URL

import Unsafe.Coerce (unsafeCoerce)

-- | A HTTP request object
Expand All @@ -52,7 +49,7 @@ foreign import data Request :: Type
foreign import data Response :: Type

-- | A HTTP request object
newtype RequestHeaders = RequestHeaders (StrMap String)
newtype RequestHeaders = RequestHeaders (Object String)

-- | The type of HTTP request options
data RequestOptions
Expand Down Expand Up @@ -110,42 +107,42 @@ familyToOption IPV4 = 4
familyToOption IPV6 = 6

-- | Make a HTTP request using the specified options and response callback.
foreign import requestImpl :: forall eff. Foreign -> (Response -> Eff (http :: HTTP | eff) Unit) -> Eff (http :: HTTP | eff) Request
foreign import requestImpl :: Foreign -> (Response -> Effect Unit) -> Effect Request

-- | Make a HTTP request using the specified options and response callback.
request :: forall eff. Options RequestOptions -> (Response -> Eff (http :: HTTP | eff) Unit) -> Eff (http :: HTTP | eff) Request
request :: Options RequestOptions -> (Response -> Effect Unit) -> Effect Request
request = requestImpl <<< options

-- | Make a HTTP request from a URI string and response callback.
requestFromURI :: forall eff. String -> (Response -> Eff (http :: HTTP | eff) Unit) -> Eff (http :: HTTP | eff) Request
requestFromURI :: String -> (Response -> Effect Unit) -> Effect Request
requestFromURI = requestImpl <<< toForeign <<< URL.parse

-- | Create a writable stream from a request object.
requestAsStream :: forall eff r. Request -> Writable r (http :: HTTP | eff)
requestAsStream :: forall r. Request -> Writable r
requestAsStream = unsafeCoerce

-- | Create a readable stream from a response object.
responseAsStream :: forall eff w. Response -> Readable w (http :: HTTP | eff)
responseAsStream :: forall w. Response -> Readable w
responseAsStream = unsafeCoerce

-- | Set the socket timeout for a `Request`
foreign import setTimeout :: forall eff. Request -> Int -> Eff (http :: HTTP | eff) Unit -> Eff (http :: HTTP | eff) Unit
foreign import setTimeout :: Request -> Int -> Effect Unit -> Effect Unit

-- | Get the request HTTP version
httpVersion :: Response -> String
httpVersion = _.httpVersion <<< unsafeCoerce

headers' :: forall a. Response -> StrMap a
headers' :: forall a. Response -> Object a
headers' = _.headers <<< unsafeCoerce

-- | Get the response headers as a hash
-- | Cookies are not included and could be retrieved with responseCookies
responseHeaders :: Response -> StrMap String
responseHeaders res = delete "set-cookie" $ headers' res
responseHeaders :: Response -> Object String
responseHeaders res = Object.delete "set-cookie" $ headers' res

-- | Get the response cookies as Just (Array String) or Nothing if no cookies
responseCookies :: Response -> Maybe (Array String)
responseCookies res = lookup "set-cookie" $ headers' res
responseCookies res = Object.lookup "set-cookie" $ headers' res

-- | Get the response status code
statusCode :: Response -> Int
Expand Down
18 changes: 8 additions & 10 deletions src/Node/HTTP/Secure.purs
Original file line number Diff line number Diff line change
Expand Up @@ -80,28 +80,26 @@ module Node.HTTP.Secure

import Prelude

import Control.Monad.Eff (Eff)
import Data.ArrayBuffer.Types (Uint8Array)
import Data.Foreign (Foreign)
import Data.Options (Options, Option, options, opt)
import Effect (Effect)
import Foreign (Foreign)
import Node.Buffer (Buffer)
import Node.HTTP (Request, Response, Server, HTTP)
import Node.HTTP (Server, Request, Response)
import Unsafe.Coerce (unsafeCoerce)

-- | Create an HTTPS server, given the SSL options and a function to be executed
-- | when a request is received.
foreign import createServerImpl ::
forall eff.
Foreign ->
(Request -> Response -> Eff (http :: HTTP | eff) Unit) ->
Eff (http :: HTTP | eff) Server
(Request -> Response -> Effect Unit) ->
Effect Server

-- | Create an HTTPS server, given the SSL options and a function to be executed
-- | when a request is received.
createServer :: forall eff.
Options SSLOptions ->
(Request -> Response -> Eff (http :: HTTP | eff) Unit) ->
Eff (http :: HTTP | eff) Server
createServer :: Options SSLOptions ->
(Request -> Response -> Effect Unit) ->
Effect Server
createServer = createServerImpl <<< options

-- | The type of HTTPS server options
Expand Down
29 changes: 13 additions & 16 deletions test/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,29 @@ module Test.Main where

import Prelude

import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log, logShow)

import Data.Foldable (foldMap)
import Data.Maybe (Maybe(..))
import Data.Options (Options, options, (:=))

import Effect (Effect)
import Effect.Console (log, logShow)
import Node.Encoding (Encoding(..))
import Node.HTTP (HTTP, Request, Response, listen, createServer, setHeader, requestMethod, requestURL, responseAsStream, requestAsStream, setStatusCode)
import Node.HTTP (Request, Response, listen, createServer, setHeader, requestMethod, requestURL, responseAsStream, requestAsStream, setStatusCode)
import Node.HTTP.Client as Client
import Node.HTTP.Secure as HTTPS
import Node.Stream (Writable, end, pipe, writeString)

import Partial.Unsafe (unsafeCrashWith)
import Unsafe.Coerce (unsafeCoerce)

foreign import stdout :: forall eff r. Writable r eff
foreign import stdout :: forall r. Writable r

main :: forall eff. Eff (console :: CONSOLE, http :: HTTP | eff) Unit
main :: Effect Unit
main = do
testBasic
testHttpsServer
testHttps
testCookies

respond :: forall eff. Request -> Response -> Eff (console :: CONSOLE, http :: HTTP | eff) Unit
respond :: Request -> Response -> Effect Unit
respond req res = do
setStatusCode res 200
let inputStream = requestAsStream req
Expand All @@ -47,7 +44,7 @@ respond req res = do
"POST" -> void $ pipe inputStream outputStream
_ -> unsafeCrashWith "Unexpected HTTP method"

testBasic :: forall eff. Eff (console :: CONSOLE, http :: HTTP | eff) Unit
testBasic :: Effect Unit
testBasic = do
server <- createServer respond
listen server { hostname: "localhost", port: 8080, backlog: Nothing } $ void do
Expand Down Expand Up @@ -108,7 +105,7 @@ FO0u08Tb/091Bir5kgglUSi7VnFD3v8ffeKpkkJvtYUj7S9yoH9NQPVhKVCq6mna
TbGfXbnVfNmqgQh71+k02p6S
-----END PRIVATE KEY-----"""

testHttpsServer :: forall eff. Eff (console :: CONSOLE, http :: HTTP | eff) Unit
testHttpsServer :: Effect Unit
testHttpsServer = do
server <- HTTPS.createServer sslOpts respond
listen server { hostname: "localhost", port: 8081, backlog: Nothing } $ void do
Expand All @@ -125,30 +122,30 @@ testHttpsServer = do
HTTPS.key := HTTPS.keyString mockKey <>
HTTPS.cert := HTTPS.certString mockCert

testHttps :: forall eff. Eff (console :: CONSOLE, http :: HTTP | eff) Unit
testHttps :: Effect Unit
testHttps =
simpleReq "https://pursuit.purescript.org/packages/purescript-node-http/badge"

testCookies :: forall eff. Eff (console :: CONSOLE, http :: HTTP | eff) Unit
testCookies :: Effect Unit
testCookies =
simpleReq
"https://httpbin.org/cookies/set?cookie1=firstcookie&cookie2=secondcookie"

simpleReq :: forall eff. String -> Eff (console :: CONSOLE, http :: HTTP | eff) Unit
simpleReq :: String -> Effect Unit
simpleReq uri = do
log ("GET " <> uri <> ":")
req <- Client.requestFromURI uri logResponse
end (Client.requestAsStream req) (pure unit)

complexReq :: forall eff. Options Client.RequestOptions -> Eff (console :: CONSOLE, http :: HTTP | eff) Unit
complexReq :: Options Client.RequestOptions -> Effect Unit
complexReq opts = do
log $ optsR.method <> " " <> optsR.protocol <> "//" <> optsR.hostname <> ":" <> optsR.port <> optsR.path <> ":"
req <- Client.request opts logResponse
end (Client.requestAsStream req) (pure unit)
where
optsR = unsafeCoerce $ options opts

logResponse :: forall eff. Client.Response -> Eff (console :: CONSOLE, http :: HTTP | eff) Unit
logResponse :: Client.Response -> Effect Unit
logResponse response = void do
log "Headers:"
logShow $ Client.responseHeaders response
Expand Down