I wrote some code that tries to communicate with a website "as a browser" (in terms of cookies & headers). I currently have four requests (GET, POST, POST, GET).
The code is pretty straightforward: opening a connection, adding headers and cookies, parsing response.
GET code:
conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setUseCaches(false);
conn.setRequestProperty("User-Agent", userAgent);
conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
conn.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
if (cookies != null) {
for (String cookie : this.cookies) {
conn.addRequestProperty("Cookie", cookie.split(";", 1)[0]);
}
}
int responseCode = conn.getResponseCode();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
setCookies(conn.getHeaderFields().get("Set-Cookie"));
return response.toString();
POST code:
conn = (HttpsURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Host", "...");
conn.setRequestProperty("User-Agent", userAgent);
conn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
conn.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
conn.setRequestProperty("Accept-Encoding","identity");
for (String cookie : this.cookies) {
conn.addRequestProperty("Cookie", cookie.split(";", 1)[0]);
}
conn.setRequestProperty("Connection", "keep-alive");
conn.setRequestProperty("Referer", "https://...");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", Integer.toString(postParams.length()));
conn.setDoOutput(true);
conn.setDoInput(true);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.writeBytes(postParams);
wr.flush();
wr.close();
int responseCode = conn.getResponseCode();
InputStream is = responseCode != 400 ? conn.getInputStream() : conn.getErrorStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return response.toString();
The program works well on my PC. However, when running it on an Android device, I face multiple problems on the second POST; on one device there's Too many redirections
exception, and in another one (which is the one I focus on) I simply receive 400 Bad Request
although the exact same request returns 200 on my PC.
I noticed that there are actually two different implementations: On PC I'm using sun.net.www.protocol.https.DelegateHttpsURLConnection
, and on Android it's com.android.okhttp.internal.http.HttpURLConnectionImpl
. Object conn
looks a bit different during runtime. However, I failed to find a meaningful difference (if needed, I can post the whole content of these objects); I found one difference in the cookies set in the first GET, but a manual manipulation resulted in the same 400.
I tried to capture the Android output request using Wireshark, but the result is encrypted and I didn't manage to decrypt it.
I basically thought of two possible scenarios:
- Find the difference(s) between those implementations and act accordingly.
- Find a way to use the
sun.net.www.protocol.https.DelegateHttpsURLConnection
on Android.
So far I didn't manage to figure out any of these. Is there any known difference/issue with these implementations? Is there a way to run the native Java library on Android? Any help will be appreciated, thanks.