dakrone / clj-http

An idiomatic clojure http client wrapping the apache client. Officially supported version.
http://clojars.org/clj-http
MIT License
1.78k stars 408 forks source link

Circumventing cookies with null domain when you need them even if the domain is null #589

Open matthewlisp opened 3 years ago

matthewlisp commented 3 years ago

Recently i had a problem that some cookies were coming from the server with the attribute domain being null, i.e: Set-Cookie: foo=bar;domain=;expires=Wed, 21 Oct 2021 07:28:00 GMT;

This results in an exception being thrown, saying that the domain of a cookie is null. I could completely ignore the cookies, however, i really need this cookie to proceed to the next request, the server is expecting him, and if he's not on the next request, i wont be able to proceed.

So, I've decided to edit the server response, and add the domain to be equal the host of the request!

I've tried adding clj-http custom middlewares but no success. I'm using cookie-store's for cookies handling, and he didn't updated with the edited cookies.

After thinking that the problem might be the order that my middleware was being called, i thought adding the response editing directly on apache, using this https://github.com/dakrone/clj-http#modifying-apache-specific-features-of-the-httpclientbuilder-and-httpasyncclientbuilder

And at the end i came up with:

(defn null-cookie-domain-formatter [^HttpClientBuilder builder {:keys [server-name] :as _request}]
  (.addInterceptorFirst
   builder
   (proxy [HttpResponseInterceptor] []
     (process [resp ctx]
       (when-let [null-domain-cookies (->> (.getHeaders resp "Set-Cookie")
                                           (filter #(string/includes? (.getValue %) "domain=;"))
                                           seq)]
         (let [modified-cookies-vals (map #(string/replace (.getValue %) "domain=;" (format "domain=%s;" server-name))
                                          null-domain-cookies)]
           (doseq [header null-domain-cookies]
             (.removeHeader resp header))
           (doseq [header-val modified-cookies-vals]
             (.addHeader resp "Set-Cookie" header-val))))))))

Then i do requests this way

(http/post "..." {:http-builder-fns [null-cookie-domain-formatter] :cookie-store cookie-store})  

And everything is working as expected! This is not exactly an issue with clj-http, however someone else might ran into a similar problem, and i wanted to know opinions about my solution, if there's something more simple than what i did, would be awesome to know.