Reputation: 1535
I want to write a proxy, which would receive a header that indicates the destination IP, port, etc.
So I have something like this:
getHeader = do
Just x <- await
let (a, rest) = splitAt headerLen x
return $ parseHeader a
-- how to send the rest data downstream ??
(resume, header) <- clientSource $$+ getHeader
-- do something according to the header
The problem is that, sometimes the header and the subsequent data are sent together, and therefore getHeader
consumes the subsequent data, which is supposed to be consumed by later conduits. So how can I send rest
downstream?
Upvotes: 2
Views: 122
Reputation: 63359
You could also consider to use a parser wrapped into a conduit, for example Data.Conduit.Attoparsec
in conduit-extra. The wrapper takes care of requesting as many input pieces as needed (in your case it can happen that the first piece is shorter than headerLen
), and also of taking care of leftovers:
import Control.Monad.Catch
import qualified Data.Attoparsec.ByteString as P
import Data.Attoparsec.Types
import qualified Data.ByteString as BS
import Data.Conduit
import Data.Conduit.Attoparsec
parseHeader :: Parser BS.ByteString BS.ByteString
parseHeader = P.take headerLen -- do whatever parsing you need to get the header
where
headerLen = 42
consumerHeader :: (MonadThrow m) => Consumer BS.ByteString m BS.ByteString
consumerHeader = sinkParser parseHeader
Consumer
is defined as
type Consumer i m r = forall o. ConduitM i o m r
so consumerHeader
takes ByteString
as input, is polymorphic in the output as well as the monad, and returns the parsed ByteString
.
Upvotes: 1