1
0
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:
Jesse Wilson
2019-05-25 20:14:08 -04:00
parent 83272f05e0
commit 053b6f1544
3 changed files with 75 additions and 55 deletions

View File

@@ -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))
}
} }
} }

View File

@@ -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.
}
}

View File

@@ -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()
} }
} }