1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-14 07:22:20 +03:00

Merge pull request #5102 from square/jakew/unify/2019-05-23

Merge UtilKt and part of InternalKt into Util
This commit is contained in:
Jake Wharton
2019-05-23 13:39:31 -04:00
committed by GitHub
14 changed files with 267 additions and 285 deletions

View File

@@ -38,7 +38,7 @@ import okio.Okio;
import okio.Source;
import static java.util.Arrays.asList;
import static okhttp3.internal.UtilKt.closeQuietly;
import static okhttp3.internal.Util.closeQuietly;
import static okhttp3.internal.platform.Platform.INFO;
import static okhttp3.tls.internal.TlsUtil.localhost;

View File

@@ -37,7 +37,7 @@ import org.junit.Before;
import org.junit.Test;
import static java.util.Arrays.asList;
import static okhttp3.internal.UtilKt.closeQuietly;
import static okhttp3.internal.Util.closeQuietly;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeFalse;

View File

@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
package okhttp3.internal
@@ -41,32 +40,3 @@ fun cacheGet(cache: Cache, request: Request) = cache.get(request)
fun applyConnectionSpec(connectionSpec: ConnectionSpec, sslSocket: SSLSocket, isFallback: Boolean) =
connectionSpec.apply(sslSocket, isFallback)
/**
* Lock and wait a duration in nanoseconds. Unlike [java.lang.Object.wait] this interprets 0 as
* "don't wait" instead of "wait forever".
*/
@Throws(InterruptedException::class)
fun Any.waitNanos(nanos: Long) {
val ms = nanos / 1_000_000L
val ns = nanos - (ms * 1_000_000L)
synchronized(this) {
this.waitMillis(ms, ns.toInt())
}
}
fun Any.wait() = (this as Object).wait()
/**
* Lock and wait a duration in milliseconds and nanos.
* Unlike [java.lang.Object.wait] this interprets 0 as "don't wait" instead of "wait forever".
*/
fun Any.waitMillis(timeout: Long, nanos: Int = 0) {
if (timeout > 0L || nanos > 0) {
(this as Object).wait(timeout, nanos)
}
}
fun Any.notify() = (this as Object).notify()
fun Any.notifyAll() = (this as Object).notifyAll()

View File

