Proposal: http-types

Hi, Hear me out, I have an idea! :-) How about creating a new package "http-types" containing Request / Response / status code / header name types for HTTP. These could be used by both server and client software, and might even allow switching between HTTP client libraries (say, if I want to switch between http-enumerator and HTTP). What do you think? Aristid

On Tue, Feb 1, 2011 at 9:55 PM, Aristid Breitkreuz
Hi, Hear me out, I have an idea! :-) How about creating a new package "http-types" containing Request / Response / status code / header name types for HTTP. These could be used by both server and client software, and might even allow switching between HTTP client libraries (say, if I want to switch between http-enumerator and HTTP). What do you think?
I'm not opposed, I tried to already create all of those types in WAI. Right now http-enumerator uses those types as well. If there are other library writers who would agree to consolidate on such an http-types package, I'll throw in these two packages as well. Michael

2011/2/1 Michael Snoyman
On Tue, Feb 1, 2011 at 9:55 PM, Aristid Breitkreuz
wrote: Hi, Hear me out, I have an idea! :-) How about creating a new package "http-types" containing Request / Response / status code / header name types for HTTP. These could be used by both server and client software, and might even allow switching between HTTP client libraries (say, if I want to switch between http-enumerator and HTTP). What do you think?
I'm not opposed, I tried to already create all of those types in WAI. Right now http-enumerator uses those types as well. If there are other library writers who would agree to consolidate on such an http-types package, I'll throw in these two packages as well.
such a package would be helpful for us as well. -- Stefan

On Wed, Feb 2, 2011 at 10:48 AM, Stefan Wehr
2011/2/1 Michael Snoyman
: On Tue, Feb 1, 2011 at 9:55 PM, Aristid Breitkreuz
wrote: Hi, Hear me out, I have an idea! :-) How about creating a new package "http-types" containing Request / Response / status code / header name types for HTTP. These could be used by both server and client software, and might even allow switching between HTTP client libraries (say, if I want to switch between http-enumerator and HTTP). What do you think?
I'm not opposed, I tried to already create all of those types in WAI. Right now http-enumerator uses those types as well. If there are other library writers who would agree to consolidate on such an http-types package, I'll throw in these two packages as well.
such a package would be helpful for us as well.
-- Stefan
Let's speak practically here about what kind of types we're dealing with: * Status, including the numeric code and status message. Eg, data Status = Status Int ByteString * Request/response header key. In WAI, I use data CIByteString = CIByteString !ByteString !ByteString, one version being the lowercase, the other the original. * Request/response header value. In WAI, I use ByteString. * Request and response datatypes themselves. I don't think this makes sense to put in http-types: just between WAI and http-enumerator I needed different versions of these. In addition to this, I think it would be convenient to have a few extra things besides types in this package: * Status values like we have in WAI: status200/statusOK, status404/statusNotFound, etc. * A bunch of header keys: hdrContentType, hdrAccept, etc Ideally, this package would only rely on base and bytestring. Michael

Hi
Let's speak practically here about what kind of types we're dealing with:
* Status, including the numeric code and status message. Eg, data Status = Status Int ByteString * Request/response header key. In WAI, I use data CIByteString = CIByteString !ByteString !ByteString, one version being the lowercase, the other the original. * Request/response header value. In WAI, I use ByteString. * Status values like we have in WAI: status200/statusOK, status404/statusNotFound, etc. * A bunch of header keys: hdrContentType, hdrAccept, etc
I think all the above is exactly what should be in the package. You shouldn't include Request/Response, but you should include all the Int/String-like values that users of http need. I also think it should be http-codes or similar, it's not defining a type. Why not do: hdrContentType :: IsString a => a And similarly for all values that are just strings. You eliminate the bytestring package dependency, and nothing will need to know whether things are String, Text, LazyByteString, ByteString or CIByteString (or even Builder values). You could also have: data HttpStatus = HttpStatus Int a statusOK :: IsString a => HttpStatus a In Hoogle I define a few things like hdrContentType, so if these were all standardized it would be great. Thanks, Neil

On Wed, Feb 2, 2011 at 12:04 PM, Neil Mitchell
Why not do:
hdrContentType :: IsString a => a
And similarly for all values that are just strings. You eliminate the bytestring package dependency, and nothing will need to know whether things are String, Text, LazyByteString, ByteString or CIByteString (or even Builder values).
You most definitely need to know whether something is Unicode or binary data. For example, the IsString type for ByteString is in essence an unsafe cast from [Word8] to [Char], assuming that the [Word8] contains latin1 encoded text. This assumption is not checked. Johan

hdrContentType :: IsString a => a
And similarly for all values that are just strings. You eliminate the bytestring package dependency, and nothing will need to know whether things are String, Text, LazyByteString, ByteString or CIByteString (or even Builder values).
You most definitely need to know whether something is Unicode or binary data. For example, the IsString type for ByteString is in essence an unsafe cast from [Word8] to [Char], assuming that the [Word8] contains latin1 encoded text. This assumption is not checked.
But everything in this package would be ASCII without the top bit set, so would work regardless of encoding. For general strings manipulated by a web page knowing the encoding is important, but the http responses should be safe. Thanks, Neil

On Wed, Feb 2, 2011 at 1:21 PM, Neil Mitchell
But everything in this package would be ASCII without the top bit set, so would work regardless of encoding. For general strings manipulated by a web page knowing the encoding is important, but the http responses should be safe.
Are you sure that no headers are defined as octets (i.e. binary data). If some are they will have all 8 bits set possibly. Johan

