$:/litapp/blog

A blog about nothing, coding, photography, and generative art

Simple Req Cookie Jar

2024/02/08 21:19

A simple req cookie jar plugin. It can be used when automating or scraping websites that implement cookie based sessions. The cookies are set using set-cookie header and are sent back to the server in the headers of each following request. The implementation is naive and probably misses advanced and corner cases.

# create the cookie jar
CookieJar.new()

# attach the plugin to the req
req = Req.new(base_url: "http://baseurl.example.com")
|> CookieJar.attach()

# when the response includes the set-cookie header, it store its value in the jar
%{body: "Ok."} = req
|> Req.post!(url: "/api/v2/auth/login", form: [username: "admin", password: "password"])

# all subsequent requests have the cookie set in the headers
%{status: 200} = req
|> Req.get!(url: "/api/v2/info?filter=foo")

The cookie is stored in an Agent. Req response and request steps are respectively used to collect the cookie string and to add to the cookie header when requests are performed.

defmodule ReqCookieJar do
  use Agent

  def new() do
    Agent.start_link(fn -> "" end, name: __MODULE__)
  end

  defp get_cookie do
    Agent.get(__MODULE__, & &1)
  end

  defp set_cookie([]), do: nil
  defp set_cookie(val) do
    Agent.update(__MODULE__, fn (_) -> val end)
  end


  def attach(%Req.Request{} = request) do
    request
    |> Req.Request.append_response_steps(
      cookie_jar: fn({req, res})->
        Req.Response.get_header(res, "set-cookie")
        |> set_cookie()

        {req,res}
      end
    )
    |> Req.Request.append_request_steps(
      cookie_jar: &Req.Request.put_header(&1, "cookie", get_cookie())
    )
  end
end