Hi there, I'll be happy to add more features to `hweblib` if you want to use it. I think your use case is important and should be covered by the library. I was also thinking to implement it via ekmett's parsers library but failed since it doesn't supply any case-insensitive parsers.
Kind Regards, On Mon, Jun 30, 2014 at 10: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]. > -- http://www.google.com/profiles/iricanaycan -- 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].
