Android getInputStream fails (HttpURLConnectionImpl.java:238) - android

Symptoms:
Unable to complete getInputStream. It fails with code (HttpURLConnectionImpl.java:238)
Original error log:
05-25 17:57:06.473 2675-2722/com.manantial.raul.photogallery E/TAG: FlickrFetchr Failed to fetch items
java.io.FileNotFoundException: http://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=6f722a706254ed716d5abb9fb1f012c7&extras=url_s
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:238)
at com.manantial.raul.photogallery.FlickrFetchr.getUrlBytes(FlickrFetchr.java:37)
at com.manantial.raul.photogallery.FlickrFetchr.getUrl(FlickrFetchr.java:69)
at com.manantial.raul.photogallery.FlickrFetchr.fetchItems(FlickrFetchr.java:79)
at com.manantial.raul.photogallery.PhotoGalleryFragment$FetchItemsTask.doInBackground(PhotoGalleryFragment.java:45)
at com.manantial.raul.photogallery.PhotoGalleryFragment$FetchItemsTask.doInBackground(PhotoGalleryFragment.java:36)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
HttpURLConnection getResponseCode = 403 / HTPP_FORBIDDEN
When using the same URL via web browser, there is no error and getResponseCode is OK / 200.
Facts:
Code used:
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = connection.getInputStream(); // fails, while HttpURLConnection = HTTP_FORBIDDEN 403
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { // connection resp code 403 FORBIDDEN
return null;
}
int bytesRead = 0;
byte[] buffer = new byte[1024];
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
out.close();
String temp = out.toByteArray().toString();
Log.i("TAG", TAG + "out.toByteArray is the data response: " + temp);
return out.toByteArray();
} finally {
Log.i("TAG", TAG + " connection response code: " + connection.getResponseCode());
connection.disconnect();
}

The URL used in the code was:
http://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=6f722a706254ed716d5abb9fb1f012c7&extras=url_s
That was converted to https, when using it via browser, but not when using it via my test Android App. The solution was simply adjusting the URL to https in the code:
https://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=6f722a706254ed716d5abb9fb1f012c7&extras=url_s

Related

Issue with http connection on samsung device but not on other device

I have an android app which works perfectly on my phone (Huawei Mate 10 Pro) but when I try to run it on my tablet (Samsung Galaxy Tab S2) I get a java.io.FileNotFoundException when the app tries to access the input stream.
(I get the exception at "InputStream stream = connection.getInputStream();")
Is there a difference between Samsung and other devices regarding http communication? how can I write the code to work on every device?
Here's the code:
public String download_organisations(String url){
String jsonString = "";
try {
if(!url.startsWith("http://")){
url = "http://" + url;
}
if(url.endsWith("/")){
url = url.substring(0, url.lastIndexOf("/"));
}
url = url + ManagerSystemStatic.URL_SERVICE_WEB_ORGANISATION_MANAGER;
URL httpUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) httpUrl.openConnection();
connection.setConnectTimeout(10000);
InputStream stream = connection.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = stream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] inputStreamByteArray = buffer.toByteArray();
byte[] base64 = Base64.decode(inputStreamByteArray, 0);
byte[] decrypted = CipherUtils.decrypt(base64);
jsonString = new String(decrypted);
stream.close();
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
Log.d("OrganisationManager", "Download succeded with response: " + connection.getResponseCode());
} else {
Log.d("OrganisationManager", "Download failed with response: " + connection.getResponseCode());
}
} catch (MalformedURLException e) {
Log.e("OrganisationManager", e.toString());
return DOWNLOAD_FAILED;
} catch (IOException e) {
Log.e("OrganisationManager", e.toString());
e.printStackTrace();
return DOWNLOAD_FAILED;
} catch (Exception e) {
Log.e("OrganisationManager", e.toString());
return DOWNLOAD_FAILED;
}
return jsonString;
}
Here's the StackTrace (with my url replaced):
E/OrganisationManager: java.io.FileNotFoundException: http://www.myurlhere.com
W/System.err: java.io.FileNotFoundException: http://www.myurlhere.com
W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:254)
W/System.err: at com.organisationmanager.ble.common.WebPortalCommunicationHelper.download_organisations(WebPortalCommunicationHelper.java:210)
at com.organisationmanager.ble.ScanningActivity$UpdateOrganisations.doInBackground(ScanningActivity.java:414)
at com.organisationmanager.ble.ScanningActivity$UpdateOrganisations.doInBackground(ScanningActivity.java:403)
W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:304)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
D/InputTransport: Input channel constructed: fd=82
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
W/System.err: at java.lang.Thread.run(Thread.java:762)
When it starts the http communication I also get this in the debugger console:
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
Is that relevant?
After a lot of trial and error I still don't know what the issue was, but I tried using the class OkHttp instead of HttpUrlConnection, and suddenly everything worked. I have no idea why, but since I now have a working code I no longer need help with this issue. I hope this solution (changing class entirely) may help someone in the future. More about the class I used can be found here: http://square.github.io/okhttp/

