[Haskell-cafe] Contributing to http-conduit

Michael Snoyman michael at snoyman.com
Wed Feb 1 12:24:45 CET 2012


You mean you're *not* making this proposal?

On Wed, Feb 1, 2012 at 7:30 AM, Myles C. Maxfield
<myles.maxfield at gmail.com> wrote:
> Well, this is embarrassing. Please disregard my previous email. I should
> learn to read the RFC *before* submitting proposals.
>
> --Myles
>
>
> On Tue, Jan 31, 2012 at 6:37 PM, Myles C. Maxfield
> <myles.maxfield at gmail.com> wrote:
>>
>> Here are my initial ideas about supporting cookies. Note that I'm using
>> Chrome for ideas since it's open source.
>>
>> Network/HTTP/Conduit/Cookies.hs file
>> Exporting the following symbols:
>>
>> type StuffedCookie = SetCookie
>>
>> A regular SetCookie can have Nothing for its Domain and Path attributes. A
>> StuffedCookie has to have these fields set.
>>
>> type CookieJar = [StuffedCookie]
>>
>> Chrome's cookie jar is implemented as (the C++ equivalent of) Map W.Ascii
>> StuffedCookie. The key is the "eTLD+1" of the domain, so lookups for all
>> cookies for a given domain are fast.
>> I think I'll stay with just a list of StuffedCookies just to keep it
>> simple. Perhaps a later revision can implement the faster map.
>>
>> getRelevantCookies :: Request m -> CookieJar -> UTCTime -> (CookieJar,
>> Cookies)
>>
>> Gets all the cookies from the cookie jar that should be set for the given
>> Request.
>> The time argument is whatever "now" is (it's pulled out of the function so
>> the function can remain pure and easily testable)
>> The function will also remove expired cookies from the cookie jar (given
>> what "now" is) and return the filtered cookie jar
>>
>> putRelevantCookies :: Request m -> CookieJar -> [StuffedCookie] ->
>> CookieJar
>>
>> Insert cookies from a server response into the cookie jar.
>> The first argument is only used for checking to see which cookies are
>> valid (which cookies match the requested domain, etc, so site1.com can't set
>> a cookie for site2.com)
>>
>> stuffCookie :: Request m -> SetCookie -> StuffedCookie
>>
>> If the SetCookie's fields are Nothing, fill them in given the Request from
>> which it originated
>>
>> getCookies :: Response a -> ([SetCookie], Response a)
>>
>> Pull cookies out of a server response. Return the response with the
>> Set-Cookie headers filtered out
>>
>> putCookies :: Request a -> Cookies -> Request a
>>
>> A wrapper around renderCookies. Inserts some cookies into a request.
>> Doesn't overwrite cookies that are already set in the request
>>
>> These functions will be exported from Network.HTTP.Conduit as well, so
>> callers can use them to re-implement redirection chains
>> I won't implement a cookie filtering function (like what Network.Browser
>> has)
>>
>> If you want to have arbitrary handling of cookies, re-implement
>> redirection following. It's not very difficult if you use the API provided,
>> and the 'http' function is open source so you can use that as a reference.
>>
>> I will implement the functions according to RFC 6265
>> I will also need to write the following functions. Should they also be
>> exported?
>>
>> canonicalizeDomain :: W.Ascii -> W.Ascii
>>
>> turns "..a.b.c..d.com..." to "a.b.c.d.com"
>> Technically necessary for domain matching (Chrome does it)
>> Perhaps unnecessary for a first pass? Perhaps we can trust users for now?
>>
>> domainMatches :: W.Ascii -> W.Ascii -> Maybe W.Ascii
>>
>> Does the first domain match against the second domain?
>> If so, return the prefix of the first that isn't in the second
>>
>> pathMatches :: W.Ascii -> W.Ascii -> Bool
>>
>> Do the paths match?
>>
>> In order to implement domain matching, I have to have knowledge of
>> the Public Suffix List so I know that sub1.sub2.pvt.k12.wy.us can set a
>> cookie for sub2.pvt.k12.wy.us but not for k12.wy.us (because pvt.k12.wy.us
>> is a "suffix"). There are a variety of ways to implement this.
>>
>> As far as I can tell, Chrome does it by using a script (which a human
>> periodically runs) which parses the list at creates a .cc file that is
>> included in the build.
>>
>> I might be wrong about the execution of the script; it might be a build
>> step. If it is a build step, however, it is suspicious that a build target
>> would try to download a file...
>>
>> Any more elegant ideas?
>>
>> Feedback on any/all of the above would be very helpful before I go off
>> into the weeds on this project.
>>
>> Thanks,
>> Myles C. Maxfield
>>
>> On Sat, Jan 28, 2012 at 8:17 PM, Michael Snoyman <michael at snoyman.com>
>> wrote:
>>>
>>> Thanks, looks great! I've merged it into the Github tree.
>>>
>>> On Sat, Jan 28, 2012 at 8:36 PM, Myles C. Maxfield
>>> <myles.maxfield at gmail.com> wrote:
>>> > Ah, yes, you're completely right. I completely agree that moving the
>>> > function into the Maybe monad increases readability. This kind of
>>> > function
>>> > is what the Maybe monad was designed for.
>>> >
>>> > Here is a revised patch.
>>> >
>>> >
>>> > On Sat, Jan 28, 2012 at 8:28 AM, Michael Snoyman <michael at snoyman.com>
>>> > wrote:
>>> >>
>>> >> On Sat, Jan 28, 2012 at 1:20 AM, Myles C. Maxfield
>>> >> <myles.maxfield at gmail.com> wrote:
>>> >> > the fromJust should never fail, beceause of the guard statement:
>>> >> >
>>> >> >     | 300 <= code && code < 400 && isJust l'' && isJust l' = Just $
>>> >> > req
>>> >> >
>>> >> > Because of the order of the && operators, it will only evaluate
>>> >> > fromJust
>>> >> > after it makes sure that the argument isJust. That function in
>>> >> > particular
>>> >> > shouldn't throw any exceptions - it should only return Nothing.
>>> >> >
>>> >> > Knowing that, I don't quite think I understand what your concern is.
>>> >> > Can
>>> >> > you
>>> >> > elaborate?
>>> >>
>>> >> You're right, but I had to squint really hard to prove to myself that
>>> >> you're right. That's the kind of code that could easily be broken in
>>> >> future updates by an unwitting maintainer (e.g., me). To protect the
>>> >> world from me, I'd prefer if the code didn't have the fromJust. This
>>> >> might be a good place to leverage the Monad instance of Maybe.
>>> >>
>>> >> Michael
>>> >
>>> >
>>
>>
>



More information about the Haskell-Cafe mailing list