Connection to session in Java and Python. HttpURLConnection and CookieManager (Java). Requests (Python)

Let's say we need to connect to a server, log in and maintain a session. In a browser, it looks like this:



  1. An empty GET request is sent to the address http: // localhost: 8080 / login .
  2. The server sends a form to fill in the login and password, and also sends a Cookie of the form "JSESSIONID = 094BC0A489335CF8EE58C8E7846FE49B".
  3. Filling in the username and password, a POST request is sent to the server with the cookie received earlier, with a line in the output stream "username = Fox & password = 123". Headers additionally specifies "Content-Type: application / x-www-form-urlencoded".
  4. In response, the server sends us a new cookie with a new "JSESSIONID =". It is immediately redirected to http: // localhost: 8080 / by a GET request with a new Cookie.
  5. Further, you can safely use the rest of the server API, passing the last cookie in each request.


Let's see how this can be implemented in Java and Python.







Content





Python implementation. Requests



When choosing a library for working with a network in Python, most sites will recommend the requests library , which fully justifies its slogan:

HTTP for Humans
The whole task is solved by the following script:



import requests
session = requests.session()  # 
url = "http://localhost:8080/login"
session.get(url)   # cookie
data = {"username": "Fox", "password": "123"} 
response = session.post(url, data=data) #


Note that cookie and redirection manipulation happens under the hood, just like in a browser. It can also be noted that if you create another variable session2 , then you can keep two connections active at once.



Java Implementation, HttpURLConnection and CookieManager



Finding a library for working with a Java network leads to several libraries at once.



For example java.net , Apache HttpClient and OkHttp3 .



I settled on HttpURLConnection (java.net). The advantages of this library is that it is an โ€œ out of the box โ€ library , and also, if you need to write an application for android, there is documentation on the official website . The downside is a very large amount of code. (After Python, it's just a pain.)



So, let's begin. According to the documentation, you can use the CookieManager to work with sessions :



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


Things to note using this approach:



  • "CookiePolicy.ACCEPT_ALL" indicates to work with all cookies.
  • The cookieManager variable will not be used anywhere else. It controls all connections, and if it is necessary to maintain several active sessions, it will be necessary to manually change the Cookie in this one variable.


With this in mind, you can write in one line:



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


Points 1 and 2. Let's execute a GET request to get the first Cookie:



URL url = new URL("http://localhost:8080/login");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
final StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
    content.append(inputLine);
}


After that, our cookieManager will contain the cookie from the server and will automatically substitute it in the next request.



The fun begins with a POST request.



url = new URL("http://localhost:8080/login");
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");


You need to write in Headers "Content-Type: application / x-www-form-urlencoded".



Why the method is called setRequestProperty and not setHeaders (or addHeaders) with the getHeaderField method is a mystery.



con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");


Next comes the code, which, for some reason, is not tucked under the hood of the library.



con.setDoOutput(true);


We need this line of code to open the outgoing stream. It's funny that without this line we get the following message:



Exception in thread "main" java.net.ProtocolException: cannot write to a URLConnection if doOutput = false - call setDoOutput (true)

Open the outgoing stream and write the username and password there:



final DataOutputStream out = new DataOutputStream(con.getOutputStream());
out.writeBytes("username=Fox&password=123");
out.flush();
out.close();


It remains to read the response from the already forwarded request.



Java implementation, HttpURLConnection without CookieManager



You can implement without the CookieManager and control the movement of cookies yourself.

Paragraphs 1 and 2. We take out the cookie.



URL url = new URL("http://localhost:8080/login");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
final StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
    content.append(inputLine);
String cookie = con.getHeaderField("Set-Cookie").split(";")[0];
}


Next, we send a POST request, only this time by inserting a cookie and disabling automatic redirection, since before it, you need to have time to pull out a new cookie:



//  
url = new URL("http://localhost:8080/login");
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
// headers  cookie
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
con.setRequestProperty("Cookie", cookie);
// 
con.setInstanceFollowRedirects(false);
//   
con.setDoOutput(true);
final DataOutputStream out = new DataOutputStream(con.getOutputStream());
out.writeBytes("username=Fox&password=123");
out.flush();
out.close();
//    cookie
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
final StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
    content.append(inputLine);
String cookie2 = con.getHeaderField("Set-Cookie").split(";")[0];


Next, in all queries, just add the following line:



con.setRequestProperty("Cookie", cookie2);


Hope it was helpful. Simpler options are welcome in the comments.



All Articles