On 2011-02-02 16:43 +0100 (Wed), Johan Tibell wrote:
Are you sure that no headers are defined as octets (i.e. binary data). If some are they will have all 8 bits set possibly.
Some are indeed so. See, e.g., comments in HTTP headers (RFC2616 section
2.2), which are 'ctext' surrounded by parens; ctext is 'any TEXT
excluding "(" and ")"'; TEXT is 'any OCTET except CTLs...', and OCTET is
'any 8-bit sequence of data.'
That said, there is no method within the standard to specify the
encoding of anything, so stuff like that needs to be treated as more or
less opaque binary data, anyway.
It's not clear to me how the Host: header interacts with I18N domain
names, but I guess you just use the canonical ASCII form and the
strictures about doing a "case-insensitive" comparison count only for
the ASCII characters in that form. (Probably one wants to include these
sorts of comparison functions in the API.)
Another issue to think about is that many interface specifications
between web servers and things that deal with web requests don't
use HTTP headers; they use a very ill-specified "CGI environment
variables" thing instead, and the translation between HTTP headers and
that is generally "defined" (if I dare even to use that word) by the
particular web server implementation. (This is more or less the bane
of my existence when I put on my "web developer" or "web framework
developer" hat.) It would pay to be clear about just how this library
and that very common use case interact.
cjs
--
Curt Sampson

On Thu, Feb 3, 2011 at 1:30 PM, Curt Sampson
On 2011-02-02 16:43 +0100 (Wed), Johan Tibell wrote:
Are you sure that no headers are defined as octets (i.e. binary data). If some are they will have all 8 bits set possibly.
Some are indeed so. See, e.g., comments in HTTP headers (RFC2616 section 2.2), which are 'ctext' surrounded by parens; ctext is 'any TEXT excluding "(" and ")"'; TEXT is 'any OCTET except CTLs...', and OCTET is 'any 8-bit sequence of data.'
That said, there is no method within the standard to specify the encoding of anything, so stuff like that needs to be treated as more or less opaque binary data, anyway.
Right. So converting it to a Unicode type is dangerous. As operations on the Unicode type might yield errors for invalid code points generated by casting binary data to Unicode.

On Wed, Feb 2, 2011 at 1:04 PM, Neil Mitchell
Hi
Let's speak practically here about what kind of types we're dealing with:
* Status, including the numeric code and status message. Eg, data Status = Status Int ByteString * Request/response header key. In WAI, I use data CIByteString = CIByteString !ByteString !ByteString, one version being the lowercase, the other the original. * Request/response header value. In WAI, I use ByteString. * Status values like we have in WAI: status200/statusOK, status404/statusNotFound, etc. * A bunch of header keys: hdrContentType, hdrAccept, etc
I think all the above is exactly what should be in the package. You shouldn't include Request/Response, but you should include all the Int/String-like values that users of http need. I also think it should be http-codes or similar, it's not defining a type.
Why not do:
hdrContentType :: IsString a => a
And similarly for all values that are just strings. You eliminate the bytestring package dependency, and nothing will need to know whether things are String, Text, LazyByteString, ByteString or CIByteString (or even Builder values).
You could also have:
data HttpStatus = HttpStatus Int a
statusOK :: IsString a => HttpStatus a
In Hoogle I define a few things like hdrContentType, so if these were all standardized it would be great.
Thanks, Neil
No matter what we will need the bytestring dependency to define the CIByteString datatype. But is there an advantage to this polymorphism? I can't think of a use case for a status message or a header to be anything but a ByteString. There *is* one possible datatype we could include which Johan hinted at: ASCII. We could in theory have: newtype ASCII = ASCII { unASCII :: ByteString } byteStringToASCII :: ByteString -> Maybe ASCII byteStringToASCII bs | S.all isValidAscii bs = Just $ ASCII bs | otherwise = Nothing And so on and so forth for String, also providing some unsafeToAscii functions and an unsafe IsString instace. I know I've wanted this datatype in the past (WAI and mime-mail in particular), but I'm not sure if it provides enough of a benefit to be worth the extra overhead. Michael

No matter what we will need the bytestring dependency to define the CIByteString datatype. But is there an advantage to this polymorphism?
Yes, there is no need to define CIByteString at all - that can come in the WAI package, and since it has a IsString instance it will work with the http-types library automatically.
I can't think of a use case for a status message or a header to be anything but a ByteString.
Perhaps, but by making them IsString you keep full flexibility, remove all debates over things like whether hdrContentType should be CIByteString, what functions should be on CIByteString etc. Thanks, Neil PS. I'm not actually too interested in the results, as long as they slot into WAI I don't mind what the types are - the IsString was just an idea that might make things simpler and more flexible (or might not).

I agree with most things.
2011/2/2 Michael Snoyman
* Request and response datatypes themselves. I don't think this makes sense to put in http-types: just between WAI and http-enumerator I needed different versions of these.
I think this is where we could derive most value, and it would be good to find a way to do it. Request actually looks pretty similar in WAI as in http-enumerator, but Response is different. Maybe distinguish between client and server versions of Response? Aristid

On Wed, Feb 2, 2011 at 2:50 PM, Aristid Breitkreuz
I agree with most things.
2011/2/2 Michael Snoyman
* Request and response datatypes themselves. I don't think this makes sense to put in http-types: just between WAI and http-enumerator I needed different versions of these.
I think this is where we could derive most value, and it would be good to find a way to do it. Request actually looks pretty similar in WAI as in http-enumerator, but Response is different. Maybe distinguish between client and server versions of Response?
I'd be very surprised if those two can be meaningfully unified. What do you do about remoteHost and errorHandler? Also, it's more useful to have the request body for http-enumerator be an Enumerator of Builders, as opposed to WAI where we want an Enumerator of ByteStrings. I have no opposition to *having* a Request type in http-types (or whatever we call it), but I doubt anyone will actually use it, and I wouldn't even want it to include Builder due to the extra dependency. Michael

http-enumerator could at least for compatibility support a Request type with
ByteString. And also a native request type. Or something along these lines.
The problem is that I want to be able to use a Request type that is
compatible between multiple client libraries, enabling me to theoretically
switch implementations without a huge amount of hassle.
Aristid
2011/2/2 Michael Snoyman
On Wed, Feb 2, 2011 at 2:50 PM, Aristid Breitkreuz
wrote: I agree with most things.
2011/2/2 Michael Snoyman
* Request and response datatypes themselves. I don't think this makes sense to put in http-types: just between WAI and http-enumerator I needed different versions of these.
I think this is where we could derive most value, and it would be good to find a way to do it. Request actually looks pretty similar in WAI as in http-enumerator, but Response is different. Maybe distinguish between client and server versions of Response?
I'd be very surprised if those two can be meaningfully unified. What do you do about remoteHost and errorHandler? Also, it's more useful to have the request body for http-enumerator be an Enumerator of Builders, as opposed to WAI where we want an Enumerator of ByteStrings.
I have no opposition to *having* a Request type in http-types (or whatever we call it), but I doubt anyone will actually use it, and I wouldn't even want it to include Builder due to the extra dependency.
Michael

I think there's general consensus that this package would be a Good
Thing(tm), and at the least you'll have my support on it. I'm sure we
can all quibble on details later, but I think the best thing now would
be to have some actual code to look at.
Aristid, I'm assuming (hoping) you were volunteering to actually write
and maintain this package, is that correct? I would recommend you get
a project started (Github, BitBucket, PatchTag, wherever), getting up
some code and then we can all nit-pick it to death ;).
Michael
On Wed, Feb 2, 2011 at 3:45 PM, Aristid Breitkreuz
http-enumerator could at least for compatibility support a Request type with ByteString. And also a native request type. Or something along these lines. The problem is that I want to be able to use a Request type that is compatible between multiple client libraries, enabling me to theoretically switch implementations without a huge amount of hassle.
Aristid
2011/2/2 Michael Snoyman
On Wed, Feb 2, 2011 at 2:50 PM, Aristid Breitkreuz
wrote: I agree with most things.
2011/2/2 Michael Snoyman
* Request and response datatypes themselves. I don't think this makes sense to put in http-types: just between WAI and http-enumerator I needed different versions of these.
I think this is where we could derive most value, and it would be good to find a way to do it. Request actually looks pretty similar in WAI as in http-enumerator, but Response is different. Maybe distinguish between client and server versions of Response?
I'd be very surprised if those two can be meaningfully unified. What do you do about remoteHost and errorHandler? Also, it's more useful to have the request body for http-enumerator be an Enumerator of Builders, as opposed to WAI where we want an Enumerator of ByteStrings.
I have no opposition to *having* a Request type in http-types (or whatever we call it), but I doubt anyone will actually use it, and I wouldn't even want it to include Builder due to the extra dependency.
Michael

You essentially forced me to do this. ;-)
So here it is, my initial version of http-types:
https://github.com/aristidb/http-types
https://github.com/aristidb/http-typesOnly Method is supported for now.
I deliberately chose to make it an ADT for type safety reasons. This is to
enable developers to write case x of POST -> ..., and the compiler will find
if they accidentally typed POSTX. However, non-standard methods are also
supported via OtherMethod.
Please take it apart and criticize! :-)
If you have implementation ideas, just fork it, or I can add you as a
contributor.
Aristid
2011/2/2 Michael Snoyman
I think there's general consensus that this package would be a Good Thing(tm), and at the least you'll have my support on it. I'm sure we can all quibble on details later, but I think the best thing now would be to have some actual code to look at.
Aristid, I'm assuming (hoping) you were volunteering to actually write and maintain this package, is that correct? I would recommend you get a project started (Github, BitBucket, PatchTag, wherever), getting up some code and then we can all nit-pick it to death ;).
Michael
http-enumerator could at least for compatibility support a Request type with ByteString. And also a native request type. Or something along these
The problem is that I want to be able to use a Request type that is compatible between multiple client libraries, enabling me to
On Wed, Feb 2, 2011 at 3:45 PM, Aristid Breitkreuz
wrote: lines. theoretically switch implementations without a huge amount of hassle.
Aristid
2011/2/2 Michael Snoyman
On Wed, Feb 2, 2011 at 2:50 PM, Aristid Breitkreuz
wrote: I agree with most things.
2011/2/2 Michael Snoyman
* Request and response datatypes themselves. I don't think this makes sense to put in http-types: just between WAI and http-enumerator I needed different versions of these.
I think this is where we could derive most value, and it would be good to find a way to do it. Request actually looks pretty similar in WAI as in http-enumerator,
but
Response is different. Maybe distinguish between client and server versions of Response?
I'd be very surprised if those two can be meaningfully unified. What do you do about remoteHost and errorHandler? Also, it's more useful to have the request body for http-enumerator be an Enumerator of Builders, as opposed to WAI where we want an Enumerator of ByteStrings.
I have no opposition to *having* a Request type in http-types (or whatever we call it), but I doubt anyone will actually use it, and I wouldn't even want it to include Builder due to the extra dependency.
Michael

