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.
Yes, there are some difference between those SDKs, the desktop is the Oracle sdk and on Android is the one published by Google.
Ony way, when doing http requests on Android it's recommended using Retrofit or Volley
Related
I'm trying to connect to salesforce production account via OAuth and exchange an access token by giving a refresh token.
When i make a call using Chrome Advanced Rest Client or CURL i'm able to get the access token; but when i'm trying to make the same call using java HttpClient or URLConnection i'm getting a 400 status.
String url = "https://login.salesforce.com/services/oauth2/token";
String requestBody = "grant_type=refresh_token&client_id=myClientId&client_secret=myClientSecret&refresh_token=myRefreshToken";
URL obj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
//add reuqest header
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "myapp/1.0");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
// Send post request
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(requestBody);
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Post parameters : " + requestBody);
System.out.println("Response Code : " + responseCode);
BufferedReader br = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = br.readLine()) != null) {
response.append(inputLine);
}
br.close();
//print result
System.out.println(response.toString());
I examined both requests using wireshark. And both the requests look identical. Since the URL is https, i posted the request to a dummy URL and verified using wireshark.
Anybody ran into this kinda of issue ? BTW the same code works for developer edition and is not working for production edition. And for production edition it works with CURL and Chrome ARC.
Salesforce only allows HTTPS connections on TLS 1.1 or higher. Since i'm running on Java 7, default is TLS 1.0. As a result the request is failing from Java.
By adding the following property we can add support for TLSv1.1 and TLSv1.2
-Dhttps.protocols=TLSv1.1,TLSv1.2
I know what is the HTTP header and how the HTTP data format , I also know how to make a HTTP post from Java ,
like
StringBuffer result = new StringBuffer();
PrintWriter out = null;
BufferedReader in = null;
StringBuffer result = new StringBuffer();
try {
URL realUrl = new URL("http://somesite/somepage.htm");
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setDoOutput(true);
conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream());
out.print(param);
out.flush();
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}
I can use some code like this write stream to web server , and read stream also .
Here is my question .
What is the HTTP POST method really do , I mean how does the client communicate to web server ?
What will happen if the web server only read the HTTP POST header and don't read the stream from client ?
Does the stream will stuck in somewhere ?
Thanks .
I am trying to do what I thought was a simple task. I need to POST data to a PHP server. I have tried this solution but in Apache HttpClient 4.5 I can't find BasicNameValuePair in the package. Upon further research I thought I'd try StringEntity...nope not in 4.5 either (that I can find at least). So I tried to do it with HttpsURLConnection. The problem with that is I can't figure out how to add a name to my parameter and with a name, I don't know how to access in PHP with $_POST['name'].
My Current Code:
String json = gson.toJson(data);
URL url = new URL("https://www.domain.com/test.php");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(json.length()));
OutputStream os = conn.getOutputStream();
os.write(json.getBytes());
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String decodedString;
while ((decodedString = in.readLine()) != null) {
System.out.println(decodedString);
}
in.close();
Try to use DataOutputStream and flush it afterward.
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeChars(json);
wr.flush();
wr.close();
i'm trying to run a soap request in a basic http request...naturally i tried with external tools the message and is correct, like the endpoint i'm using as targetUrl, the wsdl is in something like
http://00.00.00.00/a-ws/services/basic?wsdl
and my actual end point is
http://00.00.00.00/a-ws/services/basic.targetservice
and i'm using this last as target url
URL url = new URL(targetUrl);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
connection.setRequestProperty("SOAPAction", action);
connection.setRequestProperty("User-Agent", "myagent");
connection.setRequestProperty("Host", "localhost");
//connection.setRequestProperty("Content-Length", "" + Integer.toString(message.getBytes().length));
connection.setUseCaches (false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Send request
OutputStream wr = connection.getOutputStream ();
wr.write (message.getBytes());
wr.flush ();
wr.close ();
//Get Response
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line=null;
StringBuffer response = new StringBuffer();
while( (line = rd.readLine()) != null) {
if (line!=null)
response.append(line);
}
rd.close();
return response.toString();
the raw message is tested with chrome plugin, the only thing i can't test is headers but the result is always an exception on getInputStream
java.io.IOException: Server returned HTTP response code: 500 for URL:
why?
It was a very stupid issue of encoding (like I was supposing)...i didn't escape double quote inside the message.
The evidence of problem was visible using a fake http server that just echo contents.
UPDATE:
Another thing nobody already pointed out is that is useful in case of exception to retrieve
connection.getErrorStream()
that contains the response in case of error!
I've got a webserver setup ready to receive images and I'd like to have a client in Java send the image along with two POST arguments, upon searching the web I only found ways to do this with Apache's API but I'd prefer to do this in vanilla Java.
Any help will be appreciated.
Something along the lines of...
String url = "https://asite.com";
URL obj = new URL(url);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
//add reuqest header
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", USER_AGENT);
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
String urlParameters = "aparam=1&anotherparam=2";
// Send post request
con.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
int responseCode = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
You can add more headers, and add more to the output stream as required.