[Haskell-cafe] Contributing to http-conduit

Myles C. Maxfield myles.maxfield at gmail.com
Wed Feb 1 03:37:41 CET 2012

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] ->
         - 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
         - 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
   - I will implement the functions according to RFC 6265
   - I will also need to write the following functions. Should they also be
      - 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
   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.

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
> >
> >
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20120131/995879e5/attachment.htm>

More information about the Haskell-Cafe mailing list