From f62173afbb67623c4afa87549dc48cf2d3123d96 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 3 Apr 2021 05:22:56 +0100 Subject: [PATCH] Add debug helper for JSSE Handshakes (#6579) --- .../main/kotlin/okhttp3/JsseDebugLogging.kt | 82 +++++++++++++++++++ .../main/kotlin/okhttp3/OkHttpDebugLogging.kt | 27 +++--- 2 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 okhttp-testing-support/src/main/kotlin/okhttp3/JsseDebugLogging.kt diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/JsseDebugLogging.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/JsseDebugLogging.kt new file mode 100644 index 000000000..69d6aafbf --- /dev/null +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/JsseDebugLogging.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package okhttp3 + +import java.io.Closeable +import java.util.logging.Handler +import java.util.logging.LogRecord + +object JsseDebugLogging { + data class JsseDebugMessage(val message: String, val param: String?) { + enum class Type { + Handshake, Plaintext, Encrypted, Setup, Unknown + } + + val type: Type + get() = when { + message == "adding as trusted certificates" -> Type.Setup + message == "Raw read" || message == "Raw write" -> Type.Encrypted + message == "Plaintext before ENCRYPTION" || message == "Plaintext after DECRYPTION" -> Type.Plaintext + message.startsWith("System property ") -> Type.Setup + message.startsWith("Reload ") -> Type.Setup + message == "No session to resume." -> Type.Handshake + message.startsWith("Consuming ") -> Type.Handshake + message.startsWith("Produced ") -> Type.Handshake + message.startsWith("Negotiated ") -> Type.Handshake + message.startsWith("Found resumable session") -> Type.Handshake + message.startsWith("Resuming session") -> Type.Handshake + message.startsWith("Using PSK to derive early secret") -> Type.Handshake + else -> Type.Unknown + } + + override fun toString(): String { + return if (param != null) { + message + "\n" + param + } else { + message + } + } + } + + private fun quietDebug(message: JsseDebugMessage) { + if (message.message.startsWith("Ignore")) { + return + } + + when (message.type) { + JsseDebugMessage.Type.Setup, JsseDebugMessage.Type.Encrypted, JsseDebugMessage.Type.Plaintext -> { + println(message.message + " (skipped output)") + } + else -> println(message) + } + } + + fun enableJsseDebugLogging(debugHandler: (JsseDebugMessage) -> Unit = this::quietDebug): Closeable { + System.setProperty("javax.net.debug", "") + return OkHttpDebugLogging.enable("javax.net.ssl", object : Handler() { + override fun publish(record: LogRecord) { + val param = record.parameters?.firstOrNull() as? String + debugHandler(JsseDebugMessage(record.message, param)) + } + + override fun flush() { + } + + override fun close() { + } + }) + } +} \ No newline at end of file diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt index cb2d4e8e3..4c64630cb 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt @@ -15,15 +15,17 @@ */ package okhttp3 +import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.http2.Http2 +import java.io.Closeable import java.util.concurrent.CopyOnWriteArraySet import java.util.logging.ConsoleHandler +import java.util.logging.Handler import java.util.logging.Level import java.util.logging.LogRecord import java.util.logging.Logger import java.util.logging.SimpleFormatter import kotlin.reflect.KClass -import okhttp3.internal.concurrent.TaskRunner -import okhttp3.internal.http2.Http2 object OkHttpDebugLogging { // Keep references to loggers to prevent their configuration from being GC'd. @@ -33,18 +35,23 @@ object OkHttpDebugLogging { fun enableTaskRunner() = enable(TaskRunner::class) - fun enable(loggerClass: String) { + fun logHandler() = ConsoleHandler().apply { + level = Level.FINE + formatter = object : SimpleFormatter() { + override fun format(record: LogRecord) = + String.format("[%1\$tF %1\$tT] %2\$s %n", record.millis, record.message) + } + } + + fun enable(loggerClass: String, handler: Handler = logHandler()): Closeable { val logger = Logger.getLogger(loggerClass) if (configuredLoggers.add(logger)) { - logger.addHandler(ConsoleHandler().apply { - level = Level.FINE - formatter = object : SimpleFormatter() { - override fun format(record: LogRecord) = - String.format("[%1\$tF %1\$tT] %2\$s %n", record.millis, record.message) - } - }) + logger.addHandler(handler) logger.level = Level.FINEST } + return Closeable { + logger.removeHandler(handler) + } } fun enable(loggerClass: KClass<*>) = enable(loggerClass.java.name)