Here are my initial ideas about supporting cookies. Note that I&#39;m using Chrome for ideas since it&#39;s open source.<div><ul><li>Network/HTTP/Conduit/Cookies.hs file</li><li>Exporting the following symbols:</li><ul><li>

type StuffedCookie = SetCookie</li><ul><li>A regular SetCookie can have Nothing for its Domain and Path attributes. A StuffedCookie has to have these fields set.</li></ul><li>type CookieJar = [StuffedCookie]</li><ul><li>
Chrome&#39;s cookie jar is implemented as (the C++ equivalent of) Map W.Ascii StuffedCookie. The key is the &quot;eTLD+1&quot; of the domain, so lookups for all cookies for a given domain are fast.</li>
<li>I think I&#39;ll stay with just a list of StuffedCookies just to keep it simple. Perhaps a later revision can implement the faster map.</li></ul><li>getRelevantCookies :: Request m -&gt; CookieJar -&gt; UTCTime -&gt; (CookieJar, Cookies)</li>

<ul><li>Gets all the cookies from the cookie jar that should be set for the given Request.</li><li>The time argument is whatever &quot;now&quot; is (it&#39;s pulled out of the function so the function can remain pure and easily testable)</li>

<li>The function will also remove expired cookies from the cookie jar (given what &quot;now&quot; is) and return the filtered cookie jar</li></ul><li>putRelevantCookies :: Request m -&gt; CookieJar -&gt; [StuffedCookie] -&gt; CookieJar</li>

<ul><li>Insert cookies from a server response into the cookie jar.</li><li>The first argument is only used for checking to see which cookies are valid (which cookies match the requested domain, etc, so <a href="http://site1.com">site1.com</a> can&#39;t set a cookie for <a href="http://site2.com">site2.com</a>)</li>

</ul><li>stuffCookie :: Request m -&gt; SetCookie -&gt; StuffedCookie</li><ul><li>If the SetCookie&#39;s fields are Nothing, fill them in given the Request from which it originated</li></ul><li>getCookies :: Response a -&gt; ([SetCookie], Response a)</li>

<ul><li>Pull cookies out of a server response. Return the response with the Set-Cookie headers filtered out</li></ul><li>putCookies :: Request a -&gt; Cookies -&gt; Request a</li><ul><li>A wrapper around renderCookies. Inserts some cookies into a request.</li>

<li>Doesn&#39;t overwrite cookies that are already set in the request</li></ul></ul><li>These functions will be exported from Network.HTTP.Conduit as well, so callers can use them to re-implement redirection chains</li><li>

I won&#39;t implement a cookie filtering function (like what Network.Browser has)</li><ul><li>If you want to have arbitrary handling of cookies, re-implement redirection following. It&#39;s not very difficult if you use the API provided, and the &#39;http&#39; function is open source so you can use that as a reference.</li>

</ul><li>I will implement the functions according to RFC 6265</li><li>I will also need to write the following functions. Should they also be exported?</li><ul><li>canonicalizeDomain :: W.Ascii -&gt; W.Ascii</li><ul><li>turns &quot;..a.b.c..d.com...&quot; to &quot;<a href="http://a.b.c.d.com">a.b.c.d.com</a>&quot;</li>

<li>Technically necessary for domain matching (Chrome does it)</li><li>Perhaps unnecessary for a first pass? Perhaps we can trust users for now?</li></ul><li>domainMatches :: W.Ascii -&gt; W.Ascii -&gt; Maybe W.Ascii</li>

<ul><li>Does the first domain match against the second domain?</li><li>If so, return the prefix of the first that isn&#39;t in the second</li></ul><li>pathMatches :: W.Ascii -&gt; W.Ascii -&gt; Bool</li><ul><li>Do the paths match?</li>

</ul></ul><li>In order to implement domain matching, I have to have knowledge of the <a href="http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat">Public Suffix List</a> so I know that <a href="http://sub1.sub2.pvt.k12.wy.us">sub1.sub2.pvt.k12.wy.us</a> can set a cookie for <a href="http://sub2.pvt.k12.wy.us">sub2.pvt.k12.wy.us</a> but not for <a href="http://k12.wy.us">k12.wy.us</a> (because <a href="http://pvt.k12.wy.us">pvt.k12.wy.us</a> is a &quot;suffix&quot;). There are a variety of ways to implement this.</li>

<ul><li>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.</li><ul><li>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...</li>

</ul><li>Any more elegant ideas?</li></ul></ul>Feedback on any/all of the above would be very helpful before I go off into the weeds on this project.</div><div><br></div><div>Thanks,</div><div>Myles C. Maxfield</div><div>

<br><div class="gmail_quote">On Sat, Jan 28, 2012 at 8:17 PM, Michael Snoyman <span dir="ltr">&lt;<a href="mailto:michael@snoyman.com">michael@snoyman.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

Thanks, looks great! I&#39;ve merged it into the Github tree.<br>
<br>
On Sat, Jan 28, 2012 at 8:36 PM, Myles C. Maxfield<br>
<div class="HOEnZb"><div class="h5">&lt;<a href="mailto:myles.maxfield@gmail.com">myles.maxfield@gmail.com</a>&gt; wrote:<br>
&gt; Ah, yes, you&#39;re completely right. I completely agree that moving the<br>
&gt; function into the Maybe monad increases readability. This kind of function<br>
&gt; is what the Maybe monad was designed for.<br>
&gt;<br>
&gt; Here is a revised patch.<br>
&gt;<br>
&gt;<br>
&gt; On Sat, Jan 28, 2012 at 8:28 AM, Michael Snoyman &lt;<a href="mailto:michael@snoyman.com">michael@snoyman.com</a>&gt;<br>
&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; On Sat, Jan 28, 2012 at 1:20 AM, Myles C. Maxfield<br>
&gt;&gt; &lt;<a href="mailto:myles.maxfield@gmail.com">myles.maxfield@gmail.com</a>&gt; wrote:<br>
&gt;&gt; &gt; the fromJust should never fail, beceause of the guard statement:<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt;     | 300 &lt;= code &amp;&amp; code &lt; 400 &amp;&amp; isJust l&#39;&#39; &amp;&amp; isJust l&#39; = Just $ req<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; Because of the order of the &amp;&amp; operators, it will only evaluate fromJust<br>
&gt;&gt; &gt; after it makes sure that the argument isJust. That function in<br>
&gt;&gt; &gt; particular<br>
&gt;&gt; &gt; shouldn&#39;t throw any exceptions - it should only return Nothing.<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; Knowing that, I don&#39;t quite think I understand what your concern is. Can<br>
&gt;&gt; &gt; you<br>
&gt;&gt; &gt; elaborate?<br>
&gt;&gt;<br>
&gt;&gt; You&#39;re right, but I had to squint really hard to prove to myself that<br>
&gt;&gt; you&#39;re right. That&#39;s the kind of code that could easily be broken in<br>
&gt;&gt; future updates by an unwitting maintainer (e.g., me). To protect the<br>
&gt;&gt; world from me, I&#39;d prefer if the code didn&#39;t have the fromJust. This<br>
&gt;&gt; might be a good place to leverage the Monad instance of Maybe.<br>
&gt;&gt;<br>
&gt;&gt; Michael<br>
&gt;<br>
&gt;<br>
</div></div></blockquote></div><br></div>