Looking for criticism and comments on web-mongrel2.

After sufficient hand-wringing I finally uploaded web-mongrel2 up to hackage and I'm interested in criticism of my approach. The module itself is terribly simple as it's meant to provide a lightweight layer between an application or framework and Mongrel2, but if nothing else, it's a start. Anyway, the hackage page is at http://hackage.haskell.org/package/web-mongrel2-0.0.2.2 with a link to the github repo.

On Fri, Jan 21, 2011 at 2:30 PM, Clint Moore
After sufficient hand-wringing I finally uploaded web-mongrel2 up to hackage and I'm interested in criticism of my approach. The module itself is terribly simple as it's meant to provide a lightweight layer between an application or framework and Mongrel2, but if nothing else, it's a start.
Anyway, the hackage page is at http://hackage.haskell.org/package/web-mongrel2-0.0.2.2 with a link to the github repo.
Looks like you've done a good job so far, and have even put in a fair amount of docs. Impressive! Just some minor thoughts: * I think you should consider using ByteStrings instead of Strings in a lot of places (eg, headers). * In m2_parse, it looks to me like usage of Parsec is overkill, since a simple break would work. As a plus, if you also switch to ByteString, you could use breakByte which will give you a highly optimized parsing function. * For response_body, I'd **really** avoid usage of String. In fact, some form of enumerator would be very good there. But at the very least, please switch to a lazy ByteString. I can't really say too much more without knowing more of the internals of zeromq and mongrel2, but I think this is a good project to have going for the Haskell community. Thank you. Obviously I'm biased here, but I'd love to see a WAI wrapper for mongrel2. Would you be interested in either having this package provide a WAI interface, or writing a separate package that wraps this package and provides one? I'd be happy to offer some help if you're interested. Michael

On Fri, Jan 21, 2011 at 5:28 AM, Michael Snoyman
On Fri, Jan 21, 2011 at 2:30 PM, Clint Moore
wrote: Looks like you've done a good job so far, and have even put in a fair amount of docs. Impressive! Just some minor thoughts:
Well thanks for the encouragement!
* I think you should consider using ByteStrings instead of Strings in a lot of places (eg, headers).
Ugh! I forgot to include in my email that that was the first thing I am going to do. I'm actually working on that now.
* In m2_parse, it looks to me like usage of Parsec is overkill, since a simple break would work. As a plus, if you also switch to ByteString, you could use breakByte which will give you a highly optimized parsing function.
Now this I wouldn't have thought of. I'll go back into m2_parse and look it over again.
* For response_body, I'd **really** avoid usage of String. In fact, some form of enumerator would be very good there. But at the very least, please switch to a lazy ByteString.
Yep, definitely bytestrings everywhere. I guess I was overly excited to get it in front of someone and kinda jumped the gun on releasing it. There'll be a new version tomorrow.
I can't really say too much more without knowing more of the internals of zeromq and mongrel2, but I think this is a good project to have going for the Haskell community. Thank you.
Again, I appreciate the complement!
Obviously I'm biased here, but I'd love to see a WAI wrapper for mongrel2. Would you be interested in either having this package provide a WAI interface, or writing a separate package that wraps this package and provides one? I'd be happy to offer some help if you're interested.
One of the reasons the handler is so simply implemented is so that, at least I hope, is that it makes it very simple to implement handlers. Incidentally, WAI was the first library I was going to start with for implementing some handlers myself. I figure the more handlers I write the more bugs I'll catch.

On Fri, Jan 21, 2011 at 3:40 PM, Clint Moore
On Fri, Jan 21, 2011 at 5:28 AM, Michael Snoyman
wrote: On Fri, Jan 21, 2011 at 2:30 PM, Clint Moore
wrote: Looks like you've done a good job so far, and have even put in a fair amount of docs. Impressive! Just some minor thoughts: Well thanks for the encouragement!
* I think you should consider using ByteStrings instead of Strings in a lot of places (eg, headers).
Ugh! I forgot to include in my email that that was the first thing I am going to do. I'm actually working on that now.
* In m2_parse, it looks to me like usage of Parsec is overkill, since a simple break would work. As a plus, if you also switch to ByteString, you could use breakByte which will give you a highly optimized parsing function.
Now this I wouldn't have thought of. I'll go back into m2_parse and look it over again.
* For response_body, I'd **really** avoid usage of String. In fact, some form of enumerator would be very good there. But at the very least, please switch to a lazy ByteString.
Yep, definitely bytestrings everywhere. I guess I was overly excited to get it in front of someone and kinda jumped the gun on releasing it. There'll be a new version tomorrow.
I can't really say too much more without knowing more of the internals of zeromq and mongrel2, but I think this is a good project to have going for the Haskell community. Thank you.
Again, I appreciate the complement!
Obviously I'm biased here, but I'd love to see a WAI wrapper for mongrel2. Would you be interested in either having this package provide a WAI interface, or writing a separate package that wraps this package and provides one? I'd be happy to offer some help if you're interested.
One of the reasons the handler is so simply implemented is so that, at least I hope, is that it makes it very simple to implement handlers. Incidentally, WAI was the first library I was going to start with for implementing some handlers myself. I figure the more handlers I write the more bugs I'll catch.
Glad to hear you were already working on the bytestring switch, I hope I didn't focus on that too much ;). If you *are* planning on writing a WAI handler for this, you will need to provide something more powerful for the response body than lazy bytestrings. Well, either that, or use some ugly forkIO/unsafeInterleaveIO tricks that I don't mention in polite company. Out of curiosity, does mongrel2 provide any kind of optimization for serving files via a sendfile system call? I would be surprised if it didn't. Michael