Originally WAI *did* use an ADT. However, someone (I *think* Jeremy
Shaw, I'm not sure) pointed out that pattern matching is in fact
broken here:
case OtherMethod POST of
POST -> putStrLn "Will not get called"
Also, with your implementation
POST /= OtherMethod "POST"
Michael
On Wed, Feb 2, 2011 at 11:12 PM, Aristid Breitkreuz
You essentially forced me to do this. ;-) So here it is, my initial version of http-types: https://github.com/aristidb/http-types Only Method is supported for now. I deliberately chose to make it an ADT for type safety reasons. This is to enable developers to write case x of POST -> ..., and the compiler will find if they accidentally typed POSTX. However, non-standard methods are also supported via OtherMethod. Please take it apart and criticize! :-) If you have implementation ideas, just fork it, or I can add you as a contributor.
Aristid
2011/2/2 Michael Snoyman
I think there's general consensus that this package would be a Good Thing(tm), and at the least you'll have my support on it. I'm sure we can all quibble on details later, but I think the best thing now would be to have some actual code to look at.
Aristid, I'm assuming (hoping) you were volunteering to actually write and maintain this package, is that correct? I would recommend you get a project started (Github, BitBucket, PatchTag, wherever), getting up some code and then we can all nit-pick it to death ;).
Michael
On Wed, Feb 2, 2011 at 3:45 PM, Aristid Breitkreuz
wrote: http-enumerator could at least for compatibility support a Request type with ByteString. And also a native request type. Or something along these lines. The problem is that I want to be able to use a Request type that is compatible between multiple client libraries, enabling me to theoretically switch implementations without a huge amount of hassle.
Aristid
2011/2/2 Michael Snoyman
On Wed, Feb 2, 2011 at 2:50 PM, Aristid Breitkreuz
wrote: I agree with most things.
2011/2/2 Michael Snoyman
* Request and response datatypes themselves. I don't think this makes sense to put in http-types: just between WAI and http-enumerator I needed different versions of these.
I think this is where we could derive most value, and it would be good to find a way to do it. Request actually looks pretty similar in WAI as in http-enumerator, but Response is different. Maybe distinguish between client and server versions of Response?
I'd be very surprised if those two can be meaningfully unified. What do you do about remoteHost and errorHandler? Also, it's more useful to have the request body for http-enumerator be an Enumerator of Builders, as opposed to WAI where we want an Enumerator of ByteStrings.
I have no opposition to *having* a Request type in http-types (or whatever we call it), but I doubt anyone will actually use it, and I wouldn't even want it to include Builder due to the extra dependency.
Michael

This is not a problem because constructing OtherMethod "POST" is forbidden
and will/must never happen. byteStringToMethod will always construct POST,
and not OtherMethod "POST",
2011/2/2 Michael Snoyman
Originally WAI *did* use an ADT. However, someone (I *think* Jeremy Shaw, I'm not sure) pointed out that pattern matching is in fact broken here:
case OtherMethod POST of POST -> putStrLn "Will not get called"
Also, with your implementation
POST /= OtherMethod "POST"
Michael
On Wed, Feb 2, 2011 at 11:12 PM, Aristid Breitkreuz
wrote: You essentially forced me to do this. ;-) So here it is, my initial version of http-types: https://github.com/aristidb/http-types Only Method is supported for now. I deliberately chose to make it an ADT for type safety reasons. This is to enable developers to write case x of POST -> ..., and the compiler will find if they accidentally typed POSTX. However, non-standard methods are also supported via OtherMethod. Please take it apart and criticize! :-) If you have implementation ideas, just fork it, or I can add you as a contributor.
Aristid
2011/2/2 Michael Snoyman
I think there's general consensus that this package would be a Good Thing(tm), and at the least you'll have my support on it. I'm sure we can all quibble on details later, but I think the best thing now would be to have some actual code to look at.
Aristid, I'm assuming (hoping) you were volunteering to actually write and maintain this package, is that correct? I would recommend you get a project started (Github, BitBucket, PatchTag, wherever), getting up some code and then we can all nit-pick it to death ;).
Michael
On Wed, Feb 2, 2011 at 3:45 PM, Aristid Breitkreuz
wrote: http-enumerator could at least for compatibility support a Request
type
with ByteString. And also a native request type. Or something along these lines. The problem is that I want to be able to use a Request type that is compatible between multiple client libraries, enabling me to theoretically switch implementations without a huge amount of hassle.
Aristid
2011/2/2 Michael Snoyman
On Wed, Feb 2, 2011 at 2:50 PM, Aristid Breitkreuz
wrote: I agree with most things.
2011/2/2 Michael Snoyman
> > * Request and response datatypes themselves. I don't think this > makes > sense to put in http-types: just between WAI and http-enumerator I > needed different versions of these. I think this is where we could derive most value, and it would be good to find a way to do it. Request actually looks pretty similar in WAI as in http-enumerator, but Response is different. Maybe distinguish between client and server versions of Response?
I'd be very surprised if those two can be meaningfully unified. What do you do about remoteHost and errorHandler? Also, it's more useful
to
have the request body for http-enumerator be an Enumerator of Builders, as opposed to WAI where we want an Enumerator of ByteStrings.
I have no opposition to *having* a Request type in http-types (or whatever we call it), but I doubt anyone will actually use it, and I wouldn't even want it to include Builder due to the extra dependency.
Michael

