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