Skip to content

Instantly share code, notes, and snippets.

@dkunzler
Created May 23, 2013 14:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dkunzler/5636491 to your computer and use it in GitHub Desktop.
Save dkunzler/5636491 to your computer and use it in GitHub Desktop.
To use square's Picasso image loading library (http://square.github.io/picasso/) with http Basic auth the implementation of a custom loader is necessary. OkHttp (http://square.github.io/okhttp/) is also needed. Additionally on the server side cache control for such responses has to be enabled explicitly.
// inside Application or Activity, make sure Picasso gets only initalized once
Picasso picasso;
Builder builder = new Picasso.Builder(this);
picasso = builder.loader(new BasicAuthOkHttpLoader(this)).build();
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
import com.squareup.okhttp.HttpResponseCache;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.picasso.Loader;
public class BasicAuthOkHttpLoader implements Loader {
protected static final String RESPONSE_SOURCE = "X-Android-Response-Source";
private static final String CACHE_DIR_NAME = "images"
private static final int MAX_SIZE = 1024 * 1024 * 7; // 7MB (works for us)
private OkHttpClient client;
public BasicAuthOkHttpLoader(Context context) {
client = new OkHttpClient();
try {
final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ? context
.getExternalCacheDir().getPath() : context.getCacheDir().getPath();
File cacheDir = new File(cachePath + File.separator + CACHE_DIR_NAME);
client.setResponseCache(new HttpResponseCache(cacheDir, MAX_SIZE));
} catch (IOException ignored) {
}
}
@Override
public Response load(String url, boolean localCacheOnly) throws IOException {
HttpURLConnection connection = client.open(new URL(url));
String authString = "username:password";
String authStringEnc = Base64.encodeToString(authString.getBytes(), Base64.NO_WRAP);
connection.setRequestProperty("Authorization", "Basic " + authStringEnc);
connection.setUseCaches(true);
// no caching happens without this setting in our scenario
connection.setRequestProperty("Cache-Control", "max-stale=2592000");// 30 days
if (localCacheOnly) {
connection.setRequestProperty("Cache-Control", "only-if-cached");
}
boolean fromCache = parseResponseSourceHeader(connection.getHeaderField(RESPONSE_SOURCE));
return new Response(connection.getInputStream(), fromCache);
}
/** Returns {@code true} if header indicates the response body was loaded from the disk cache. */
private boolean parseResponseSourceHeader(String header) {
if (header == null) {
return false;
}
String[] parts = header.split(" ", 2);
if ("CACHE".equals(parts[0])) {
return true;
}
if (parts.length == 1) {
return false;
}
try {
return "CONDITIONAL_CACHE".equals(parts[0]) && Integer.parseInt(parts[1]) == 304;
} catch (NumberFormatException e) {
return false;
}
}
}
// server has to enable cache explicitly for responses that are served with authentication
Cache-Control:public
@EvanKnowles
Copy link

This appears to have gone a little out of date - it looks like there are some extra header fields we need to check now, otherwise disk caching breaks. As per the new source, the header fields are:

        static final String RESPONSE_SOURCE_OKHTTP = "OkHttp-Response-Source";


        String responseSource = connection.getHeaderField(RESPONSE_SOURCE_OKHTTP);
        if (responseSource == null) {
            responseSource = connection.getHeaderField(RESPONSE_SOURCE_ANDROID);
        }
        boolean fromCache = parseResponseSourceHeader(responseSource);

@stonecs
Copy link

stonecs commented Feb 18, 2014

Hi,

I already replied to you in the square community. This gist is rather outdated, at least the part for the custom Loader.
Something like this should work,without duplicating code from the base class:
https://gist.github.com/stonecs/9068920

For the reference, here the conversation about this:
https://plus.google.com/111643829251040701555/posts/faPTjd8qMzs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment