Content-Length on http GET causing IIS to timeout? - android

So we're encountering a scenario where our Android clients are receiving a redirect from the server (following a POST -- Post/Redirect/Get) and Android is removing the body for the conversion to GET but seems to be leaving the Content-Length header in the GET request. I've verified that the request isn't making it into the web application (by placing a delegating handler that fires before a controller is selected). We also verified via cURL that if the content-length is removed from the request, the request goes through just fine.
So we're trying to find a solution on either front:
a) how do we stop android from sending that header? or
b) how do we tell IIS to allow or strip out the content-length header so that the request can get through?
UPDATE:
Requested java code that makes the call, as requested...
OutputStream postOut = null;
HttpURLConnection connection = null;
try {
URL url = new URL("<<url here>>");
connection = (HttpURLConnection) url.openConnection();
final String method = "POST";
final String data = "name=frank";
final String contentType = "application/x-www-form-urlencoded";
connection.setDoInput(true);
connection.setRequestProperty("Accept", contentType);
connection.setRequestProperty("Connection", "Close");
connection.setRequestProperty("Content-Type", contentType);
connection.setRequestMethod(method);
connection.setConnectTimeout(0);
connection.setReadTimeout(0);
connection.setUseCaches(false);
connection.setDefaultUseCaches(false);
connection.setChunkedStreamingMode(0);
if (method.equals("POST")) {
byte[] bits = data.getBytes();
connection.addRequestProperty("Content-Length", "" + bits.length);
connection.setDoOutput(true);
dumpHeaders(connection.getRequestProperties());
postOut = connection.getOutputStream();
if (postOut != null)
{
postOut.write(bits, 0, bits.length);
postOut.flush();
postOut.close();
postOut = null;
}
} else {
dumpHeaders(connection.getRequestProperties());
}
int httpStatus = connection.getResponseCode();
if (httpStatus / 100 > 3) {
Log.d("TEST", readResponse(connection.getErrorStream(), connection));
} else {
Log.d("TEST", readResponse(connection.getInputStream(), connection));
}
String finalUrl = connection.getURL().toExternalForm();
Log.d("TEST", "HTTP Status: " + httpStatus + ", URL: " + finalUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
if (connection.getErrorStream() != null) {
Log.d("TEST", readResponse(connection.getErrorStream(), connection));
} else {
Log.d("TEST", e.getMessage());
}
}
if (connection != null) {
connection.disconnect();
}

Related

How to get a working HttpsUrlConnection with Steam Web API?

im currently trying to implement the Steam Web API using the given code in the following repository -> https://github.com/Overv/SteamWebAPI/blob/master/SteamAPISession.cs into my Android app and im getting different exceptions dependend on using the given wep api ip ( 63.228.223.110 ) or the adress ( https://api.steampowered.com/ ) itself.
my code actually looks like this in the given method when building up a connection to the web api:
private String steamRequest( String get, String post ) {
final int MAX_RETRIES = 3;
int numberOfTries = 0;
HttpsURLConnection request = null;
while(numberOfTries < MAX_RETRIES) {
if (numberOfTries != 0) {
Log.d(TAG, "Retry -> " + numberOfTries);
}
try {
request = (HttpsURLConnection) new URL("https://api.steampowered.com/" + get).openConnection(); //or 63.228.223.110/ ???
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
String host = "api.steampowered.com";
int port = 443;
int header = 0;
socketFactory.createSocket(new Socket(host, port), host, port, false);
request.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
request.setSSLSocketFactory(socketFactory);
request.setDoOutput(false);
// request.setRequestProperty("Host", "api.steampowered.com:443");
// request.setRequestProperty("Protocol-Version", "httpVersion");
request.setRequestProperty("Accept", "*/*");
request.setRequestProperty("Accept-Encoding", "gzip, deflate");
request.setRequestProperty("Accept-Language", "en-us");
request.setRequestProperty("User-Agent", "Steam 1291812 / iPhone");
request.setRequestProperty("Connection", "close");
if (post != null) {
byte[] postBytes;
try {
request.setRequestMethod("POST");
postBytes = post.getBytes("US-ASCII");
// request.setRequestProperty("Content-Length", Integer.toString(postBytes.length));
request.setFixedLengthStreamingMode(postBytes.length);
request.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
PrintWriter out = new PrintWriter(request.getOutputStream());
out.print(post);
out.close();
// DataOutputStream requestStream = new DataOutputStream(request.getOutputStream());
//// OutputStreamWriter stream = new OutputStreamWriter(request.getOutputStream());
//// stream.write(postBytes, 0, postBytes.length);
// requestStream.write(postBytes, 0, postBytes.length);
// requestStream.close();
message++;
} catch (ProtocolException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
int statusCode = request.getResponseCode();
InputStream is;
Log.d(TAG, "The response code of the status code is" + statusCode);
if (statusCode != 200) {
is = request.getErrorStream();
Log.d(TAG, String.valueOf(is));
}
// String src = null;
// OutputStreamWriter out = new OutputStreamWriter(request.getOutputStream());
// out.write(src);
// out.close();
Scanner inStream = new Scanner(request.getInputStream());
String response = "";
while (inStream.hasNextLine()) {
response += (inStream.nextLine());
}
// String src;
// BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
// StringBuilder builder = new StringBuilder();
// while ((src = in.readLine()) != null) {
// builder.append(src);
// }
// String jsonData = builder.toString();
Log.d(TAG, response); //jsonData
// in.close();
return response; //jsonData
} catch (MalformedURLException ex) {
Toast.makeText(getActivity(), ex.toString(), Toast.LENGTH_LONG).show();
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (request != null) {
request.disconnect();
}
}
numberOfTries++;
}
Log.d(TAG, "Max retries reached. Giving up on connecting to Steam Web API...");
return null;
}
following exception occurs when using https://api.steampowered.com/ as url:
W/System.err﹕ java.io.FileNotFoundException: https://api.steampowered.com/ISteamOAuth2/GetTokenWithCredentials/v0001
D/OptionsFragment﹕ Failed to log in!
i've really tried and researched on those issues, but i just can't get a solution. If someone got a good hint on helping to solve these exceptions please let me know!
EDIT:
I've researched some more!
Looking up on https://partner.steamgames.com/documentation/webapi#creating the direct ip adress shouldn't be used and therefore only the DNS name itself (for further clarification look on the given link). Hence, looking up on the API interface list itself -> http://api.steampowered.com/ISteamWebAPIUtil/GetSupportedAPIList/v0001/?format=json there doesn't seem to be a given Interface with a method called ISteamOAuth2/GetTokenWithCredentials.(Or not anymore!) Only ISteamUserAuth and ISteamUserOAuth which seem to handle Authentication stuff.
I will update this post again if i should get a working connection and handling with the steam web api.
Cheers!

Trouble with setting the Nest field values via java/android code

I am writing android code to change the field in a Nest thermostat using the newly released API. Authentication and getting the field values is working just perfect, however I am haing problem with changing the field values. Based on the the API for changing the field values you need to use HTTP put, but once I am doing this, nothing happens in the device (the value (e.g. the value of target_temperature_f doesn't change!))
Here is my android code:
String url = "https://developer-api.nest.com/devices/thermostats/"
+ this.device_id + "?auth=" + this.access_token;
try{
HttpClient httpclient = new DefaultHttpClient();
/** set the proxy , not always needed */
HttpHost proxy = new HttpHost(proxy_ip,proxy_port);
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,proxy);
// Set the new value
HttpPut httpPut = new HttpPut(url);
httpPut.setHeader("Content-Type", "application/json");
JSONObject jsonObj = new JSONObject("{\"target_temperature_f\":'60'}");
HttpEntity put_entity = new StringEntity(jsonObj.toString());
httpPut.setEntity(put_entity);
HttpResponse put_response = httpclient.execute(httpPut);
I can set the field in the device via "curl" command in linux though!! So the device is working fine.
Any help is highly appreciated!
I'm unsure of how to do it using the DefaultHttpClient and according to the documentation it has been deprecated in favor of HttpURLConnection.
Here's some code that uses HttpURLConnection that I've tested with Hue lights.
This will open a URL connection and perform a POST query with the given body. The readFromHttpConnection method expects a JSON response. It looks like Nest uses JSON so this may work for your needs.
private String synchronousPostMethod(String destination, String body)
{
Log.i(TAG, "Attempting HTTP POST method. Address=" + destination + "; Body=" + body);
String responseReturn;
try
{
HttpURLConnection httpConnection = openConnection(destination);
httpConnection.setDoOutput(true);
httpConnection.setRequestMethod("POST");
writeToHttpConnection(httpConnection, body);
responseReturn = readFromHttpConnection(httpConnection);
}
catch(Exception e)
{
responseReturn = RESPONSE_FAIL_MESSAGE + "; exception = " + e;
}
Log.i(TAG, "Result of HTTP POST method: " + responseReturn);
return responseReturn;
}
These are the helper methods.
private HttpURLConnection openConnection(String destination)
{
HttpURLConnection httpConnection = null;
try
{
URL connectionUrl = new URL(destination);
httpConnection = (HttpURLConnection) connectionUrl.openConnection();
}
catch(MalformedURLException malformedUrlException)
{
Log.w(TAG, "Failed to generate URL from malformed destination: " + destination);
Log.w(TAG, "MalformedURLException = " + malformedUrlException);
}
catch(IOException ioException)
{
Log.w(TAG, "Could not open HTTP connection. IOException = " + ioException);
}
return httpConnection;
}
private boolean writeToHttpConnection(HttpURLConnection httpConnection, String data)
{
// No data can be written if there is no connection or data
if(httpConnection == null || data == null)
{
return false;
}
try
{
OutputStreamWriter outputStream = new OutputStreamWriter(httpConnection.getOutputStream());
outputStream.write(data);
outputStream.close();
}
catch(IOException ioException)
{
Log.w(TAG, "Failed to get output stream from HttpUrlConnection. IOException = " + ioException);
return false;
}
return true;
}
private String readFromHttpConnection(HttpURLConnection httpConnection)
{
String responseReturn = "";
if(httpConnection != null)
{
try
{
InputStream response = httpConnection.getInputStream();
int size;
do
{
byte[] buffer = new byte[mResponseBufferSize];
size = response.read(buffer, 0, mResponseBufferSize);
// Convert the response to a string then add it to the end of the buffer
responseReturn += new String(buffer, 0, size);
}while(size < mResponseBufferSize || size <= 0);
// Cleanup
response.close();
}
catch (IOException ioException)
{
Log.w(TAG, "Failed to get input stream from HttpUrlConnection. IOException = " + ioException);
}
}
return responseReturn;
}

java.net.SocketTimeoutException: Transport endpoint is not connected

I'm developing my application on a Samsung Galaxy S which I've upgraded to Android 4.2. The application run normally on this device.
When I test it on a phone which is running Android 2.2, an exception occurs.
I check it again and again,I find that the problem happen after the application sends a UDP DatagramPacket.
The problem never happen when I comment the code referring to sending UDP DatagramPacket.
Could anyone please tell me what‘s the reason why? How to solve the problem?
Main method:
public static String getDataFromServerInPostMethod(String url,
String content) {
HttpURLConnection httpurlconnection = null;
String result = "";
try {
InputStream stream = null;
// String host = android.net.Proxy.getDefaultHost();
// if (host != null) {
// int port = android.net.Proxy.getDefaultPort();
// SocketAddress vAddress = new InetSocketAddress(host, port);
// java.net.Proxy vProxy = new java.net.Proxy(
// java.net.Proxy.Type.HTTP, vAddress);
// httpurlconnection = (HttpURLConnection) new URL(url)
// .openConnection(vProxy);
// } else {
// httpurlconnection = (HttpURLConnection) new URL(url)
// .openConnection();
// }
httpurlconnection = (HttpURLConnection) new URL(url)
.openConnection();
httpurlconnection.setDoOutput(true);
httpurlconnection.setRequestMethod("POST");
// httpurlconnection.setRequestProperty("Connection", "Keep-Alive");
httpurlconnection.setReadTimeout(TIMEOUT * 1000);
httpurlconnection.setConnectTimeout(TIMEOUT * 1000);
try {
httpurlconnection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
httpurlconnection.connect();
MyLog.e(TAG, "getURL:" + httpurlconnection.getURL());
httpurlconnection.getOutputStream().write(content.getBytes());
httpurlconnection.getOutputStream().flush();
httpurlconnection.getOutputStream().close();
stream = httpurlconnection.getInputStream();
result = SystemUtil.convertStreamToString(stream);
if (httpurlconnection.getResponseCode() == 200) {
MyLog.w(TAG,
"Responsed-->>getURL:" + httpurlconnection.getURL());
} else {
MyLog.e(TAG,
"not Responsed,ResponseCode:"
+ httpurlconnection.getResponseCode());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (httpurlconnection != null) {
httpurlconnection.disconnect();
}
}
return result;
}
Do you have this permission in your AndroidManifest.xml file?
<uses-permission android:name="android.permission.INTERNET" />

Why does Android not send my second SSL request?

My Android app is talking to a webserver using SSL and GET requests. After switching to API 10 (Gingerbread) the SSL connection works - but only for the first time after the app starts...
The first request is sent by the main activity - after getting a response, another activity starts and sends multiple requests. And none of them is answered. In both cases the request is sent using a litte WebService class that is initiated in a new AsyncTask. After downsizing this alass, the only thing it actually contains is the URL(-String). Each activity starts its own instance of this class.
Here is the method that should do the GET request. As easily visible I included some code to avoid keep-alive - not that I don't like it, but it has been suggested in other answers to do so to avoid problems with multiple connections. Well, it did not work in my case.
public String webGet(String methodName, Map<String, String> params) {
String getUrl = webServiceUrl + methodName;
index++;
final int connectionID = index;
int i = 0;
for (Map.Entry<String, String> param : params.entrySet()) {
if (i == 0) {
getUrl += "?";
} else {
getUrl += "&";
}
try {
getUrl += param.getKey() + "=" + URLEncoder.encode(param.getValue(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
i++;
}
String response;
Log.e("WebGetURL", "["+connectionID+"] " + getUrl);
URL url;
try {
url = new URL(getUrl);
} catch (MalformedURLException e) {
Log.e("WebService", "Malformed URL: " + getUrl);
return null;
}
HttpURLConnection urlConnection;
try {
Log.e("WebGetResponse", "["+connectionID+"] openConnection()");
System.setProperty("http.keepAlive", "false");
if (webServiceSsl) {
Log.e("WebService", "Using HTTPS");
urlConnection = (HttpsURLConnection) url.openConnection();
} else {
urlConnection = (HttpURLConnection) url.openConnection();
}
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("Connection","Keep-Alive");
urlConnection.setDoOutput(false);
urlConnection.setDoInput(true);
urlConnection.setRequestMethod("GET");
} catch (IOException e) {
Log.e("WebService", "I/O exception opening connection: " + e.getMessage());
e.printStackTrace();
return null;
}
urlConnection.setConnectTimeout(5000);
urlConnection.setReadTimeout(10000);
urlConnection.setRequestProperty("Connection", "close");
try {
urlConnection.connect();
Log.e("WebGetResponse", "["+connectionID+"] getInputStream()");
// This is the last thing I hear from my thread
BufferedInputStream bin = new BufferedInputStream(urlConnection.getInputStream());
Log.e("WebGetResponse", "["+connectionID+"] gotInputStream()");
byte[] contents = new byte[1024];
int bytesRead=0;
StringBuilder strFileContents = new StringBuilder();
Log.e("WebGetResponse", "["+connectionID+"] Waiting for data");
while((bytesRead = bin.read(contents)) != -1) {
String add = new String(contents, 0, bytesRead);
strFileContents.append(add);
}
bin.close();
response = strFileContents.toString();
} catch (IOException e) {
Log.e("WebService", "I/O exception reading stream: " + e.getMessage());
e.printStackTrace();
return null;
} finally {
urlConnection.disconnect();
}
Log.e("WebGetResponse", "["+connectionID+"] " + response);
return response;
}
I have been trying ans searching - I don't get the problem. Actually I cannot test the class on a non-https server currently, so I am unaware if the problem occurs in HTTP as well. However, the handshake seems to work, because the first request works well.
And here is the code that should start the request (final param is the GET content to send):
class ServerDataThread extends AsyncTask<Integer, Integer, String[]> {
#Override
protected String[] doInBackground(Integer... attempts) {
sendActive++;
int count = attempts.length;
String[] responses = new String[count];
for (int i = 0; i < count; i++) {
responses[i] = server.webGet("collector.php", params);
}
return responses;
}
protected void onPostExecute(String[] responses) {
sendActive--;
for (int i = 0; i < responses.length; i++) {
if (responses[i] == null) {
continue;
}
onResponseData(responses[i]);
}
}
}
new ServerDataThread().execute(0);
Could anyone please help me out with a hint what I am doing wrong? Thank you very much!
BurninLeo

Android Https Status code -1

I'm connecting to a web server from my android application via HttpsUrlConnection or HttpUrlConnection depending on settings. For now I didn't have any kind of problem, but yesterday I start getting http/https status response -1. There is no way the web server return me this even if there is some kind of error. The server which I'm connection to is designed to return errorCode and errorString when there is some kind of problem. Here is the code I'm using,but I don't think the problem is here.
public void UseHttpConnection(String url, String charset, String query) {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url)
.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Charset", charset);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=" + charset);
OutputStream output = null;
try {
output = connection.getOutputStream();
output.write(query.getBytes(charset));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (output != null)
try {
output.close();
} catch (IOException logOrIgnore) {
}
}
int status = ((HttpURLConnection) connection).getResponseCode();
Log.i("", "Status : " + status);
for (Entry<String, List<String>> header : connection
.getHeaderFields().entrySet()) {
Log.i("Headers",
"Headers : " + header.getKey() + "="
+ header.getValue());
}
InputStream response = new BufferedInputStream(
connection.getInputStream());
int bytesRead = -1;
byte[] buffer = new byte[30 * 1024];
while ((bytesRead = response.read(buffer)) > 0) {
byte[] buffer2 = new byte[bytesRead];
System.arraycopy(buffer, 0, buffer2, 0, bytesRead);
handleDataFromSync(buffer2);
}
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
So my question is, what should -1 stands for. Is it response for some kind of error or something else?
HTTP response code -1, means that something went wrong with connection or response handling. The HttpURLConnection in often buggy with keeping connections alive.
If you want to turn if off, you have to set the http.keepAlive system property into false.
The way to do this programmatically is putting this at the beginning of your application:
System.setProperty("http.keepAlive", "false");

Categories

Resources