2

I have a web application that makes HTTP requests using HttpURLConnection. I need it to handle cookies. I know that it's easily done by adding just one line of code, something like

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

The problem is this way I'm setting the system-wide cookie handler as the documentation describes. This also affects other web applications that run in the same servlet container. For example if I want CookiePolicy.ACCEPT_ORIGINAL_SERVER in one application and CookiePolicy.ACCEPT_ALL in another, it won't work.

Is there a way to have a CookieHandler that is only used by a single HttpURLConnection instance?

John29
  • 3,340
  • 3
  • 32
  • 50
  • Maybe this is a solution for you? https://stackoverflow.com/questions/16305486/cookiemanager-for-multiple-threads – chromanoid Nov 29 '18 at 16:43
  • @chromanoid No, the solutions from it only help to separate cookies between different threads. – John29 Nov 29 '18 at 20:07

1 Answers1

3

In standard oracle implementation the HttpURLConnection get the default CookieHandler on the constructor, so this is one possible solution. Create a synchronized singleton factory that create the HttpURLConnections using a specific manager for each application. Not good idea in my opinion.

Other bad idea is provide your own CookiePolicy and do the trick on the shouldAccept method.

Or you can manually control cookies on the app that should not share the CookieHandler:

        HttpURLConnection firstCall = (HttpURLConnection) new URL("http://www.google.com").openConnection();
        firstCall.connect();
        List<HttpCookie> cookieList = HttpCookie.parse(firstCall.getHeaderField("Set-Cookie"));
        firstCall.disconnect();
        StringBuilder cookies = new StringBuilder();
        for(HttpCookie cookie:cookieList) {
            //if(cookie.SOME_VALIDATION) {
                if(cookies.length() > 0) {
                    cookies.append("; ");
                }
                cookies.append(cookie.toString());
            //}
        }
        HttpURLConnection secondCall = (HttpURLConnection) new URL("http://www.google.com").openConnection();
        secondCall.setRequestProperty("Cookie", cookies.toString());
        secondCall.connect();
        //dosomething
        secondCall.disconnect();
fhofmann
  • 847
  • 7
  • 15
  • I agree that the first 2 options are bad ideas. Unfortunatelly your code also won't work in my case. The reason is the server I connect to redirects multiple times and some redirects contain cookies. If these cookies are not preserved, the server ends up redirecting in an infinite loop. I can use `setInstanceFollowRedirects(false)` and handle redirects manually, but it will complicate the code even more. I guess there's no good way to do it with `HttpURLConnection`, but thanks for the answer anyway. – John29 Nov 27 '18 at 15:38
  • There is no Parameter to change `CookieHandler` behavior and I imagine that you cannot isolate the web apps in different VMs (or can you? what is your servlet container?). Maybe use apache HTTP client or other API that do not use HTTPUrlConnection internally. – fhofmann Nov 28 '18 at 07:10
  • The servlet container is Tomcat. Using multiple Tomcats is undesirable. I don't want to switch from `HttpURLConnection` because I already have a lot of code specific to it. – John29 Nov 28 '18 at 16:42
  • I ended up using some custom code to handle cookies. The idea is similar to the code in this answer, but I used `CookieManager` to save and load cookies. I also added code similar to https://stackoverflow.com/a/26046079/2324685 because I need to preserve cookies between redirects. – John29 Dec 03 '19 at 18:02