-- 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.7.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 SessionClientPollThread_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 -- | Concrete Exception. Used internally to signal that the server broke -- the connection. This is a public exception that clients of the library -- will see when acting as an HTTP client. data ClientSessionAbortedException ClientSessionAbortedException :: ConnectionCloseReason -> ClientSessionAbortedException -- | 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 -- | Reasons for a remote server interrupting a connectionn of this client data ConnectionCloseReason -- | Corresponds to NO_ERROR NormalTermination_CCR :: ConnectionCloseReason -- | A request was done after the session was previously closed. SessionAlreadyClosed_CCR :: ConnectionCloseReason -- | This one happens when one of the IO channels is closed and a -- BlockedIndefinitelyOnMVar bubbles up. It should only happen in the -- test suite, as the OpenSSL_TLS channel uses a specialized exception -- type. If you see it in the wild, it is a bug. IOChannelClosed_CCR :: ConnectionCloseReason -- | Any other reason ProtocolError_CCR :: ConnectionCloseReason -- | 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.ClientSessionAbortedException instance GHC.Show.Show SecondTransfer.Exception.ConnectionCloseReason 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.Exception.Exception SecondTransfer.Exception.ClientSessionAbortedException 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 -- | Callback type to pull data from a channel in a best-effort basis. When -- the first argument is True, the data-providing backend can block if -- the input buffers are empty and await for new data. Otherwise, it will -- return immediately with an empty ByteString type BestEffortPullAction = Bool -> 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 = IOCallbacks -> 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 IOCallbacks IOCallbacks :: PushAction -> PullAction -> BestEffortPullAction -> CloseAction -> IOCallbacks -- | put some data in the channel [_pushAction_IOC] :: IOCallbacks -> 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_IOC] :: IOCallbacks -> 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_IOC] :: IOCallbacks -> BestEffortPullAction -- | this is called when we wish to close the channel. [_closeAction_IOC] :: IOCallbacks -> CloseAction pushAction_IOC :: Lens' IOCallbacks PushAction pullAction_IOC :: Lens' IOCallbacks PullAction closeAction_IOC :: Lens' IOCallbacks CloseAction bestEffortPullAction_IOC :: Lens' IOCallbacks 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 -> Maybe InterruptEffect -> Effect -- | A callback to be called whenever a data-packet for this stream is -- called. [_fragmentDeliveryCallback_Ef] :: Effect -> Maybe FragmentDeliveryCallback -- | In certain circunstances a stream can use an internal priority, not -- given by the browser and the protocol. Lowest values here are given -- more priority. Default (when Nothing) is given zero. Cases with -- negative numbers also work. [_priorityEffect_Ef] :: Effect -> Maybe Int -- | There are situations when it is desirable to close a stream or the -- entire connection. Use this member to indicate that. [_interrupt_Ef] :: Effect -> Maybe InterruptEffect -- | 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... they will be -- pushed to the client. 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 -- peer 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 () -- | Types of interrupt effects that can be signaled by aware workers. -- These include whole connection shutdowns and stream resets. In all the -- cases, the reason given will be NO_ERROR. data InterruptEffect -- | Close and send GoAway after this stream finishes delivery InterruptConnectionAfter_IEf :: InterruptEffect -- | Close and send GoAway without delivering this stream. This -- implies that other fields of the PrincipalStream record will be -- ignored. |InterruptThisStream_IEf -- ^ Just reset this stream, -- disabled for now. InterruptConnectionNow_IEf :: InterruptEffect 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) interrupt_Ef :: Lens' Effect (Maybe InterruptEffect) 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 -- | Given an AwareWorker, 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. There is an -- equivalent 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 HTTP/1.1 and HTTP/2 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, the protocol the client is using -- and in the future things like the remote address. -- -- 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... they will be -- pushed to the client. 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 -- peer 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 = IOCallbacks -> IO () -- | Session attendant that speaks HTTP/1.1 http11Attendant :: SessionsContext -> AwareWorker -> Attendant -- | Given an AwareWorker, 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. There is an -- equivalent 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 ()