@@ -21,20 +21,34 @@ import okhttp3.EventListener
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.RequestBody
import okhttp3.Response
import okhttp3.ResponseBody
import okhttp3.internal.http2.Header
import okio.Buffer
import okio.BufferedSink
import okio.BufferedSource
import okio.ByteString.Companion.decodeHex
import okio.Options
import okio.Source
import java.io.Closeable
import java.io.IOException
import java.io.InterruptedIOException
import java.net.InetSocketAddress
import java.net.ServerSocket
import java.net.Socket
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets.UTF_16BE
import java.nio.charset.StandardCharsets.UTF_16LE
import java.nio.charset.StandardCharsets.UTF_8
import java.util.ArrayList
import java.util.Arrays
import java.util.Collections
import java.util.Comparator
import java.util.LinkedHashMap
import java.util.Locale
import java.util.TimeZone
import java.util.concurrent.Executor
import java.util.concurrent.RejectedExecutionException
import java.util.concurrent.ThreadFactory
import java.util.concurrent.TimeUnit
import kotlin.text.Charsets.UTF_32BE
@@ -284,3 +298,245 @@ fun HttpUrl.canReuseConnectionFor(other: HttpUrl): Boolean = host == other.host
scheme == other.scheme
fun EventListener.asFactory() = EventListener.Factory { this }
infix fun Byte.and(mask: Int): Int = toInt() and mask
infix fun Short.and(mask: Int): Int = toInt() and mask
infix fun Int.and(mask: Long): Long = toLong() and mask
@Throws(IOException::class)
fun BufferedSink.writeMedium(medium: Int) {
writeByte(medium.ushr(16) and 0xff)
writeByte(medium.ushr(8) and 0xff)
writeByte(medium and 0xff)
}
@Throws(IOException::class)
fun BufferedSource.readMedium(): Int {
return (readByte() and 0xff shl 16
or (readByte() and 0xff shl 8)
or (readByte() and 0xff))
}
/**
* Reads until this is exhausted or the deadline has been reached. This is careful to not extend the
* deadline if one exists already.
*/
@Throws(IOException::class)
fun Source.skipAll(duration: Int, timeUnit: TimeUnit): Boolean {
val now = System.nanoTime()
val originalDuration = if (timeout().hasDeadline()) {
timeout().deadlineNanoTime() - now
} else {
Long.MAX_VALUE
}
timeout().deadlineNanoTime(now + minOf(originalDuration, timeUnit.toNanos(duration.toLong())))
return try {
val skipBuffer = Buffer()
while (read(skipBuffer, 8192) != -1L) {
skipBuffer.clear()
}
true // Success! The source has been exhausted.
} catch (_: InterruptedIOException) {
false // We ran out of time before exhausting the source.
} finally {
if (originalDuration == Long.MAX_VALUE) {
timeout().clearDeadline()
} else {
timeout().deadlineNanoTime(now + originalDuration)
}
}
}
/**
* Attempts to exhaust this, returning true if successful. This is useful when reading a complete
* source is helpful, such as when doing so completes a cache body or frees a socket connection for
* reuse.
*/
fun Source.discard(timeout: Int, timeUnit: TimeUnit): Boolean = try {
this.skipAll(timeout, timeUnit)
} catch (_: IOException) {
false
}
fun Socket.connectionName(): String {
val address = remoteSocketAddress
return if (address is InetSocketAddress) address.hostName else address.toString()
}
/** Run [block] until it either throws an [IOException] or completes. */
inline fun ignoreIoExceptions(block: () -> Unit) {
try {
block()
} catch (_: IOException) {
}
}
inline fun threadName(name: String, block: () -> Unit) {
val currentThread = Thread.currentThread()
val oldName = currentThread.name
currentThread.name = name
try {
block()
} finally {
currentThread.name = oldName
}
}
/** Execute [block], setting the executing thread's name to [name] for the duration. */
inline fun Executor.execute(name: String, crossinline block: () -> Unit) {
execute {
threadName(name) {
block()
}
}
}
/** Executes [block] unless this executor has been shutdown, in which case this does nothing. */
inline fun Executor.tryExecute(name: String, crossinline block: () -> Unit) {
try {
execute(name, block)
} catch (_: RejectedExecutionException) {
}
}
fun Buffer.skipAll(b: Byte): Int {
var count = 0
while (!exhausted() && this[0] == b) {
count++
readByte()
}
return count
}
/**
* Returns the index of the next non-whitespace character in this. Result is undefined if input
* contains newline characters.
*/
fun String.indexOfNonWhitespace(startIndex: Int = 0): Int {
for (i in startIndex until length) {
val c = this[i]
if (c != ' ' && c != '\t') {
return i
}
}
return length
}
/** Returns the Content-Length as reported by the response headers. */
fun Response.headersContentLength(): Long {
return headers()["Content-Length"]?.toLongOrDefault(-1L) ?: -1L
}
fun String.toLongOrDefault(defaultValue: Long): Long {
return try {
toLong()
} catch (_: NumberFormatException) {
defaultValue
}
}
/**
* Returns this as a non-negative integer, or 0 if it is negative, or [Int.MAX_VALUE] if it is too
* large, or [defaultValue] if it cannot be parsed.
*/
fun String?.toNonNegativeInt(defaultValue: Int): Int {
try {
val value = this?.toLong() ?: return defaultValue
return when {
value > Int.MAX_VALUE -> Int.MAX_VALUE
value < 0 -> 0
else -> value.toInt()
}
} catch (_: NumberFormatException) {
return defaultValue
}
}
/** Returns an immutable copy of this. */
fun <T> List<T>.toImmutableList(): List<T> {
return Collections.unmodifiableList(toMutableList())
}
/** Returns an immutable list containing [elements]. */
@SafeVarargs
fun <T> immutableListOf(vararg elements: T): List<T> {
return Collections.unmodifiableList(Arrays.asList(*elements.clone()))
}
/** Returns an immutable copy of this. */
fun <K, V> Map<K, V>.toImmutableMap(): Map<K, V> {
return if (isEmpty()) {
emptyMap()
} else {
Collections.unmodifiableMap(LinkedHashMap(this))
}
}
/** Closes this, ignoring any checked exceptions. Does nothing if this is null. */
fun Closeable.closeQuietly() {
try {
close()
} catch (rethrown: RuntimeException) {
throw rethrown
} catch (_: Exception) {
}
}
/** Closes this, ignoring any checked exceptions. Does nothing if this is null. */
fun Socket.closeQuietly() {
try {
close()
} catch (e: AssertionError) {
throw e
} catch (rethrown: RuntimeException) {
throw rethrown
} catch (_: Exception) {
}
}
/** Closes this, ignoring any checked exceptions. Does nothing if this is null. */
fun ServerSocket.closeQuietly() {
try {
close()
} catch (rethrown: RuntimeException) {
throw rethrown
} catch (_: Exception) {
}
}
fun Long.toHexString(): String = java.lang.Long.toHexString(this)
fun Int.toHexString(): String = Integer.toHexString(this)
/**
* Lock and wait a duration in nanoseconds. Unlike [java.lang.Object.wait] this interprets 0 as
* "don't wait" instead of "wait forever".
*/
@Throws(InterruptedException::class)
fun Any.waitNanos(nanos: Long) {
val ms = nanos / 1_000_000L
val ns = nanos - (ms * 1_000_000L)
synchronized(this) {
waitMillis(ms, ns.toInt())
}
}
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
fun Any.wait() = (this as Object).wait()
/**
* Lock and wait a duration in milliseconds and nanos.
* Unlike [java.lang.Object.wait] this interprets 0 as "don't wait" instead of "wait forever".
*/
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
fun Any.waitMillis(timeout: Long, nanos: Int = 0) {
if (timeout > 0L || nanos > 0) {
(this as Object).wait(timeout, nanos)
}
}
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
fun Any.notify() = (this as Object).notify()
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
fun Any.notifyAll() = (this as Object).notifyAll()

