package fr.ydelouis.selfoss.rest; import android.net.Uri; import android.util.Base64; import android.util.Log; import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.EBean; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRequest; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; import java.nio.charset.Charset; import fr.ydelouis.selfoss.BuildConfig; import fr.ydelouis.selfoss.config.model.Config; import fr.ydelouis.selfoss.config.model.ConfigManager; import fr.ydelouis.selfoss.util.Streams; @EBean public class SelfossApiInterceptor implements ClientHttpRequestInterceptor { private static final String TAG = "Selfoss API"; private static final String KEY_USERNAME = "username"; private static final String KEY_PASSWORD = "password"; private static boolean LOG_REQUEST = BuildConfig.DEBUG && true; private static boolean LOG_FULL_REQUEST = BuildConfig.DEBUG && true; private static boolean LOG_RESPONSE = BuildConfig.DEBUG && true; @Bean protected ConfigManager configManager; private Config config; public void setConfig(Config config) { this.config = config; } private Config getConfig() { if (config != null) { return config; } return configManager.get(); } public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { HttpRequest apiRequest = new ApiHttpRequest(request); logRequest(apiRequest); ApiHttpResponse response = new ApiHttpResponse(execution.execute(apiRequest, body)); logResponse(response); return response; } private void logResponse(ApiHttpResponse response) throws IOException { if(LOG_RESPONSE) Log.i(TAG, response.getStatusCode().value() + " : " + Streams.stringOf(response.getBody())); } private void logRequest(HttpRequest request) throws UnsupportedEncodingException { String requestUri = URLDecoder.decode(request.getURI().toString(), "UTF-8"); if(!LOG_FULL_REQUEST && LOG_REQUEST) { String url = getConfig().getUrl(); int start = requestUri.indexOf(url); if (start != -1) { requestUri = requestUri.substring(start+url.length()); } } requestUri = hidePassword(requestUri); Log.i(TAG, request.getMethod() + " : " + requestUri); } private String hidePassword(String requestUri) { if (getConfig().requireAuth()) { return requestUri.replace(getConfig().getPassword(), "************"); } return requestUri; } private class ApiHttpRequest implements HttpRequest { private HttpRequest httpRequest; public ApiHttpRequest(HttpRequest httpRequest) { this.httpRequest = httpRequest; this.httpRequest.getHeaders().set("Content-Length", "0"); this.httpRequest.getHeaders().remove("Content-Type"); if (getConfig().requireAuth()) { String auth = getConfig().getUsername() + ":" + getConfig().getPassword(); String authHeader = "Basic " + Base64.encodeToString(auth.getBytes(Charset.forName("US-ASCII")), Base64.DEFAULT); this.httpRequest.getHeaders().set("Authorization", authHeader); } } @Override public HttpHeaders getHeaders() { return httpRequest.getHeaders(); } @Override public HttpMethod getMethod() { return httpRequest.getMethod(); } @Override public URI getURI() { URI uri = httpRequest.getURI(); Uri.Builder builder = new Uri.Builder(); builder.scheme(getScheme()); builder.authority(getConfig().getUrl()); builder.path(uri.getPath()); builder.encodedQuery(uri.getQuery()); if (getConfig().requireAuth()) { builder.appendQueryParameter(KEY_USERNAME, getConfig().getUsername()); builder.appendQueryParameter(KEY_PASSWORD, getConfig().getPassword()); } Uri newUri = builder.build(); String uriStr = newUri.toString().replace(newUri.getEncodedAuthority(), newUri.getAuthority()); return URI.create(uriStr); } private String getScheme() { return getConfig().useHttps() ? "https" : "http"; } } private class ApiHttpResponse implements ClientHttpResponse { private ClientHttpResponse response; private byte[] byteResponse; public ApiHttpResponse(ClientHttpResponse response) { try { this.response = response; this.response.getHeaders().set("Content-Type", "application/json"); byteResponse = Streams.byteArrayOf(response.getBody()); } catch (IOException e) { e.printStackTrace(); } } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream(byteResponse); } @Override public HttpHeaders getHeaders() { return response.getHeaders(); } @Override public void close() { response.close(); } @Override public int getRawStatusCode() throws IOException { return response.getRawStatusCode(); } @Override public HttpStatus getStatusCode() throws IOException { return response.getStatusCode(); } @Override public String getStatusText() throws IOException { return response.getStatusText(); } } }