16c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer/*
26c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * Copyright (C) 2015 Square, Inc.
36c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer *
46c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * Licensed under the Apache License, Version 2.0 (the "License");
56c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * you may not use this file except in compliance with the License.
66c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * You may obtain a copy of the License at
76c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer *
86c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer *      http://www.apache.org/licenses/LICENSE-2.0
96c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer *
106c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * Unless required by applicable law or agreed to in writing, software
116c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * distributed under the License is distributed on an "AS IS" BASIS,
126c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * See the License for the specific language governing permissions and
146c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * limitations under the License.
156c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer */
166c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererpackage com.squareup.okhttp.logging;
176c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
186c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.Connection;
196c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.Headers;
206c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.Interceptor;
216c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.MediaType;
226c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.OkHttpClient;
236c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.Protocol;
246c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.Request;
256c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.RequestBody;
266c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.Response;
276c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.ResponseBody;
286c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.internal.Platform;
296c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.internal.http.HttpEngine;
306c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport java.io.IOException;
316c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport java.nio.charset.Charset;
326c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport java.util.concurrent.TimeUnit;
336c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport okio.Buffer;
346c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport okio.BufferedSource;
356c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
366c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer/**
376c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * An OkHttp interceptor which logs request and response information. Can be applied as an
386c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * {@linkplain OkHttpClient#interceptors() application interceptor} or as a
396c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * {@linkplain OkHttpClient#networkInterceptors() network interceptor}.
406c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * <p>
416c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * The format of the logs created by this class should not be considered stable and may change
426c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer * slightly between releases. If you need a stable logging format, use your own interceptor.
436c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer */
446c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererpublic final class HttpLoggingInterceptor implements Interceptor {
456c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  private static final Charset UTF8 = Charset.forName("UTF-8");
466c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
476c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  public enum Level {
486c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    /** No logs. */
496c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    NONE,
506c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    /**
516c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Logs request and response lines.
526c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <p>
536c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Example:
546c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <pre>{@code
556c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * --> POST /greeting HTTP/1.1 (3-byte body)
566c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     *
576c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <-- HTTP/1.1 200 OK (22ms, 6-byte body)
586c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * }</pre>
596c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     */
606c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    BASIC,
616c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    /**
626c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Logs request and response lines and their respective headers.
636c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <p>
646c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Example:
656c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <pre>{@code
666c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * --> POST /greeting HTTP/1.1
676c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Host: example.com
686c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Content-Type: plain/text
696c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Content-Length: 3
706c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * --> END POST
716c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     *
726c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <-- HTTP/1.1 200 OK (22ms)
736c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Content-Type: plain/text
746c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Content-Length: 6
756c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <-- END HTTP
766c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * }</pre>
776c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     */
786c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    HEADERS,
796c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    /**
806c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Logs request and response lines and their respective headers and bodies (if present).
816c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <p>
826c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Example:
836c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <pre>{@code
846c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * --> POST /greeting HTTP/1.1
856c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Host: example.com
866c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Content-Type: plain/text
876c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Content-Length: 3
886c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     *
896c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Hi?
906c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * --> END GET
916c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     *
926c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <-- HTTP/1.1 200 OK (22ms)
936c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Content-Type: plain/text
946c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Content-Length: 6
956c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     *
966c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * Hello!
976c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * <-- END HTTP
986c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     * }</pre>
996c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer     */
1006c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    BODY
1016c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
1026c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1036c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  public interface Logger {
1046c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    void log(String message);
1056c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1066c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    /** A {@link Logger} defaults output appropriate for the current platform. */
1076c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    Logger DEFAULT = new Logger() {
1086c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      @Override public void log(String message) {
1096c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        Platform.get().log(message);
1106c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      }
1116c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    };
1126c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
1136c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1146c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  public HttpLoggingInterceptor() {
1156c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    this(Logger.DEFAULT);
1166c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
1176c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1186c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  public HttpLoggingInterceptor(Logger logger) {
1196c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    this.logger = logger;
1206c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
1216c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1226c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  private final Logger logger;
1236c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1246c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  private volatile Level level = Level.NONE;
1256c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1266c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  /** Change the level at which this interceptor logs. */
1276c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  public HttpLoggingInterceptor setLevel(Level level) {
1286c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead.");
1296c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    this.level = level;
1306c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    return this;
1316c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
1326c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1336c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  public Level getLevel() {
1346c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    return level;
1356c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
1366c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1376c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  @Override public Response intercept(Chain chain) throws IOException {
1386c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    Level level = this.level;
1396c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1406c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    Request request = chain.request();
1416c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    if (level == Level.NONE) {
1426c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      return chain.proceed(request);
1436c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    }
1446c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1456c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    boolean logBody = level == Level.BODY;
1466c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    boolean logHeaders = logBody || level == Level.HEADERS;
1476c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1486c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    RequestBody requestBody = request.body();
1496c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    boolean hasRequestBody = requestBody != null;
1506c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1516c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    Connection connection = chain.connection();
1526c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    Protocol protocol = connection != null ? connection.getProtocol() : Protocol.HTTP_1_1;
1536c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    String requestStartMessage =
1546c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        "--> " + request.method() + ' ' + request.httpUrl() + ' ' + protocol(protocol);
1556c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    if (!logHeaders && hasRequestBody) {
1566c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      requestStartMessage += " (" + requestBody.contentLength() + "-byte body)";
1576c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    }
1586c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    logger.log(requestStartMessage);
1596c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1606c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    if (logHeaders) {
1616c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      if (hasRequestBody) {
1626c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        // Request body headers are only present when installed as a network interceptor. Force
1636c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        // them to be included (when available) so there values are known.
1646c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        if (requestBody.contentType() != null) {
1656c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer          logger.log("Content-Type: " + requestBody.contentType());
1666c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        }
1676c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        if (requestBody.contentLength() != -1) {
1686c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer          logger.log("Content-Length: " + requestBody.contentLength());
1696c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        }
1706c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      }
1716c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1726c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      Headers headers = request.headers();
1736c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      for (int i = 0, count = headers.size(); i < count; i++) {
1746c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        String name = headers.name(i);
1756c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        // Skip headers from the request body as they are explicitly logged above.
1766c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
1776c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer          logger.log(name + ": " + headers.value(i));
1786c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        }
1796c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      }
1806c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1816c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      if (!logBody || !hasRequestBody) {
1826c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        logger.log("--> END " + request.method());
1836c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      } else if (bodyEncoded(request.headers())) {
1846c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        logger.log("--> END " + request.method() + " (encoded body omitted)");
1856c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      } else {
1866c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        Buffer buffer = new Buffer();
1876c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        requestBody.writeTo(buffer);
1886c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1896c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        Charset charset = UTF8;
1906c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        MediaType contentType = requestBody.contentType();
1916c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        if (contentType != null) {
1926c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer          contentType.charset(UTF8);
1936c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        }
1946c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1956c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        logger.log("");
1966c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        logger.log(buffer.readString(charset));
1976c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
1986c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        logger.log("--> END " + request.method()
1996c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer            + " (" + requestBody.contentLength() + "-byte body)");
2006c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      }
2016c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    }
2026c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2036c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    long startNs = System.nanoTime();
2046c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    Response response = chain.proceed(request);
2056c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
2066c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2076c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    ResponseBody responseBody = response.body();
2086c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    logger.log("<-- " + protocol(response.protocol()) + ' ' + response.code() + ' '
2096c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        + response.message() + " (" + tookMs + "ms"
2106c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        + (!logHeaders ? ", " + responseBody.contentLength() + "-byte body" : "") + ')');
2116c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2126c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    if (logHeaders) {
2136c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      Headers headers = response.headers();
2146c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      for (int i = 0, count = headers.size(); i < count; i++) {
2156c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        logger.log(headers.name(i) + ": " + headers.value(i));
2166c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      }
2176c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2186c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      if (!logBody || !HttpEngine.hasBody(response)) {
2196c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        logger.log("<-- END HTTP");
2206c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      } else if (bodyEncoded(response.headers())) {
2216c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        logger.log("<-- END HTTP (encoded body omitted)");
2226c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      } else {
2236c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        BufferedSource source = responseBody.source();
2246c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        source.request(Long.MAX_VALUE); // Buffer the entire body.
2256c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        Buffer buffer = source.buffer();
2266c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2276c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        Charset charset = UTF8;
2286c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        MediaType contentType = responseBody.contentType();
2296c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        if (contentType != null) {
2306c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer          charset = contentType.charset(UTF8);
2316c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        }
2326c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2336c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        if (responseBody.contentLength() != 0) {
2346c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer          logger.log("");
2356c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer          logger.log(buffer.clone().readString(charset));
2366c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        }
2376c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2386c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer        logger.log("<-- END HTTP (" + buffer.size() + "-byte body)");
2396c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer      }
2406c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    }
2416c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2426c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    return response;
2436c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
2446c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2456c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  private boolean bodyEncoded(Headers headers) {
2466c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    String contentEncoding = headers.get("Content-Encoding");
2476c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
2486c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
2496c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
2506c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  private static String protocol(Protocol protocol) {
2516c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1";
2526c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
2536c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer}
254