Skip to content

HTTP/2 #45

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Type-annotate all unsafeCoerce JavaScript object casts
  • Loading branch information
jamesdbrock committed Jan 11, 2023
commit 12792b26c8f27fbcdb3ac18d0a8a350ebd086a55
7 changes: 7 additions & 0 deletions src/Node/HTTP2/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ export const onceReady = socket => callback => () => {
return () => socket.removeEventListener("ready", callback);
};

// https://nodejs.org/docs/latest/api/http2.html#event-stream
export const onceStream = foreign => callback => () => {
const cb = (stream, headers, flags) => callback(stream)(headers)(flags)();
foreign.once("stream", cb);
return () => {foreign.removeListener("stream", cb);};
};

// https://nodejs.org/docs/latest/api/http2.html#clienthttp2sessionrequestheaders-options
export const request = clienthttp2session => headers => options => () => {
return clienthttp2session.request(headers, options);
Expand Down
55 changes: 27 additions & 28 deletions src/Node/HTTP2/Client.purs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ module Node.HTTP2.Client
, request
, onceErrorSession
, onceResponse
, onStream
, onceStream
, onceHeaders
, closeSession
Expand All @@ -64,6 +63,7 @@ import Effect (Effect)
import Effect.Exception (Error)
import Node.Buffer (Buffer)
import Node.HTTP2 (Flags, HeadersObject, OptionsObject)
import Node.HTTP2.Internal (Http2Session, Http2Stream)
import Node.HTTP2.Internal as Internal
import Node.Net.Socket (Socket)
import Node.Stream (Duplex)
Expand All @@ -75,6 +75,9 @@ import Unsafe.Coerce (unsafeCoerce)
-- | See [__Class: ClientHttp2Session__](https://nodejs.org/docs/latest/api/http2.html#class-clienthttp2session)
foreign import data ClientHttp2Session :: Type

upcastClientHttp2Session :: ClientHttp2Session -> Http2Session
upcastClientHttp2Session = unsafeCoerce

-- | https://nodejs.org/docs/latest/api/http2.html#http2connectauthority-options-listener
foreign import connect :: URL -> OptionsObject -> (ClientHttp2Session -> Socket -> Effect Unit) -> Effect ClientHttp2Session

Expand All @@ -89,6 +92,9 @@ foreign import onceReady :: Socket -> (Effect Unit) -> Effect (Effect Unit)
-- | See [__Class: ClientHttp2Stream__](https://nodejs.org/docs/latest/api/http2.html#class-clienthttp2stream)
foreign import data ClientHttp2Stream :: Type

upcastClientHttp2Stream :: ClientHttp2Stream -> Http2Stream
upcastClientHttp2Stream = unsafeCoerce

-- |https://nodejs.org/docs/latest/api/http2.html#clienthttp2sessionrequestheaders-options
foreign import request :: ClientHttp2Session -> HeadersObject -> OptionsObject -> Effect ClientHttp2Stream

Expand All @@ -97,19 +103,19 @@ foreign import destroy :: ClientHttp2Stream -> Effect Unit

-- | https://nodejs.org/docs/latest/api/http2.html#http2sessionclosecallback
closeSession :: ClientHttp2Session -> Effect Unit -> Effect Unit
closeSession http2session = Internal.closeSession (unsafeCoerce http2session)
closeSession http2session = Internal.closeSession (upcastClientHttp2Session http2session)

-- | https://nodejs.org/docs/latest/api/http2.html#event-response
-- |
-- | Listen for one event, then remove the event listener.
-- | Listen for one event, call the callback, then remove the event listener.
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
foreign import onceResponse :: ClientHttp2Stream -> (HeadersObject -> Flags -> Effect Unit) -> Effect (Effect Unit)

-- | https://nodejs.org/docs/latest/api/http2.html#event-headers
-- |
-- | Listen for one event, then remove the event listener.
-- | Listen for one event, call the callback, then remove the event listener.
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
Expand All @@ -119,38 +125,31 @@ foreign import onceHeaders :: ClientHttp2Stream -> (HeadersObject -> Flags -> Ef
-- |
-- | https://nodejs.org/docs/latest/api/http2.html#push-streams-on-the-client
-- |
-- | Listen for one event, then remove the event listener.
-- | Listen for one event, call the callback, then remove the event listener.
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
onceStream :: ClientHttp2Session -> (ClientHttp2Stream -> HeadersObject -> Flags -> Effect Unit) -> Effect (Effect Unit)
onceStream http2session callback = Internal.onceStream (unsafeCoerce http2session) (\http2stream -> callback (unsafeCoerce http2stream))

-- | https://nodejs.org/docs/latest/api/http2.html#event-stream
-- |
-- | https://nodejs.org/docs/latest/api/http2.html#push-streams-on-the-client
-- |
-- | Returns an effect for removing the event listener.
onStream :: ClientHttp2Session -> (ClientHttp2Stream -> HeadersObject -> Flags -> Effect Unit) -> Effect (Effect Unit)
onStream http2session callback = Internal.onStream (unsafeCoerce http2session) (\http2stream -> callback (unsafeCoerce http2stream))
-- | https://nodejs.org/docs/latest/api/http2.html#event-stream
-- | is raised.
foreign import onceStream :: ClientHttp2Session -> (ClientHttp2Stream -> HeadersObject -> Flags -> Effect Unit) -> Effect (Effect Unit)

-- | https://nodejs.org/docs/latest/api/http2.html#event-error
-- |
-- | Listen for one event, then remove the event listener.
-- | Listen for one event, call the callback, then remove the event listener.
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
onceErrorSession :: ClientHttp2Session -> (Error -> Effect Unit) -> Effect (Effect Unit)
onceErrorSession http2session = Internal.onceEmitterError (unsafeCoerce http2session)
onceErrorSession http2session = Internal.onceSessionEmitterError (upcastClientHttp2Session http2session)

-- | https://nodejs.org/docs/latest/api/http2.html#event-error_1
-- |
-- | Listen for one event, then remove the event listener.
-- | Listen for one event, call the callback, then remove the event listener.
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
onceErrorStream :: ClientHttp2Stream -> (Error -> Effect Unit) -> Effect (Effect Unit)
onceErrorStream http2stream = Internal.onceEmitterError (unsafeCoerce http2stream)
onceErrorStream http2stream = Internal.onceStreamEmitterError (upcastClientHttp2Stream http2stream)

-- | https://nodejs.org/docs/latest/api/http2.html#event-push
-- |
Expand All @@ -159,46 +158,46 @@ foreign import oncePush :: ClientHttp2Stream -> (HeadersObject -> Flags -> Effec

-- | https://nodejs.org/docs/latest/api/http2.html#event-trailers
-- |
-- | Listen for one event, then remove the event listener.
-- | Listen for one event, call the callback, then remove the event listener.
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
onceTrailers :: ClientHttp2Stream -> (HeadersObject -> Flags -> Effect Unit) -> Effect (Effect Unit)
onceTrailers http2stream = Internal.onceTrailers (unsafeCoerce http2stream)
onceTrailers http2stream = Internal.onceTrailers (upcastClientHttp2Stream http2stream)

-- | https://nodejs.org/docs/latest/api/http2.html#event-wanttrailers
-- |
-- | Listen for one event, then remove the event listener.
-- | Listen for one event, call the callback, then remove the event listener.
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
onceWantTrailers :: ClientHttp2Stream -> Effect Unit -> Effect (Effect Unit)
onceWantTrailers http2stream = Internal.onceWantTrailers (unsafeCoerce http2stream)
onceWantTrailers http2stream = Internal.onceWantTrailers (upcastClientHttp2Stream http2stream)

-- | https://nodejs.org/docs/latest/api/http2.html#http2streamsendtrailersheaders
-- |
-- | > When sending a request or sending a response, the `options.waitForTrailers` option must be set in order to keep the `Http2Stream` open after the final `DATA` frame so that trailers can be sent.
sendTrailers :: ClientHttp2Stream -> HeadersObject -> Effect Unit
sendTrailers http2stream = Internal.sendTrailers (unsafeCoerce http2stream)
sendTrailers http2stream = Internal.sendTrailers (upcastClientHttp2Stream http2stream)

-- | https://nodejs.org/docs/latest/api/stream.html#event-data
-- |
-- | Returns an effect for removing the event listener.
onData :: ClientHttp2Stream -> (Buffer -> Effect Unit) -> Effect (Effect Unit)
onData http2stream = Internal.onData (unsafeCoerce http2stream)
onData http2stream = Internal.onData (upcastClientHttp2Stream http2stream)

-- | https://nodejs.org/docs/latest/api/net.html#event-end
-- |
-- | Listen for one event, then remove the event listener.
-- | Listen for one event, call the callback, then remove the event listener.
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
onceEnd :: ClientHttp2Stream -> Effect Unit -> Effect (Effect Unit)
onceEnd http2stream = Internal.onceEnd (unsafeCoerce http2stream)
onceEnd http2stream = Internal.onceEnd (upcastClientHttp2Stream http2stream)

-- | https://nodejs.org/docs/latest/api/http2.html#http2streamclosecode-callback
closeStream :: ClientHttp2Stream -> Int -> Effect Unit -> Effect Unit
closeStream stream = Internal.closeStream (unsafeCoerce stream)
closeStream stream = Internal.closeStream (upcastClientHttp2Stream stream)

-- | Coerce to a duplex stream.
toDuplex :: ClientHttp2Stream -> Duplex
Expand Down
53 changes: 7 additions & 46 deletions src/Node/HTTP2/Internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,62 +18,27 @@ export const closeSession = http2session => callback => () => {
}
};

// https://nodejs.org/docs/latest/api/http2.html#serverclosecallback
export const closeServer = http2server => callback => () => {
http2server.close(() => callback());
};

// https://nodejs.org/docs/latest/api/http2.html#event-close_1
export const onceClose = http2stream => callback => () => {
const cb = () => callback(http2stream.rstCode)();
http2stream.once("close", cb);
return () => {http2stream.removeEventListener("close", cb);};
};

// https://nodejs.org/docs/latest/api/http2.html#event-stream
export const onceStream = foreign => callback => () => {
const cb = (stream, headers, flags) => callback(stream)(headers)(flags)();
foreign.once("stream", cb);
return () => {foreign.removeListener("stream", cb);};
};

// https://nodejs.org/docs/latest/api/http2.html#event-stream
export const onStream = foreign => callback => () => {
const cb = (stream, headers, flags) => callback(stream)(headers)(flags)();
foreign.on("stream", cb);
return () => {foreign.removeListener("stream", cb);};
};

// https://nodejs.org/docs/latest/api/events.html#nodeeventtargetoncetype-listener-options
export const onceError = eventtarget => callback => () => {
const cb = error => callback(error)();
eventtarget.once("error", cb);
return () => {eventtarget.removeEventListener("error", cb);};
};

// https://nodejs.org/docs/latest/api/net.html#event-close
export const onceServerClose = server => callback => () => {
const cb = () => callback();
server.once("close", cb);
return () => {server.removeEventListener("close", cb);};
};

// https://nodejs.org/docs/latest/api/events.html#emitteronceeventname-listener
export const onceEmitterError = eventemitter => callback => () => {
const onceEmitterError = eventemitter => callback => () => {
const cb = error => callback(error)();
eventemitter.once("error", cb);
return () => {eventemitter.removeListener("error", cb);};
};

export const onEmitterError = eventemitter => callback => () => {
const cb = error => callback(error)();
eventemitter.on("error", cb);
return () => {eventemitter.removeListener("error", cb);};
};
// During PR review it was requested that there be no `unsafeCoerce`, so
// we unsafely coerce in JavaScript instead.
export const onceStreamEmitterError = onceEmitterError;

export const throwAllErrors = eventtarget => () => {
eventtarget.addEventListener("error", error => {throw error;});
};
// During PR review it was requested that there be no `unsafeCoerce`, so
// we unsafely coerce in JavaScript instead.
export const onceSessionEmitterError = onceEmitterError;

export const onceWantTrailers = http2stream => callback => () => {
const cb = () => callback();
Expand Down Expand Up @@ -104,10 +69,6 @@ export const onceEnd = netsocket => callback => () => {
return () => {netsocket.removeListener("end", cb);};
};

export const session = http2stream => {
return http2stream.session;
};

// https://nodejs.org/docs/latest/api/http2.html#http2streamclosecode-callback
export const closeStream = http2stream => code => callback => () => {
http2stream.close(code, () => callback());
Expand Down
46 changes: 3 additions & 43 deletions src/Node/HTTP2/Internal.purs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import Prelude

import Effect (Effect)
import Effect.Exception (Error)
import Foreign (Foreign)
import Node.Buffer (Buffer)
import Node.HTTP2 (Flags, HeadersObject, OptionsObject, SettingsObject)
import Node.HTTP2.Constants (NGHTTP2)
Expand All @@ -25,59 +24,23 @@ foreign import data Http2Session :: Type
-- | https://nodejs.org/api/http2.html#http2sessionlocalsettings
foreign import localSettings :: Http2Session -> Effect SettingsObject

-- | Listen for one event, call the callback, then remove
-- | Listen for one EventEmitter `'error'`, call the callback, then remove
-- | the event listener.
-- | Returns an effect for removing the event listener before the event
-- | is raised.
-- |
-- | https://nodejs.org/docs/latest/api/http2.html#event-stream
foreign import onceStream :: Foreign -> (Http2Stream -> HeadersObject -> Flags -> Effect Unit) -> Effect (Effect Unit)

-- | https://nodejs.org/docs/latest/api/http2.html#event-stream
foreign import onStream :: Foreign -> (Http2Stream -> HeadersObject -> Flags -> Effect Unit) -> Effect (Effect Unit)

-- | Listen for one NodeEventTarget `'error'`, call the callback, then remove
-- | the event listener.
-- | Returns an effect for removing the event listener before the event
-- | is raised.
foreign import onceError :: Foreign -> (Error -> Effect Unit) -> Effect (Effect Unit)
foreign import onceStreamEmitterError :: Http2Stream -> (Error -> Effect Unit) -> Effect (Effect Unit)

-- | Listen for one EventEmitter `'error'`, call the callback, then remove
-- | the event listener.
-- | Returns an effect for removing the event listener before the event
-- | is raised.
foreign import onceEmitterError :: Foreign -> (Error -> Effect Unit) -> Effect (Effect Unit)

-- | EventEmitter `on 'error'`
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
foreign import onEmitterError :: Foreign -> (Error -> Effect Unit) -> Effect (Effect Unit)
foreign import onceSessionEmitterError :: Http2Session -> (Error -> Effect Unit) -> Effect (Effect Unit)

-- | https://nodejs.org/docs/latest/api/http2.html#http2sessionclosecallback
foreign import closeSession :: Http2Session -> Effect Unit -> Effect Unit

-- | https://nodejs.org/docs/latest/api/http2.html#serverclosecallback
foreign import closeServer :: Foreign -> Effect Unit -> Effect Unit

-- | https://nodejs.org/docs/latest/api/net.html#event-close
-- |
-- | Returns an effect for removing the event listener before the event
-- | is raised.
foreign import onceServerClose :: Foreign -> Effect Unit -> Effect (Effect Unit)

-- | To an `EventTarget` attach an `'error'` listener which will always throw
-- | a synchronous `Error`.
-- |
-- | https://nodejs.org/docs/latest/api/http2.html#error-handling
-- |
-- | > (Errors) will be reported using either a synchronous throw or via
-- | > an 'error' event on the `Http2Stream`, `Http2Session` or
-- | > `Http2Server` objects, depending on where and when the error occurs.
-- |
-- | https://nodejs.org/api/events.html#eventtargetaddeventlistenertype-listener-options
foreign import throwAllErrors :: Foreign -> Effect Unit

-- | Private type which can be coerced into ClientHttp2Stream
-- | or ServerHttp2Stream or Duplex.
-- |
Expand Down Expand Up @@ -105,8 +68,5 @@ foreign import onData :: Http2Stream -> (Buffer -> Effect Unit) -> Effect (Effec
-- | https://nodejs.org/docs/latest/api/net.html#event-end
foreign import onceEnd :: Http2Stream -> Effect Unit -> Effect (Effect Unit)

-- | https://nodejs.org/api/http2.html#http2streamsession
foreign import session :: Http2Stream -> Http2Session

-- | https://nodejs.org/docs/latest/api/http2.html#http2streamclosecode-callback
foreign import closeStream :: Http2Stream -> Int -> Effect Unit -> Effect Unit
31 changes: 27 additions & 4 deletions src/Node/HTTP2/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,33 @@ export const listen = server => options => callback => () => {
server.listen(options, () => callback());
};

export const onceSession = http2server => callback => () => {
const cb = session => callback(session)();
http2server.once("session", cb);
return () => http2server.removeEventListener("session", cb);
// https://nodejs.org/docs/latest/api/http2.html#serverclosecallback
export const closeServer = http2server => callback => () => {
http2server.close(() => callback());
};

// https://nodejs.org/docs/latest/api/net.html#event-close
export const onceServerClose = server => callback => () => {
const cb = () => callback();
server.once("close", cb);
return () => {server.removeEventListener("close", cb);};
};

export const onEmitterError = eventemitter => callback => () => {
const cb = error => callback(error)();
eventemitter.on("error", cb);
return () => {eventemitter.removeListener("error", cb);};
};

export const session = http2stream => {
return http2stream.session;
};

// https://nodejs.org/docs/latest/api/http2.html#event-stream
export const onStream = http2server => callback => () => {
const cb = (stream, headers, flags) => callback(stream)(headers)(flags)();
http2server.on("stream", cb);
return () => {http2server.removeListener("stream", cb);};
};

// https://nodejs.org/docs/latest/api/http2.html#http2streampushallowed
Expand Down
Loading