mirror of
https://github.com/square/okhttp.git
synced 2025-08-08 23:42:08 +03:00
Adopt idiomatic Kotlin in HttpLoggingInterceptor
This commit is contained in:
@@ -24,7 +24,6 @@ import okhttp3.internal.platform.Platform
|
|||||||
import okhttp3.internal.platform.Platform.Companion.INFO
|
import okhttp3.internal.platform.Platform.Companion.INFO
|
||||||
import okio.Buffer
|
import okio.Buffer
|
||||||
import okio.GzipSource
|
import okio.GzipSource
|
||||||
import java.io.EOFException
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import java.nio.charset.StandardCharsets.UTF_8
|
import java.nio.charset.StandardCharsets.UTF_8
|
||||||
@@ -44,7 +43,8 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
|
|||||||
|
|
||||||
@Volatile private var headersToRedact = emptySet<String>()
|
@Volatile private var headersToRedact = emptySet<String>()
|
||||||
|
|
||||||
@Volatile @set:JvmName("-deprecated_setLevel") var level = Level.NONE
|
@set:JvmName("level")
|
||||||
|
@Volatile var level = Level.NONE
|
||||||
|
|
||||||
enum class Level {
|
enum class Level {
|
||||||
/** No logs. */
|
/** No logs. */
|
||||||
@@ -129,16 +129,24 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
|
|||||||
|
|
||||||
fun redactHeader(name: String) {
|
fun redactHeader(name: String) {
|
||||||
val newHeadersToRedact = TreeSet(String.CASE_INSENSITIVE_ORDER)
|
val newHeadersToRedact = TreeSet(String.CASE_INSENSITIVE_ORDER)
|
||||||
newHeadersToRedact.addAll(headersToRedact)
|
newHeadersToRedact += headersToRedact
|
||||||
newHeadersToRedact.add(name)
|
newHeadersToRedact += name
|
||||||
headersToRedact = newHeadersToRedact
|
headersToRedact = newHeadersToRedact
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(
|
||||||
|
message = "Moved to var. Replace setLevel(...) with level(...) to fix Java",
|
||||||
|
replaceWith = ReplaceWith(expression = "apply { this.level = level }"),
|
||||||
|
level = DeprecationLevel.WARNING)
|
||||||
fun setLevel(level: Level) = apply {
|
fun setLevel(level: Level) = apply {
|
||||||
this.level = level
|
this.level = level
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("-deprecated_getLevel")
|
@JvmName("-deprecated_level")
|
||||||
|
@Deprecated(
|
||||||
|
message = "moved to var",
|
||||||
|
replaceWith = ReplaceWith(expression = "level"),
|
||||||
|
level = DeprecationLevel.WARNING)
|
||||||
fun getLevel(): Level = level
|
fun getLevel(): Level = level
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
@@ -176,16 +184,13 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val headers = request.headers
|
val headers = request.headers
|
||||||
var i = 0
|
for (i in 0 until headers.size) {
|
||||||
val count = headers.size
|
|
||||||
while (i < count) {
|
|
||||||
val name = headers.name(i)
|
val name = headers.name(i)
|
||||||
// Skip headers from the request body as they are explicitly logged above.
|
// Skip headers from the request body as they are explicitly logged above.
|
||||||
if (!"Content-Type".equals(name, ignoreCase = true) && !"Content-Length".equals(name,
|
if (!"Content-Type".equals(name, ignoreCase = true) &&
|
||||||
ignoreCase = true)) {
|
!"Content-Length".equals(name, ignoreCase = true)) {
|
||||||
logHeader(headers, i)
|
logHeader(headers, i)
|
||||||
}
|
}
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!logBody || requestBody == null) {
|
if (!logBody || requestBody == null) {
|
||||||
@@ -202,7 +207,7 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
|
|||||||
val charset: Charset = contentType?.charset(UTF_8) ?: UTF_8
|
val charset: Charset = contentType?.charset(UTF_8) ?: UTF_8
|
||||||
|
|
||||||
logger.log("")
|
logger.log("")
|
||||||
if (buffer.isUtf8()) {
|
if (buffer.isProbablyUtf8()) {
|
||||||
logger.log(buffer.readString(charset))
|
logger.log(buffer.readString(charset))
|
||||||
logger.log("--> END ${request.method} (${requestBody.contentLength()}-byte body)")
|
logger.log("--> END ${request.method} (${requestBody.contentLength()}-byte body)")
|
||||||
} else {
|
} else {
|
||||||
@@ -256,7 +261,7 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
|
|||||||
val contentType = responseBody.contentType()
|
val contentType = responseBody.contentType()
|
||||||
val charset: Charset = contentType?.charset(UTF_8) ?: UTF_8
|
val charset: Charset = contentType?.charset(UTF_8) ?: UTF_8
|
||||||
|
|
||||||
if (!buffer.isUtf8()) {
|
if (!buffer.isProbablyUtf8()) {
|
||||||
logger.log("")
|
logger.log("")
|
||||||
logger.log("<-- END HTTP (binary ${buffer.size}-byte body omitted)")
|
logger.log("<-- END HTTP (binary ${buffer.size}-byte body omitted)")
|
||||||
return response
|
return response
|
||||||
@@ -283,37 +288,9 @@ class HttpLoggingInterceptor @JvmOverloads constructor(
|
|||||||
logger.log(headers.name(i) + ": " + value)
|
logger.log(headers.name(i) + ": " + value)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
private fun bodyHasUnknownEncoding(headers: Headers): Boolean {
|
||||||
/**
|
val contentEncoding = headers["Content-Encoding"] ?: return false
|
||||||
* Returns true if the body in question probably contains human readable text. Uses a small
|
return !contentEncoding.equals("identity", ignoreCase = true) &&
|
||||||
* sample of code points to detect unicode control characters commonly used in binary file
|
!contentEncoding.equals("gzip", ignoreCase = true)
|
||||||
* signatures.
|
|
||||||
*/
|
|
||||||
internal fun Buffer.isUtf8(): Boolean {
|
|
||||||
try {
|
|
||||||
val prefix = Buffer()
|
|
||||||
val byteCount = size.coerceAtMost(64)
|
|
||||||
copyTo(prefix, 0, byteCount)
|
|
||||||
for (i in 0 until 16) {
|
|
||||||
if (prefix.exhausted()) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
val codePoint = prefix.readUtf8CodePoint()
|
|
||||||
if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
} catch (e: EOFException) {
|
|
||||||
return false // Truncated UTF-8 sequence.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bodyHasUnknownEncoding(headers: Headers): Boolean {
|
|
||||||
val contentEncoding = headers["Content-Encoding"]
|
|
||||||
return (contentEncoding != null &&
|
|
||||||
!contentEncoding.equals("identity", ignoreCase = true) &&
|
|
||||||
!contentEncoding.equals("gzip", ignoreCase = true))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.logging
|
||||||
|
|
||||||
|
import okio.Buffer
|
||||||
|
import java.io.EOFException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the body in question probably contains human readable text. Uses a small
|
||||||
|
* sample of code points to detect unicode control characters commonly used in binary file
|
||||||
|
* signatures.
|
||||||
|
*/
|
||||||
|
internal fun Buffer.isProbablyUtf8(): Boolean {
|
||||||
|
try {
|
||||||
|
val prefix = Buffer()
|
||||||
|
val byteCount = size.coerceAtMost(64)
|
||||||
|
copyTo(prefix, 0, byteCount)
|
||||||
|
for (i in 0 until 16) {
|
||||||
|
if (prefix.exhausted()) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
val codePoint = prefix.readUtf8CodePoint()
|
||||||
|
if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} catch (_: EOFException) {
|
||||||
|
return false // Truncated UTF-8 sequence.
|
||||||
|
}
|
||||||
|
}
|
@@ -15,19 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package okhttp3.logging
|
package okhttp3.logging
|
||||||
|
|
||||||
import okhttp3.logging.HttpLoggingInterceptor.Companion.isUtf8
|
|
||||||
import okio.Buffer
|
import okio.Buffer
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class HttpLoggingInterceptorKotlinTest {
|
class IsProbablyUtf8Test {
|
||||||
@Test fun isPlaintext() {
|
@Test fun isProbablyUtf8() {
|
||||||
assertThat(Buffer().isUtf8()).isTrue()
|
assertThat(Buffer().isProbablyUtf8()).isTrue()
|
||||||
assertThat(Buffer().writeUtf8("abc").isUtf8()).isTrue()
|
assertThat(Buffer().writeUtf8("abc").isProbablyUtf8()).isTrue()
|
||||||
assertThat(Buffer().writeUtf8("new\r\nlines").isUtf8()).isTrue()
|
assertThat(Buffer().writeUtf8("new\r\nlines").isProbablyUtf8()).isTrue()
|
||||||
assertThat(Buffer().writeUtf8("white\t space").isUtf8()).isTrue()
|
assertThat(Buffer().writeUtf8("white\t space").isProbablyUtf8()).isTrue()
|
||||||
assertThat(Buffer().writeByte(0x80).isUtf8()).isTrue()
|
assertThat(Buffer().writeByte(0x80).isProbablyUtf8()).isTrue()
|
||||||
assertThat(Buffer().writeByte(0x00).isUtf8()).isFalse()
|
assertThat(Buffer().writeByte(0x00).isProbablyUtf8()).isFalse()
|
||||||
assertThat(Buffer().writeByte(0xc0).isUtf8()).isFalse()
|
assertThat(Buffer().writeByte(0xc0).isProbablyUtf8()).isFalse()
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user