-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Second Transfer HTTP/2 web server -- -- Second Transfer HTTP/2 web server @package second-transfer @version 0.6.1.0 -- | Configuration and settings for the server. All constructor names are -- exported, but notice that they start with an underscore. They also -- have an equivalent lens without the underscore. Please prefer to use -- the lens interface. module SecondTransfer.Sessions.Config -- | Get/set a numeric Id from a SessionCoordinates. For example, to -- get the session id with this, import `Control.Lens.(^.)` and then do -- --
--   session_id = session_coordinates ^. sessionId
--   
sessionId :: Functor f => (Int -> f Int) -> SessionCoordinates -> f SessionCoordinates -- | Creates a default sessions context. Modify as needed using the lenses -- interfaces defaultSessionsConfig :: SessionsConfig -- | Don't insert any extra-headers by default. defaultSessionsEnrichedHeaders :: SessionsEnrichedHeaders sessionsCallbacks :: Lens' SessionsConfig SessionsCallbacks sessionsEnrichedHeaders :: Lens' SessionsConfig SessionsEnrichedHeaders reportErrorCallback_SC :: Lens' SessionsCallbacks (Maybe ErrorCallback) dataDeliveryCallback_SC :: Lens' SessionsCallbacks (Maybe DataFrameDeliveryCallback) dataFrameSize :: Lens' SessionsConfig Int addUsedProtocol :: Iso' SessionsEnrichedHeaders Bool -- | Components at an individual session. Used to report where in the -- session an error was produced. This interface is likely to change in -- the future, as we add more metadata to exceptions data SessionComponent SessionInputThread_HTTP2SessionComponent :: SessionComponent SessionHeadersOutputThread_HTTP2SessionComponent :: SessionComponent SessionDataOutputThread_HTTP2SessionComponent :: SessionComponent Framer_HTTP2SessionComponent :: SessionComponent Session_HTTP11 :: SessionComponent -- | Information used to identify a particular session. newtype SessionCoordinates SessionCoordinates :: Int -> SessionCoordinates -- | Callbacks that you can provide your sessions to notify you of -- interesting things happening in the server. data SessionsCallbacks SessionsCallbacks :: Maybe ErrorCallback -> Maybe DataFrameDeliveryCallback -> SessionsCallbacks [_reportErrorCallback_SC] :: SessionsCallbacks -> Maybe ErrorCallback [_dataDeliveryCallback_SC] :: SessionsCallbacks -> Maybe DataFrameDeliveryCallback -- | This is a temporal interface, but an useful one nonetheless. By -- setting some values here to True, second-transfer will add some -- headers to inbound requests, and some headers to outbound requests. -- -- This interface is deprecated in favor of the AwareWorker -- functionality.... data SessionsEnrichedHeaders SessionsEnrichedHeaders :: Bool -> SessionsEnrichedHeaders -- | Adds a second-transfer-eh--used-protocol header to inbound requests. -- Default: False [_addUsedProtocol] :: SessionsEnrichedHeaders -> Bool -- | Configuration information you can provide to the session maker. data SessionsConfig SessionsConfig :: SessionsCallbacks -> SessionsEnrichedHeaders -> Int -> SessionsConfig -- | Session callbacks [_sessionsCallbacks] :: SessionsConfig -> SessionsCallbacks [_sessionsEnrichedHeaders] :: SessionsConfig -> SessionsEnrichedHeaders -- | Size to use when splitting data in data frames [_dataFrameSize] :: SessionsConfig -> Int -- | Used by this session engine to report an error at some component, in a -- particular session. type ErrorCallback = (SessionComponent, SessionCoordinates, SomeException) -> IO () -- | Used by the session engine to report delivery of each data frame. Keep -- this callback very light, it runs in the main sending thread. It is -- called as f session_id stream_id ordinal when_delivered type DataFrameDeliveryCallback = Int -> Int -> Int -> TimeSpec -> IO () instance GHC.Show.Show SecondTransfer.Sessions.Config.SessionComponent instance GHC.Show.Show SecondTransfer.Sessions.Config.SessionCoordinates instance GHC.Classes.Eq SecondTransfer.Sessions.Config.SessionCoordinates module SecondTransfer.Sessions makeSessionsContext :: SessionsConfig -> IO SessionsContext -- | Contains information that applies to all sessions created in the -- program. Use the lenses interface to access members of this struct. data SessionsContext module SecondTransfer.Exception -- | Abstract exception. All HTTP/2 exceptions derive from here data HTTP2SessionException HTTP2SessionException :: e -> HTTP2SessionException -- | Abstract exception. Thrown when encoding/decoding of a frame fails data FramerException FramerException :: e -> FramerException -- | Thrown when the HTTP/2 connection prefix doesn't match the expected -- prefix. data BadPrefaceException BadPrefaceException :: BadPrefaceException -- | Abstract exception. All HTTP/1.1 related exceptions derive from here. -- Notice that this includes a lot of logical errors and they can be -- raised when handling HTTP/2 sessions as well data HTTP11Exception HTTP11Exception :: e -> HTTP11Exception data HTTP11SyntaxException HTTP11SyntaxException :: String -> HTTP11SyntaxException -- | Abstract exception. It is an error if an exception of this type -- bubbles to this library, but we will do our best to handle it -- gracefully. All internal error precursors at the workers can thus -- inherit from here to have a fallback option in case they forget to -- handle the error. This exception inherits from HTTP11Exception data HTTP500PrecursorException HTTP500PrecursorException :: e -> HTTP500PrecursorException -- | Use the traditional idiom if you need to derive from -- HTTP500PrecursorException, this is one of the helpers convertHTTP500PrecursorExceptionToException :: Exception e => e -> SomeException -- | Use the traditional idiom if you need to derive from -- HTTP500PrecursorException, this is one of the helpers getHTTP500PrecursorExceptionFromException :: Exception e => SomeException -> Maybe e -- | Thrown with HTTP1.1 over HTTP1.1 sessions when the response -- body or the request body doesn't include a Content-Length header -- field, given that should have included it data ContentLengthMissingException ContentLengthMissingException :: ContentLengthMissingException -- | Throw exceptions derived from this (e.g, GenericIOProblem -- below) to have the HTTP/2 session to terminate gracefully. data IOProblem IOProblem :: e -> IOProblem -- | A concrete case of the above exception. Throw one of this if you don't -- want to implement your own type. Use IOProblem in catch -- signatures. data GenericIOProblem GenericIOProblem :: GenericIOProblem -- | This exception will be raised inside a CoherentWorker when -- the underlying stream is cancelled (STREAM_RESET in HTTP/2). Do any -- necessary cleanup in a handler, or simply use the fact that the -- exception is asynchronously delivered to your CoherentWorker Haskell -- thread, giving you an opportunity to interrupt any blocked operations. data StreamCancelledException StreamCancelledException :: StreamCancelledException -- | Concrete exception. Used internally to signal that the client violated -- the protocol. Clients of the library shall never see this exception. data HTTP2ProtocolException HTTP2ProtocolException :: HTTP2ProtocolException instance GHC.Show.Show SecondTransfer.Exception.StreamCancelledException instance GHC.Show.Show SecondTransfer.Exception.GenericIOProblem instance GHC.Show.Show SecondTransfer.Exception.HTTP11SyntaxException instance GHC.Show.Show SecondTransfer.Exception.ContentLengthMissingException instance GHC.Show.Show SecondTransfer.Exception.BadPrefaceException instance GHC.Show.Show SecondTransfer.Exception.HTTP2ProtocolException instance GHC.Show.Show SecondTransfer.Exception.HTTP2SessionException instance GHC.Exception.Exception SecondTransfer.Exception.HTTP2SessionException instance GHC.Exception.Exception SecondTransfer.Exception.HTTP2ProtocolException instance GHC.Show.Show SecondTransfer.Exception.FramerException instance GHC.Exception.Exception SecondTransfer.Exception.FramerException instance GHC.Exception.Exception SecondTransfer.Exception.BadPrefaceException instance GHC.Show.Show SecondTransfer.Exception.HTTP11Exception instance GHC.Exception.Exception SecondTransfer.Exception.HTTP11Exception instance GHC.Show.Show SecondTransfer.Exception.HTTP500PrecursorException instance GHC.Exception.Exception SecondTransfer.Exception.HTTP500PrecursorException instance GHC.Exception.Exception SecondTransfer.Exception.ContentLengthMissingException instance GHC.Exception.Exception SecondTransfer.Exception.HTTP11SyntaxException instance GHC.Show.Show SecondTransfer.Exception.IOProblem instance GHC.Exception.Exception SecondTransfer.Exception.IOProblem instance GHC.Exception.Exception SecondTransfer.Exception.GenericIOProblem instance GHC.Exception.Exception SecondTransfer.Exception.StreamCancelledException module SecondTransfer.Types -- | Callback type to push data to a channel. Part of this interface is the -- abstract exception type IOProblem. Throw an instance of it from here -- to notify the session that the connection has been broken. There is no -- way to signal "normal termination", since HTTP/2's normal termination -- can be observed at a higher level when a GO_AWAY frame is seen. type PushAction = ByteString -> IO () -- | Callback type to pull data from a channel. The same as to PushAction -- applies to exceptions thrown from there. The first argument is the -- number of bytes to pull from the medium. Barring exceptions, we always -- know how many bytes we are expecting with HTTP/2. type PullAction = Int -> IO ByteString -- | This is an intermediate type. It represents what you obtain by -- combining something that speaks the protocol and an AwareWorker. In -- turn, you need to feed a bundle of callbacks implementing I/O to -- finally start a server. -- -- You can implement one of these to let somebody else supply the push, -- pull and close callbacks. For example, tlsServeWithALPN will -- supply these arguments to an Attendant. -- -- Attendants encapsulate all the session book-keeping functionality, -- which for HTTP/2 is quite complicated. You use the functions -- http**Attendant to create one of these from a CoherentWorker. -- -- This library supplies two of such Attendant factories, -- http11Attendant for HTTP 1.1 sessions, and -- http2Attendant for HTTP/2 sessions. type Attendant = AttendantCallbacks -> IO () -- | Callback that the session calls to realease resources associated with -- the channels. Take into account that your callback should be able to -- deal with non-clean shutdowns also, for example, if the connection to -- the remote peer is severed suddenly. type CloseAction = IO () -- | A set of functions describing how to do I/O in a session. As usual, we -- provide lenses accessors. data AttendantCallbacks AttendantCallbacks :: PushAction -> PullAction -> BestEffortPullAction -> CloseAction -> AttendantCallbacks -- | put some data in the channel [_pushAction_AtC] :: AttendantCallbacks -> PushAction -- | get exactly this much data from the channel. This function can be used -- by HTTP/2 since lengths are pretty well built inside the protocoll -- itself. [_pullAction_AtC] :: AttendantCallbacks -> PullAction -- | pull data from the channel, as much as the TCP stack wants to provide. -- we have no option but use this one when talking HTTP/1.1, where the -- best way to know the length is to scan until a Content-Length is -- found. [_bestEffortPullAction_AtC] :: AttendantCallbacks -> BestEffortPullAction -- | this is called when we wish to close the channel. [_closeAction_AtC] :: AttendantCallbacks -> CloseAction pushAction_AtC :: Lens' AttendantCallbacks PushAction pullAction_AtC :: Lens' AttendantCallbacks PullAction closeAction_AtC :: Lens' AttendantCallbacks CloseAction bestEffortPullAction_AtC :: Lens' AttendantCallbacks BestEffortPullAction -- | Gets a single header from the list getHeaderFromFlatList :: Headers -> ByteString -> Maybe ByteString -- | If you want to skip the footers, i.e., they are empty, use this -- function to convert an ordinary Source to a DataAndConclusion. nullFooter :: Source IO ByteString -> DataAndConclusion -- | The name part of a header type HeaderName = ByteString -- | The value part of a header type HeaderValue = ByteString -- | The complete header type Header = (HeaderName, HeaderValue) -- | List of headers. The first part of each tuple is the header name (be -- sure to conform to the HTTP/2 convention of using lowercase) and the -- second part is the headers contents. This list needs to include the -- special :method, :scheme, :authority and :path pseudo-headers for -- requests; and :status (with a plain numeric value represented in ascii -- digits) for responses. type Headers = [Header] -- | Finalization headers. If you don't know what they are, chances are -- that you don't need to worry about them for now. The support in this -- library for those are at best sketchy. type FinalizationHeaders = Headers -- | A request is a set of headers and a request body.... which will -- normally be empty, except for POST and PUT requests. But this library -- enforces none of that. data Request Request :: !Headers -> Maybe InputDataStream -> !Perception -> Request [_headers_RQ] :: Request -> !Headers [_inputData_RQ] :: Request -> Maybe InputDataStream [_perception_RQ] :: Request -> !Perception -- | Finalization headers type Footers = FinalizationHeaders -- | Data related to the request data Perception Perception :: Int -> Int -> TimeSpec -> HttpProtocolVersion -> Maybe [ByteString] -> Perception -- | The HTTP/2 stream id. Or the serial number of the request in an -- HTTP/1.1 session. [_streamId_Pr] :: Perception -> Int -- | A number uniquely identifying the session. This number is unique and -- the same for each TPC connection that a client opens using a given -- protocol. [_sessionId_Pr] :: Perception -> Int -- | Monotonic time close to when the request was first seen in the -- processing pipeline. [_startedTime_Pr] :: Perception -> TimeSpec -- | Which protocol is serving the request [_protocol_Pr] :: Perception -> HttpProtocolVersion -- | For new connections, probably a list of anounced protocols [_anouncedProtocols_Pr] :: Perception -> Maybe [ByteString] -- | Sometimes a response needs to be handled a bit specially, for example -- by reporting delivery details back to the worker data Effect Effect :: Maybe FragmentDeliveryCallback -> Maybe Int -> Effect [_fragmentDeliveryCallback_Ef] :: Effect -> Maybe FragmentDeliveryCallback [_priorityEffect_Ef] :: Effect -> Maybe Int -- | Main type of this library. You implement one of these for your server. -- This is a callback that the library calls as soon as it has all the -- headers of a request. For GET requests that's the entire request -- basically, but for POST and PUT requests this is just before the data -- starts arriving to the server. -- -- It is important that you consume the data in the cases where there is -- an input stream, otherwise the memory is lost for the duration of the -- request, and a malicious client can use that. -- -- Also, notice that when handling requests your worker can be -- interrupted with an asynchronous exception of type -- StreamCancelledException, if the peer cancels the stream type AwareWorker = Request -> IO PrincipalStream -- | You use this type to answer a request. The Headers are thus -- response headers and they should contain the :status pseudo-header. -- The PushedStreams is a list of pushed streams...(I don't thaink -- that I'm handling those yet) data PrincipalStream PrincipalStream :: Headers -> PushedStreams -> DataAndConclusion -> Effect -> PrincipalStream [_headers_PS] :: PrincipalStream -> Headers [_pushedStreams_PS] :: PrincipalStream -> PushedStreams [_dataAndConclusion_PS] :: PrincipalStream -> DataAndConclusion [_effect_PS] :: PrincipalStream -> Effect -- | A list of pushed streams. Notice that a list of IO computations is -- required here. These computations only happen when and if the streams -- are pushed to the client. The lazy nature of Haskell helps to avoid -- unneeded computations if the streams are not going to be sent to the -- client. type PushedStreams = [IO PushedStream] -- | A pushed stream, represented by a list of request headers, a list of -- response headers, and the usual response body (which may include final -- footers (not implemented yet)). data PushedStream PushedStream :: Headers -> Headers -> DataAndConclusion -> PushedStream [_requestHeaders_Psh] :: PushedStream -> Headers [_responseHeaders_Psh] :: PushedStream -> Headers [_dataAndConclusion_Psh] :: PushedStream -> DataAndConclusion -- | A source-like conduit with the data returned in the response. The -- return value of the conduit is a list of footers. For now that list -- can be anything (even bottom), I'm not handling it just yet. type DataAndConclusion = ConduitM () ByteString IO Footers -- | A CoherentWorker is a simplified callback that you can implement to -- handle requests. Then you can convert it to an AwareWorker with -- tupledPrincipalStreamToPrincipalStream. type CoherentWorker = TupledRequest -> IO TupledPrincipalStream -- | This is a Source conduit (see Haskell Data.Conduit library from -- Michael Snoyman) that you can use to retrieve the data sent by the -- client piece-wise. type InputDataStream = Source IO ByteString -- | A tuple representing the data alone that you usually need to give as a -- response, that is, the headers in the response (including the HTTP/2 -- :status), any pushed streams, a stream with the response data and the -- footers. type TupledPrincipalStream = (Headers, PushedStreams, DataAndConclusion) -- | A tuple representing the data alone usually needed to create a -- response. That is, the headers (including HTTP/2 :path, :authority, -- etc) and maybe an input data stream for requests that include it, that -- is, POST and PUT. type TupledRequest = (Headers, Maybe InputDataStream) -- | First argument is the ordinal of this data frame, second an -- approximation of when the frame was delivered, according to the -- monotonic clock. Do not linger in this call, it may delay some -- important thread type FragmentDeliveryCallback = Int -> TimeSpec -> IO () headers_RQ :: Lens' Request Headers inputData_RQ :: Lens' Request (Maybe InputDataStream) perception_RQ :: Lens' Request Perception headers_PS :: Lens' PrincipalStream Headers pushedStreams_PS :: Lens' PrincipalStream PushedStreams dataAndConclusion_PS :: Lens' PrincipalStream DataAndConclusion dataAndConclusion_Psh :: Lens' PushedStream DataAndConclusion requestHeaders_Psh :: Lens' PushedStream Headers responseHeaders_Psh :: Lens' PushedStream Headers effect_PS :: Lens' PrincipalStream Effect startedTime_Pr :: Lens' Perception TimeSpec streamId_Pr :: Lens' Perception Int sessionId_Pr :: Lens' Perception Int anouncedProtocols_Pr :: Lens' Perception (Maybe [ByteString]) protocol_Pr :: Lens' Perception HttpProtocolVersion fragmentDeliveryCallback_Ef :: Lens' Effect (Maybe FragmentDeliveryCallback) priorityEffect_Ef :: Lens' Effect (Maybe Int) defaultEffects :: Effect coherentToAwareWorker :: CoherentWorker -> AwareWorker -- | Convert between the two types of callback. tupledPrincipalStreamToPrincipalStream :: TupledPrincipalStream -> PrincipalStream requestToTupledRequest :: Request -> TupledRequest -- | The protocol version used. Here we distinguish only between HTTP1.1 -- and HTTP2 data HttpProtocolVersion Http11_HPV :: HttpProtocolVersion Http2_HPV :: HttpProtocolVersion module SecondTransfer.Utils.DevNull -- | If you are not processing the potential POST input in a request, use -- this consumer to drop the data to oblivion. Otherwise it will remain -- in an internal queue until the client closes the stream, and if the -- client doesn't want to do so.... dropIncomingData :: Maybe InputDataStream -> IO () -- | Utilities for working with headers. module SecondTransfer.Utils.HTTPHeaders -- | HTTP headers are case-insensitive, so we can use lowercase versions -- everywhere lowercaseHeaders :: Headers -> Headers -- | Checks that headers are lowercase headersAreLowercase :: Headers -> Bool headersAreLowercaseAtHeaderEditor :: HeaderEditor -> Bool -- | Looks for a given header fetchHeader :: Headers -> ByteString -> Maybe ByteString -- | Abstract data-type. Use fromList to get one of these from -- Headers. The underlying representation admits better -- asymptotics. data HeaderEditor -- | List of headers. The first part of each tuple is the header name (be -- sure to conform to the HTTP/2 convention of using lowercase) and the -- second part is the headers contents. This list needs to include the -- special :method, :scheme, :authority and :path pseudo-headers for -- requests; and :status (with a plain numeric value represented in ascii -- digits) for responses. type Headers = [Header] -- | O(n*log n) Builds the editor from a list. fromList :: Headers -> HeaderEditor -- | O(n) Takes the HeaderEditor back to Headers toList :: HeaderEditor -> Headers -- | headerLens header_name represents a lens into the headers, and you can -- use it then to add, alter and remove headers. It uses the same -- semantics than replaceHeaderValue headerLens :: ByteString -> Lens' HeaderEditor (Maybe ByteString) -- | replaceHeaderValue headers header_name maybe_header_value looks for -- header_name. If header_name is found and maybe_header_value is -- nothing, it returns a new headers list with the header deleted. If -- header_name is found and header_value is Just new_value, it returns a -- new list with the header containing the new value. If header_name is -- not in headers and maybe_header_value is Nothing, it returns the -- original headers list. If header_name is not in headers and -- maybe_header_value is Just new_value, it returns a new list where the -- last element is (header_name, new_value) replaceHeaderValue :: HeaderEditor -> ByteString -> Maybe ByteString -> HeaderEditor -- | Replaces a "host" HTTP/1.1 header by an ":authority" HTTP/2 header. -- The list is expected to be already in lowercase, so nothing will -- happen if there the header name portion is "Host" instead of "host". -- -- Notice that having a Host header in an HTTP/2 message is -- perfectly valid in certain circumstances, check Section 8.1.2.3 -- of the spec for details. replaceHostByAuthority :: HeaderEditor -> HeaderEditor -- | Given a header editor, introduces a Date header. This function -- has a side-effect: to get the current time introduceDateHeader :: HeaderEditor -> IO HeaderEditor instance GHC.Classes.Eq SecondTransfer.Utils.HTTPHeaders.Autosorted instance GHC.Classes.Ord SecondTransfer.Utils.HTTPHeaders.Autosorted instance GHC.Base.Monoid SecondTransfer.Utils.HTTPHeaders.HeaderEditor module SecondTransfer.MainLoop -- | Simple function to open tlsServeWithALPN :: FilePath -> FilePath -> String -> [(String, Attendant)] -> Int -> IO () -- | Interruptible version of tlsServeWithALPN. Use the extra -- argument to ask the server to finish: you pass an empty MVar and when -- you want to finish you just populate it. tlsServeWithALPNAndFinishOnRequest :: FilePath -> FilePath -> String -> [(String, Attendant)] -> Int -> MVar FinishRequest -> IO () -- | Activates logging to terminal enableConsoleLogging :: IO () logit :: ByteString -> IO () -- | Exceptions inheriting from IOProblem. This is thrown by the -- OpenSSL subsystem to signal that the connection was broken or that -- otherwise there was a problem at the SSL layer. data TLSLayerGenericProblem TLSLayerGenericProblem :: String -> TLSLayerGenericProblem -- | Singleton type. Used in conjunction with an MVar. If the MVar -- is full, the fuction tlsServeWithALPNAndFinishOnRequest knows -- that it should finish at its earliest convenience and call the -- CloseAction for any open sessions. data FinishRequest FinishRequest :: FinishRequest module SecondTransfer.Http2 -- | The type of this function is equivalent to: -- --
--   http2Attendant :: CoherentWorker -> AttendantCallbacks ->  IO ()
--   
-- -- Given a CoherentWorker, this function wraps it with flow -- control, multiplexing, and state maintenance needed to run an HTTP/2 -- session. -- -- Notice that this function is using HTTP/2 over TLS. We haven't -- implemented yet a session handling mechanism for HTTP/1.1 . http2Attendant :: SessionsContext -> AwareWorker -> Attendant module SecondTransfer.Http1 -- | Session attendant that speaks HTTP/1.1 http11Attendant :: SessionsContext -> AwareWorker -> Attendant -- | SecondTransfer is a HTTP1.1 and HTTP2 server session library, -- with an emphasis towards experimentation (so far). -- -- This library implements enough of the HTTP/2 to build compliant HTTP/2 -- servers. It also implements enough of HTTP/1.1 so you can actually use -- it to build polyglot web-servers. -- -- For HTTP/2, frame encoding and decoding is done with Kazu Yamamoto's -- http2 package. This library just takes care of making sense of -- sent and received frames. -- -- The library -- -- -- -- Setting up TLS for HTTP/2 correctly is a shore, so I have bundled here -- the TLS setup logic. Before you read any further, ATTENTION: enable -- always the threaded ghc runtime in your final programs if you want TLS -- to work. -- -- Here is how you create a very basic HTTP/2 webserver: -- --
--   import SecondTransfer(
--       AwareWorker
--       , Footers
--       , DataAndConclusion
--       , tlsServeWithALPN
--       , http2Attendant
--       , http11Attendant
--       , coherentToAwareWorker
--       )
--   import SecondTransfer.Sessions(
--         makeSessionsContext
--       , defaultSessionsConfig
--       )
--   
--   import Data.Conduit
--   
--   
--   saysHello :: DataAndConclusion
--   saysHello = do
--       -- The data in each yield will be automatically split across multiple
--       -- data frames if needed, so you can yield a large block of contents here
--       -- if you wish.
--       -- If you do multiple yields, no data will be left buffered between them,
--       -- so that you can for example implement a chat client in a single HTTP/2 stream.
--       -- Not that browsers support that. 
--       yield "Hello world!"
--       -- The HTTP/2 protocol supports sending headers *after* stream data. So, you usually
--       -- return an empty list to signal that you don't want any of those headers. 
--       -- In these docs, the post headers are often called "footers".
--       return []
--   
--   
--   helloWorldWorker :: AwareWorker
--   helloWorldWorker (_request_headers, _maybe_post_data) = coherentToAwareWorker $ do
--       dropIncomingData _maybe_post_data
--       return (
--           [
--               (":status", "200")
--           ],
--           [], -- No pushed streams
--           saysHello
--           )
--   
--   
--   -- For this program to work, it should be run from the top of
--   -- the developement directory.
--   main = do
--       sessions_context <- makeSessionsContext defaultSessionsConfig
--       let
--           http2_attendant = http2Attendant sessions_context helloWorldWorker
--           http11_attendant = http11Attendant sessions_context helloWorldWorker
--       tlsServeWithALPN
--           "tests/support/servercert.pem"   -- Server certificate
--           "tests/support/privkey.pem"      -- Certificate private key
--           "127.0.0.1"                      -- On which interface to bind
--           [
--               ("no-protocol", http11_attendant), -- The first protocol in the list is used when
--                                                  -- when no ALPN negotiation happens, and the
--                                                  -- name is really a filler.
--               ("h2-14", http2_attendant),    -- Protocols present in the ALPN negotiation
--               ("h2",    http2_attendant),    -- they may be slightly different, but for this
--                                              -- test it doesn't matter.
--   
--               ("http1.1", http11_attendant) -- Let's talk HTTP1.1 if everything else fails.
--           ]
--           8000
--   
-- -- AwareWorker is the type of the basic callback function that you -- need to implement, but most times you can do with a simplified version -- called CoherentWorker. The function -- coherentToAwareWorker does the conversion. The difference -- between the two callbacks is the level of information that you manage. -- With AwareWorker, you get a record on the request with all sort of -- details, things like the session id and the -- -- The callback is used to handle all requests to the server on a given -- negotiated ALPN protocol. If you need routing functionality (and you -- most certainly will need it), you need to build that functionality -- inside the callback. -- -- The above program uses a test certificate by a fake certificate -- authority. The certificate is valid for the server name ("authority", -- in HTTP/2 lingo) www.httpdos.com. So, in order for the above program -- to run, you probably need to add an alias to your /etc/hosts file. You -- also need very up-to-date versions of OpenSSL (I'm using OpenSSL -- 1.0.2) to be compliant with the cipher suites demanded by HTTP/2. The -- easiest way to test the above program is using a fairly recent version -- of curl. If everything is allright, you should be able to do: -- --
--   $ curl -k --http2 https://www.httpdos.com:8000/
--   Hello world!
--   
module SecondTransfer -- | List of headers. The first part of each tuple is the header name (be -- sure to conform to the HTTP/2 convention of using lowercase) and the -- second part is the headers contents. This list needs to include the -- special :method, :scheme, :authority and :path pseudo-headers for -- requests; and :status (with a plain numeric value represented in ascii -- digits) for responses. type Headers = [Header] -- | The name part of a header type HeaderName = ByteString -- | The value part of a header type HeaderValue = ByteString -- | The complete header type Header = (HeaderName, HeaderValue) -- | A request is a set of headers and a request body.... which will -- normally be empty, except for POST and PUT requests. But this library -- enforces none of that. data Request -- | Finalization headers type Footers = FinalizationHeaders -- | A CoherentWorker is a simplified callback that you can implement to -- handle requests. Then you can convert it to an AwareWorker with -- tupledPrincipalStreamToPrincipalStream. type CoherentWorker = TupledRequest -> IO TupledPrincipalStream -- | Main type of this library. You implement one of these for your server. -- This is a callback that the library calls as soon as it has all the -- headers of a request. For GET requests that's the entire request -- basically, but for POST and PUT requests this is just before the data -- starts arriving to the server. -- -- It is important that you consume the data in the cases where there is -- an input stream, otherwise the memory is lost for the duration of the -- request, and a malicious client can use that. -- -- Also, notice that when handling requests your worker can be -- interrupted with an asynchronous exception of type -- StreamCancelledException, if the peer cancels the stream type AwareWorker = Request -> IO PrincipalStream -- | You use this type to answer a request. The Headers are thus -- response headers and they should contain the :status pseudo-header. -- The PushedStreams is a list of pushed streams...(I don't thaink -- that I'm handling those yet) data PrincipalStream -- | A list of pushed streams. Notice that a list of IO computations is -- required here. These computations only happen when and if the streams -- are pushed to the client. The lazy nature of Haskell helps to avoid -- unneeded computations if the streams are not going to be sent to the -- client. type PushedStreams = [IO PushedStream] -- | A pushed stream, represented by a list of request headers, a list of -- response headers, and the usual response body (which may include final -- footers (not implemented yet)). data PushedStream -- | A source-like conduit with the data returned in the response. The -- return value of the conduit is a list of footers. For now that list -- can be anything (even bottom), I'm not handling it just yet. type DataAndConclusion = ConduitM () ByteString IO Footers -- | This is a Source conduit (see Haskell Data.Conduit library from -- Michael Snoyman) that you can use to retrieve the data sent by the -- client piece-wise. type InputDataStream = Source IO ByteString -- | Finalization headers. If you don't know what they are, chances are -- that you don't need to worry about them for now. The support in this -- library for those are at best sketchy. type FinalizationHeaders = Headers -- | This is an intermediate type. It represents what you obtain by -- combining something that speaks the protocol and an AwareWorker. In -- turn, you need to feed a bundle of callbacks implementing I/O to -- finally start a server. -- -- You can implement one of these to let somebody else supply the push, -- pull and close callbacks. For example, tlsServeWithALPN will -- supply these arguments to an Attendant. -- -- Attendants encapsulate all the session book-keeping functionality, -- which for HTTP/2 is quite complicated. You use the functions -- http**Attendant to create one of these from a CoherentWorker. -- -- This library supplies two of such Attendant factories, -- http11Attendant for HTTP 1.1 sessions, and -- http2Attendant for HTTP/2 sessions. type Attendant = AttendantCallbacks -> IO () -- | Session attendant that speaks HTTP/1.1 http11Attendant :: SessionsContext -> AwareWorker -> Attendant -- | The type of this function is equivalent to: -- --
--   http2Attendant :: CoherentWorker -> AttendantCallbacks ->  IO ()
--   
-- -- Given a CoherentWorker, this function wraps it with flow -- control, multiplexing, and state maintenance needed to run an HTTP/2 -- session. -- -- Notice that this function is using HTTP/2 over TLS. We haven't -- implemented yet a session handling mechanism for HTTP/1.1 . http2Attendant :: SessionsContext -> AwareWorker -> Attendant coherentToAwareWorker :: CoherentWorker -> AwareWorker -- | Simple function to open tlsServeWithALPN :: FilePath -> FilePath -> String -> [(String, Attendant)] -> Int -> IO () -- | Interruptible version of tlsServeWithALPN. Use the extra -- argument to ask the server to finish: you pass an empty MVar and when -- you want to finish you just populate it. tlsServeWithALPNAndFinishOnRequest :: FilePath -> FilePath -> String -> [(String, Attendant)] -> Int -> MVar FinishRequest -> IO () -- | Exceptions inheriting from IOProblem. This is thrown by the -- OpenSSL subsystem to signal that the connection was broken or that -- otherwise there was a problem at the SSL layer. data TLSLayerGenericProblem TLSLayerGenericProblem :: String -> TLSLayerGenericProblem -- | Singleton type. Used in conjunction with an MVar. If the MVar -- is full, the fuction tlsServeWithALPNAndFinishOnRequest knows -- that it should finish at its earliest convenience and call the -- CloseAction for any open sessions. data FinishRequest FinishRequest :: FinishRequest -- | If you are not processing the potential POST input in a request, use -- this consumer to drop the data to oblivion. Otherwise it will remain -- in an internal queue until the client closes the stream, and if the -- client doesn't want to do so.... dropIncomingData :: Maybe InputDataStream -> IO () -- | Activates logging to terminal enableConsoleLogging :: IO ()