Am 02.02.2011 22:34, schrieb Aristid Breitkreuz:
This is not a problem because constructing OtherMethod "POST" is forbidden and will/must never happen. byteStringToMethod will always construct POST, and not OtherMethod "POST",
Similar discussions come up again and again. http://hackage.haskell.org/packages/archive/HTTP/4000.1.1/doc/html/Network-H... even contains a comment "Encoding HTTP header names differently, as Strings perhaps, is an equally fine choice..no decidedly clear winner" Network.HTTP.Base.RequestMethod is a similar data type. My own conclusion is: avoid as many variants as possible, otherwise you'll get lots of repetitions of similar code. A single variant wrapping a String or ByteString is the best for uniform treatment (i.e. just for implementing show). You loose (possibly faster and shorter) pattern matching, but I think it is just as good to use predefined constants and "==" for comparisons. Cheers Christian
2011/2/2 Michael Snoyman
mailto:michael@snoyman.com> Originally WAI *did* use an ADT. However, someone (I *think* Jeremy Shaw, I'm not sure) pointed out that pattern matching is in fact broken here:
case OtherMethod POST of POST -> putStrLn "Will not get called"
Also, with your implementation
POST /= OtherMethod "POST"
Michael
On Wed, Feb 2, 2011 at 11:12 PM, Aristid Breitkreuz
mailto:aristidb@googlemail.com> wrote: > You essentially forced me to do this. ;-) > So here it is, my initial version of > http-types: https://github.com/aristidb/http-types > Only Method is supported for now. > I deliberately chose to make it an ADT for type safety reasons. This is to > enable developers to write case x of POST -> ..., and the compiler will find > if they accidentally typed POSTX. However, non-standard methods are also > supported via OtherMethod. > Please take it apart and criticize! :-) > If you have implementation ideas, just fork it, or I can add you as a > contributor. > > Aristid > > 2011/2/2 Michael Snoyman mailto:michael-cq0OxgmGHj5BDgjK7y7TUQ@public.gmane.org> >> >> I think there's general consensus that this package would be a Good >> Thing(tm), and at the least you'll have my support on it. I'm sure we >> can all quibble on details later, but I think the best thing now would >> be to have some actual code to look at. >> >> Aristid, I'm assuming (hoping) you were volunteering to actually write >> and maintain this package, is that correct? I would recommend you get >> a project started (Github, BitBucket, PatchTag, wherever), getting up >> some code and then we can all nit-pick it to death ;). >> >> Michael >> >> On Wed, Feb 2, 2011 at 3:45 PM, Aristid Breitkreuz >> mailto:aristidb-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote: >> > http-enumerator could at least for compatibility support a Request type >> > with >> > ByteString. And also a native request type. Or something along these >> > lines. >> > The problem is that I want to be able to use a Request type that is >> > compatible between multiple client libraries, enabling me to >> > theoretically >> > switch implementations without a huge amount of hassle. >> > >> > Aristid >> > >> > 2011/2/2 Michael Snoyman mailto:michael@snoyman.com> >> >> >> >> On Wed, Feb 2, 2011 at 2:50 PM, Aristid Breitkreuz >> >> mailto:aristidb-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote: >> >> > I agree with most things. >> >> > >> >> > 2011/2/2 Michael Snoyman mailto:michael-cq0OxgmGHj5BDgjK7y7TUQ@public.gmane.org> >> >> >> >> >> >> * Request and response datatypes themselves. I don't think this >> >> >> makes >> >> >> sense to put in http-types: just between WAI and http-enumerator I >> >> >> needed different versions of these. >> >> > >> >> > I think this is where we could derive most value, and it would be >> >> > good >> >> > to >> >> > find a way to do it. >> >> > Request actually looks pretty similar in WAI as in http-enumerator, >> >> > but >> >> > Response is different. Maybe distinguish between client and server >> >> > versions >> >> > of Response? >> >> >> >> I'd be very surprised if those two can be meaningfully unified. What >> >> do you do about remoteHost and errorHandler? Also, it's more useful to >> >> have the request body for http-enumerator be an Enumerator of >> >> Builders, as opposed to WAI where we want an Enumerator of >> >> ByteStrings. >> >> >> >> I have no opposition to *having* a Request type in http-types (or >> >> whatever we call it), but I doubt anyone will actually use it, and I >> >> wouldn't even want it to include Builder due to the extra dependency. >> >> >> >> Michael >> > >> > > > _______________________________________________ web-devel mailing list web-devel-HC+Z4NTRIlBAfugRpC6u6w@public.gmane.org http://www.haskell.org/mailman/listinfo/web-devel

2011/2/3 Christian Maeder
Am 02.02.2011 22:34, schrieb Aristid Breitkreuz:
This is not a problem because constructing OtherMethod "POST" is forbidden and will/must never happen. byteStringToMethod will always construct POST, and not OtherMethod "POST",
My own conclusion is: avoid as many variants as possible, otherwise you'll get lots of repetitions of similar code. A single variant wrapping a String or ByteString is the best for uniform treatment (i.e. just for implementing show).
I don't see how it follows that there will be lots of repetitions of similar code. Please explain why you think this occurs, and why it is presumably hard to avoid. In my, possibly naïve, view, you only need to implement methodToByteString once, and methodToString can be implemented as B8.unpack . methodToByteString.
You loose (possibly faster and shorter) pattern matching, but I think it is just as good to use predefined constants and "==" for comparisons.
With my Method type you also get case-insensitivity for free. :-) And it removes the temptation of just writing "PUT" instead of, say, HTTP.methodPut. (You can get non-standard methods with byteStringToMethod, which is a total function.) Aristid

