ureq icon indicating copy to clipboard operation
ureq copied to clipboard

Tutorial or example on how to use CookieStore?

Open narigama opened this issue 2 years ago • 4 comments

I see in 2.0.0, the built in Agent::set_cookie was dropped in favour of using CookieStore, but I don't see an example in the docs/examples of how to use it. Can I get some guidance on how to add cookies to the Agent as to enable them in my requests?

narigama avatar Jun 24 '22 10:06 narigama

I was just looking at the same problem. Here is a solution that may help for you, even though it didn't help me. You need to add "cookie_store" and "url" to your Cargo.toml, with the same versions as ureq uses.

For ureq 2.4.0

cookie_store = "0.15.1"
url = "2.2.2"

Then you have to build a CookieStore:

let mut store = CookieStore::default();
store.insert_raw(&your_cookie1, &url1);
store.insert_raw(&your_cookie2, &url2);

Use insert_raw to insert cookies produced using the "cookie" crate, which is the Cookie type that ureq exposes. The url value has to be of the Url type from the "url" crate. So far as I can tell the only way to produce one to order is with the Url::parse() method, which can return an error. That URL represents the page which supposedly set the cookie. This rather inconvenient if you want to make the URL from a domain in an &str, since the Url::parse() method requires the leading "https://" part (or "http://", "ftp://", or whatever), so that forces an allocation for a new String.

Once you have all your cookies added to the CookieStore you can create an Agent that uses it with an AgentBuilder.

let agent = AgentBuilder::new().cookie_store(store).build();

After that you can use this agent to get, post, etc. to web pages and it will use the cookies you put into store.

This does mean that there seems to be no way to add cookies to the Agent after creating it (since the cookie_store() method on an actual agent provides read-only access). This is why I can't use it myself, since I need to add cookies to an agent based on user actions.

Hopefully that helps somewhat.

BoydstonNicholas avatar Jul 06 '22 15:07 BoydstonNicholas

I'm not clear why we only exposed a read-only version of the cookie store. The code uses an RwLock, which means we can have agent requests "in flight" while reading. With the provisio that write permission would lock down any current requests interacting with the cookie store, we could add a mut version too.

@jsha Thoughts?

algesten avatar Aug 28 '22 10:08 algesten

We removed Agent::set_cookie here: https://github.com/algesten/ureq/commit/1f8bb532fee3ae290aaabfb085dbfefd14a03003

After discussion here: https://github.com/algesten/ureq/issues/203#issuecomment-716385310

The short version is: Agent is meant to be shared widely across your program, to maximize connection reuse. It uses internal mutability to achieve connection reuse. However, it would be surprising if component A expected a logged-out state, but component B called set_cookie on their shared Agent, changing it to a logged-in state.

Looking at this decision a second time, I'm realizing there's an important inconsistency: component A can make requests and receive responses that modify the cookie jar (for example POSTing to a login form), and that will modify the shared state in the same potentially surprising way.

To address the immediate problem: @BoydstonNicholas outlines a good approach. @BoydstonNicholas for your use case, is it practical to maintain two Agents, one that has no cookies, and one that is built later with cookies based on user actions?

jsha avatar Sep 04 '22 18:09 jsha

@jsha Amazing that I managed to blank this discussion.

As you point out, we're in a half way state still.

The question: is Agent a state boundary? Either it is, in which case we might as well allow mutation. Or it isn't, in which case we nees to think more about how cookies are handled.

algesten avatar Sep 04 '22 20:09 algesten