On Fri, Jan 21, 2011 at 5:44 AM, Michael Snoyman
Glad to hear you were already working on the bytestring switch, I hope I didn't focus on that too much ;). If you *are* planning on writing a
Naw, you didn't. Using bytestrings as much as possible especially when dealing with network services are a definite best practice.
WAI handler for this, you will need to provide something more powerful for the response body than lazy bytestrings. Well, either that, or use some ugly forkIO/unsafeInterleaveIO tricks that I don't mention in polite company.
Well, then I'll have to figure something out. I'm morally opposed to unsafe* No, forkIO I love. But haven't yet had to resort to using anything unsafe, though I haven't done any FFI or other things that apparently make it necessary.
Out of curiosity, does mongrel2 provide any kind of optimization for serving files via a sendfile system call? I would be surprised if it didn't.
I don't know. I'll check that out and report back. As far as handling files, one thing that I really like about M2 is the way it handles file uploads. From the manual: "Mongrel2 uses an asynchronous method of doing uploads that helps you avoid receiving files you either can't accept or shouldn't accept. It does this by sending your handler an initial message with just the headers, streaming the file to disk, and then a final message so you can read the resulting file. If you don't want the upload, then you can send a kill message (a 0 length message) and the connection closes, and the file never lands." I'm going to write a couple of simple examples later today, one of them being a file upload handler to illustrate how to use it from the application side.

On Fri, Jan 21, 2011 at 3:55 PM, Clint Moore
On Fri, Jan 21, 2011 at 5:44 AM, Michael Snoyman
wrote: Glad to hear you were already working on the bytestring switch, I hope I didn't focus on that too much ;). If you *are* planning on writing a
Naw, you didn't. Using bytestrings as much as possible especially when dealing with network services are a definite best practice.
WAI handler for this, you will need to provide something more powerful for the response body than lazy bytestrings. Well, either that, or use some ugly forkIO/unsafeInterleaveIO tricks that I don't mention in polite company.
Well, then I'll have to figure something out. I'm morally opposed to unsafe*
No, forkIO I love. But haven't yet had to resort to using anything unsafe, though I haven't done any FFI or other things that apparently make it necessary.
The most powerful interface (powerful meaning user can do whatever they want) is a simple ByteString -> IO () function that can be called multiple times to keep sending data to the client. Since you need to send the headers first, you could consider some kind of interface similar to: Application :: Request -> (Status -> Headers -> IO (ByteString -> IO ()) -> IO () This would basically mean that an application is given a request and function to call. That function, after taking the status code and headers (however you encode them) would return a *new* function that would allow you to send chunks of data to the client. You could also completely skip the status/headers part and make it the user's responsibility to add them. Another option is using blaze-builder Builders instead of ByteStrings. Now that I looked more closely at the response_template, a few questions: * Why are you sending Connection: close? * I'm not sure if it can ever cause a problem, but it's probably a bad idea to give a message of OK for every status code. * Not every content type will have a charset associated with it (eg, image/png).
Out of curiosity, does mongrel2 provide any kind of optimization for serving files via a sendfile system call? I would be surprised if it didn't.
I don't know. I'll check that out and report back.
As far as handling files, one thing that I really like about M2 is the way it handles file uploads. From the manual:
"Mongrel2 uses an asynchronous method of doing uploads that helps you avoid receiving files you either can't accept or shouldn't accept. It does this by sending your handler an initial message with just the headers, streaming the file to disk, and then a final message so you can read the resulting file. If you don't want the upload, then you can send a kill message (a 0 length message) and the connection closes, and the file never lands."
I'm going to write a couple of simple examples later today, one of them being a file upload handler to illustrate how to use it from the application side.
That sounds like a nice interface if you're just targeting mongrel directly. However: * How does it handle request which are neither url-encoded or multipart form data? * To provide a proper WAI backend, it would need to provide the raw request body. Does mongrel2 support that in any way? Michael
participants (2)
-
Clint Moore
-
Michael Snoyman