Am 03.02.2011 17:47, schrieb Aristid Breitkreuz:
I don't see how it follows that there will be lots of repetitions of similar code. Please explain why you think this occurs, and why it is presumably hard to avoid.
Maybe it is no big deal, if you basically use "show" (and even parsing could be done using "show" without many case distinctions). But in "instance Show RequestMethod" of http://hackage.haskell.org/packages/archive/HTTP/4000.1.1/doc/html/src/Netwo... all constructors must be covered and your derived instance is wrong for the "Custom" or "OtherMethod" variant.
In my, possibly naïve, view, you only need to implement methodToByteString once, and methodToString can be implemented as B8.unpack . methodToByteString.
Sure, that's no big deal.
You loose (possibly faster and shorter) pattern matching, but I think it is just as good to use predefined constants and "==" for comparisons.
With my Method type you also get case-insensitivity for free. :-) And it removes the temptation of just writing "PUT" instead of, say, HTTP.methodPut. (You can get non-standard methods with byteStringToMethod, which is a total function.)
Case-insensitive testing is also no big deal. (Write your own equality.) Surely, something like HTTP.methodPut should be used, but (byteStringToMethod "PUT") will also type-check and only give you a run-time error. As an alternative, I've attached my version of request methods just for illustration purposes. The constructor is not exported, therefore you can only create upper-case strings. My methodList is enough to create rqMethodMap or your methodListA. (The data type can be a newtype.) Cheers Christian

I'm not sure how to proceed with the Headers type. Or specifically the
Header name type.
WAI uses CIByteString, but I'm not sure if this approach can find a
consensus...
How should I proceed?
Aristid
2011/2/2 Michael Snoyman
I think there's general consensus that this package would be a Good Thing(tm), and at the least you'll have my support on it. I'm sure we can all quibble on details later, but I think the best thing now would be to have some actual code to look at.
Aristid, I'm assuming (hoping) you were volunteering to actually write and maintain this package, is that correct? I would recommend you get a project started (Github, BitBucket, PatchTag, wherever), getting up some code and then we can all nit-pick it to death ;).
Michael
http-enumerator could at least for compatibility support a Request type with ByteString. And also a native request type. Or something along these
The problem is that I want to be able to use a Request type that is compatible between multiple client libraries, enabling me to
On Wed, Feb 2, 2011 at 3:45 PM, Aristid Breitkreuz
wrote: lines. theoretically switch implementations without a huge amount of hassle.
Aristid
2011/2/2 Michael Snoyman
On Wed, Feb 2, 2011 at 2:50 PM, Aristid Breitkreuz
wrote: I agree with most things.
2011/2/2 Michael Snoyman
* Request and response datatypes themselves. I don't think this makes sense to put in http-types: just between WAI and http-enumerator I needed different versions of these.
I think this is where we could derive most value, and it would be good to find a way to do it. Request actually looks pretty similar in WAI as in http-enumerator,
but
Response is different. Maybe distinguish between client and server versions of Response?
I'd be very surprised if those two can be meaningfully unified. What do you do about remoteHost and errorHandler? Also, it's more useful to have the request body for http-enumerator be an Enumerator of Builders, as opposed to WAI where we want an Enumerator of ByteStrings.
I have no opposition to *having* a Request type in http-types (or whatever we call it), but I doubt anyone will actually use it, and I wouldn't even want it to include Builder due to the extra dependency.
Michael

Maybe I should have been more conservative in my previous comments:
assuming that this http-types package is not vastly different than
what I'm already using I can support it. I have no intention of
breaking API compatibility for no reason. Neither change you've
mentioned so far (Method and ditching CIByteString) seems like a wise
move to me.
It seems prudent to point out that WAI started off closer to the
package you're designing now, and after input from others and some
experience got to where it is now. I don't want it to take a step
backwards.
Michael
On Thu, Feb 3, 2011 at 12:53 AM, Aristid Breitkreuz
I'm not sure how to proceed with the Headers type. Or specifically the Header name type. WAI uses CIByteString, but I'm not sure if this approach can find a consensus... How should I proceed?
Aristid
2011/2/2 Michael Snoyman
I think there's general consensus that this package would be a Good Thing(tm), and at the least you'll have my support on it. I'm sure we can all quibble on details later, but I think the best thing now would be to have some actual code to look at.
Aristid, I'm assuming (hoping) you were volunteering to actually write and maintain this package, is that correct? I would recommend you get a project started (Github, BitBucket, PatchTag, wherever), getting up some code and then we can all nit-pick it to death ;).
Michael
On Wed, Feb 2, 2011 at 3:45 PM, Aristid Breitkreuz
wrote: http-enumerator could at least for compatibility support a Request type with ByteString. And also a native request type. Or something along these lines. The problem is that I want to be able to use a Request type that is compatible between multiple client libraries, enabling me to theoretically switch implementations without a huge amount of hassle.
Aristid
2011/2/2 Michael Snoyman
On Wed, Feb 2, 2011 at 2:50 PM, Aristid Breitkreuz
wrote: I agree with most things.
2011/2/2 Michael Snoyman
* Request and response datatypes themselves. I don't think this makes sense to put in http-types: just between WAI and http-enumerator I needed different versions of these.
I think this is where we could derive most value, and it would be good to find a way to do it. Request actually looks pretty similar in WAI as in http-enumerator, but Response is different. Maybe distinguish between client and server versions of Response?
I'd be very surprised if those two can be meaningfully unified. What do you do about remoteHost and errorHandler? Also, it's more useful to have the request body for http-enumerator be an Enumerator of Builders, as opposed to WAI where we want an Enumerator of ByteStrings.
I have no opposition to *having* a Request type in http-types (or whatever we call it), but I doubt anyone will actually use it, and I wouldn't even want it to include Builder due to the extra dependency.
Michael