View File

@@ -1,244 +0,0 @@
/*
* Copyright (C) 2019 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.
*/
@file:JvmName("UtilKt")
package okhttp3.internal
import okhttp3.Response
import okio.Buffer
import okio.BufferedSink
import okio.BufferedSource
import okio.Source
import java.io.Closeable
import java.io.IOException
import java.io.InterruptedIOException
import java.net.InetSocketAddress
import java.net.ServerSocket
import java.net.Socket
import java.util.Arrays
import java.util.Collections
import java.util.LinkedHashMap
import java.util.concurrent.Executor
import java.util.concurrent.RejectedExecutionException
import java.util.concurrent.TimeUnit
infix fun Byte.and(mask: Int): Int = toInt() and mask
infix fun Short.and(mask: Int): Int = toInt() and mask
infix fun Int.and(mask: Long): Long = toLong() and mask
@Throws(IOException::class)
fun BufferedSink.writeMedium(medium: Int) {
writeByte(medium.ushr(16) and 0xff)
writeByte(medium.ushr(8) and 0xff)
writeByte(medium and 0xff)
}
@Throws(IOException::class)
fun BufferedSource.readMedium(): Int {
return (readByte() and 0xff shl 16
or (readByte() and 0xff shl 8)
or (readByte() and 0xff))
}
/**
* Reads until this is exhausted or the deadline has been reached. This is careful to not extend the
* deadline if one exists already.
*/
@Throws(IOException::class)
fun Source.skipAll(duration: Int, timeUnit: TimeUnit): Boolean {
val now = System.nanoTime()
val originalDuration = if (timeout().hasDeadline()) {
timeout().deadlineNanoTime() - now
} else {
Long.MAX_VALUE
}
timeout().deadlineNanoTime(now + minOf(originalDuration, timeUnit.toNanos(duration.toLong())))
return try {
val skipBuffer = Buffer()
while (read(skipBuffer, 8192) != -1L) {
skipBuffer.clear()
}
true // Success! The source has been exhausted.
} catch (_: InterruptedIOException) {
false // We ran out of time before exhausting the source.
} finally {
if (originalDuration == Long.MAX_VALUE) {
timeout().clearDeadline()
} else {
timeout().deadlineNanoTime(now + originalDuration)
}
}
}
/**
* Attempts to exhaust this, returning true if successful. This is useful when reading a complete
* source is helpful, such as when doing so completes a cache body or frees a socket connection for
* reuse.
*/
fun Source.discard(timeout: Int, timeUnit: TimeUnit): Boolean = try {
this.skipAll(timeout, timeUnit)
} catch (_: IOException) {
false
}
fun Socket.connectionName(): String {
val address = remoteSocketAddress
return if (address is InetSocketAddress) address.hostName else address.toString()
}
/** Run [block] until it either throws an [IOException] or completes. */
inline fun ignoreIoExceptions(block: () -> Unit) {
try {
block()
} catch (_: IOException) {
}
}
inline fun threadName(name: String, block: () -> Unit) {
val currentThread = Thread.currentThread()
val oldName = currentThread.name
currentThread.name = name
try {
block()
} finally {
currentThread.name = oldName
}
}
/** Execute [block], setting the executing thread's name to [name] for the duration. */
inline fun Executor.execute(name: String, crossinline block: () -> Unit) {
execute {
threadName(name) {
block()
}
}
}
/** Executes [block] unless this executor has been shutdown, in which case this does nothing. */
inline fun Executor.tryExecute(name: String, crossinline block: () -> Unit) {
try {
execute(name, block)
} catch (_: RejectedExecutionException) {
}
}
fun Buffer.skipAll(b: Byte): Int {
var count = 0
while (!exhausted() && this[0] == b) {
count++
readByte()
}
return count
}
/**
* Returns the index of the next non-whitespace character in this. Result is undefined if input
* contains newline characters.
*/
fun String.indexOfNonWhitespace(startIndex: Int = 0): Int {
for (i in startIndex until length) {
val c = this[i]
if (c != ' ' && c != '\t') {
return i
}
}
return length
}
/** Returns the Content-Length as reported by the response headers. */
fun Response.headersContentLength(): Long {
return headers()["Content-Length"]?.toLongOrDefault(-1L) ?: -1L
}
fun String.toLongOrDefault(defaultValue: Long): Long {
return try {
toLong()
} catch (_: NumberFormatException) {
defaultValue
}
}
/**
* Returns this as a non-negative integer, or 0 if it is negative, or [Int.MAX_VALUE] if it is too
* large, or [defaultValue] if it cannot be parsed.
*/
fun String?.toNonNegativeInt(defaultValue: Int): Int {
try {
val value = this?.toLong() ?: return defaultValue
return when {
value > Int.MAX_VALUE -> Int.MAX_VALUE
value < 0 -> 0
else -> value.toInt()
}
} catch (_: NumberFormatException) {
return defaultValue
}
}
/** Returns an immutable copy of this. */
fun <T> List<T>.toImmutableList(): List<T> {
return Collections.unmodifiableList(toMutableList())
}
/** Returns an immutable list containing [elements]. */
@SafeVarargs
fun <T> immutableListOf(vararg elements: T): List<T> {
return Collections.unmodifiableList(Arrays.asList(*elements.clone()))
}
/** Returns an immutable copy of this. */
fun <K, V> Map<K, V>.toImmutableMap(): Map<K, V> {
return if (isEmpty()) {
emptyMap()
} else {
Collections.unmodifiableMap(LinkedHashMap(this))
}
}
/** Closes this, ignoring any checked exceptions. Does nothing if this is null. */
fun Closeable.closeQuietly() {
try {
close()
} catch (rethrown: RuntimeException) {
throw rethrown
} catch (_: Exception) {
}
}
/** Closes this, ignoring any checked exceptions. Does nothing if this is null. */
fun Socket.closeQuietly() {
try {
close()
} catch (e: AssertionError) {
throw e
} catch (rethrown: RuntimeException) {
throw rethrown
} catch (_: Exception) {
}
}
/** Closes this, ignoring any checked exceptions. Does nothing if this is null. */
fun ServerSocket.closeQuietly() {
try {
close()
} catch (rethrown: RuntimeException) {
throw rethrown
} catch (_: Exception) {
}
}
fun Long.toHexString() = java.lang.Long.toHexString(this)
fun Int.toHexString() = Integer.toHexString(this)

