1a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee/* 2a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * Copyright (C) 2014 The Android Open Source Project 3a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * 4a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * Licensed under the Apache License, Version 2.0 (the "License"); 5a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * you may not use this file except in compliance with the License. 6a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * You may obtain a copy of the License at 7a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * 8a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * http://www.apache.org/licenses/LICENSE-2.0 9a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * 10a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * Unless required by applicable law or agreed to in writing, software 11a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * distributed under the License is distributed on an "AS IS" BASIS, 12a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * See the License for the specific language governing permissions and 14a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * limitations under the License. 15a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee */ 16a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 17a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leepackage com.android.exchange.utility; 18a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 19a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport android.util.Base64; 20a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport android.util.Log; 21a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 22a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport com.android.exchange.Eas; 23a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport com.android.mail.utils.LogUtils; 24a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 25a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport org.apache.http.Header; 26a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport org.apache.http.HttpEntity; 27a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport org.apache.http.entity.BufferedHttpEntity; 28a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport org.apache.http.HttpResponse; 29a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport org.apache.http.HttpResponseInterceptor; 30a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport org.apache.http.protocol.HttpContext; 31a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 32a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport java.io.ByteArrayOutputStream; 33a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport java.io.IOException; 34a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport java.io.InputStream; 35a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport java.util.zip.GZIPInputStream; 36a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 37a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee/** 38a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * Dumps the wbxml in base64 (much like {@link CurlLogger}) so that the 39a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee * response from Exchange can be viewed for debugging purposes. 40a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee */ 41a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leepublic class WbxmlResponseLogger implements HttpResponseInterceptor { 42a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee private static final String TAG = Eas.LOG_TAG; 43a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee protected static final int MAX_LENGTH = 1024; 44a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 45a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee protected static boolean shouldLogResponse(final long contentLength) { 46a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // Not going to bother if there is a lot of content since most of that information 47a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // will probably just be message contents anyways. 48a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee return contentLength < MAX_LENGTH; 49a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } 50a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 51a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee protected static String processContentEncoding(final Header encodingHeader) { 52a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee if (encodingHeader != null) { 53a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final String encodingValue = encodingHeader.getValue(); 54a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee return (encodingValue == null) ? "UTF-8" : encodingValue; 55a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } 56a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee return "UTF-8"; 57a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } 58a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 59a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee protected static byte[] getContentAsByteArray(InputStream is, int batchSize) 60a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee throws IOException { 61a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // Start building our byte array to encode and dump. 62a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee int count; 63a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final byte[] data = new byte[batchSize]; 64a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 65a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee while ((count = is.read(data, 0, data.length)) != -1) { 66a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee buffer.write(data, 0, count); 67a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } 68a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee buffer.flush(); 69a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee return buffer.toByteArray(); 70a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } 71a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 72a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee @Override 73a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee public void process(HttpResponse response, HttpContext context) throws IOException { 74a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee if (Log.isLoggable(TAG, Log.DEBUG)) { 75a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // Wrap the HttpEntity so the response InputStream can be requested and processed 76a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // numerous times. 77a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee response.setEntity(new BufferedHttpEntity(response.getEntity())); 78a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 79a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // Now grab the wrapped HttpEntity so that you safely can process the response w/o 80a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // affecting the core response processing module. 81a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final HttpEntity entity = response.getEntity(); 82a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee if (!shouldLogResponse(entity.getContentLength())) { 83a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee LogUtils.d(TAG, "wbxml response: [TOO MUCH DATA TO INCLUDE]"); 84a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee return; 85a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } 86a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 87a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // We need to figure out the encoding in the case that it is gzip and we need to 88a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // inflate it during processing. 89a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final Header encodingHeader = entity.getContentEncoding(); 90a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final String encoding = processContentEncoding(encodingHeader); 91a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 92a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final InputStream is; 93a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee if (encoding.equals("gzip")) { 94a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // We need to inflate this first. 95a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final InputStream unwrappedIs = response.getEntity().getContent(); 96a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee is = new GZIPInputStream(unwrappedIs); 97a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } else { 98a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee is = response.getEntity().getContent(); 99a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } 100a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 101a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final byte currentXMLBytes[] = getContentAsByteArray(is, MAX_LENGTH); 102a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 103a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // Now let's dump out the base 64 encoded bytes and the rest of the command that will 104a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee // tell us what the response is. 105a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee final String base64 = Base64.encodeToString(currentXMLBytes, Base64.NO_WRAP); 106a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee LogUtils.d(TAG, "wbxml response: echo '%s' | base64 -d | wbxml", base64); 107a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } 108a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee } 109a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee 110a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee} 111