Setting a cookie using JavaFX's WebEngine/WebView
Asked Answered
B

2

45

I cannot seem to find any way to set a cookie programatically using WebEngine / WebView in JavaFX. The API doesn't give any idea as to how to obtain an HttpRequest-like object to modify the headers (which is what I use in the app for XML-RPC), or any sort of cookie manager.

No questions on this page seem to touch on the issue either - there is this but it just disables cookies when in applet to fix a bug, my app is on desktop btw.

The only way I image I could do it is by requesting the first page (which requires a cookie with a sessionID to load properly), getting an "access denied"-style message, executing some javascript in the page context which sets the cookie and then refreshing. This solution would be a horrible user experience though.

How do I set a cookie using WebEngine?


Update: Taking a clue from a question linked above, I tried digging around for some examples of using CookieManager and related APIs. I found this code, which I then tried to incorporate into my app, with weird results;

MyCookieStore cookie_store = new MyCookieStore();
CookieManager cookie_manager = new CookieManager(cookie_store, new MyCookiePolicy());
CookieHandler.setDefault(cookie_manager);
WebView wv = new WebView();

Now lets say we do this:

String url = "http://www.google.com/";
wv.getEngine.go(url);

Debugging in Eclipse after this request has been made shows that the cookie store map holds a cookie:

{http://www.google.com/=[NID=67=XWOQNK5VeRGEIEovNQhKsQZ5-laDaFXkzHci_uEI_UrFFkq_1d6kC-4Xg7SLSB8ZZVDjTUqJC_ot8vaVfX4ZllJ2SHEYaPnXmbq8NZVotgoQ372eU8NCIa_7X7uGl8GS, PREF=ID=6505d5000db18c8c:FF=0:TM=1358526181:LM=1358526181:S=Nzb5yzBzXiKPLk48]}

THAT IS AWESOME

WebEngine simply uses the underlying registered cookie engine! But wait, is it really? Lets try adding a cookie, prior to making the request...

cookie_store.add(new URL(url).toURI(), new HttpCookie("testCookieKey", "testCookieValue"));

Then I look at the request in Wireshark...

GET / HTTP/1.1
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/535.14 (KHTML, like Gecko) JavaFX/2.2 Safari/535.14
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cache-Control: no-cache
Pragma: no-cache
Host: www.google.com
Connection: keep-alive

No cookie for me :(

What am I doing wrong?

Billiot answered 17/1, 2013 at 17:59 Comment(0)
B
49

I have managed to solve this issue with the help of Vasiliy Baranov from Oracle. Vasiliy wrote to me:

Try putting the cookie into java.net.CookieHandler.getDefault() after the WebView is instantiated for the first time and before the call to WebEngine.load, e.g. as follows:

WebView webView = new WebView();
URI uri = URI.create("http://mysite.com");
Map<String, List<String>> headers = new LinkedHashMap<String, List<String>>();
headers.put("Set-Cookie", Arrays.asList("name=value"));
java.net.CookieHandler.getDefault().put(uri, headers);
webView.getEngine().load("http://mysite.com");

This will place the cookie into the store permanently, it should be sent out on every subsequent request (presumably provided that the server doesn't unset it).

Vasiliy also explained that WebView will install it's own implementation of the CookieHandler, while retaining cookies put into the default one.

Lastly, he mentions something quite intriguing:

Do not waste your time trying to use java.net.CookieManager, and java.net.CookieStore. They are likely to cause problems with many sites because they implement the wrong standard.

I tried googling after this but it doesn't seem to be common knowledge. If anyone is able to provide more details I would be grateful. It seems weird, since it seems CookieStore and CookieManager are used by a lot of software out there.

Billiot answered 25/1, 2013 at 10:25 Comment(3)
When i use this code i am getting the bellow exception, groovy.lang.MissingMethodException: No signature of method: java.net.CookieManager.put() is applicable for argument types: (java.lang.String, java.util.LinkedHashMap)Shadshadberry
Worked for me thanks a lot! Basically, when the program exits I read the cookies using cookieManager.getCookieStore().getCookies(), save them in a file and use your code at startup to set them.Trustful
@MinasMina when I run cookieManager.getCookieStore().getCookies() I get a blank list.Squeeze
Q
2

Solution for java.net.CookieManager

Cookies serialization:

        List<HttpCookie> httpCookies = cookieManager.getCookieStore().getCookies();
        Gson gson = new GsonBuilder().create();
        String jsonCookie = gson.toJson(httpCookies);

Cookies deserialization:

Gson gson = new GsonBuilder().create();
List<HttpCookie> httpCookies = new ArrayList<>();
Type type = new TypeToken<List<HttpCookie>>() {}.getType();
httpCookies = gson.fromJson(json, type);   // convert json string to list
for (HttpCookie cookie : httpCookies) {
    cookieManager.getCookieStore().add(URI.create(cookie.getDomain()), cookie);
}
Quaint answered 6/6, 2018 at 10:51 Comment(1)
This was the only solution I could get working over the course of the past few days. Such an absurdly simple solution that I overlooked it for far too long. The only concern I haven't handled yet is this causes some warnings for "Illegal reflective access by com.google.gson.internal.reflect.UnsafeReflectionAccessor". I'm fighting through Java 12 though, so I know it's extra picky.Hautegaronne

© 2022 - 2024 — McMap. All rights reserved.