Skip to content

Instantly share code, notes, and snippets.

@imminent
Last active December 14, 2015 06:38
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imminent/5043565 to your computer and use it in GitHub Desktop.
Save imminent/5043565 to your computer and use it in GitHub Desktop.
Collection of code to use the Client interface of Retrofit to use HttpUrlConnection with SharedPreferences persistent cookies.
import android.annotation.TargetApi;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.PatternMatcher;
import com.keepandshare.android.utils.CryptographyUtil;
import com.keepandshare.android.utils.Ln;
import javax.inject.Singleton;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static com.keepandshare.android.utils.SharedPreferencesCompat.apply;
/**
* A simple {@linkplain CookieStore cookie jar} that only cares to store the {@link #_COOKIE_AUTH_TOKEN}.
* It persists the cookie through app launches and maintains it securely.
* @author Dandré Allison
*/
@Singleton
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class AndroidCookieStore implements CookieStore {
/* Constructor */
public AndroidCookieStore(SharedPreferences settings, CryptographyUtil crypto) {
_settings = settings;
_crypto = crypto;
}
/* Cookie Store */
@Override
public void add(URI _, HttpCookie cookie) {
Ln.v("Adding Cookie: %s", cookie);
// Stores the cookie in shared preferences
if (_auth_token_pattern.match(cookie.getName())) {
final SharedPreferences.Editor editor = _settings.edit();
try {
editor.putString(_KEY_AUTH_TOKEN, _crypto.encrypt(cookie.getValue()));
} catch (Exception error) {
Ln.e(error.getCause());
}
apply(editor);
}
}
@Override
public List<HttpCookie> getCookies() {
return get(null);
}
@Override
public List<HttpCookie> get(URI _) {
// Loads in cookies from shared preferences
final String auth_token = _settings.getString(_KEY_AUTH_TOKEN, null);
if (auth_token != null)
try {
final HttpCookie cookie = new HttpCookie(_COOKIE_AUTH_TOKEN, _crypto.decrypt(auth_token));
cookie.setPath("/");
cookie.setVersion(0);
Ln.v("Retrieved Cookie: %s", cookie);
return newArrayList(cookie);
} catch (Exception error) {
Ln.e(error.getCause());
}
return newArrayList();
}
@Override
public List<URI> getURIs() {
return newArrayList();
}
@Override
public boolean remove(URI _, HttpCookie __) {
final boolean had_auth_token = _settings.getString(_KEY_AUTH_TOKEN, null) != null;
final SharedPreferences.Editor editor = _settings.edit();
apply(editor.remove(_KEY_AUTH_TOKEN));
return had_auth_token;
}
@Override
public boolean removeAll() {
return remove(null,null);
}
private static final String _KEY_AUTH_TOKEN = "AUTH_TOKEN";
private static final String _COOKIE_AUTH_TOKEN = "PHPSESSID";
private static final PatternMatcher _auth_token_pattern = new PatternMatcher(_COOKIE_AUTH_TOKEN, PatternMatcher.PATTERN_LITERAL);
private final SharedPreferences _settings;
private final CryptographyUtil _crypto;
}
import android.os.PatternMatcher;
import com.github.kevinsawicki.http.HttpRequest;
import com.keepandshare.android.utils.CircularByteBuffer;
import com.keepandshare.android.utils.Ln;
import org.apache.http.protocol.HttpContext;
import retrofit.http.Header;
import retrofit.http.client.Client;
import retrofit.http.client.Request;
import retrofit.http.client.Response;
import retrofit.http.mime.TypedInput;
import retrofit.http.mime.TypedOutput;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.google.common.collect.Maps.newHashMap;
/**
* Custom implementation of {@link Client} that can utilize an {@link HttpContext}.
* @author Dandré Allison
*/
public class RecommendedAndroidClient implements Client {
@Override
public Response execute(Request request) throws IOException {
Ln.v("Request: %s '%s'", request.getMethod(), _sanitize_passwords.reset(request.getUrl()).replaceAll("p=***"));
// Creates the request
final HttpRequest http_response = new HttpRequest(request.getUrl(), request.getMethod())
// Requests compressed responses
.acceptGzipEncoding()
// Automatically uncompresses response
.uncompress(true);
prepareRequest(http_response);
final List<Header> headers = request.getHeaders();
if (headers != null)
http_response.headers(prepareHeaders(request.getHeaders()));
final TypedOutput body = request.getBody();
if (body != null) {
final CircularByteBuffer byte_buffer = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
request.getBody().writeTo(byte_buffer.getOutputStream());
http_response.send(byte_buffer.getInputStream());
}
// Creates the response
return parseResponse(http_response);
}
Response parseResponse(HttpRequest response) throws IOException {
final InputStream stream = response.buffer();
final int status = response.code();
final String reason = response.message();
final List<Header> headers = new ArrayList<Header>();
String content_type = "application/octet-stream";
for (Map.Entry<String, List<String>> header : response.headers().entrySet()) {
final String name = header.getKey();
final String value = header.getValue().get(0);
if (_content_type_header.match(name))
content_type = value;
headers.add(new Header(name, value));
}
prepareResponse(response, stream);
final TypedInputStream body = stream == null? null : new TypedInputStream(content_type, stream);
return new Response(status, reason, headers, body);
}
/** Callback for additional preparation of the request before execution. */
protected void prepareRequest(HttpRequest request) { }
/** Callback for additional preparation of the response before parsing. */
protected void prepareResponse(HttpRequest response, InputStream body) { }
static class TypedInputStream implements TypedInput {
public TypedInputStream(String mime_type, InputStream in) {
_mime_type = mime_type;
_in = new BufferedInputStream(in);
}
@Override
public String mimeType() {
return _mime_type;
}
@Override
public long length() {
return -1;
}
@Override
public InputStream in() throws IOException {
return _in;
}
private final String _mime_type;
public final InputStream _in;
}
private Map<String, String> prepareHeaders(List<Header> headers) {
if (headers == null) return null;
final Map<String, String> header_map = newHashMap();
for (Header header : headers)
header_map.put(header.getName(), header.getValue());
return header_map;
}
private static final PatternMatcher _content_type_header = new PatternMatcher(HttpRequest.HEADER_CONTENT_TYPE, PatternMatcher.PATTERN_LITERAL);
private static final Matcher _sanitize_passwords = Pattern.compile("(p=)[^&]*").matcher("");
}
// Sets the AndroidCookieStore as the CookieStore to use for managing magic-cookies
final CookieManager cookie_manager = new CookieManager(cookie_jar, CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(new CookieManager());
// Configures the RestAdapter to use RecommendedAndroidClient instead of AndroidHttpClient
RestAdapter rest_adapter = new RestAdapter.Builder().setServer("http://www.example.com)
.setClient(http_client).build();
@dannyroa
Copy link

Where can I get the code for com.keepandshare.android.utils.CryptographyUtil?

Thanks.

@feresr
Copy link

feresr commented May 27, 2014

setClient(http_client) ? what is http_client, is not defined anywhere!.

@androidexample1
Copy link

Hi
I have found one good example here
Android Session Management Using SharedPreferences

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