I found your tone disappointing and to some degree upsetting, but I will try
to stay objective. (I had a few hours to calm down.)
2011/2/3 Michael Snoyman
Maybe I should have been more conservative in my previous comments: assuming that this http-types package is not vastly different than what I'm already using I can support it. I have no intention of breaking API compatibility for no reason. Neither change you've mentioned so far (Method and ditching CIByteString) seems like a wise move to me.
First of all, it is simply not possible to avoid API breakage: WAI is not the only relevant package, even YOUR OWN package http-enumerator uses different types. Given that you break APIs almost regularly, I think you could find a way to do this. Secondly, please provide reasons for why said things are not wise moves. If you want to command me, pay me or do this yourself, but given that you do neither, I demand explanations, reasoning and debate. I did not even claim that I want to ditch CIByteString, just that I am unsure how to proceed with it. Note that you yourself do not even use CIByteString consistently: You use it for the header names in WAI, but not for Method, and not at all in http-enumerator.
It seems prudent to point out that WAI started off closer to the package you're designing now, and after input from others and some experience got to where it is now. I don't want it to take a step backwards.
It is probably irrational, but I take pride in what I do, and I do not like when people call it "a step backwards" without any explanation whatsoever. Aristid

On Thu, Feb 3, 2011 at 5:33 PM, Aristid Breitkreuz
I found your tone disappointing and to some degree upsetting, but I will try to stay objective. (I had a few hours to calm down.)
Oh, please. If a debate this mild is enough to make you angry for hours, I don't understand how you can even leave your house in the morning.
I did not even claim that I want to ditch CIByteString, just that I am unsure how to proceed with it. Note that you yourself do not even use CIByteString consistently: You use it for the header names in WAI, but not for Method, and not at all in http-enumerator.
According to the spec, methods are not case-insensitive, the defined
ones are explicitly uppercase and "extension-method" has type "token",
see RFC 2616 section 5.1.1. Headers *are* case-insensitive (see
section 4.2) so it's convenient to treat them as such in datatypes,
especially where lookup is concerned -- hence CIByteString.
Re: method, Snap uses a datatype because 5.1.1 gives an explicit
enumeration, but you could do it either way and have a reasonable
rationale.
G
--
Gregory Collins

2011/2/3 Gregory Collins
On Thu, Feb 3, 2011 at 5:33 PM, Aristid Breitkreuz
wrote: I did not even claim that I want to ditch CIByteString, just that I am unsure how to proceed with it. Note that you yourself do not even use CIByteString consistently: You use it for the header names in WAI, but not for Method, and not at all in http-enumerator.
According to the spec, methods are not case-insensitive, the defined ones are explicitly uppercase and "extension-method" has type "token", see RFC 2616 section 5.1.1. Headers *are* case-insensitive (see section 4.2) so it's convenient to treat them as such in datatypes, especially where lookup is concerned -- hence CIByteString.
Oh, sorry, my mistake. I thought both were case-insensitive and failed to look it up.
Re: method, Snap uses a datatype because 5.1.1 gives an explicit enumeration, but you could do it either way and have a reasonable rationale.
True. I am not really attached to either approach, even if it may have seemed differently, I just need explanations. So, I think for now I may just implement both variants, and provide conversion functions. Aristid

2011/2/3 Aristid Breitkreuz
Secondly, please provide reasons for why said things are not wise moves. If you want to command me, pay me or do this yourself, but given that you do neither, I demand explanations, reasoning and debate.
My personal gain from writing http-types is only the joy of programming, because my main external reason to propose http-types (a common Request/Response type) has already evaporated: Even I realize now that it is foolish to attempt to define a common Request/Response type.

On Thu, Feb 3, 2011 at 6:33 PM, Aristid Breitkreuz
I found your tone disappointing and to some degree upsetting, but I will try to stay objective. (I had a few hours to calm down.)
I'm sorry if my email came off as offensive: that was not my intention. I have no desire to upset you. I think what you're proposing is good. As I said, we're at the nit-pick phase now, where we get to pick apart tiny little details of proposals to everyone's mutual annoyance. For prior art, see the discussion regarding the text package. </ducks>
2011/2/3 Michael Snoyman
Maybe I should have been more conservative in my previous comments: assuming that this http-types package is not vastly different than what I'm already using I can support it. I have no intention of breaking API compatibility for no reason. Neither change you've mentioned so far (Method and ditching CIByteString) seems like a wise move to me.
First of all, it is simply not possible to avoid API breakage: WAI is not the only relevant package, even YOUR OWN package http-enumerator uses different types. Given that you break APIs almost regularly, I think you could find a way to do this.
I only break APIs when I think it is beneficial. That is the question on the table: are your proposals going to make WAI better, and is the "good differential" great enough to warrant a breaking change.
Secondly, please provide reasons for why said things are not wise moves. If you want to command me, pay me or do this yourself, but given that you do neither, I demand explanations, reasoning and debate.
Firstly, let's not get into the "command me" thing. Remember, you're actually asking *me* to change my packages. You should feel free to make your package however you see fit. However, if I think it's not beneficial to WAI and http-enumerator users, I won't support it. Point in case: you can implement Method however you want, but I won't necessarily use it.
I did not even claim that I want to ditch CIByteString, just that I am unsure how to proceed with it.
OK. I think putting it back on the table is a "step backwards": the decision to add CIByteString was a suggestion from Snap (Greg Collins) that has a lot of merit, both semantically and performance wise, and I don't really want to rehash the discussion. If we must rehash, then we will, but please at least look up the old discussions first. Claiming CIByteString doesn't have "buy-in" is not really true.
Note that you yourself do not even use CIByteString consistently: You use it for the header names in WAI, but not for Method, and not at all in http-enumerator.
Universal usage is not the same as consistent usage. To quote the HTTP spec (5.1.1), "The method is case-sensitive." Therefore, it wouldn't make sense to use CIByteString for Method. And i'm not sure why you think I don't use CIByteString in http-enumerator: look at the definition of Headers[1].
It seems prudent to point out that WAI started off closer to the package you're designing now, and after input from others and some experience got to where it is now. I don't want it to take a step backwards.
It is probably irrational, but I take pride in what I do, and I do not like when people call it "a step backwards" without any explanation whatsoever.
I really did think I addressed why I did not like your proposed change to method: it breaks pattern matching. All the rules in the world about how you *should* use the datatype doesn't change that. Hiding the export of the OtherMethod constructor helps, but this introduces so many special cases as opposed to just using a ByteString. I personally don't see matching POST as enough better than "POST" to warrant the extra overhead of the calls to byteStringToMethod and methodToByteString. And I have good reason for this: I've implemented both approaches in WAI, and find the current one superior. As for the issue of not including CIByteString, I think it should be obvious why I would be opposed: CIByteString is the more appropriate data type for case-insensitive datatypes. I'm not completely shutting out any other possibilities, but I'm also going to be honest about my opinions. Do not take any of this personally: nothing is meant as an attack on you or your code. Michael [1] http://hackage.haskell.org/packages/archive/http-enumerator/0.3.1/doc/html/N...

