How to handle cookies in httpUrlConnection using cookieManager
Asked Answered
C

5

46

I have a server request that returns multiple cookies, like that:

enter image description here

This is how I'm storing these cookies to the cookieManager:

HttpURLConnection connection = ... ;
static java.net.CookieManager msCookieManager = new java.net.CookieManager();
msCookieManager.put(COOKIES_URI, connection.getHeaderFields());

This is how I'm adding these cookies to the next connection:

connection.setRequestProperty("Cookie", 
  msCookieManager.getCookieStore().get(COOKIES_URI).toString());

Is it the right way to get the cookies from the cookieManager?, I'm quite sure there is a better one...

Cordes answered 22/4, 2013 at 14:50 Comment(0)
C
108

Ok, the right way to do it is just like that:

Get Cookies from response header and load them into cookieManager:

static final String COOKIES_HEADER = "Set-Cookie";
HttpURLConnection connection = ... ;
static java.net.CookieManager msCookieManager = new java.net.CookieManager();

Map<String, List<String>> headerFields = connection.getHeaderFields();
List<String> cookiesHeader = headerFields.get(COOKIES_HEADER);

if (cookiesHeader != null) {
    for (String cookie : cookiesHeader) {
        msCookieManager.getCookieStore().add(null,HttpCookie.parse(cookie).get(0));
    }               
}

Get Cookies from cookieManager and load them into connection:

if (msCookieManager.getCookieStore().getCookies().size() > 0) {
    // While joining the Cookies, use ',' or ';' as needed. Most of the servers are using ';'
    connection.setRequestProperty("Cookie",
    TextUtils.join(";",  msCookieManager.getCookieStore().getCookies()));    
}
Cordes answered 23/4, 2013 at 14:16 Comment(9)
When should you read the cookies? Right after opening the connection? Thanks.Hesky
+1 When using multiple cookies I had more luck with using a semicolon: TextUtils.join(";", msCookieManager.getCookieStore().getCookies()));Crescentia
Woah buddy! I've been trying to do this with an http keepalive / httpurlconnection persistent connection when THIS is the correct way to handle my login session. Thank you for this answer!Libido
Thank you so much, this was a life saver after I spent hours struggling with CookieHandler.setDefaultSubmarginal
Hi, I tried this one, but when I add the requestProperty for the Cookie got this error java.lang.IllegalStateException: Cannot set request property after connection is madeMedian
This code can't be right because it sends all the cookies you have for all sites. Not only those belonging to server set them, but all. This is security issue.Trivandrum
HttpCookie.parse(cookie) adds quotes. Eg. I get this header from response Set-Cookie: session=12345. When load cookies in url connection, it is sending like session="12345" in Cookie header. How can I send cookies without quotes ?Keck
Found the solution for quotes. Setting version 0 of HttpCookie before adding it into Cookie store will not add quotes. Version 1 will add quotes as per RFC.Keck
Cannot believe this is the accepted answer and has so many upvotes. This sends ALL cookies ever received to ALL requests ever made. @AlexanderDyagilev is right in pointing out that this is a security issue first of all. Secondly, it ignores all the options the cookie may have, like the Expires field. See here for a full list of options a cookie may have: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-CookieRobin
V
59

I've been searching/trying for days to fix my issue: cannot access protected web resources even after logging in successfully

I created the same app on iOS and didn't have the same problem because NSUrlConnection did the cookie maintenance for us behind the scene. On Android, I tried manually adding cookie

connection.setRequestProperty("Cookie", "PHPSESSID=str_from_server")

without any luck.

Finally I read this

and added the following 2 lines somewhere in the beginning of my app:

CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);

and everything works fine now.

Versieversification answered 11/2, 2014 at 16:33 Comment(7)
Works great thanks, only those 2 lines are needed yay ^_^, tried the other answer too both works but this one is more convenientWaybill
This should be the accepted answer. I've tried to handle cookies manually without success. These two lines are just what you need to handle cookies with HttpUrlConnection! Thanks Gold Thumb !Ghost
This didn't quite work for me, cookies were sent with first couple of requests but not with subsequent ones, I have no idea why...Norland
@HeisenBerg put anywhere as long as it is executed once, and before your first use of HttpURLConnection.Each
This doesn't compile on my AS 2.3.3 As typical of this environment.... Always a moving target, and never backward compatible. CookieHandler.setDefault(...) doesn't take a data type of cookieManager.Osana
Update Strike that above.... It is necessary to use the correct "import". And there is more than one that uses the same identifier. (why that was done is another mystery)Osana
added those two lines above and loaded my page cookieManager.getCookieStore().getCookies().size returned 2. Works good!Washedup
S
3

@David's answer is the best of the lot. Its easiest to maintain a local CookieManager and manually write into and read from the cookie store associated with this cookie manager.

This code loads the Cookies from a response into the cookie manager :

