I am using Android-Universal-Image-Loader to load images from remote server over HTTPS
on my Android application. To have access to images the client should provide a valid token and sometimes server can return "expired crsf token" error. In order to handle this behavior a custom ImageDownloader should be defined. Below is the base implementation of method that should be overrrided in my implementation.
protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
HttpURLConnection conn = createConnection(imageUri, extra);
int redirectCount = 0;
while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {
conn = createConnection(conn.getHeaderField("Location"), extra);
redirectCount++;
}
InputStream imageStream;
try {
imageStream = conn.getInputStream();
} catch (IOException e) {
// Read all data to allow reuse connection (http://bit.ly/1ad35PY)
IoUtils.readAndCloseStream(conn.getErrorStream());
throw e;
}
if (!shouldBeProcessed(conn)) {
IoUtils.closeSilently(imageStream);
throw new IOException("Image request failed with response code " + conn.getResponseCode());
}
return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength());
}
I want to rewrite it to handle invalid token errors. For example, if the server returns such error it should be recognized, token should be regenerated and request repeated.
The only solution I come up with is like this (shortened code):
imageStream = conn.getInputStream();
byte[] body = org.apache.commons.io.IOUtils.toByteArray(imageStream);
if (body.length < 300 // high probability to contain err message
&& isInvalidToken(body)) {
// handle error
}
return new ByteArrayInputStream(body);
Is is safe to use such kind of solution, considering I use it only for thumbnails of max 80kb size? Are there any other solutions?
Methods of InputStream read() - reads one byte of data from the input stream. read(byte[] array) - reads bytes from the stream and stores in the specified array. available() - returns the number of bytes available in the input stream. mark() - marks the position in the input stream up to which data has been read.
URL resource = classLoader. getResource("resource. ext"); File file = new File(resource. toURI()); FileInputStream input = new FileInputStream(file); // ...
Your solution is safe, although it's nicer if you create your ImageDownloaderInputStream
class that implements InputStream
and wraps the original InputStream
. You can pre-load (buffer) some chunk from the underlying input stream to detect if the content is valid or not.
The only method you should override is read().
If the content is valid, you can serve the buffer content to the caller, when the buffer is empty, directly stream from the underlying InputStream
.
If the content is invalid, just simply read another stream, or return a zero-length stream.
public class ImageDownloaderInputStream extends InputStream {
private byte[] buffer = null;
private int bufLen = 0;
private int bufIndex = 0;
private boolean isContentValid;
private InputStream wrapped;
public ImageDownloaderInputStream (InputStream wrapped) {
this.wrapped = wrapped;
}
@Override
public ind read() {
if(buffer == null) {
// check content and fill buffer
this.isContentValid = checkContent();
}
if (this.isContentValid) {
if(bufIndex < bufLen) {
return buffer[bufIndex++] & 0xFF;
} else {
return wrapped.read();
}
} else {
// error handling: zero-length stream
return -1;
}
}
private boolean checkContent() {
// fill the buffer
this.buffer = new byte[1024];
this.bufLen = wrapped.read(this.buffer);
// read more if not enough
// check the content
return true;
// return false;
}
}
You can check for a valid token after you checked that the response was 200 OK like so:
conn.getResponseCode() == HttpStatus.RESPONSE_OK && isValidToken(body)
If these conditions are not met then you handle it accordingly i.e repeat the request x times.
I would consider having a isValidToken(...)
method instead of your isInvalidToken(...)
so that you don't have to negate the response of the method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With