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");
Related
I'm using HttpURLConnection to retrieve some configuration from a server. It works fine but for some reason I'm getting the following warning in the logcat:
OkHttpClient: A connection to ... was leaked. Did you forget to close a response body?
As pointed out in this question, Android is using OkHttp internally in HttpUrlConnection. What am I doing to cause this warning?
Here is the code I'm using:
HttpURLConnection connection = null;
OutputStream outputStream = null;
String result;
try {
URL url = new URL(CONFIG_URL);
connection = (HttpURLConnection) url.openConnection();
connection.setReadTimeout(READ_TIMEOUT_MILLI);
connection.setConnectTimeout(CONNECT_TIMEOUT_MILLI);
connection.setRequestMethod(REQUEST_METHOD);
connection.setDoInput(true);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Accept", "application/json");
outputStream = connection.getOutputStream();
try (DataOutputStream wr = new DataOutputStream(outputStream)) {
wr.write(data.toString().getBytes(STRING_ENCODING));
wr.flush();
wr.close();
int responseCode = connection.getResponseCode();
if (responseCode != HttpsURLConnection.HTTP_OK) {
Log.e(TAG, "HTTP error code: " + responseCode);
return;
}
try (InputStream stream = connection.getInputStream()) {
if (stream != null) {
result = readStream(stream, READ_STREAM_MAX_LENGTH_CHARS);
//...
connection.disconnect();
}
} catch (Throwable e) {
Log.e(TAG, "run: failed to parse server response: " +e.getMessage());
}
}
} catch (Exception e) {
Log.e(TAG, "HttpSendTask: failed to send configuration request " + data +": " +e.getMessage());
} finally {
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null) {
connection.disconnect();
}
}
Closing the inputstream of the connection solved my problem.
Try to close it in the finally block :
connection.getInputStream().close()
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();
}
I want to download a file with his url.
I use an AsyncTask with HttpURLConnection but when I get response code, server return error 403.
I use the HttpURLConnection in doInBackground.
Code :
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
ext = FilenameUtils.getExtension(sUrl[0]);
fileName = FilenameUtils.getBaseName(sUrl[0]);
Log.i("Brieg", "storage : /storage/emulated/0/" + fileName + "." + ext);
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode() + " " + connection.getResponseMessage();
}
int fileLength = connection.getContentLength();
input = connection.getInputStream();
output = new FileOutputStream("/storage/emulated/0/" + fileName + "." + ext);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
if (isCancelled()) {
input.close();
return null;
}
total += count;
if (fileLength > 0)
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
}
catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
}
catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return null;
}
Where is the problem ?
Knowing that when I get URL in a browser, the download file starts up.
Thank you in advance.
The cause should be you are not setting User-Agent:
connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:221.0) Gecko/20100101 Firefox/31.0"); // add this line to your code
connection.connect();
HTTP 403 Forbidden
Where is the problem
Error code says it clearly - you are forbidden from accessing the resource on the server. Maybe you need to authenticate first, maybe you are simply banned. Many possibilities.
So, I can't get rid of this problem:
I need to upload a XML file and a .jpg file from my android app(API 8) to a HTTP server (win 2008 server with IIS 7.5). I've already enabled PUT verbs and uninstalled WebDav & webdav methods as suggested from previous searches.
Plus, i'm not sure i'm doing it right server side because i can't get any response back.
here's my code
URL fileurl = new URL("Server Upload Path");
HttpURLConnection urlConnection = (HttpURLConnection) fileurl
.openConnection();
urlConnection.setRequestMethod("PUT");
urlConnection.setDoOutput(true);
urlConnection.connect();
OutputStream os = urlConnection.getOutputStream();
File upFile = new File("My Local File");
//I'm sure the file exists
FileInputStream fis = new FileInputStream(upFile);
BufferedInputStream bfis = new BufferedInputStream(fis);
byte[] buffer = new byte[1024];
int bufferLength = 0;
// now, read through the input buffer and write the contents to the
// file
while ((bufferLength = bfis.read(buffer)) > 0) {
os.write(buffer, 0, bufferLength);
}
Sorry if I forget some info you may need to help. I'm new to android and IIS too.
Why not try a standard multi-part file upload request (based on POST and not PUT):
final static String MULTIPART_BOUNDARY = "------------------563i2ndDfv2rTHiSsdfsdbouNdArYfORhxcvxcvefj3q2f";
public static void sendFileToServer(String url, File logFiles) {
HttpURLConnection connection = null;
OutputStream os = null;
DataInputStream is = null;
try {
StringBuilder fullUrl = new StringBuilder(url);
connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + MULTIPART_BOUNDARY);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestProperty("Connection", "Keep-Alive");
connection.connect();
os = new BufferedOutputStream(connection.getOutputStream());
if(os != null) {
os.write(("--" + MULTIPART_BOUNDARY + EOL).getBytes());
os.write(String.format("Content-Disposition:form-data;name=\"UploadedFile\";filename=\"%s\"\r\nContent-Type: application/x-zip-compressed\r\n\r\n", UPLOADED_FILE_NAME).getBytes());
// Upload file(s) data here and send
os.write((EOL + "--" + MULTIPART_BOUNDARY + "--" + EOL + EOL).getBytes());
os.flush();
os.close();
os = null;
}
if(connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// Process server response
}
} catch (MalformedURLException e) {
} catch (IOException e) {
} catch (Exception e1) {
} finally {
try {
if(os != null) {
os.close();
}
} catch (IOException e) {
Log.e(TAG, "sendFileToServer exception: close OutputStream", e);
}
try {
if(is != null) {
is.close();
}
} catch (IOException e) {
Log.e(TAG, "sendFileToServer exception: close InputStream", e);
}
if(connection != null) {
connection.disconnect();
}
}
}
My code (reproduced below), connects to a url and downloads the file to disk on android. All standard stuff. When I try using this code on a file on S3 accessed via a subdomain on our server mapped to a bucket (e.g. foo.example.com => bucket called foo.example.com), it often fails. Turns out (using the handy curl command..
"curl -v -L -X GET http://foo.example.com/f/a.txt")
.. that there's a redirect going on here.
The file download works ok, as HttpURLConnection will follow redirects by default, but the calls that require the header infomation (getContentLength, getHeaderFieldDate("Last-Modified", 0 ) etc) are returns the headers from the 307 redirect, and not the actual file thats downloaded.
Anyone know how to get around this?
Thanks
File local = null;
try {
Log.i(TAG, "Downloading file " + source);
conn = (HttpURLConnection) new URL(source).openConnection();
fileSize = conn.getContentLength(); // ** THIS IS WRONG ON REDIRECTED FILES
out = new BufferedOutputStream(new FileOutputStream(destination, false), 8 * 1024);
conn.connect();
stream = new BufferedInputStream(conn.getInputStream(), 8 * 1024);
byte[] buffer = new byte[MAX_BUFFER_SIZE];
while (true) {
int read = stream.read(buffer);
if (read == -1) {
break;
}
// writing to buffer
out.write(buffer, 0, read);
downloaded += read;
publishProgress(downloaded, fileSize);
if (isCancelled()) {
return "The user cancelled the download";
}
}
} catch (Exception e) {
String msg = "Failed to download file " + source + ". " + e.getMessage();
Log.e(TAG, msg );
return msg;
} finally {
if (out != null) {
try {
out.flush();
out.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close file " + destination);
e.printStackTrace();
}
}
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close file " + destination);
e.printStackTrace();
}
} else {
long dateLong = conn.getHeaderFieldDate("Last-Modified", 0 ); // ** THIS IS WRONG ON REDIRECTED FILES
Date d = new Date(dateLong);
local.setLastModified(dateLong);
}
have you tried to set redirects to false and try to manually capture the redirected URL and associated header fields with it?
For example something like this:
URL url = new URL(url);
HttpURLConnection ucon = (HttpURLConnection) url.openConnection();
ucon.setInstanceFollowRedirects(false);
URL secondURL = new URL(ucon.getHeaderField("Location"));
URLConnection conn = secondURL.openConnection();
This example captures the redirected URL, but you could easily tweak this to try for any other header field. Does this help?
Consider using httpclient-android. You should get the right headers after redirection with this:
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(YOUR_URL);
HttpResponse response = client.execute(request);
response.getAllHeaders()
Note that android comes with an older version of httpclient, but it has the same problem as you reported. You actually need to import "httpclient-android" for a newer version.
Note: The code snippet is for v4.3. For other versions, look for how to do it in regular apache HttpClient.
Well, I've been playing a bit and this code, which uses the HttpClient library rather than HttpUrlConnection works fine. The headers it returns are those of the final redirect hop.
At least on the devices I've tested it on.
HttpClient client = null;
HttpGet get = null;
HttpResponse response = null;
try {
client = new DefaultHttpClient();
get = new HttpGet(source);
response = client.execute(get);
Header contentSize = response.getFirstHeader("Content-Length");
if (contentSize != null) {
String value = contentSize.getValue();
fileSize = Long.parseLong(value);
}
if (fileSize == -1) {
Log.e(TAG, "Failed to read the content length for the file " + source);
}
Header lastModified = response.getFirstHeader("Last-Modified");
lastModifiedDate = null;
if (lastModified != null) {
lastModifiedDate = DateUtils.parseDate(lastModified.getValue());
}
if (lastModifiedDate == null) {
Log.e(TAG, "Failed to read the last modified date for the file " + source);
}
out = new BufferedOutputStream(new FileOutputStream(destination, false), 8 * 1024); // false means don't append
stream = new BufferedInputStream(response.getEntity().getContent(), 8 * 1024);
byte[] buffer = new byte[MAX_BUFFER_SIZE];
int count = 0;
while (true) {
int read = stream.read(buffer);
if (read == -1) {
break;
}
// writing to buffer
out.write(buffer, 0, read);
downloaded += read;
publishProgress(downloaded, fileSize);
if (isCancelled()) {
Log.w(TAG, "User Cancelled");
return; // NOTE that onPostExecute is not called here..
}
}// end of while
publishProgress(downloaded, fileSize);
} catch (Exception e) {
String msg = "Failed to download file " + source + ". " + e.getMessage();
Log.e(TAG, msg );
return msg;
} finally {
if (out != null) {
try {
out.flush();
out.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close file " + destination);
e.printStackTrace();
}
}
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
Log.e(TAG, "Failed to close file " + destination);
e.printStackTrace();
}
}
}