-- 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.10.0.2 module SecondTransfer.MainLoop.DebugMonitor module SecondTransfer.MainLoop.Disruptible -- | This is an entity that can be disrupted and closed. Good to force -- shutdown in some places. class Disruptible d disrupt :: Disruptible d => d -> IO () -- | Monomorphic encapsulation of a Disruptible data MonoDisruptible MonoDisruptible :: d -> MonoDisruptible instance SecondTransfer.MainLoop.Disruptible.Disruptible SecondTransfer.MainLoop.Disruptible.MonoDisruptible module SecondTransfer.Sessions.HashableSockAddr -- | Since SockAddr is not hashable, we need our own. TODO: IPv6. data HashableSockAddr hashableSockAddrFromNSSockAddr :: SockAddr -> Maybe HashableSockAddr instance GHC.Generics.Constructor SecondTransfer.Sessions.HashableSockAddr.C1_0HashableSockAddr instance GHC.Generics.Datatype SecondTransfer.Sessions.HashableSockAddr.D1HashableSockAddr instance GHC.Generics.Generic SecondTransfer.Sessions.HashableSockAddr.HashableSockAddr instance GHC.Show.Show SecondTransfer.Sessions.HashableSockAddr.HashableSockAddr instance GHC.Classes.Eq SecondTransfer.Sessions.HashableSockAddr.HashableSockAddr instance Data.Hashable.Class.Hashable SecondTransfer.Sessions.HashableSockAddr.HashableSockAddr module SecondTransfer.Socks5.Types data ClientAuthMethods_Packet ClientAuthMethods_Packet :: ProtocolVersion -> ByteString -> ClientAuthMethods_Packet [_version_SP1] :: ClientAuthMethods_Packet -> ProtocolVersion [_methods_SP1] :: ClientAuthMethods_Packet -> ByteString data ServerSelectsMethod_Packet ServerSelectsMethod_Packet :: ProtocolVersion -> Word8 -> ServerSelectsMethod_Packet [_version_SP2] :: ServerSelectsMethod_Packet -> ProtocolVersion [_method_SP2] :: ServerSelectsMethod_Packet -> Word8 data ClientRequest_Packet ClientRequest_Packet :: ProtocolVersion -> ProtocolCommand -> Word8 -> IndicatedAddress -> Word16 -> ClientRequest_Packet [_version_SP3] :: ClientRequest_Packet -> ProtocolVersion [_cmd_SP3] :: ClientRequest_Packet -> ProtocolCommand [_reserved_SP3] :: ClientRequest_Packet -> Word8 [_address_SP3] :: ClientRequest_Packet -> IndicatedAddress [_port_SP3] :: ClientRequest_Packet -> Word16 cmd_SP3 :: Lens' ClientRequest_Packet ProtocolCommand address_SP3 :: Lens' ClientRequest_Packet IndicatedAddress port_SP3 :: Lens' ClientRequest_Packet Word16 data ServerReply_Packet ServerReply_Packet :: ProtocolVersion -> ReplyField -> Word8 -> IndicatedAddress -> Word16 -> ServerReply_Packet [_version_SP4] :: ServerReply_Packet -> ProtocolVersion [_replyField_SP4] :: ServerReply_Packet -> ReplyField [_reservedField_SP4] :: ServerReply_Packet -> Word8 [_address_SP4] :: ServerReply_Packet -> IndicatedAddress [_port_SP4] :: ServerReply_Packet -> Word16 replyField_SP4 :: Lens' ServerReply_Packet ReplyField address_SP4 :: Lens' ServerReply_Packet IndicatedAddress port_SP4 :: Lens' ServerReply_Packet Word16 data AddressType IPv4_S5AT :: AddressType DomainName_S5AT :: AddressType IPv6_S5AT :: AddressType -- | The command sent by the client data ProtocolCommand Connect_S5PC :: ProtocolCommand Bind_S5PC :: ProtocolCommand UdpAssociate_S5PC :: ProtocolCommand -- | A nonce which is always equal to five... or we are in troubles data ProtocolVersion ProtocolVersion :: ProtocolVersion data IndicatedAddress IPv4_IA :: Word32 -> IndicatedAddress DomainName_IA :: ByteString -> IndicatedAddress IPv6_IA :: ByteString -> IndicatedAddress data ReplyField Succeeded_S5RF :: ReplyField GeneralFailure_S5RF :: ReplyField iaToAddressType :: IndicatedAddress -> AddressType -- | Connection ID for SOCKS5 Connections newtype S5ConnectionId S5ConnectionId :: Int64 -> S5ConnectionId -- | SOCKS5 Connections, and where are they handled data Socks5ConnectEvent Established_S5Ev :: SockAddr -> S5ConnectionId -> Socks5ConnectEvent HandlingHere_S5Ev :: ByteString -> S5ConnectionId -> Socks5ConnectEvent ToExternal_S5Ev :: ByteString -> Word16 -> S5ConnectionId -> Socks5ConnectEvent Dropped_S5Ev :: ByteString -> S5ConnectionId -> Socks5ConnectEvent type Socks5LogCallback = Socks5ConnectEvent -> IO () -- | Callbacks used by client applications to get notified about -- interesting events happening at a connection level, or to get asked -- about things (e.g, about if it is proper to accept a connection). -- These are used from CoreServer data Socks5ConnectionCallbacks Socks5ConnectionCallbacks :: Maybe Socks5LogCallback -> Socks5ConnectionCallbacks -- | Invoked after the connection is accepted, and after it is finished. [_logEvents_S5CC] :: Socks5ConnectionCallbacks -> Maybe Socks5LogCallback logEvents_S5CC :: Iso' Socks5ConnectionCallbacks (Maybe Socks5LogCallback) instance GHC.Show.Show SecondTransfer.Socks5.Types.ServerReply_Packet instance GHC.Show.Show SecondTransfer.Socks5.Types.ClientRequest_Packet instance GHC.Show.Show SecondTransfer.Socks5.Types.IndicatedAddress instance GHC.Show.Show SecondTransfer.Socks5.Types.ServerSelectsMethod_Packet instance GHC.Show.Show SecondTransfer.Socks5.Types.ClientAuthMethods_Packet instance GHC.Enum.Enum SecondTransfer.Socks5.Types.ReplyField instance GHC.Classes.Eq SecondTransfer.Socks5.Types.ReplyField instance GHC.Show.Show SecondTransfer.Socks5.Types.ReplyField instance GHC.Enum.Enum SecondTransfer.Socks5.Types.ProtocolCommand instance GHC.Classes.Eq SecondTransfer.Socks5.Types.ProtocolCommand instance GHC.Show.Show SecondTransfer.Socks5.Types.ProtocolCommand instance GHC.Enum.Enum SecondTransfer.Socks5.Types.AddressType instance GHC.Classes.Eq SecondTransfer.Socks5.Types.AddressType instance GHC.Show.Show SecondTransfer.Socks5.Types.AddressType instance GHC.Show.Show SecondTransfer.Socks5.Types.ProtocolVersion instance GHC.Enum.Enum SecondTransfer.Socks5.Types.S5ConnectionId instance GHC.Show.Show SecondTransfer.Socks5.Types.S5ConnectionId instance GHC.Classes.Ord SecondTransfer.Socks5.Types.S5ConnectionId instance GHC.Classes.Eq SecondTransfer.Socks5.Types.S5ConnectionId module SecondTransfer.IOCallbacks.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 -- | An Attendant is an entity that can speak a protocol, given the -- presented I/O callbacks. It's work is to spawn a set of threads to -- handle a client's session, and then return to the caller. It shouldn'r -- busy the calling thread. type Attendant = ConnectionData -> 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. There is one -- rule for IOCallbacks: only one user of it. That is, only one can -- write, only one can read concurrently. We don't protect for anything -- else, so concurrent read and writes would result in terrible things -- happening. 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. An exception of type NoMoreDataException can be raised from -- here inside if the channel is closed. This is done to notify the -- caller that there is no more data. The alternative would be to return -- an empty string, but that looks more hazardous for the caller. [_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. This will also raise NoMoreDataException when there is no more -- data. Notice that with argument False, this may return an empty -- string. [_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 -- | An object a which is IOChannels class IOChannels a -- | This method should only be invoked once for the a instance. It will -- block/wait for any handshakes to complete, and only then return a -- usable set of callbacks. handshake :: IOChannels a => a -> IO IOCallbacks -- | Data exchanged through this channel is plain text class IOChannels a => PlainTextIO a -- | Data exchanged through this channel is the data of a TLS session class IOChannels a => TLSEncryptedIO a -- | The agent putting and retrieving data in this side of the channel -- should behave as a TLS server class TLSEncryptedIO a => TLSServerIO a -- | The agent putting and retrieving data in this side of the channel -- should behave as a TLS client class TLSEncryptedIO a => TLSClientIO a -- | Data exchanged through this channel begins with a SOCKS5 negotiation class IOChannels a => SOCKS5Preface a -- | Some context related to a connection newtype ConnectionData ConnectionData :: Maybe HashableSockAddr -> ConnectionData [_addr_CnD] :: ConnectionData -> Maybe HashableSockAddr addr_CnD :: Iso' ConnectionData (Maybe HashableSockAddr) nullConnectionData :: ConnectionData -- | Generic implementation of PullAction from BestEffortPullAction, where -- we keep around any leftovers data ... data PullActionWrapping newPullActionWrapping :: BestEffortPullAction -> IO PullActionWrapping -- | The type of this function is also PullActionWrapping -> PullAction -- There should be only one reader concurrently. pullFromWrapping' :: PullActionWrapping -> Int -> IO ByteString bestEffortPullFromWrapping :: PullActionWrapping -> Bool -> IO ByteString instance SecondTransfer.IOCallbacks.Types.IOChannels SecondTransfer.IOCallbacks.Types.PlainText instance SecondTransfer.IOCallbacks.Types.PlainTextIO SecondTransfer.IOCallbacks.Types.PlainText instance SecondTransfer.IOCallbacks.Types.IOChannels SecondTransfer.IOCallbacks.Types.TLSServer instance SecondTransfer.IOCallbacks.Types.TLSEncryptedIO SecondTransfer.IOCallbacks.Types.TLSServer instance SecondTransfer.IOCallbacks.Types.TLSServerIO SecondTransfer.IOCallbacks.Types.TLSServer module SecondTransfer.TLS.Types -- | 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 -- | Callback function to select a protocol during the ALPN negotiation -- phase. Given a list of ALPN identifiers, if something is suitable, -- return it. type ProtocolSelector = [ByteString] -> IO (Maybe Int) -- | Class to have different kinds of TLS backends. Included here and -- enabled through 'enable-botan' is support for using Botan as a -- backend. HTTP/2 requires TLS 1.2 and ALPN, so older versions of many -- TLS libraries are not suitable. class IOChannels session => TLSContext ctx session | ctx -> session, session -> ctx -- | newTLSContextFromMemory cert_data key_data protocol_selector -- creates a new context, provided certificate data. The certificate data -- must be in X509 format. The private key should be in PKCS8 format -- without password. newTLSContextFromMemory :: TLSContext ctx session => ByteString -> ByteString -> ProtocolSelector -> IO ctx newTLSContextFromCertFileNames :: TLSContext ctx session => ByteString -> ByteString -> ProtocolSelector -> IO ctx -- | Returns the protocoll finally selected for a session. unencryptTLSServerIO :: (TLSContext ctx session, TLSServerIO cipherio) => ctx -> cipherio -> IO session getSelectedProtocol :: TLSContext ctx session => session -> IO (Maybe (Int, ByteString)) -- | A connection number newtype ConnectionId ConnectionId :: Int64 -> ConnectionId -- | Connection events data ConnectionEvent -- | New connection. The second member says how many live connections are -- now Established_CoEv :: SockAddr -> ConnectionId -> Int64 -> ConnectionEvent -- | An ALPN negotiation failed ALPNFailed_CoEv :: ConnectionId -> ConnectionEvent -- | A connection ended. Ended_CoEv :: ConnectionId -> ConnectionEvent -- | Callbacks used by client applications to get notified about -- interesting events happening at a connection level, or to get asked -- about things (e.g, about if it is proper to accept a connection). -- These are used from CoreServer data ConnectionCallbacks ConnectionCallbacks :: Maybe LogCallback -> ConnectionCallbacks -- | Invoked after the connection is accepted, and after it is finished. [_logEvents_CoCa] :: ConnectionCallbacks -> Maybe LogCallback logEvents_CoCa :: Iso' ConnectionCallbacks (Maybe LogCallback) -- | Default connections callback. Empty defaultConnectionCallbacks :: ConnectionCallbacks instance GHC.Enum.Enum SecondTransfer.TLS.Types.ConnectionId instance GHC.Show.Show SecondTransfer.TLS.Types.ConnectionId instance GHC.Classes.Ord SecondTransfer.TLS.Types.ConnectionId instance GHC.Classes.Eq SecondTransfer.TLS.Types.ConnectionId -- | 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) newSessionCallback_SC :: Lens' SessionsCallbacks (Maybe NewSessionCallback) dataFrameSize :: Lens' SessionsConfig Int addUsedProtocol :: Iso' SessionsEnrichedHeaders Bool pushEnabled :: Lens' SessionsConfig Bool firstPushStream :: Lens' SessionsConfig Int networkChunkSize :: Lens' SessionsConfig Int trayMaxSize :: Lens' SessionsConfig Int -- | 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 -> Maybe NewSessionCallback -> SessionsCallbacks -- | Used to report errors during this session [_reportErrorCallback_SC] :: SessionsCallbacks -> Maybe ErrorCallback -- | Used to report delivery of individual data frames [_dataDeliveryCallback_SC] :: SessionsCallbacks -> Maybe DataFrameDeliveryCallback -- | Used to notify the session manager of new sessions, so that the -- session manager registers them (in a weak map) if need comes [_newSessionCallback_SC] :: SessionsCallbacks -> Maybe NewSessionCallback -- | 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 -> Bool -> Int -> Int -> Int -> SessionsConfig -- | Session callbacks [_sessionsCallbacks] :: SessionsConfig -> SessionsCallbacks [_sessionsEnrichedHeaders] :: SessionsConfig -> SessionsEnrichedHeaders -- | Size to use when splitting data in data frames, to be sent. TODO: An -- equivalent maxRecvSize should be defined here... [_dataFrameSize] :: SessionsConfig -> Int -- | Should we enable PUSH in sessions? Notice that the client can still -- disable PUSH at will. Also users of the library can decide not to use -- it. This just puts another layer ... [_pushEnabled] :: SessionsConfig -> Bool -- | The number to use for the first pushed stream. Should be even [_firstPushStream] :: SessionsConfig -> Int -- | Max amount of bytes to try to send in one go. The session will send -- less data if less is available, otherwise it will send slightly more -- than this amount, depending on packet boundaries. This is used to -- avoid TCP and TLS fragmentation at the network layer [_networkChunkSize] :: SessionsConfig -> Int -- | Max number of packets to hold in the output tray. A high number means -- that more memory is used by the packets have a higher chance of going -- out in a favourable order. [_trayMaxSize] :: SessionsConfig -> Int -- | An object with information about a new session, wrapped in a weak -- pointer. At the time the newSessionCallback_SC is invoked, the -- reference inside the weak pointer is guranteed to be alive. It may die -- later though. data SessionGenericHandle Whole_SGH :: a -> SessionGenericHandle Partial_SGH :: a -> IOCallbacks -> SessionGenericHandle -- | 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 () -- | Callback to be invoked when a client establishes a new session. The -- first parameter is the address of the client, and the second parameter -- is a controller that can be used to reduce the number of connections -- from time to time, the third parameter is a key on which the second -- paramter should be made a weak pointer newtype NewSessionCallback NewSessionCallback :: (HashableSockAddr -> SessionGenericHandle -> forall a. a -> IO ()) -> NewSessionCallback -- | Since SockAddr is not hashable, we need our own. TODO: IPv6. data HashableSockAddr -- | Sessions follow this class, so that they can be rescinded on -- inactivity class ActivityMeteredSession a sessionLastActivity :: ActivityMeteredSession a => a -> IO TimeSpec -- | Clean-cut of sessions class CleanlyPrunableSession a cleanlyCloseSession :: CleanlyPrunableSession a => a -> 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 instance SecondTransfer.Sessions.Config.ActivityMeteredSession SecondTransfer.Sessions.Config.SessionGenericHandle module SecondTransfer.IOCallbacks.SaveFragment data SaveReadFragment newSaveReadFragment :: IOCallbacks -> ByteString -> IO SaveReadFragment instance SecondTransfer.IOCallbacks.Types.IOChannels SecondTransfer.IOCallbacks.SaveFragment.SaveReadFragment -- | A simple session manager that prunes the number of connections from -- time to time.... module SecondTransfer.Sessions.Tidal -- | Configuration structure data TidalContext TidalContext :: Int -> Int -> TidalContext -- | Number of admissible connections per peer [_maxConnectionPerPeer_TiC] :: TidalContext -> Int -- | Callback to be used when a connection to a peer is lost. | High water -- mark. When the number of connections go higher than this number, some -- of them are pruned. [_highWaterMark_TiC] :: TidalContext -> Int maxConnectionPerPeer_TiC :: Lens' TidalContext Int highWaterMark_TiC :: Lens' TidalContext Int newTidalSession :: TidalContext -> IO TidalS defaultTidalContext :: TidalContext tidalConnectionManager :: TidalS -> NewSessionCallback 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 in the Session engines. 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. It should also be used for the -- case of streaming requests that are interrupted by the upstream -- server. This exception inherits from HTTP11Exception data HTTP500PrecursorException HTTP500PrecursorException :: e -> HTTP500PrecursorException -- | Used by the ReverseProxy to signal an error from the upstream/Gateway data GatewayAbortedException GatewayAbortedException :: GatewayAbortedException -- | 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 -- | This is raised by the IOCallbacks when the endpoint is not willing to -- return or to accept more data data NoMoreDataException NoMoreDataException :: NoMoreDataException -- | Exception to denote that something failed with the SOCKS5 protocol data SOCKS5ProtocolException SOCKS5ProtocolException :: SOCKS5ProtocolException -- | 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 -- | Simple utility function that ignores an exception. Good to work on -- threads when we know stuff. It takes as a first parameter a proxy. ignoreException :: Exception e => Proxy e -> a -> IO a -> IO a -- | Simple utility function that reports exceptions reportExceptions :: IO a -> IO a keyedReportExceptions :: String -> IO a -> IO a -- | Just report all unhandled and un-ignored exceptions forkIOExc :: String -> IO () -> IO ThreadId blockedIndefinitelyOnMVar :: Proxy BlockedIndefinitelyOnMVar blockedIndefinitelyOnSTM :: Proxy BlockedIndefinitelyOnSTM noMoreDataException :: Proxy NoMoreDataException ioProblem :: Proxy IOProblem gatewayAbortedException :: Proxy GatewayAbortedException ioException :: Proxy IOException instance GHC.Show.Show SecondTransfer.Exception.SOCKS5ProtocolException instance GHC.Show.Show SecondTransfer.Exception.StreamCancelledException instance GHC.Show.Show SecondTransfer.Exception.NoMoreDataException 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.GatewayAbortedException 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.GatewayAbortedException 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.NoMoreDataException instance GHC.Exception.Exception SecondTransfer.Exception.StreamCancelledException instance GHC.Exception.Exception SecondTransfer.Exception.SOCKS5ProtocolException module SecondTransfer.IOCallbacks.WrapSocket -- | This function wraps an active socket (e.g., one where it is possible -- to send and receive data) in something with a set of active callbacks socketIOCallbacks :: Socket -> IO SocketIOCallbacks -- | IOCallbacks around an active socket data SocketIOCallbacks socket_SS :: Lens' SocketIOCallbacks Socket class HasSocketPeer a getSocketPeerAddress :: HasSocketPeer a => a -> IO SockAddr data SomeHasSocketPeer SomeHasSocketPeer :: a -> SomeHasSocketPeer instance SecondTransfer.IOCallbacks.Types.IOChannels SecondTransfer.IOCallbacks.WrapSocket.SocketIOCallbacks instance SecondTransfer.IOCallbacks.WrapSocket.HasSocketPeer SecondTransfer.IOCallbacks.WrapSocket.SocketIOCallbacks module SecondTransfer.IOCallbacks.SocketServer -- | IOCallbacks around an active socket data SocketIOCallbacks -- | Simple alias to SocketIOCallbacks where we expect encrypted contents newtype TLSServerSocketIOCallbacks TLSServerSocketIOCallbacks :: SocketIOCallbacks -> TLSServerSocketIOCallbacks -- | Creates a listening socket at the provided network address -- (potentially a local interface) and the given port number. It returns -- the socket. This result can be used by the function tcpServe below createAndBindListeningSocket :: String -> Int -> IO Socket -- | Same as above, but it takes a pre-built address createAndBindListeningSocketNSSockAddr :: SockAddr -> IO Socket -- | This function wraps an active socket (e.g., one where it is possible -- to send and receive data) in something with a set of active callbacks socketIOCallbacks :: Socket -> IO SocketIOCallbacks -- | Simple TCP server. You must give a very short action, as the action is -- run straight in the calling thread. For a typical server, you would be -- doing a forkIO in the provided action. Do prefer to use tcpItcli -- directly. tcpServe :: Socket -> (Socket -> IO ()) -> IO () -- | Convenience function to create a TLS server. You are in charge of -- actually setting up the TLS session, this only receives a type tagged -- with the IO thing... Notice that the action should be short before -- actually forking towards something doing the rest of the conversation. -- If you do the TLS handshake in this thread, you will be in trouble -- when more than one client try to handshake simultaeneusly... ibidem if -- one of the clients blocks the handshake. tlsServe :: Socket -> (TLSServerSocketIOCallbacks -> IO ()) -> IO () -- | Itcli is a word made from ITerate-on-CLIents. This function -- makes an iterated listen... tcpItcli :: Socket -> Source IO (Socket, SockAddr) tlsItcli :: Socket -> Source IO (TLSServerSocketIOCallbacks, SockAddr) instance SecondTransfer.IOCallbacks.Types.IOChannels SecondTransfer.IOCallbacks.SocketServer.TLSServerSocketIOCallbacks instance SecondTransfer.IOCallbacks.Types.TLSEncryptedIO SecondTransfer.IOCallbacks.SocketServer.TLSServerSocketIOCallbacks instance SecondTransfer.IOCallbacks.Types.TLSServerIO SecondTransfer.IOCallbacks.SocketServer.TLSServerSocketIOCallbacks instance SecondTransfer.IOCallbacks.WrapSocket.HasSocketPeer SecondTransfer.IOCallbacks.SocketServer.TLSServerSocketIOCallbacks module SecondTransfer.IOCallbacks.Coupling -- | A coupling between two IOCallbacks. It is breakable... data Coupling -- | Connects two IO callbacks so that data received in one is sent to the -- other. couple :: IOCallbacks -> IOCallbacks -> IO Coupling breakCoupling :: Coupling -> IO () -- | Sends the data coming from the source to the IOCallbacks. No -- exceptions are handled here. This consumes the thread until it -- finishes. The iocallbacks is not closed. sendSourceToIO :: MonadIO m => Source m ByteString -> IOCallbacks -> m () iocallbacksToSink :: MonadIO m => IOCallbacks -> Sink ByteString m () popIOCallbacksIntoExistance :: IO (IOCSideA, IOCSideB) data IOCSideA data IOCSideB instance SecondTransfer.IOCallbacks.Types.IOChannels SecondTransfer.IOCallbacks.Coupling.IOCSideA instance SecondTransfer.IOCallbacks.Types.IOChannels SecondTransfer.IOCallbacks.Coupling.IOCSideB module SecondTransfer.Socks5.Session -- | tlsSOCKS5Serve approver listening_socket onsocks5_action The approver -- should return True for host names that are served by this software -- (otherwise the connection will be closed, just for now, in the close -- future we will implement a way to forward requests to external -- Internet hosts.) Pass a bound and listening TCP socket where you -- expect a SOCKS5 exchange to have to tke place. And pass an action that -- can do something with the callbacks. The passed-in action is expected -- to fork a thread and return inmediately. tlsSOCKS5Serve :: MVar Socks5ServerState -> Socks5ConnectionCallbacks -> (ByteString -> Bool) -> Bool -> Socket -> (TLSServerSOCKS5Callbacks -> IO ()) -> IO () data ConnectOrForward Connect_COF :: ByteString -> IOCallbacks -> ConnectOrForward Forward_COF :: ByteString -> Word16 -> ConnectOrForward Drop_COF :: ByteString -> ConnectOrForward data Socks5ServerState initSocks5ServerState :: Socks5ServerState instance SecondTransfer.IOCallbacks.Types.IOChannels SecondTransfer.Socks5.Session.TLSServerSOCKS5Callbacks instance SecondTransfer.IOCallbacks.Types.TLSEncryptedIO SecondTransfer.Socks5.Session.TLSServerSOCKS5Callbacks instance SecondTransfer.IOCallbacks.Types.TLSServerIO SecondTransfer.Socks5.Session.TLSServerSOCKS5Callbacks instance SecondTransfer.IOCallbacks.WrapSocket.HasSocketPeer SecondTransfer.Socks5.Session.TLSServerSOCKS5Callbacks module SecondTransfer.Sessions.Internal -- | Contains information that applies to all sessions created in the -- program. Use the lenses interface to access members of this struct. -- -- TODO: members of this record should be renamed to the "suffix" -- convention. data SessionsContext SessionsContext :: SessionsConfig -> MVar Int -> SessionsContext -- | Read-only configuration information passed-in at construction time [_sessionsConfig] :: SessionsContext -> SessionsConfig -- | MVar with enumerator for sessions [_nextSessionId] :: SessionsContext -> MVar Int sessionsConfig :: Lens' SessionsContext SessionsConfig nextSessionId :: Lens' SessionsContext (MVar Int) sessionsConfig_Sctx :: Lens' SessionsContext SessionsConfig nextSessionId_Sctx :: Lens' SessionsContext (MVar Int) acquireNewSessionTag :: SessionsContext -> IO Int makeSessionsContext :: SessionsConfig -> IO SessionsContext makeDefaultSessionsContext :: IO SessionsContext sessionExceptionHandler :: Exception e => SessionComponent -> Int -> SessionsContext -> e -> IO () module SecondTransfer.Sessions makeSessionsContext :: SessionsConfig -> IO SessionsContext makeDefaultSessionsContext :: IO SessionsContext -- | Contains information that applies to all sessions created in the -- program. Use the lenses interface to access members of this struct. -- -- TODO: members of this record should be renamed to the "suffix" -- convention. data SessionsContext SessionsContext :: SessionsConfig -> MVar Int -> SessionsContext -- | Read-only configuration information passed-in at construction time [_sessionsConfig] :: SessionsContext -> SessionsConfig -- | MVar with enumerator for sessions [_nextSessionId] :: SessionsContext -> MVar Int module SecondTransfer.TLS.CoreServer -- | Convenience function to open a port and listen there for connections -- and select protocols and so on. tlsServeWithALPN :: (TLSContext ctx session) => (Proxy ctx) -> ConnectionCallbacks -> ByteString -> ByteString -> String -> NamedAttendants -> Int -> IO () -- | Use a previously given network address tlsServeWithALPNNSSockAddr :: (TLSContext ctx session) => (Proxy ctx) -> ConnectionCallbacks -> ByteString -> ByteString -> SockAddr -> NamedAttendants -> IO () tlsSessionHandler :: (TLSContext ctx session, TLSServerIO encrypted_io, HasSocketPeer encrypted_io) => MVar SessionHandlerState -> NamedAttendants -> ctx -> encrypted_io -> IO () tlsServeWithALPNUnderSOCKS5SockAddr :: (TLSContext ctx session) => Proxy ctx -> ConnectionCallbacks -> Socks5ConnectionCallbacks -> ByteString -> ByteString -> SockAddr -> NamedAttendants -> [ByteString] -> Bool -> IO () data NormalTCPHold -- | The prefork way requires a first step where we create the sockets and -- then we listen on them... This function is identical otherwise to the -- one without _Prepare. The real thing is done by the one with _Do -- below... tlsServeWithALPNNSSockAddr_Prepare :: (TLSContext ctx session) => (Proxy ctx) -> ConnectionCallbacks -> ByteString -> ByteString -> SockAddr -> IO NamedAttendants -> IO NormalTCPHold -- | Actually listen, possibly at the other side of the fork. tlsServeWithALPNNSSockAddr_Do :: NormalTCPHold -> IO () -- | Opaque hold type data Socks5Hold tlsServeWithALPNUnderSOCKS5SockAddr_Prepare :: (TLSContext ctx session) => Proxy ctx -> ConnectionCallbacks -> Socks5ConnectionCallbacks -> ByteString -> ByteString -> SockAddr -> IO NamedAttendants -> [ByteString] -> Bool -> IO Socks5Hold tlsServeWithALPNUnderSOCKS5SockAddr_Do :: Socks5Hold -> IO () coreListen :: (TLSContext ctx session, TLSServerIO b, HasSocketPeer b) => (Proxy ctx) -> ConnectionCallbacks -> ByteString -> ByteString -> a -> (a -> (b -> IO ()) -> IO ()) -> [(String, Attendant)] -> IO () -- | A simple Alias type NamedAttendants = [(String, Attendant)] chooseProtocol :: [(String, a)] -> [ByteString] -> IO (Maybe Int) -- | A CoherentWorker is one that doesn't need to compute everything at -- once... This one is simpler than the SPDY one, because it enforces -- certain order.... module SecondTransfer.MainLoop.CoherentWorker -- | 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 AwareWorkerStack 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] -> Maybe HashableSockAddr -> 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 announced protocols [_anouncedProtocols_Pr] :: Perception -> Maybe [ByteString] -- | tuple with something like the IPv4 number for the requesting host [_peerAddress_Pr] :: Perception -> Maybe HashableSockAddr -- | 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 -> PriorityEffect -> Maybe InterruptEffect -> Effect -- | A callback to be called whenever a data-packet for this stream is . [_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 -> PriorityEffect -- | 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 -- | Has kind * -> * Used to allow for registered cleanup functions to -- be safely called, evenspecially in the event of a BrowserUser -- hanging-up the connection before the worker has finished doing its -- work. Alleviates the need for handling async. execeptions. type AwareWorkerStack = ResourceT IO -- | 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 AwareWorkerStack 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 AwareWorkerStack 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. InterruptConnectionNow_IEf :: InterruptEffect -- | Valid priority effects -- -- 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. Since higher numbers mean *lower* -- priority, we often call this number *calm*, so that higher numbers -- mean higher calm. -- -- Notice that SecondTransfer still assigns "system priorities" to frames -- which are used before the priorities computed by this mechanism. data PriorityEffect -- | Leaves on default priorities NoEffect_PrEf :: PriorityEffect -- | Assigns a uniform priority to all data in this stream Uniform_PrEf :: !Int -> PriorityEffect -- | Starts with the given priority, and as the sender crosses each byte -- boundary in the first part of the pair, the calm is raised (e.g., the -- priority is lowered), by the positive number given as second part of -- the pair PerYield_PrEf :: Int -> [(Word, Word)] -> PriorityEffect 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]) peerAddress_Pr :: Lens' Perception (Maybe HashableSockAddr) protocol_Pr :: Lens' Perception HttpProtocolVersion fragmentDeliveryCallback_Ef :: Lens' Effect (Maybe FragmentDeliveryCallback) priorityEffect_Ef :: Lens' Effect PriorityEffect interrupt_Ef :: Lens' Effect (Maybe InterruptEffect) defaultEffects :: Effect coherentToAwareWorker :: CoherentWorker -> AwareWorker -- | Convert between the two types of callback. tupledPrincipalStreamToPrincipalStream :: TupledPrincipalStream -> PrincipalStream requestToTupledRequest :: Request -> TupledRequest instance GHC.Show.Show SecondTransfer.MainLoop.CoherentWorker.Effect module SecondTransfer.Types -- | 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 :: MonadIO m => Maybe InputDataStream -> m () dropWouldGoData :: DataAndConclusion -> 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 -> HeaderName -> Maybe HeaderValue -- | 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. Notice that these -- headers are good for both HTTP1.1 and HTTP2, as combined -- headers won't be merged. It will even work for Cookie 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 -> HeaderName -> Maybe HeaderValue -> 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 headerIsPseudo :: HeaderName -> Bool -- | Combines ":authority" and "host", giving priority to the first. This -- is used when proxying HTTP2 to HTTP1.1. It leaves whichever -- header of highest priority is present combineAuthorityAndHost :: HeaderEditor -> HeaderEditor -- | Remove connection-specific headers as required by HTTP/2 removeConnectionHeaders :: Headers -> Headers -- | Fusion values for a specific header, using a provided separator. fusionHeaders :: HeaderName -> ByteString -> Headers -> Headers data PrettyPrintHeadersConfig PrettyPrintHeadersConfig :: Int -> PrettyPrintHeadersConfig [_indentSpace_PPHC] :: PrettyPrintHeadersConfig -> Int indentSpace_PPHC :: Iso' PrettyPrintHeadersConfig Int prettyPrintHeaders :: PrettyPrintHeadersConfig -> Headers -> ByteString defaultPrettyPrintHeadersConfig :: PrettyPrintHeadersConfig instance GHC.Generics.Constructor SecondTransfer.Utils.HTTPHeaders.C1_0Autosorted instance GHC.Generics.Datatype SecondTransfer.Utils.HTTPHeaders.D1Autosorted instance GHC.Generics.Constructor SecondTransfer.Utils.HTTPHeaders.C1_2HeaderPriority instance GHC.Generics.Constructor SecondTransfer.Utils.HTTPHeaders.C1_1HeaderPriority instance GHC.Generics.Constructor SecondTransfer.Utils.HTTPHeaders.C1_0HeaderPriority instance GHC.Generics.Datatype SecondTransfer.Utils.HTTPHeaders.D1HeaderPriority instance GHC.Generics.Generic SecondTransfer.Utils.HTTPHeaders.Autosorted instance GHC.Show.Show SecondTransfer.Utils.HTTPHeaders.Autosorted instance GHC.Classes.Ord SecondTransfer.Utils.HTTPHeaders.Autosorted instance GHC.Classes.Eq SecondTransfer.Utils.HTTPHeaders.Autosorted instance GHC.Generics.Generic SecondTransfer.Utils.HTTPHeaders.HeaderPriority instance GHC.Show.Show SecondTransfer.Utils.HTTPHeaders.HeaderPriority instance GHC.Classes.Ord SecondTransfer.Utils.HTTPHeaders.HeaderPriority instance GHC.Classes.Eq SecondTransfer.Utils.HTTPHeaders.HeaderPriority instance GHC.Base.Monoid SecondTransfer.Utils.HTTPHeaders.HeaderEditor module SecondTransfer.Http1.Types -- | Request. This is an old-fashioned HTTP request, with less data than -- that defined at CoherentWorker: just headers and perhaps a request -- streaming body. As in other places in this library, we expect method -- and path to be given as pseudo-headers data HttpRequest m HttpRequest :: Headers -> Source m ByteString -> HttpRequest m [_headers_Rq] :: HttpRequest m -> Headers [_body_Rq] :: HttpRequest m -> Source m ByteString headers_Rq :: Lens' (HttpRequest m_a2ZZa) Headers body_Rq :: Lens (HttpRequest m_a2ZZa) (HttpRequest m_a2ZZx) (Source m_a2ZZa ByteString) (Source m_a2ZZx ByteString) -- | Response. Status should be given as a pseudo-header data HttpResponse m HttpResponse :: Headers -> Source m ByteString -> HttpResponse m [_headers_Rp] :: HttpResponse m -> Headers [_body_Rp] :: HttpResponse m -> Source m ByteString headers_Rp :: Lens' (HttpResponse m_a2ZZM) Headers body_Rp :: Lens (HttpResponse m_a2ZZM) (HttpResponse m_a3014) (Source m_a2ZZM ByteString) (Source m_a3014 ByteString) class Monad m => Http1CycleController m contrl releaseResponseResources :: Http1CycleController m contrl => contrl -> m () -- | Something that can talk to a HTTP 1.1 server by using a connection and -- sending the request to it class (Http1CycleController m contrl, Monad m) => ProxyToHttpServer m conn contrl | conn -> contrl m proxyToConnection :: ProxyToHttpServer m conn contrl => conn -> HttpRequest m -> m (HttpResponse m, contrl) module SecondTransfer.Http1.Proxy -- | Takes an IOCallbacks and serializes a request (encoded HTTP/2 style in -- headers and streams) on top of the callback, waits for the results, -- and returns the response. Notice that this proxy may fail for any -- reason, do take measures and handle exceptions. Also, must headers -- manipulations (e.g. removing the Connection header) are left to the -- upper layers. And this doesn't include managing any kind of pipelining -- in the http/1.1 connection, however, close is not done, so keep-alive -- (not pipelineing) should be OK. ioProxyToConnection :: MonadIO m => IOCallbacks -> HttpRequest m -> m (HttpResponse m, IOCallbacks) module SecondTransfer.MainLoop.ClientPetitioner class ClientPetitioner a request :: ClientPetitioner a => a -> Headers -> InputDataStream -> IO (Headers, InputDataStream) module SecondTransfer.MainLoop _nonce :: () -- | Convenience function to open a port and listen there for connections -- and select protocols and so on. tlsServeWithALPN :: (TLSContext ctx session) => (Proxy ctx) -> ConnectionCallbacks -> ByteString -> ByteString -> String -> NamedAttendants -> Int -> IO () module SecondTransfer.Http2 -- |
--   http2Attendant :: AwareWorker -> AttendantCallbacks ->  IO ()
--   
-- -- Given a 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. http2Attendant :: SessionsContext -> AwareWorker -> Attendant module SecondTransfer.Http1 -- | Session attendant that speaks HTTP/1.1 -- -- This attendant should be OK with keep-alive, but not with pipelining. 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 we have bundled -- here the TLS setup logic. 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 AwareWorkerStack 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 AwareWorkerStack 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 -- | An Attendant is an entity that can speak a protocol, given the -- presented I/O callbacks. It's work is to spawn a set of threads to -- handle a client's session, and then return to the caller. It shouldn'r -- busy the calling thread. type Attendant = ConnectionData -> IOCallbacks -> IO () -- | Session attendant that speaks HTTP/1.1 -- -- This attendant should be OK with keep-alive, but not with pipelining. http11Attendant :: SessionsContext -> AwareWorker -> Attendant -- |
--   http2Attendant :: AwareWorker -> AttendantCallbacks ->  IO ()
--   
-- -- Given a 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. http2Attendant :: SessionsContext -> AwareWorker -> Attendant coherentToAwareWorker :: CoherentWorker -> AwareWorker -- | Convenience function to open a port and listen there for connections -- and select protocols and so on. tlsServeWithALPN :: (TLSContext ctx session) => (Proxy ctx) -> ConnectionCallbacks -> ByteString -> ByteString -> String -> NamedAttendants -> Int -> IO () -- | 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 :: MonadIO m => Maybe InputDataStream -> m ()