View File

@@ -21,7 +21,7 @@ import javax.net.SocketFactory;
import okhttp3.internal.http.RecordingProxySelector;
import org.junit.Test;
import static okhttp3.internal.UtilKt.immutableListOf;
import static okhttp3.internal.Util.immutableListOf;
import static org.assertj.core.api.Assertions.assertThat;
public final class AddressTest {

View File

@@ -29,7 +29,7 @@ import org.junit.rules.TestRule;
import org.junit.rules.Timeout;
import static java.util.Arrays.asList;
import static okhttp3.internal.UtilKt.closeQuietly;
import static okhttp3.internal.Util.closeQuietly;
import static okhttp3.tls.internal.TlsUtil.localhost;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;

View File

@@ -38,7 +38,7 @@ import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;
import static okhttp3.internal.UtilKt.closeQuietly;
import static okhttp3.internal.Util.closeQuietly;
/**
* A limited implementation of SOCKS Protocol Version 5, intended to be similar to MockWebServer.

View File

@@ -89,7 +89,7 @@ import static java.util.Locale.US;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static okhttp3.internal.InternalKtKt.addHeaderLenient;
import static okhttp3.internal.UtilKt.immutableListOf;
import static okhttp3.internal.Util.immutableListOf;
import static okhttp3.internal.http.StatusLine.HTTP_PERM_REDIRECT;
import static okhttp3.internal.http.StatusLine.HTTP_TEMP_REDIRECT;
import static okhttp3.mockwebserver.SocketPolicy.DISCONNECT_AFTER_REQUEST;

View File

@@ -25,7 +25,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import static okhttp3.internal.UtilKt.immutableListOf;
import static okhttp3.internal.Util.immutableListOf;
import static org.assertj.core.api.Assertions.assertThat;
/** Runs the web platform URL tests against Java URL models. */

View File

@@ -46,7 +46,7 @@ import org.junit.Before;
import org.junit.Test;
import static java.net.Proxy.NO_PROXY;
import static okhttp3.internal.UtilKt.immutableListOf;
import static okhttp3.internal.Util.immutableListOf;
import static okhttp3.tls.internal.TlsUtil.localhost;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;

View File

@@ -22,7 +22,7 @@ import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.Response;
import static okhttp3.internal.UtilKt.immutableListOf;
import static okhttp3.internal.Util.immutableListOf;
public final class ExternalHttp2Example {
public static void main(String[] args) throws Exception {

View File

@@ -85,7 +85,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static okhttp3.internal.UtilKt.discard;
import static okhttp3.internal.Util.discard;
import static okhttp3.tls.internal.TlsUtil.localhost;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.Offset.offset;

View File

@@ -37,7 +37,7 @@ import okio.BufferedSource;
import okio.ByteString;
import okio.Okio;
import static okhttp3.internal.UtilKt.closeQuietly;
import static okhttp3.internal.Util.closeQuietly;
/** Replays prerecorded outgoing frames and records incoming frames. */
public final class MockHttp2Peer implements Closeable {