FileNotFoundException in Android Studio, but works fine in browser

I am trying to connect to a website to receive some JSON information. When I run the app in Android Studio using a connected Nexus 7 device I get a java.io.FileNotFound exception, but if I click on the name of the file that was not found, the response expected immediately shows in my browser. This is a new app for me, but I have done similar things in the past that have worked. I have been trying multiple things over the last 2 days and just can't seem to find the problem. Code blows up when I call connection.getInputStream(). All of this is running in an AsyncTask.
My Code
public byte[] getUrlBytes(String urlSpec) throws IOException{
URL url = new URL(urlSpec);
// urlSpec: https://api.weather.gov/points/48.0174,-115.2278
try {
connection = (HttpsURLConnection) url.openConnection();
} catch (IOException ioe) {
Log.d(TAG, "connection ioe: " + ioe.toString());
Toast.makeText(context, "#string/can_not_connect",
Toast.LENGTH_LONG).show();
}
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = connection.getInputStream(); *** Blows up here ****
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.d(TAG, "connection Response code: " +
connection.getResponseMessage());
}
int bytesRead = 0;
byte[] buffer = new byte[1024];
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
out.close();
return out.toByteArray();
} finally {
connection.disconnect();
}
}
Logcat
04-02 15:40:59.693 32471-32495/com.drme.weathertest E/WeatherFetcher: Failed
to fetch items
java.io.FileNotFoundException: https://api.weather.gov/points/48.0174,-115.2278
*** Note that if I click on this file name, it works in my browser ***
at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:206)
at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:25)
at com.drme.weatherNoaa.WeatherFetcher.getUrlBytes(WeatherFetcher.java:148)
at com.drme.weatherNoaa.WeatherFetcher.getUrlString(WeatherFetcher.java:183)
at com.drme.weatherNoaa.WeatherFetcher.downloadGridPoints(WeatherFetcher.java:202)
at com.drme.weatherNoaa.WeatherFetcher.requestForecast(WeatherFetcher.java:262)
at com.drme.weatherNoaa.WeatherFragment$SearchTask.doInBackground(WeatherFragment.java:329)
at com.drme.weatherNoaa.WeatherFragment$SearchTask.doInBackground(WeatherFragment.java:296)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Thanks for the help.
After additional reading of webservice documentation (some of it seems a little thin to me) and some additional posts on the web, the answer is that they require Acceptance and User-agent headers in the request. I have made these changes and the code now works as desired.
New static constants
private static final String ACCEPT_PROPERTY = "application/geo+json;version=1";
private static final String USER_AGENT_PROPERTY = "xxxx.com (xxxxxxxxx#gmail.com)";
Code changes
connection = (HttpsURLConnection) url.openConnection();
connection.setRequestProperty("Accept", ACCEPT_PROPERTY); // added
connection.setRequestProperty("User-Agent", USER_AGENT_PROPERTY); // added
No other changes were required, although it took me awhile to figure out how to add the headers and what their format might be.
Thanks for checking this out.

Heroku not processing multipart form POST from Android