The current state of http-types:
* Both Method = ByteString and MethodADT (and ADT) exist now, and you can
use whichever you prefer. Conversion functions exist.
* Headers use CIByteString (I named it HttpCIByteString, though.)
* Status is basically like in WAI
* HttpVersion is a record containing two Ints (with bang).
* There are two variants of Query string types: Query and QuerySimple. The
former allows creating Query strings like a&b=c, by setting the value in the
tuple for a to Nothing.
2011/2/3 Michael Snoyman
I found your tone disappointing and to some degree upsetting, but I will
On Thu, Feb 3, 2011 at 6:33 PM, Aristid Breitkreuz
wrote: try to stay objective. (I had a few hours to calm down.)
I'm sorry if my email came off as offensive: that was not my intention. I have no desire to upset you. I think what you're proposing is good. As I said, we're at the nit-pick phase now, where we get to pick apart tiny little details of proposals to everyone's mutual annoyance. For prior art, see the discussion regarding the text package. </ducks>
I'm sorry, too. I'm really bad at controlling my emotions.
2011/2/3 Michael Snoyman
Maybe I should have been more conservative in my previous comments: assuming that this http-types package is not vastly different than what I'm already using I can support it. I have no intention of breaking API compatibility for no reason. Neither change you've mentioned so far (Method and ditching CIByteString) seems like a wise move to me.
First of all, it is simply not possible to avoid API breakage: WAI is not the only relevant package, even YOUR OWN package http-enumerator uses different types. Given that you break APIs almost regularly, I think you could find a way to do this.
I only break APIs when I think it is beneficial. That is the question on the table: are your proposals going to make WAI better, and is the "good differential" great enough to warrant a breaking change.
Of course.
Secondly, please provide reasons for why said things are not wise moves. If you want to command me, pay me or do this yourself, but given that you do neither, I demand explanations, reasoning and debate.
Firstly, let's not get into the "command me" thing. Remember, you're actually asking *me* to change my packages. You should feel free to make your package however you see fit. However, if I think it's not beneficial to WAI and http-enumerator users, I won't support it. Point in case: you can implement Method however you want, but I won't necessarily use it.
Just like not everybody in the server space is going to use WAI? :-P
I did not even claim that I want to ditch CIByteString, just that I am unsure how to proceed with it.
OK. I think putting it back on the table is a "step backwards": the decision to add CIByteString was a suggestion from Snap (Greg Collins) that has a lot of merit, both semantically and performance wise, and I don't really want to rehash the discussion. If we must rehash, then we will, but please at least look up the old discussions first. Claiming CIByteString doesn't have "buy-in" is not really true.
Well, I joined the mailing list only recently (on your suggestion), and do not know which discussions you mean. It would be nice if you could provide pointers to these discussions. But I have implemented CIByteString now, and see the merit now.
Note that you yourself do not even use CIByteString consistently: You use it for the header names in WAI, but not for Method, and not at all in http-enumerator.
Universal usage is not the same as consistent usage. To quote the HTTP spec (5.1.1), "The method is case-sensitive." Therefore, it wouldn't make sense to use CIByteString for Method. And i'm not sure why you think I don't use CIByteString in http-enumerator: look at the definition of Headers[1].
Wow, I made two mistakes in a row: I thought HTTP methods are case-insensitive (but I already learned from Gregory Collins that this is not the case), and I did not notice the fact that Headers now uses CIByteString. In http-enumerator 0.2.1.5, Headers used ByteString for the name, but this obviously changed, and I to my shame did not notice it.
I really did think I addressed why I did not like your proposed change to method: it breaks pattern matching. All the rules in the world about how you *should* use the datatype doesn't change that. Hiding the export of the OtherMethod constructor helps, but this introduces so many special cases as opposed to just using a ByteString. I personally don't see matching POST as enough better than "POST" to warrant the extra overhead of the calls to byteStringToMethod and methodToByteString. And I have good reason for this: I've implemented both approaches in WAI, and find the current one superior.
Well, even before the OtherMethod constructor was hidden, it was considered invalid to use it on standard methods.
As for the issue of not including CIByteString, I think it should be obvious why I would be opposed: CIByteString is the more appropriate data type for case-insensitive datatypes.
It is not flawless: It breaks for all non-ASCII/non-Latin1 encodings. This is probably not a problem in this case, however. Aristid
participants (8)
-
Aristid Breitkreuz
-
Christian Maeder
-
Curt Sampson
-
Gregory Collins
-
Johan Tibell
-
Michael Snoyman
-
Neil Mitchell
-
Stefan Wehr