There are two methods that I know of for making parsers that can also
be unparsers. One is the approach used in Boomerang:

On Mon, Jun 30, 2014 at 2:20 PM, Nicolas Trangez <[email protected]> wrote:
> On Sun, 2014-06-29 at 18:05 -0700, Gabriel Gonzalez wrote:
>> So if I understand correctly, you only need a way to:
>>
>> A) Parse requests from a raw byte stream (i.e. your `Producer`)
>> B) Create responses
>> C) Serialize responses to a byte stream
>
> That's about it indeed.
>
>> `pipes-attoparsec` is the most idiomatic way to do (A).  You can get the
>> necessary parsers from `hweblib`, which provides RFC2616-compliant parsers.
>
> Aha, interesting. I didn't know that package, guess it could suit my
> needs.
>
> Too bad the Warp parser can't be reused though. I'd expect it's more
> battle-tested. On first sight, `hweblib` doesn't handle request bodies
> (not to mention chunked encodings). I guess I could not support that for
> now, maybe look into it later.
>
>> For (B), you can also use the `hweblib` library, which provides a
>> `Response` type you can build.
>>
>> For (C), I'm not as sure.  Ask Aycan (the maintainer of `hweblib`) if
>> there is a way to serialize `Response`s to `ByteString`s.
>
> According to the package Haddocks, the `Response` constructor &
> accessors are exported, so I can write `responseProducer` myself :-)
>
>> The main issue in general is that most web server libraries don't have a
>> separate library just for parsing requests and serializing responses.
>> `hweblib` is the closest library I've found for this purpose.
>
> Yeah. It's somewhat sad: HTTP seems deceivingly simple, but being able
> to parse every valid HTTP request, including all possible quirks, is
> harder than one might think, and writing a parser over and over again
> seems rather useless.
>
> Maybe I should create a package, using `http-types`.
>
> On a side note: would it be hard to create a parser library (most likely
> limited to an applicative interface, not monadic) which, given a parser
> definition, can also create an 'unparser', up to an isomorphism (~
> ignored elements)? I'm aware of some research in this area, but given
> Lens and its combination of getters & setters in one, there might be
> some new opportunities.
>
> Nicolas
>
>>
>> On 06/29/2014 05:00 PM, Nicolas Trangez wrote:
>> > Gabriel,
>> >
>> > On Sun, 2014-06-29 at 12:37 -0700, Gabriel Gonzalez wrote:
>> >> This is a simple "echo" server written using `pipes-wai`:
>> >>
>> >>       {-# LANGUAGE OverloadedStrings #-}
>> >>
>> >>       import Blaze.ByteString.Builder (fromByteString)
>> >>       import Pipes
>> >>       import qualified Pipes.Prelude as Pipes
>> >>       import Pipes.Wai
>> >>       import Network.Wai.Handler.Warp
>> >>       import Network.HTTP.Types (Status(..))
>> >>
>> >>       main = run 8000 $ \request onResponse -> do
>> >>           let p = do
>> >>                   producerRequestBody request >-> Pipes.map (Chunk .
>> >> fromByteString)
>> >>                   yield Flush
>> >>
>> >>           onResponse (responseProducer (Status 200 "") [] p)
>> >>
>> >> `producerRequestBody` turns the incoming client's request into a
>> >> `Producer`.  Then you can do whatever you want with that `Producer`,
>> >> like read in its contents, discard it, or (in the above example) stream
>> >> it directly to the response.
>> >>
>> >> If you give a more specific example of what you want to do, I can give a
>> >> more specific example.
>> > Thanks for taking time looking into this. It looks like I might have
>> > been somewhat unclear before.
>> >
>> > Whilst your example above indeed turns a client request into a Producer
>> > and turns a Producer into a response, this is all at another layer than
>> > what I'm trying to accomplish.
>> >
>> > Here's the difference: in your example, the 'run' function (as provided
>> > by Warp) takes care of setting up a listening socket, accepting client
>> > connections, forking threads,...
>> >
>> > Whilst in my application, all this functionality is provided already,
>> > all I'm left with are a ByteString Producer and ByteString Consumer
>> > representing a client socket connection. Now a Request should be
>> > read/parsed from the Producer, handled, and then a Response should be
>> > yield'ed to the Consumer. All of this for this single client connection,
>> > no need to accept connections, spawn threads,...
>> >
>> > This could boil down to, e.g.
>> >
>> > runHTTPInteraction :: Monad m => Pipe ByteString ByteString m r
>> > runHTTPInteraction = do
>> >     req <- readRequest
>> >     let resp = ...
>> >     renderResponse resp
>> >
>> > Then, when my client handler function is called with a `Producer
>> > ByteString m r` and `Consumer ByteString m r`, I can use the above using
>> > something like
>> >
>> > -- Interact with a single client. This runs in its own thread etc.
>> > myHandler :: Monad m => Producer ByteString IO () -> Consumer ByteString
>> > IO () -> ()
>> > myHandler prod cons =
>> >      runEffect $
>> >      {- for HTTP pipelining / connection re-use... -} forever $
>> >      prod >-> runHTTPInteractoin >-> cons
>> >
>> > (or something along those lines, this is no real code so might not even
>> > type-check).
>> >
>> > Thanks,
>> >
>> > Nicolas
>> >
>> >
>> >> On 06/28/2014 02:20 PM, Nicolas Trangez wrote:
>> >>> On Sat, 2014-06-28 at 14:12 -0700, Gabriel Gonzalez wrote:
>> >>>> Have you tried the `pipes-wai` library?
>> >>> I passed by it during my search, but its operations seem client-centric:
>> >>> turning a `Request` into a `Producer ByteString m ()` (in order to
>> >>> stream the data from that producer to some server?), or create a
>> >>> `Response` out of a `Producer (Flush Builder) IO ()` (in order to stream
>> >>> data from the producer to a client on some server?).
>> >>>
>> >>> I could be missing something very obvious, but I don't think that's what
>> >>> I need.
>> >>>
>> >>> Thanks,
>> >>>
>> >>> Nicolas
>> >>>
>> >>>> On Jun 28, 2014 1:52 PM, "Nicolas Trangez" <[email protected]> wrote:
>> >>>>
>> >>>>> All,
>> >>>>>
>> >>>>> Has anyone ever written anything HTTP-server-like using Pipes? I looked
>> >>>>> into Warp to check whether it could be integrated, but Warp seems to do
>> >>>>> connection management, thread management, timeout handling, whatnot,
>> >>>>> which is not what I need.
>> >>>>>
>> >>>>> I'm looking for something simpler: given a `Producer ByteString m r` 
>> >>>>> and
>> >>>>> a `Consumer ByteString m r`, read a `Request` from the producer, then 
>> >>>>> do
>> >>>>> some handling, and render a `Response` to the consumer.
>> >>>>>
>> >>>>> Are there any libraries I could look into, or is Warp easy to integrate
>> >>>>> yet I'm failing to see how?
>> >>>>>
>> >>>>> Thanks,
>> >>>>>
>> >>>>> Nicolas
>> >>>>>
>> >>>>> --
>> >>>>> You received this message because you are subscribed to the Google 
>> >>>>> Groups
>> >>>>> "Haskell Pipes" group.
>> >>>>> To unsubscribe from this group and stop receiving emails from it, send 
>> >>>>> an
>> >>>>> email to [email protected].
>> >>>>> To post to this group, send email to [email protected].
>> >>>>>
>> >
>>
>
>
> --
> You received this message because you are subscribed to the Google Groups 
> "Haskell Pipes" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
> To post to this group, send email to [email protected].

-- 
You received this message because you are subscribed to the Google Groups 
"Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].

Reply via email to