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].