More pontificating about HTTP client APIs. Say you want to support a default cookie value that's sent by default in every request, but you also want to allow overriding the default cookie on a per-method-call basis via an additional cookie: keyword argument. Should the method's cookie: keyword argument fully override the default cookie, or should it be merged _with_ the default cookie values?
Putting it up to vote:
If you had an HTTP client API that supported setting default cookie values that automatically get sent with every request, and you supported passing in your own per-request cookie value(s), should the custom cookie value(s) override the default cookie or be merged with the default cookie values?
@postmodern My experience in working with enterprise web scraping always prefers having a default set of cookies available, with the ability to merge additional cookies in as needed. Sometimes you need a set of base cookies for all requests, and then additional cookies to set things like store ids or auth. Allowing the request cookie to set “my cookie” => nil gives the ability to truly override the default cookies if needed, but still keep the additive behavior. That’s my take anyway.
@timtilberg would you prefer the `cookie:` keyword argument to merge by default, or would you be OK with explicit merging? `cookie: http.cookie.merge(...)`?
@postmodern I prefer `cookies: {a_cookie: “val”}` and for that hash to be merged with a default hash of cookies I have previously set. I know the “cookie” header is technically a single header, but practically it’s more like a hash of “cookies”. I like when can set default headers and add to them for individual requests. The cookie header is like another layer of that. It’s easy to nil if needed. If you find that you need to replace them often, you probably shouldn’t have set it as a default.
@timtilberg indeed, and that's what makes this tricky. `Cookie` can contain multiple key=value pairs, so it's not really a single monolithic header like the `User-Agent` or `Referer` headers.
@postmodern for what it’s worth, you should always be able to use `headers: {cookie: “some_cookie=val;”}` to treat the cookie header as normal, but generally I think a “cookie” focused api should have more flexibility than the usual header. Including defaults + merges. (My take anyway!)
@timtilberg this was another interesting debate. I already have a default headers Hash which gets added to the request object first, then `cookie:` is added, then the `headers:` keyword argument is added to the request possibly overriding previously set Headers, then any additional keyword arguments are added. The idea being that explicitly given headers should override the defaults.
@postmodern Interesting, I’ve never had to consider the implementation at this level, but it seems that the order of prec should be default headers (which may hardcode a cookie), default cookies… which would… ahem. Well, here we are. Lol. I see what you mean. Well, I think ideally they all get merged upwards. Default headers, default cookies, request headers, finally request cookies, creating a big messy pool of cookies. Ultimately the users are responsible for that they’ve put in!
@postmodern I don’t know. I already regret this as I type up an example. Hard to overwrite a previous bad decision. I can feel your discomfort in this decision. But, again, I feel like the user should probably be able to manage it by not putting bad cookies in places they don’t belong.
@timtilberg well the context of this is a security toolkit, so the expectation is for people to use it to exercise web apps or try to break them. So I'm expecting an instance of the HTTP class to be initialized with some kind of pre-existing session cookie, then additional method calls to add their own cookie. However, there's also an argument for allowing overriding the default cookie entirely to try to break out of the default session.
@postmodern After writing this out, I felt like if you explicitly set
`header: {cookie: "string"}` for the request, that should clear whatever may have happened before. I've always been a user at the mercy of whatever the author decided, this is pretty interesting!
@timtilberg ooooh I now see the issue with `this` and multiple header/cookie sets.
Currently I have `#user_agent=` write it's value directly into `#headers`. However, this pattern doesn't exactly work neatly with cookies, if you override `#headers=` after setting `#cookie=`.