I have an API on rails 4 that accepts HTTP requests in the form of a file upload. Everything works fine on Localhost but on Heroku the POST request doesn't seem to do anything.
This is what my Android POST request looks like:
public static byte[] postData(String operation, byte[] binaryData) {
String urlString = baseUrl + "/" + operation;
String boundary = "uahbkjqtjgecuaoehuaebkjahj";
byte[] postData = null;
URLConnection urlConnection;
DataInputStream responseDataInputStream;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
StringBuffer startBuffer = new StringBuffer("--").append(boundary).append("\r\n");
startBuffer.append("Content-Disposition: form-data; name=\"data\"; ").append("filename=\"data.dat\"\r\n");
startBuffer.append("Content-Type: application/octet-stream\r\n\r\n");
StringBuffer endBuffer = new StringBuffer("\r\n--").append(boundary).append("--\r\n");
String startRequestData = startBuffer.toString();
String endRequestData = endBuffer.toString();
try {
URL url = new URL(urlString);
urlConnection = url.openConnection();
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
urlConnection.setUseCaches(false);
urlConnection.setConnectTimeout(5000); //5 seconds
urlConnection.setReadTimeout(5000);//5 seconds
urlConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
urlConnection.connect();
DataOutputStream _request = new DataOutputStream(urlConnection.getOutputStream());
// Write the start portion of the request
byteArrayOutputStream.write(startRequestData.getBytes());
postData = byteArrayOutputStream.toByteArray();
_request.write(postData);
// Write the Binary Packet
_request.write(binaryData);
// Write the end portion of the request
byteArrayOutputStream.reset();
byteArrayOutputStream.write(endRequestData.getBytes());
postData = byteArrayOutputStream.toByteArray();
_request.write(postData);
_request.flush();
_request.close();
// Read in the response bytes
InputStream is = urlConnection.getInputStream();
responseDataInputStream = new DataInputStream(is);
byteArrayOutputStream.reset();
byte[] buffer = new byte[responseDataInputStream.available()];
while (responseDataInputStream.read(buffer) != -1) {
byteArrayOutputStream.write(buffer);
buffer = new byte[responseDataInputStream.available()];
}
byte[] responseData = byteArrayOutputStream.toByteArray();
return responseData;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (SocketTimeoutException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return new byte[0];
}
My rails controller
skip_before_filter :verify_authenticity_token
respond_to :raw
before_filter :read_file
def read_file
data = params[:data].tempfile
data_compressed = ''
File.open(data, 'r') do |file|
file.each do |line|
data_compressed.concat(line)
end
end
#json_data = Zlib::Inflate.inflate(data_compressed)
end
def an_action
#processing stuff
response = Zlib::Deflate.deflate(j_response)
send_data #json_response.to_s
end
Heroku logs shows that the controller action is hit but nothing more from the logs
2015-05-05T22:39:29.860161+00:00 heroku[router]: at=info method=POST path="/api/login" host=[my app].herokuapp.com request_id=9d9c91b1-2ce2-4db5-9b54-3dea0322e211 fwd="197.237.24.179" dyno=web.1 connect=4ms service=12ms status=500 bytes=1683
2015-05-05T22:40:40.952219+00:00 heroku[router]: at=info method=POST path="/api/signup" host=[my app].herokuapp.com request_id=4adac44c-66e6-4001-a568-8eb913176091 fwd="197.237.24.179" dyno=web.1 connect=4ms service=8ms status=500 bytes=1683
After shifting my focus from Heroku to the Android code I figured out that there was an endless loop at this section of the code:
while (responseDataInputStream.read(buffer) != -1) {
byteArrayOutputStream.write(buffer);
buffer = new byte[responseDataInputStream.available()];
}
When theres nothing to read the return value is 0 instead of -1. So I updated it to:
while (responseDataInputStream.read(buffer) > 0) {
byteArrayOutputStream.write(buffer);
buffer = new byte[responseDataInputStream.available()];
}
Something strange is that on localhost the first piece of code works and it should work on production too. The documentation states that -1 is returned if the end of stream is reached DataInputStream.read(). Maybe thats a discussion for another day, for now I'm using the second piece of code.
EDIT
This issue has haunted me for weeks and after alot of googling and tweaking of the code I would like to point out that this approach was the WRONG route. The code worked on a WIFI connection but always failed on 3G. So i'll list the code changes that finally worked.
use HttpURLConnection instead of URLConnection. Reason here
Increased the size of Connect and Read timeouts from 5000 to 30000 and 120000 respectively.
Revert the while condition to while (responseDataInputStream.read(buffer) != -1)

Android read remote text files exits with Unexpected End Of Stream

I'm downloading different medias files from my http server; mp3, jpg/png/ and html.
Everything worked fine when I used the now deprecated HttpClient.
I decided to use the HttpURLConnection.
But I encounter a problem with text files(html).
read() blocks on small html files, maybe waiting for a EOF or I don't know what, during few seconds and exits with the Exception "unexpected end of stream".
My code is:
URL url = new URL(urlString);
postParams = String.format("registration=%s&"....);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setDoOutput(true); // It's a POST request which replies sending a file
urlConnection.setChunkedStreamingMode(0);
if (fileName.contains(".htm")) { // Tried this to see...
urlConnection.setRequestProperty("Accept-Charset", "UTF-8");
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + "UTF-8");
}
OutputStream output = urlConnection.getOutputStream();
output.write(postParams.getBytes("UTF-8"));
is = new BufferedInputStream(urlConnection.getInputStream());
/* Get information from the HttpURLConnection automatically fires the request
* http://stackoverflow.com/questions/2793150/using-java-net-urlconnection-to-fire-and-handle-http-requests
*/
int status = urlConnection.getResponseCode();
if (status == 200) {
int len, size = 0;
byte[] buf = new byte[128 * 1024];
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));
try {
while ((len = is.read(buf, 0, buf.length)) > 0) {
os.write(buf, 0, len);
size += len;
}
os.flush();
} catch (IOException e) {
Log.d(Constants.APP_TAG, "IOException." + e); // HTML files end here after few seconds
} finally {
nbFilesDownloaded++;
is.close();
os.close();
file.setReadable(true, false);
file.setWritable(true, false);
}
}
Any idea to explain why it cannot normally exit from read()??
EDIT: I verified that for the html files which cause this exception, my webserver doesn't include Content-Length in the header. Can it be the cause of the problem?
Try to use okhttp http://square.github.io/okhttp/. I have downloaded the files correctly. I hope to help.
Paul.