/**
 * Gets Cookies from the response header and loads them into cookie manager
 *
 * @param conn          instance of {@link HttpURLConnection} object
 * @param cookieManager the cookie manager({@link CookieManager} instance) in which the cookies are to be loaded<p>In case a null object is passed, the function will not perform any action and return back to the caller. </p>
 */
public static void loadResponseCookies(@Nullable HttpURLConnection conn,@Nullable CookieManager cookieManager) {

    //do nothing in case a null cokkie manager object is passed
    if (cookieManager == null || conn == null){
        return;
    }

    List<String> cookiesHeader = conn.getHeaderFields().get(COOKIES_HEADER);
    if (cookiesHeader != null) {
        for (String cookieHeader : cookiesHeader) {
            List<HttpCookie> cookies;
            try {
                cookies = HttpCookie.parse(cookieHeader);
            } catch (NullPointerException e) {
                log.warn(MessageFormat.format("{0} -- Null header for the cookie : {1}",conn.getURL().toString(), cookieHeader.toString()));
                //ignore the Null cookie header and proceed to the next cookie header
                continue;
            }

            if (cookies != null) {
                Debug("{0} -- Reading Cookies from the response :", conn.getURL().toString());
                for (HttpCookie cookie : cookies) {
                    Debug(cookie.toString());
                }
                if (cookies.size() > 0) {
                    cookieManager.getCookieStore().add(null, HttpCookie.parse(cookieHeader).get(0));
                }
            }
        }
    }
}

This code populates the HttpUrlConnection object with the cookies associated with the cookie manager :

public void populateCookieHeaders(HttpURLConnection conn) {

    if (this.cookieManager != null) {
        //getting cookies(if any) and manually adding them to the request header
        List<HttpCookie> cookies = this.cookieManager.getCookieStore().getCookies();

        if (cookies != null) {
            if (cookies.size() > 0) {
                Debug("{0} -- Adding Cookie Headers : ", url.toString());
                for (HttpCookie cookie : cookies) {
                    Debug(cookie.toString(), null);
                }

                //adding the cookie header
                conn.setRequestProperty(COOKIE_REQUEST_HEADER, StringUtils.join(cookies, ";"));
            }
        }
    }
}

This is the most thread safe way to handle cookies.

I tried using a threadlocal cookiestore and an extension of CookieManager. Neither of these approaches worked in my case.

Samite answered 30/5, 2016 at 11:53 Comment(4)
There is no conn.getHeaderFields() member to the HttpURLConnection object.Osana
@Osana That would depend on which version of Java you were using. I'd given this solution when I was using Java 7. This is the link:docs.oracle.com/javase/7/docs/api/java/net/… to the documentation. It's possible that this function was deprecated in whatever version of Java you're using now ?Samite
Who the heck can tell what version I'm using?? This is Android Studio and it is so bloated and obfuscated, I have no idea what it's doing "under the covers". The setting just says "use javac". But I know it's not either of the 32 or 64 bit compilers that I installed. It's got it's own, buried somewhere, which you apparently are not allowed to know anything about.Osana
@Osana You can go to the terminal in Android Studio and simply type java --version. It will tell you the version of java being used.Samite
A
3

The other answers are appropriate for their contexts, but nobody is saying the obvious: CookieHandler automatically deals with your cookies in most cases. To just maintain cookies from one request to the next -- for instance to maintain a server session -- then this line of code is sufficient:

CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));

Make sure to run it once before your first request with UrlConnection.

Now I do zero cookie management myself, and all of my server session data is flawlessly maintained from request to request.

Am I crazy? Why is the internet silent on this? I can't even find it in the docs.

Alvaroalveolar answered 23/9, 2020 at 19:39 Comment(1)
You're right, this works. Amazing. The accepted top comment not only contains tons of unnecessary code when this one-liner is enough, it's also a serious security issue because it sends all cookies ever received to all hosts ever connected to. I think this is the worst case of a bad top answer I've ever seen on StackOverflow.Robin
M
0

using java.net.HttpURLConnection and groovy, simply add URLConnection#addRequestProperty(String key, String value) inside with closure.

import java.net.HttpURLConnection

HttpURLConnection createRequest(String chatRequestBody) {
    HttpURLConnection httpChatRequest = new URL("${endpoint}").openConnection() as HttpURLConnection

    httpChatRequest.with {
        doOutput = true
        requestMethod = 'POST'

        //headers
        addRequestProperty("Content-Type", "application/json")
        addRequestProperty("Client-Platform", "android")

        //cookies
        addRequestProperty("Cookie", "cookie_key1=cookie_value1,cookie_key2=cookie_value2")

        getOutputStream().write(chatRequestBody.getBytes("UTF-8"))
    }
    httpChatRequest
}
Monsoon answered 8/11, 2017 at 1:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.