My file downloader occur error suddenly

#Override
public void run() {
URL imgurl;
int Read;
try {
imgurl = new URL(ServerUrl);
HttpURLConnection conn = (HttpURLConnection) imgurl.openConnection();
int len = conn.getContentLength();
Log.d("check", "ContentLength:" + len);
Log.d("check", "ServerUrl:" + ServerUrl);
Log.d("check", "LocalPath:" + LocalPath);
byte[] tmpByte = new byte[len];
InputStream is = conn.getInputStream();
File file = new File(LocalPath);
FileOutputStream fos = new FileOutputStream(file);
for (;;) {
Read = is.read(tmpByte);
if (Read <= 0) {
break;
}
fos.write(tmpByte, 0, Read);
}
is.close();
fos.flush();
fos.close();
conn.disconnect();
} catch (MalformedURLException e) {
ut.CalltoAlertDialog_ok(getString(R.string.alert), getString(R.string.setting_skin_downloadfail));
} catch (IOException e) {
ut.CalltoAlertDialog_ok(getString(R.string.alert), getString(R.string.setting_skin_downloadfail));
}
mAfterDown.sendEmptyMessage(0);
}
This is file download source.
This code prints error "NegativeArraySizeException" from here
byte[] tmpByte = new byte[len];
So, I checked len's value.
len's value was -1.
But..
When i created yesterday, This code was not print error.
I have 2 apk file.
The apk created yesterday is not a problem. Even now this apk is no problem.
But, The apk created today is problem.
I did not modify anything.
What is the cause of this?
I think your problem is here:
HttpURLConnection conn = (HttpURLConnection) imgurl.openConnection();
int len = conn.getContentLength();
Read documentation about the getContentLength method
Returns the content length in bytes specified by the response header
field content-length or -1 if this field is not set.
Returns the value of the response header field content-length.
So this case that getContentLength returned -1 seems to have happened to you. Then you use this -1 to set your Array size. => Exception thrown
Check the solution of this question about getContentLength returning -1, maybe you will have to do something similar.
But at least you will have to check that len > 0 before setting your array size

Categories

Resources