From b4614e466ce1217be72c1075b60fd36ec7382df5 Mon Sep 17 00:00:00 2001 From: Minh Date: Sat, 6 Apr 2024 16:14:38 +0700 Subject: [PATCH 001/134] Hide the value of sensitive query parameters in log (#8242) Add option to redact sensitive query params. --- .../api/logging-interceptor.api | 1 + .../okhttp3/logging/HttpLoggingInterceptor.kt | 28 +++++- .../logging/HttpLoggingInterceptorTest.kt | 98 +++++++++++++++++++ 3 files changed, 125 insertions(+), 2 deletions(-) diff --git a/okhttp-logging-interceptor/api/logging-interceptor.api b/okhttp-logging-interceptor/api/logging-interceptor.api index 264c2e88fbce..b6b4d7e94399 100644 --- a/okhttp-logging-interceptor/api/logging-interceptor.api +++ b/okhttp-logging-interceptor/api/logging-interceptor.api @@ -8,6 +8,7 @@ public final class okhttp3/logging/HttpLoggingInterceptor : okhttp3/Interceptor public fun intercept (Lokhttp3/Interceptor$Chain;)Lokhttp3/Response; public final fun level (Lokhttp3/logging/HttpLoggingInterceptor$Level;)V public final fun redactHeader (Ljava/lang/String;)V + public final fun redactQueryParams ([Ljava/lang/String;)V public final fun setLevel (Lokhttp3/logging/HttpLoggingInterceptor$Level;)Lokhttp3/logging/HttpLoggingInterceptor; } diff --git a/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/HttpLoggingInterceptor.kt b/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/HttpLoggingInterceptor.kt index 5d03adb5c71c..99bcfc58ab68 100644 --- a/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/HttpLoggingInterceptor.kt +++ b/okhttp-logging-interceptor/src/main/kotlin/okhttp3/logging/HttpLoggingInterceptor.kt @@ -22,6 +22,7 @@ import java.nio.charset.Charset import java.util.TreeSet import java.util.concurrent.TimeUnit import okhttp3.Headers +import okhttp3.HttpUrl import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.Response @@ -46,6 +47,8 @@ class HttpLoggingInterceptor ) : Interceptor { @Volatile private var headersToRedact = emptySet() + @Volatile private var queryParamsNameToRedact = emptySet() + @set:JvmName("level") @Volatile var level = Level.NONE @@ -132,6 +135,13 @@ class HttpLoggingInterceptor headersToRedact = newHeadersToRedact } + fun redactQueryParams(vararg name: String) { + val newQueryParamsNameToRedact = TreeSet(String.CASE_INSENSITIVE_ORDER) + newQueryParamsNameToRedact += queryParamsNameToRedact + newQueryParamsNameToRedact.addAll(name) + queryParamsNameToRedact = newQueryParamsNameToRedact + } + /** * Sets the level and returns this. * @@ -168,7 +178,7 @@ class HttpLoggingInterceptor val connection = chain.connection() var requestStartMessage = - ("--> ${request.method} ${request.url}${if (connection != null) " " + connection.protocol() else ""}") + ("--> ${request.method} ${redactUrl(request.url)}${if (connection != null) " " + connection.protocol() else ""}") if (!logHeaders && requestBody != null) { requestStartMessage += " (${requestBody.contentLength()}-byte body)" } @@ -251,7 +261,7 @@ class HttpLoggingInterceptor buildString { append("<-- ${response.code}") if (response.message.isNotEmpty()) append(" ${response.message}") - append(" ${response.request.url} (${tookMs}ms") + append(" ${redactUrl(response.request.url)} (${tookMs}ms") if (!logHeaders) append(", $bodySize body") append(")") }, @@ -312,6 +322,20 @@ class HttpLoggingInterceptor return response } + internal fun redactUrl(url: HttpUrl): String { + if (queryParamsNameToRedact.isEmpty() || url.querySize == 0) { + return url.toString() + } + return url.newBuilder().query(null).apply { + for (i in 0 until url.querySize) { + val parameterName = url.queryParameterName(i) + val newValue = if (parameterName in queryParamsNameToRedact) "██" else url.queryParameterValue(i) + + addEncodedQueryParameter(parameterName, newValue) + } + }.toString() + } + private fun logHeader( headers: Headers, i: Int, diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt index bc93ac55d5fd..0c8549a171c7 100644 --- a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt @@ -903,6 +903,104 @@ class HttpLoggingInterceptorTest { .assertNoMoreLogs() } + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + @Test + fun sensitiveQueryParamsAreRedacted() { + url = server.url("/api/login?user=test_user&authentication=basic&password=confidential_password") + val networkInterceptor = + HttpLoggingInterceptor(networkLogs).setLevel( + Level.BASIC, + ) + networkInterceptor.redactQueryParams("user", "passWord") + + val applicationInterceptor = + HttpLoggingInterceptor(applicationLogs).setLevel( + Level.BASIC, + ) + applicationInterceptor.redactQueryParams("user", "PassworD") + + client = + OkHttpClient.Builder() + .addNetworkInterceptor(networkInterceptor) + .addInterceptor(applicationInterceptor) + .build() + server.enqueue( + MockResponse.Builder() + .build(), + ) + val response = + client + .newCall( + request() + .build(), + ) + .execute() + response.body.close() + val redactedUrl = networkInterceptor.redactUrl(url) + val redactedUrlPattern = redactedUrl.replace("?", """\?""") + applicationLogs + .assertLogEqual("--> GET $redactedUrl") + .assertLogMatch(Regex("""<-- 200 OK $redactedUrlPattern \(\d+ms, \d+-byte body\)""")) + .assertNoMoreLogs() + networkLogs + .assertLogEqual("--> GET $redactedUrl http/1.1") + .assertLogMatch(Regex("""<-- 200 OK $redactedUrlPattern \(\d+ms, \d+-byte body\)""")) + .assertNoMoreLogs() + } + + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + @Test + fun preserveQueryParamsAfterRedacted() { + url = + server.url( + """/api/login? + |user=test_user& + |authentication=basic& + |password=confidential_password& + |authentication=rather simple login method + """.trimMargin(), + ) + val networkInterceptor = + HttpLoggingInterceptor(networkLogs).setLevel( + Level.BASIC, + ) + networkInterceptor.redactQueryParams("user", "passWord") + + val applicationInterceptor = + HttpLoggingInterceptor(applicationLogs).setLevel( + Level.BASIC, + ) + applicationInterceptor.redactQueryParams("user", "PassworD") + + client = + OkHttpClient.Builder() + .addNetworkInterceptor(networkInterceptor) + .addInterceptor(applicationInterceptor) + .build() + server.enqueue( + MockResponse.Builder() + .build(), + ) + val response = + client + .newCall( + request() + .build(), + ) + .execute() + response.body.close() + val redactedUrl = networkInterceptor.redactUrl(url) + val redactedUrlPattern = redactedUrl.replace("?", """\?""") + applicationLogs + .assertLogEqual("--> GET $redactedUrl") + .assertLogMatch(Regex("""<-- 200 OK $redactedUrlPattern \(\d+ms, \d+-byte body\)""")) + .assertNoMoreLogs() + networkLogs + .assertLogEqual("--> GET $redactedUrl http/1.1") + .assertLogMatch(Regex("""<-- 200 OK $redactedUrlPattern \(\d+ms, \d+-byte body\)""")) + .assertNoMoreLogs() + } + @Test fun duplexRequestsAreNotLogged() { platform.assumeHttp2Support() From dba8478dff0d2492d9d7bfe9c9471b6b3cdb6002 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 6 Apr 2024 12:15:46 +0100 Subject: [PATCH 002/134] Comments on loom test (#8340) --- .../src/test/java/okhttp3/containers/BasicLoomTest.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/container-tests/src/test/java/okhttp3/containers/BasicLoomTest.kt b/container-tests/src/test/java/okhttp3/containers/BasicLoomTest.kt index bf65399bcc06..4063a2e95033 100644 --- a/container-tests/src/test/java/okhttp3/containers/BasicLoomTest.kt +++ b/container-tests/src/test/java/okhttp3/containers/BasicLoomTest.kt @@ -49,6 +49,8 @@ class BasicLoomTest { @RegisterExtension val platform = PlatformRule() + // Use mock server so we are strictly testing OkHttp client only in this test. + // We should test MockWebServer later. @Container val mockServer: MockServerContainer = MockServerContainer(MOCKSERVER_IMAGE) @@ -71,6 +73,8 @@ class BasicLoomTest { executor = newVirtualThreadPerTaskExecutor() + // Capture non-deterministic but probable sysout warnings of pinned threads + // https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html System.setOut(PrintStream(capturedOut)) } From 461b5ac9dea2d6c66a3782f01a65ea64298007f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Apr 2024 22:47:59 -0400 Subject: [PATCH 003/134] Update dependency org.robolectric:robolectric to v4.12.1 (#8350) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 358debd3b74d..58cce71a1722 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -82,7 +82,7 @@ nativeImageSvm = { module = "org.graalvm.nativeimage:svm", version.ref = "graalv openjsse = "org.openjsse:openjsse:1.1.14" playservices-safetynet = "com.google.android.gms:play-services-safetynet:18.0.1" robolectric-android = "org.robolectric:android-all:14-robolectric-10818077" -robolectric = "org.robolectric:robolectric:4.12" +robolectric = "org.robolectric:robolectric:4.12.1" signature-android-apilevel21 = "net.sf.androidscents.signature:android-api-level-21:5.0.1_r2" signature-android-apilevel24 = "net.sf.androidscents.signature:android-api-level-24:7.0_r2" squareup-moshi = { module = "com.squareup.moshi:moshi", version.ref = "com-squareup-moshi" } From f4af7f2033c73f42e12631f9f449896063a27c24 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 7 Apr 2024 22:48:17 -0400 Subject: [PATCH 004/134] Update plugin com.google.devtools.ksp to v1.9.23-1.0.20 (#8351) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- samples/tlssurvey/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/tlssurvey/build.gradle.kts b/samples/tlssurvey/build.gradle.kts index 586fbfbbf7f6..aa1c1192a297 100644 --- a/samples/tlssurvey/build.gradle.kts +++ b/samples/tlssurvey/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("jvm") application - id("com.google.devtools.ksp").version("1.9.23-1.0.19") + id("com.google.devtools.ksp").version("1.9.23-1.0.20") } application { From 5f008f382d67c79a990b31d4baebbdbc24365e64 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 8 Apr 2024 23:31:17 -0400 Subject: [PATCH 005/134] Tidy RealConnectionPool's new policy code (#8345) * Tidy RealConnectionPool's new policy code * Fixup connection pool changes * Rename policiesUpdater * Unless it's old --- .../internal/connection/RealConnection.kt | 4 +- .../internal/connection/RealConnectionPool.kt | 226 +++++++++++------- .../internal/connection/ConnectionPoolTest.kt | 32 +-- 3 files changed, 159 insertions(+), 103 deletions(-) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt index b19c52492a18..f379a4e29efa 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt @@ -350,10 +350,10 @@ class RealConnection( if (allocationLimit < oldLimit) { // We might need new connections to keep policies satisfied - connectionPool.scheduleConnectionOpener() + connectionPool.scheduleOpener(route.address) } else if (allocationLimit > oldLimit) { // We might no longer need some connections - connectionPool.scheduleConnectionCloser() + connectionPool.scheduleCloser() } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt index 9c57a44e3b89..c4d376c92f11 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt @@ -20,6 +20,7 @@ import java.net.Socket import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ThreadLocalRandom import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater import okhttp3.Address import okhttp3.ConnectionListener import okhttp3.ConnectionPool @@ -32,6 +33,7 @@ import okhttp3.internal.concurrent.TaskRunner import okhttp3.internal.connection.RealCall.CallReference import okhttp3.internal.okHttpName import okhttp3.internal.platform.Platform +import okio.IOException class RealConnectionPool( private val taskRunner: TaskRunner, @@ -47,21 +49,19 @@ class RealConnectionPool( ) { internal val keepAliveDurationNs: Long = timeUnit.toNanos(keepAliveDuration) - // guarded by [this] - private var policies: Map = mapOf() - private val user = PoolConnectionUser + @Volatile + private var addressStates: Map = mapOf() private val cleanupQueue: TaskQueue = taskRunner.newQueue() private val cleanupTask = object : Task("$okHttpName ConnectionPool connection closer") { - override fun runOnce(): Long = cleanup(System.nanoTime()) + override fun runOnce(): Long = closeConnections(System.nanoTime()) } - private fun MinimumConnectionState.schedule() { - val state = this + private fun AddressState.scheduleOpener() { queue.schedule( object : Task("$okHttpName ConnectionPool connection opener") { - override fun runOnce(): Long = ensureMinimumConnections(state) + override fun runOnce(): Long = openConnections(this@scheduleOpener) }, ) } @@ -149,7 +149,7 @@ class RealConnectionPool( connections.add(connection) // connection.queueEvent { connectionListener.connectEnd(connection) } - scheduleConnectionCloser() + scheduleCloser() } /** @@ -163,10 +163,10 @@ class RealConnectionPool( connection.noNewExchanges = true connections.remove(connection) if (connections.isEmpty()) cleanupQueue.cancelAll() - scheduleConnectionOpener() + scheduleOpener(connection.route.address) true } else { - scheduleConnectionCloser() + scheduleCloser() false } } @@ -192,7 +192,10 @@ class RealConnectionPool( } if (connections.isEmpty()) cleanupQueue.cancelAll() - scheduleConnectionOpener() + + for (policy in addressStates.values) { + policy.scheduleOpener() + } } /** @@ -202,74 +205,108 @@ class RealConnectionPool( * Returns the duration in nanoseconds to sleep until the next scheduled call to this method. * Returns -1 if no further cleanups are required. */ - fun cleanup(now: Long): Long { - var inUseConnectionCount = 0 - var idleConnectionCount = 0 - var longestIdleConnection: RealConnection? = null - var longestIdleDurationNs = Long.MIN_VALUE - var policyAffected: MinimumConnectionState? = null - policies - .forEach { it.value.unsatisfiedCountCleanupTask = it.value.policy.minimumConcurrentCalls } - - // Find either a connection to evict, or the time that the next eviction is due. + fun closeConnections(now: Long): Long { + // Compute the concurrent call capacity for each address. We won't close a connection if doing + // so would violate a policy, unless it's OLD. + val addressStates = this.addressStates + for (state in addressStates.values) { + state.concurrentCallCapacity = 0 + } for (connection in connections) { + val addressState = addressStates[connection.route.address] ?: continue synchronized(connection) { - val satisfiablePolicy = - policies.entries.firstOrNull { - it.value.unsatisfiedCountCleanupTask > 0 && connection.isEligible(it.key, null) - }?.value - val idleDurationNs = now - connection.idleAtNs + addressState.concurrentCallCapacity += connection.allocationLimit + } + } + // Find the longest-idle connections in 2 categories: + // + // 1. OLD: Connections that have been idle for at least keepAliveDurationNs. We close these if + // we find them, regardless of what the address policies need. + // + // 2. EVICTABLE: Connections not required by any address policy. This matches connections that + // don't participate in any policy, plus connections whose policies won't be violated if the + // connection is closed. We only close these if the idle connection limit is exceeded. + // + // Also count the evictable connections to find out if we must close an EVICTABLE connection + // before its keepAliveDurationNs is reached. + var earliestOldIdleAtNs = (now - keepAliveDurationNs) + 1 + var earliestOldConnection: RealConnection? = null + var earliestEvictableIdleAtNs = Long.MAX_VALUE + var earliestEvictableConnection: RealConnection? = null + var inUseConnectionCount = 0 + var evictableConnectionCount = 0 + for (connection in connections) { + synchronized(connection) { + // If the connection is in use, keep searching. if (pruneAndGetAllocationCount(connection, now) > 0) { - // If the connection is in use, keep searching. inUseConnectionCount++ - } else if (satisfiablePolicy != null && idleDurationNs < this.keepAliveDurationNs) { - // If the connection hasn't expired and helps satisfy a policy, keep searching. - satisfiablePolicy.unsatisfiedCountCleanupTask -= connection.allocationLimit - inUseConnectionCount++ - } else { - idleConnectionCount++ - - // If the connection is ready to be evicted, we're done. - if (idleDurationNs > longestIdleDurationNs) { - longestIdleDurationNs = idleDurationNs - longestIdleConnection = connection - policyAffected = satisfiablePolicy - } else { - Unit + return@synchronized + } + + val idleAtNs = connection.idleAtNs + + if (idleAtNs < earliestOldIdleAtNs) { + earliestOldIdleAtNs = idleAtNs + earliestOldConnection = connection + } + + if (isEvictable(addressStates, connection)) { + evictableConnectionCount++ + if (idleAtNs < earliestEvictableIdleAtNs) { + earliestEvictableIdleAtNs = idleAtNs + earliestEvictableConnection = connection } } } } + val toEvict: RealConnection? + val toEvictIdleAtNs: Long + when { + // We had at least one OLD connection. Close the oldest one. + earliestOldConnection != null -> { + toEvict = earliestOldConnection + toEvictIdleAtNs = earliestOldIdleAtNs + } + + // We have too many EVICTABLE connections. Close the oldest one. + evictableConnectionCount > maxIdleConnections -> { + toEvict = earliestEvictableConnection + toEvictIdleAtNs = earliestEvictableIdleAtNs + } + + else -> { + toEvict = null + toEvictIdleAtNs = -1L + } + } + when { - longestIdleDurationNs >= this.keepAliveDurationNs || - idleConnectionCount > this.maxIdleConnections -> { + toEvict != null -> { // We've chosen a connection to evict. Confirm it's still okay to be evicted, then close it. - val connection = longestIdleConnection!! - synchronized(connection) { - if (connection.calls.isNotEmpty()) return 0L // No longer idle. - if (connection.idleAtNs + longestIdleDurationNs != now) return 0L // No longer oldest. - connection.noNewExchanges = true - connections.remove(longestIdleConnection) + synchronized(toEvict) { + if (toEvict.calls.isNotEmpty()) return 0L // No longer idle. + if (toEvict.idleAtNs != toEvictIdleAtNs) return 0L // No longer oldest. + toEvict.noNewExchanges = true + connections.remove(toEvict) } - policyAffected?.schedule() - connection.socket().closeQuietly() - connectionListener.connectionClosed(connection) + addressStates[toEvict.route.address]?.scheduleOpener() + toEvict.socket().closeQuietly() + connectionListener.connectionClosed(toEvict) if (connections.isEmpty()) cleanupQueue.cancelAll() // Clean up again immediately. return 0L } - idleConnectionCount > 0 -> { + earliestEvictableConnection != null -> { // A connection will be ready to evict soon. - return keepAliveDurationNs - longestIdleDurationNs + return earliestEvictableIdleAtNs + keepAliveDurationNs - now } inUseConnectionCount > 0 -> { - // All connections are in use. It'll be at least the keep alive duration 'til we run - // again. + // All connections are in use. It'll be at least the keep alive duration 'til we run again. return keepAliveDurationNs } @@ -280,6 +317,16 @@ class RealConnectionPool( } } + /** Returns true if no address policies prevent [connection] from being evicted. */ + private fun isEvictable( + addressStates: Map, + connection: RealConnection, + ): Boolean { + val addressState = addressStates[connection.route.address] ?: return true + val capacityWithoutIt = addressState.concurrentCallCapacity - connection.allocationLimit + return capacityWithoutIt >= addressState.policy.minimumConcurrentCalls + } + /** * Prunes any leaked calls and then returns the number of remaining live calls on [connection]. * Calls are leaked if the connection is tracking them but the application code has abandoned @@ -328,27 +375,31 @@ class RealConnectionPool( address: Address, policy: ConnectionPool.AddressPolicy, ) { - val state = MinimumConnectionState(address, taskRunner.newQueue(), policy) - val oldPolicy: ConnectionPool.AddressPolicy? - synchronized(this) { - oldPolicy = policies[address]?.policy - policies = policies + (address to state) + val state = AddressState(address, taskRunner.newQueue(), policy) + val newConnectionsNeeded: Int + + while (true) { + val oldMap = this.addressStates + val newMap = oldMap + (address to state) + if (addressStatesUpdater.compareAndSet(this, oldMap, newMap)) { + val oldPolicyMinimumConcurrentCalls = oldMap[address]?.policy?.minimumConcurrentCalls ?: 0 + newConnectionsNeeded = policy.minimumConcurrentCalls - oldPolicyMinimumConcurrentCalls + break + } } - val newConnectionsNeeded = - policy.minimumConcurrentCalls - (oldPolicy?.minimumConcurrentCalls ?: 0) - if (newConnectionsNeeded > 0) { - state.schedule() - } else if (newConnectionsNeeded < 0) { - scheduleConnectionCloser() + when { + newConnectionsNeeded > 0 -> state.scheduleOpener() + newConnectionsNeeded < 0 -> scheduleCloser() } } - fun scheduleConnectionOpener() { - policies.values.forEach { it.schedule() } + /** Open connections to [address], if required by the address policy. */ + fun scheduleOpener(address: Address) { + addressStates[address]?.scheduleOpener() } - fun scheduleConnectionCloser() { + fun scheduleCloser() { cleanupQueue.schedule(cleanupTask) } @@ -357,26 +408,24 @@ class RealConnectionPool( * If there are already enough connections, we're done. * If not, we create one and then schedule the task to run again immediately. */ - private fun ensureMinimumConnections(state: MinimumConnectionState): Long { + private fun openConnections(state: AddressState): Long { // This policy does not require minimum connections, don't run again - if (state.policy.minimumConcurrentCalls < 1) return -1 - - var unsatisfiedCountMinTask = state.policy.minimumConcurrentCalls + if (state.policy.minimumConcurrentCalls == 0) return -1L + var concurrentCallCapacity = 0 for (connection in connections) { + if (state.address != connection.route.address) continue synchronized(connection) { - if (connection.isEligible(state.address, null)) { - unsatisfiedCountMinTask -= connection.allocationLimit - } + concurrentCallCapacity += connection.allocationLimit } // The policy was satisfied by existing connections, don't run again - if (unsatisfiedCountMinTask < 1) return -1 + if (concurrentCallCapacity >= state.policy.minimumConcurrentCalls) return -1L } // If we got here then the policy was not satisfied -- open a connection! try { - val connection = exchangeFinderFactory(this, state.address, user).find() + val connection = exchangeFinderFactory(this, state.address, PoolConnectionUser).find() // RealRoutePlanner will add the connection to the pool itself, other RoutePlanners may not // TODO: make all RoutePlanners consistent in this behavior @@ -384,8 +433,8 @@ class RealConnectionPool( synchronized(connection) { put(connection) } } - return 0 // run again immediately to create more connections if needed - } catch (ex: Exception) { + return 0L // run again immediately to create more connections if needed + } catch (e: IOException) { // No need to log, user.connectFailed() will already have been called. Just try again later. return state.policy.backoffDelayMillis.jitterBy(state.policy.backoffJitterMillis) * 1_000_000 } @@ -395,19 +444,26 @@ class RealConnectionPool( return this + ThreadLocalRandom.current().nextInt(amount * -1, amount) } - class MinimumConnectionState( + class AddressState( val address: Address, val queue: TaskQueue, var policy: ConnectionPool.AddressPolicy, ) { /** - * This field is only ever accessed by the cleanup task, and it tracks - * how many concurrent calls are already satisfied by existing connections. + * How many calls the pool can carry without opening new connections. This field must only be + * accessed by the connection closer task. */ - var unsatisfiedCountCleanupTask: Int = 0 + var concurrentCallCapacity: Int = 0 } companion object { fun get(connectionPool: ConnectionPool): RealConnectionPool = connectionPool.delegate + + private var addressStatesUpdater = + AtomicReferenceFieldUpdater.newUpdater( + RealConnectionPool::class.java, + Map::class.java, + "addressStates", + ) } } diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index 1cfa0f774702..6063d99da140 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -53,27 +53,27 @@ class ConnectionPoolTest { val c1 = factory.newConnection(pool, routeA1, 50L) // Running at time 50, the pool returns that nothing can be evicted until time 150. - assertThat(pool.cleanup(50L)).isEqualTo(100L) + assertThat(pool.closeConnections(50L)).isEqualTo(100L) assertThat(pool.connectionCount()).isEqualTo(1) assertThat(c1.socket().isClosed).isFalse() // Running at time 60, the pool returns that nothing can be evicted until time 150. - assertThat(pool.cleanup(60L)).isEqualTo(90L) + assertThat(pool.closeConnections(60L)).isEqualTo(90L) assertThat(pool.connectionCount()).isEqualTo(1) assertThat(c1.socket().isClosed).isFalse() // Running at time 149, the pool returns that nothing can be evicted until time 150. - assertThat(pool.cleanup(149L)).isEqualTo(1L) + assertThat(pool.closeConnections(149L)).isEqualTo(1L) assertThat(pool.connectionCount()).isEqualTo(1) assertThat(c1.socket().isClosed).isFalse() // Running at time 150, the pool evicts. - assertThat(pool.cleanup(150L)).isEqualTo(0) + assertThat(pool.closeConnections(150L)).isEqualTo(0) assertThat(pool.connectionCount()).isEqualTo(0) assertThat(c1.socket().isClosed).isTrue() // Running again, the pool reports that no further runs are necessary. - assertThat(pool.cleanup(150L)).isEqualTo(-1) + assertThat(pool.closeConnections(150L)).isEqualTo(-1) assertThat(pool.connectionCount()).isEqualTo(0) assertThat(c1.socket().isClosed).isTrue() } @@ -91,17 +91,17 @@ class ConnectionPoolTest { synchronized(c1) { call.acquireConnectionNoEvents(c1) } // Running at time 50, the pool returns that nothing can be evicted until time 150. - assertThat(pool.cleanup(50L)).isEqualTo(100L) + assertThat(pool.closeConnections(50L)).isEqualTo(100L) assertThat(pool.connectionCount()).isEqualTo(1) assertThat(c1.socket().isClosed).isFalse() // Running at time 60, the pool returns that nothing can be evicted until time 160. - assertThat(pool.cleanup(60L)).isEqualTo(100L) + assertThat(pool.closeConnections(60L)).isEqualTo(100L) assertThat(pool.connectionCount()).isEqualTo(1) assertThat(c1.socket().isClosed).isFalse() // Running at time 160, the pool returns that nothing can be evicted until time 260. - assertThat(pool.cleanup(160L)).isEqualTo(100L) + assertThat(pool.closeConnections(160L)).isEqualTo(100L) assertThat(pool.connectionCount()).isEqualTo(1) assertThat(c1.socket().isClosed).isFalse() } @@ -112,25 +112,25 @@ class ConnectionPoolTest { val c2 = factory.newConnection(pool, routeB1, 50L) // Running at time 75, the pool returns that nothing can be evicted until time 150. - assertThat(pool.cleanup(75L)).isEqualTo(75L) + assertThat(pool.closeConnections(75L)).isEqualTo(75L) assertThat(pool.connectionCount()).isEqualTo(2) // Running at time 149, the pool returns that nothing can be evicted until time 150. - assertThat(pool.cleanup(149L)).isEqualTo(1L) + assertThat(pool.closeConnections(149L)).isEqualTo(1L) assertThat(pool.connectionCount()).isEqualTo(2) // Running at time 150, the pool evicts c2. - assertThat(pool.cleanup(150L)).isEqualTo(0L) + assertThat(pool.closeConnections(150L)).isEqualTo(0L) assertThat(pool.connectionCount()).isEqualTo(1) assertThat(c1.socket().isClosed).isFalse() assertThat(c2.socket().isClosed).isTrue() // Running at time 150, the pool returns that nothing can be evicted until time 175. - assertThat(pool.cleanup(150L)).isEqualTo(25L) + assertThat(pool.closeConnections(150L)).isEqualTo(25L) assertThat(pool.connectionCount()).isEqualTo(1) // Running at time 175, the pool evicts c1. - assertThat(pool.cleanup(175L)).isEqualTo(0L) + assertThat(pool.closeConnections(175L)).isEqualTo(0L) assertThat(pool.connectionCount()).isEqualTo(0) assertThat(c1.socket().isClosed).isTrue() assertThat(c2.socket().isClosed).isTrue() @@ -145,7 +145,7 @@ class ConnectionPoolTest { val c2 = factory.newConnection(pool, routeB1, 75L) // With 2 connections, there's no need to evict until the connections time out. - assertThat(pool.cleanup(100L)).isEqualTo(50L) + assertThat(pool.closeConnections(100L)).isEqualTo(50L) assertThat(pool.connectionCount()).isEqualTo(2) assertThat(c1.socket().isClosed).isFalse() assertThat(c2.socket().isClosed).isFalse() @@ -154,7 +154,7 @@ class ConnectionPoolTest { val c3 = factory.newConnection(pool, routeC1, 75L) // The third connection bounces the first. - assertThat(pool.cleanup(100L)).isEqualTo(0L) + assertThat(pool.closeConnections(100L)).isEqualTo(0L) assertThat(pool.connectionCount()).isEqualTo(2) assertThat(c1.socket().isClosed).isTrue() assertThat(c2.socket().isClosed).isFalse() @@ -167,7 +167,7 @@ class ConnectionPoolTest { val c1 = factory.newConnection(pool, routeA1, 0L) allocateAndLeakAllocation(poolApi, c1) awaitGarbageCollection() - assertThat(pool.cleanup(100L)).isEqualTo(0L) + assertThat(pool.closeConnections(100L)).isEqualTo(0L) assertThat(c1.calls).isEmpty() // Can't allocate once a leak has been detected. From d2e91f7cb481c70f0a45d47d27d17d0ca61272f0 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 10 Apr 2024 15:46:48 -0400 Subject: [PATCH 006/134] Change parameter order for Cache constructor (#8338) * Change parameter order for Cache constructor Put FileSystem before Path, as is convention. Also put this new constructor in the public API. * apiDump * Track the change in RunSurvey * Track signature change --- .../android/RobolectricOkHttpClientTest.kt | 2 +- .../okhttp3/dnsoverhttps/DnsOverHttpsTest.kt | 4 ++-- okhttp/api/okhttp.api | 2 +- okhttp/src/main/kotlin/okhttp3/Cache.kt | 19 +++++++++---------- .../internal/NativeImageTestsAccessors.kt | 2 +- okhttp/src/test/java/okhttp3/CacheTest.kt | 12 ++++++------ okhttp/src/test/java/okhttp3/CallTest.kt | 2 +- .../internal/http2/HttpOverHttp2Test.kt | 2 +- .../main/kotlin/okhttp3/survey/RunSurvey.kt | 2 +- 9 files changed, 23 insertions(+), 24 deletions(-) diff --git a/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt b/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt index 137c27fa7ed6..1ffaefa723e9 100644 --- a/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt +++ b/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt @@ -51,7 +51,7 @@ class RobolectricOkHttpClientTest { context = ApplicationProvider.getApplicationContext() client = OkHttpClient.Builder() - .cache(Cache("/cache".toPath(), 10_000_000, FakeFileSystem())) + .cache(Cache(FakeFileSystem(), "/cache".toPath(), 10_000_000)) .build() } diff --git a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt index 78bbaaac78fc..bfe84cb34800 100644 --- a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt +++ b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt @@ -170,7 +170,7 @@ class DnsOverHttpsTest { // 5. unsuccessful response @Test fun usesCache() { - val cache = Cache("cache".toPath(), (100 * 1024).toLong(), cacheFs) + val cache = Cache(cacheFs, "cache".toPath(), (100 * 1024).toLong()) val cachedClient = bootstrapClient.newBuilder().cache(cache).build() val cachedDns = buildLocalhost(cachedClient, false) @@ -208,7 +208,7 @@ class DnsOverHttpsTest { @Test fun usesCacheEvenForPost() { - val cache = Cache("cache".toPath(), (100 * 1024).toLong(), cacheFs) + val cache = Cache(cacheFs, "cache".toPath(), (100 * 1024).toLong()) val cachedClient = bootstrapClient.newBuilder().cache(cache).build() val cachedDns = buildLocalhost(cachedClient, false, post = true) repeat(2) { diff --git a/okhttp/api/okhttp.api b/okhttp/api/okhttp.api index 6eb3024b6f21..866cf47a3839 100644 --- a/okhttp/api/okhttp.api +++ b/okhttp/api/okhttp.api @@ -68,7 +68,7 @@ public final class okhttp3/Cache : java/io/Closeable, java/io/Flushable { public static final field Companion Lokhttp3/Cache$Companion; public final fun -deprecated_directory ()Ljava/io/File; public fun (Ljava/io/File;J)V - public fun (Lokio/Path;JLokio/FileSystem;)V + public fun (Lokio/FileSystem;Lokio/Path;J)V public fun close ()V public final fun delete ()V public final fun directory ()Ljava/io/File; diff --git a/okhttp/src/main/kotlin/okhttp3/Cache.kt b/okhttp/src/main/kotlin/okhttp3/Cache.kt index e9cc322d36fd..69d79cd9394f 100644 --- a/okhttp/src/main/kotlin/okhttp3/Cache.kt +++ b/okhttp/src/main/kotlin/okhttp3/Cache.kt @@ -151,11 +151,11 @@ class Cache internal constructor( fileSystem: FileSystem, taskRunner: TaskRunner, ) : Closeable, Flushable { - @ExperimentalOkHttpApi + /** Create a cache of at most [maxSize] bytes in [directory]. */ constructor( + fileSystem: FileSystem, directory: Path, maxSize: Long, - fileSystem: FileSystem, ) : this( directory, maxSize, @@ -163,6 +163,13 @@ class Cache internal constructor( TaskRunner.INSTANCE, ) + /** Create a cache of at most [maxSize] bytes in [directory]. */ + constructor(directory: File, maxSize: Long) : this( + FileSystem.SYSTEM, + directory.toOkioPath(), + maxSize, + ) + internal val cache = DiskLruCache( fileSystem = fileSystem, @@ -183,13 +190,6 @@ class Cache internal constructor( val isClosed: Boolean get() = cache.isClosed() - /** Create a cache of at most [maxSize] bytes in [directory]. */ - constructor(directory: File, maxSize: Long) : this( - directory.toOkioPath(), - maxSize, - FileSystem.SYSTEM, - ) - internal fun get(request: Request): Response? { val key = key(request.url) val snapshot: DiskLruCache.Snapshot = @@ -389,7 +389,6 @@ class Cache internal constructor( get() = cache.directory.toFile() @get:JvmName("directoryPath") - @ExperimentalOkHttpApi val directoryPath: Path get() = cache.directory diff --git a/okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt b/okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt index cdf6fb62cfcf..db5f173887e4 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt @@ -29,7 +29,7 @@ internal fun buildCache( maxSize: Long, fileSystem: FileSystem, ): Cache { - return Cache(file, maxSize, fileSystem) + return Cache(fileSystem, file, maxSize) } internal var RealConnection.idleAtNsAccessor: Long diff --git a/okhttp/src/test/java/okhttp3/CacheTest.kt b/okhttp/src/test/java/okhttp3/CacheTest.kt index 707f0fcebd95..1400aadaeb68 100644 --- a/okhttp/src/test/java/okhttp3/CacheTest.kt +++ b/okhttp/src/test/java/okhttp3/CacheTest.kt @@ -92,7 +92,7 @@ class CacheTest { platform.assumeNotOpenJSSE() server.protocolNegotiationEnabled = false fileSystem.emulateUnix() - cache = Cache("/cache/".toPath(), Long.MAX_VALUE, fileSystem) + cache = Cache(fileSystem, "/cache/".toPath(), Long.MAX_VALUE) client = clientTestRule.newClientBuilder() .cache(cache) @@ -2758,7 +2758,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} writeFile(cache.directoryPath, "$urlKey.0", entryMetadata) writeFile(cache.directoryPath, "$urlKey.1", entryBody) writeFile(cache.directoryPath, "journal", journalBody) - cache = Cache(cache.directory.path.toPath(), Int.MAX_VALUE.toLong(), fileSystem) + cache = Cache(fileSystem, cache.directory.path.toPath(), Int.MAX_VALUE.toLong()) client = client.newBuilder() .cache(cache) @@ -2807,7 +2807,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} writeFile(cache.directoryPath, "$urlKey.1", entryBody) writeFile(cache.directoryPath, "journal", journalBody) cache.close() - cache = Cache(cache.directory.path.toPath(), Int.MAX_VALUE.toLong(), fileSystem) + cache = Cache(fileSystem, cache.directory.path.toPath(), Int.MAX_VALUE.toLong()) client = client.newBuilder() .cache(cache) @@ -2860,7 +2860,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} writeFile(cache.directoryPath, "$urlKey.1", entryBody) writeFile(cache.directoryPath, "journal", journalBody) cache.close() - cache = Cache(cache.directory.path.toPath(), Int.MAX_VALUE.toLong(), fileSystem) + cache = Cache(fileSystem, cache.directory.path.toPath(), Int.MAX_VALUE.toLong()) client = client.newBuilder() .cache(cache) @@ -2905,7 +2905,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} writeFile(cache.directoryPath, "$urlKey.1", entryBody) writeFile(cache.directoryPath, "journal", journalBody) cache.close() - cache = Cache(cache.directory.path.toPath(), Int.MAX_VALUE.toLong(), fileSystem) + cache = Cache(fileSystem, cache.directory.path.toPath(), Int.MAX_VALUE.toLong()) client = client.newBuilder() .cache(cache) @@ -3496,7 +3496,7 @@ CLEAN $urlKey ${entryMetadata.length} ${entryBody.length} } } val path: Path = "/cache".toPath() - val c = Cache(path, 100000L, loggingFileSystem) + val c = Cache(loggingFileSystem, path, 100000L) assertThat(c.directoryPath).isEqualTo(path) c.size() assertThat(events).containsExactly( diff --git a/okhttp/src/test/java/okhttp3/CallTest.kt b/okhttp/src/test/java/okhttp3/CallTest.kt index 2d8827faee08..e59e0de7b6ee 100644 --- a/okhttp/src/test/java/okhttp3/CallTest.kt +++ b/okhttp/src/test/java/okhttp3/CallTest.kt @@ -146,9 +146,9 @@ open class CallTest { private val callback = RecordingCallback() private val cache = Cache( + fileSystem = LoggingFilesystem(fileSystem), directory = "/cache".toPath(), maxSize = Int.MAX_VALUE.toLong(), - fileSystem = LoggingFilesystem(fileSystem), ) @BeforeEach diff --git a/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt b/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt index 4c1f4b795171..2cc53897fcf8 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt @@ -125,7 +125,7 @@ class HttpOverHttp2Test { private lateinit var protocol: Protocol private lateinit var client: OkHttpClient private val fileSystem: FakeFileSystem = FakeFileSystem() - private val cache: Cache = Cache("/tmp/cache".toPath(), Long.MAX_VALUE, fileSystem) + private val cache: Cache = Cache(fileSystem, "/tmp/cache".toPath(), Long.MAX_VALUE) private lateinit var scheme: String private fun configureClientTestRule(): OkHttpClientTestRule { diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/RunSurvey.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/RunSurvey.kt index dfb272b72e13..543ffae84510 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/RunSurvey.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/RunSurvey.kt @@ -31,7 +31,7 @@ suspend fun main() { val client = OkHttpClient.Builder() - .cache(Cache("build/okhttp_cache".toPath(), 100_000_000, FileSystem.SYSTEM)) + .cache(Cache(FileSystem.SYSTEM, "build/okhttp_cache".toPath(), 100_000_000)) .build() val sslLabsClients = SslLabsClient(client).clients() From 27670f9eb1e6019566b245b0e2f9ca5974f6e42f Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 10 Apr 2024 21:59:58 -0400 Subject: [PATCH 007/134] Redo TaskFaker's internal queue (#8348) * Redo TaskFaker's internal queue Previously this used locks to stop threads from executing. Now it uses a custom 'yield' function to accomplish a similar purpose. The main benefit of the new approach is we're no longer subject to unspecified lock release order - we maintain our own queue and get true deterministic order of execution. * Fix interruption * Fixup tests * Spotless * Use an enum rather than two booleans --- .../okhttp3/internal/concurrent/TaskFaker.kt | 357 +++++++++++------- .../FastFallbackExchangeFinderTest.kt | 11 +- .../okhttp3/internal/ws/RealWebSocketTest.kt | 14 +- 3 files changed, 217 insertions(+), 165 deletions(-) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt index ae953c32d407..894a858d59a4 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt @@ -16,14 +16,13 @@ package okhttp3.internal.concurrent import assertk.assertThat -import assertk.assertions.isEmpty +import assertk.assertions.isEqualTo import java.io.Closeable import java.util.AbstractQueue import java.util.concurrent.BlockingQueue import java.util.concurrent.Executors -import java.util.concurrent.Semaphore +import java.util.concurrent.ThreadFactory import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean import java.util.logging.Logger import kotlin.concurrent.withLock import okhttp3.OkHttpClient @@ -33,18 +32,14 @@ import okhttp3.OkHttpClient * deterministic. * * This class ensures that at most one thread is running at a time. This is initially the JUnit test - * thread, which temporarily shares its execution privilege by calling [runTasks], [runNextTask], or - * [advanceUntil]. These methods wait for its task threads to stop executing before it returns. + * thread, which yields its execution privilege while calling [runTasks], [runNextTask], or + * [advanceUntil]. These functions don't return until the task threads are all idle. * - * Task threads stall execution in these ways: + * Task threads release their execution privilege in these ways: * - * * By being ready to start. Newly-created tasks don't run immediately. - * * By finishing their work. This occurs when [Runnable.run] returns. - * * By waiting until the simulated clock reaches a specific time. - * * By requesting to wait by calling [TaskRunner.Backend.coordinatorWait]. - * - * Most test methods start by unblocking task threads, then wait for those task threads to stall - * again before returning. + * * By yielding in [TaskRunner.Backend.coordinatorWait]. + * * By yielding in [BlockingQueue.poll]. + * * By completing. */ class TaskFaker : Closeable { @Suppress("NOTHING_TO_INLINE") @@ -64,22 +59,14 @@ class TaskFaker : Closeable { val logger = Logger.getLogger("TaskFaker." + instance++) /** Though this executor service may hold many threads, they are not executed concurrently. */ - private val tasksExecutor = Executors.newCachedThreadPool() - - /** The number of runnables known to [tasksExecutor]. Guarded by [taskRunner]. */ - private var tasksRunningCount = 0 - - /** - * Threads in this list are waiting for either [interruptCoordinatorThread] or [notifyAll]. - * Guarded by [taskRunner]. - */ - private val stalledTasks = mutableListOf() + private val tasksExecutor = + Executors.newCachedThreadPool( + object : ThreadFactory { + private var nextId = 1 - /** - * Released whenever a thread is either added to [stalledTasks] or completes. The test thread - * uses this to wait until all subject threads complete or stall. - */ - private val taskBecameStalled = Semaphore(0) + override fun newThread(runnable: Runnable) = Thread(runnable, "TaskFaker-${nextId++}") + }, + ) /** * True if this task faker has ever had multiple tasks scheduled to run concurrently. Guarded by @@ -91,11 +78,22 @@ class TaskFaker : Closeable { var nanoTime = 0L private set - /** The thread currently waiting for time to advance. Guarded by [taskRunner]. */ - private var waitingCoordinatorThread: Thread? = null + /** Backlog of tasks to run. Only one task runs at a time. Guarded by [taskRunner]. */ + private val serialTaskQueue = ArrayDeque() + + /** The task that's currently executing. Guarded by [taskRunner]. */ + private var currentTask: SerialTask = TestThreadSerialTask - /** True if new tasks should run immediately without stalling. Guarded by [taskRunner]. */ - private var isRunningAllTasks = false + /** The coordinator task if it's waiting, and how it will resume. Guarded by [taskRunner]. */ + private var waitingCoordinatorTask: SerialTask? = null + private var waitingCoordinatorInterrupted = false + private var waitingCoordinatorNotified = false + + /** How many times a new task has been started. Guarded by [taskRunner]. */ + private var contextSwitchCount = 0 + + /** Guarded by [taskRunner]. */ + private var activeThreads = 0 /** A task runner that posts tasks to this fake. Tasks won't be executed until requested. */ val taskRunner: TaskRunner = @@ -106,43 +104,33 @@ class TaskFaker : Closeable { runnable: Runnable, ) { taskRunner.assertThreadHoldsLock() - val acquiredTaskRunnerLock = AtomicBoolean() - - tasksExecutor.execute { - taskRunner.lock.withLock { - acquiredTaskRunnerLock.set(true) - taskRunner.condition.signalAll() - - tasksRunningCount++ - if (tasksRunningCount > 1) isParallel = true - try { - if (!isRunningAllTasks) { - stall() - } - runnable.run() - } catch (e: InterruptedException) { - if (!tasksExecutor.isShutdown) throw e // Ignore shutdown-triggered interruptions. - } finally { - tasksRunningCount-- - taskBecameStalled.release() - } - } - } - // Execute() must not return until the launched task stalls. - while (!acquiredTaskRunnerLock.get()) { - taskRunner.condition.await() - } + val queuedTask = RunnableSerialTask(runnable) + serialTaskQueue += queuedTask + isParallel = serialTaskQueue.size > 1 } override fun nanoTime() = nanoTime override fun coordinatorNotify(taskRunner: TaskRunner) { taskRunner.assertThreadHoldsLock() - check(waitingCoordinatorThread != null) - - stalledTasks.remove(waitingCoordinatorThread) - taskRunner.condition.signalAll() + check(waitingCoordinatorTask != null) + + // Queue a task to resume the waiting coordinator. + serialTaskQueue += + object : SerialTask { + override fun start() { + taskRunner.assertThreadHoldsLock() + val coordinatorTask = waitingCoordinatorTask + if (coordinatorTask != null) { + waitingCoordinatorNotified = true + currentTask = coordinatorTask + taskRunner.condition.signalAll() + } else { + startNextTask() + } + } + } } override fun coordinatorWait( @@ -150,15 +138,24 @@ class TaskFaker : Closeable { nanos: Long, ) { taskRunner.assertThreadHoldsLock() - - check(waitingCoordinatorThread == null) + check(waitingCoordinatorTask == null) if (nanos == 0L) return - waitingCoordinatorThread = Thread.currentThread() - try { - stall() - } finally { - waitingCoordinatorThread = null + // Yield until notified, interrupted, or the duration elapses. + val waitUntil = nanoTime + nanos + val self = currentTask + waitingCoordinatorTask = self + waitingCoordinatorNotified = false + waitingCoordinatorInterrupted = false + yieldUntil { + waitingCoordinatorNotified || waitingCoordinatorInterrupted || nanoTime >= waitUntil + } + + waitingCoordinatorTask = null + waitingCoordinatorNotified = false + if (waitingCoordinatorInterrupted) { + waitingCoordinatorInterrupted = false + throw InterruptedException() } } @@ -167,30 +164,6 @@ class TaskFaker : Closeable { logger = logger, ) - /** Wait for the test thread to proceed. */ - private fun stall() { - taskRunner.assertThreadHoldsLock() - - val currentThread = Thread.currentThread() - taskBecameStalled.release() - stalledTasks += currentThread - try { - while (currentThread in stalledTasks) { - taskRunner.condition.await() - } - } catch (e: InterruptedException) { - stalledTasks.remove(currentThread) - throw e - } - } - - private fun unstallTasks() { - taskRunner.assertThreadHoldsLock() - - stalledTasks.clear() - taskRunner.condition.signalAll() - } - /** Runs all tasks that are ready. Used by the test thread only. */ fun runTasks() { advanceUntil(nanoTime) @@ -201,26 +174,9 @@ class TaskFaker : Closeable { taskRunner.assertThreadDoesntHoldLock() taskRunner.lock.withLock { - isRunningAllTasks = true + check(currentTask == TestThreadSerialTask) nanoTime = newTime - unstallTasks() - } - - waitForTasksToStall() - } - - private fun waitForTasksToStall() { - taskRunner.assertThreadDoesntHoldLock() - - while (true) { - taskRunner.lock.withLock { - if (tasksRunningCount == stalledTasks.size) { - isRunningAllTasks = false - return@waitForTasksToStall // All stalled. - } - taskBecameStalled.drainPermits() - } - taskBecameStalled.acquire() + yieldUntil(ResumePriority.AfterOtherTasks) } } @@ -229,24 +185,29 @@ class TaskFaker : Closeable { taskRunner.assertThreadDoesntHoldLock() taskRunner.lock.withLock { - assertThat(stalledTasks).isEmpty() + assertThat(activeThreads).isEqualTo(0) } } /** Unblock a waiting task thread. Used by the test thread only. */ fun interruptCoordinatorThread() { taskRunner.assertThreadDoesntHoldLock() + require(currentTask == TestThreadSerialTask) - // Make sure the coordinator is ready to be interrupted. - runTasks() - - taskRunner.lock.withLock { - val toInterrupt = waitingCoordinatorThread ?: error("no thread currently waiting") - taskBecameStalled.drainPermits() - toInterrupt.interrupt() - } + // Queue a task to interrupt the waiting coordinator. + serialTaskQueue += + object : SerialTask { + override fun start() { + taskRunner.assertThreadHoldsLock() + waitingCoordinatorInterrupted = true + val coordinatorTask = waitingCoordinatorTask ?: error("no coordinator waiting") + currentTask = coordinatorTask + taskRunner.condition.signalAll() + } + } - waitForTasksToStall() + // Let the coordinator process its interruption. + runTasks() } /** Ask a single task to proceed. Used by the test thread only. */ @@ -254,21 +215,18 @@ class TaskFaker : Closeable { taskRunner.assertThreadDoesntHoldLock() taskRunner.lock.withLock { - check(stalledTasks.size >= 1) { "no tasks to run" } - stalledTasks.removeFirst() - taskRunner.condition.signalAll() + val contextSwitchCountBefore = contextSwitchCount + yieldUntil(ResumePriority.BeforeOtherTasks) { + contextSwitchCount > contextSwitchCountBefore + } } - - waitForTasksToStall() } /** Sleep until [durationNanos] elapses. For use by the task threads. */ fun sleep(durationNanos: Long) { - taskRunner.assertThreadHoldsLock() - - val waitUntil = nanoTime + durationNanos - while (nanoTime < waitUntil) { - stall() + taskRunner.lock.withLock { + val sleepUntil = nanoTime + durationNanos + yieldUntil { nanoTime >= sleepUntil } } } @@ -277,7 +235,113 @@ class TaskFaker : Closeable { * simulate races in tasks that doesn't have a deterministic sequence. */ fun yield() { - stall() + taskRunner.assertThreadDoesntHoldLock() + taskRunner.lock.withLock { + yieldUntil() + } + } + + /** Process the queue until [condition] returns true. */ + private tailrec fun yieldUntil( + strategy: ResumePriority = ResumePriority.AfterEnqueuedTasks, + condition: () -> Boolean = { true }, + ) { + taskRunner.assertThreadHoldsLock() + val self = currentTask + + val yieldCompleteTask = + object : SerialTask { + override fun isReady() = condition() + + override fun start() { + taskRunner.assertThreadHoldsLock() + currentTask = self + taskRunner.condition.signalAll() + } + } + + if (strategy == ResumePriority.BeforeOtherTasks) { + serialTaskQueue.addFirst(yieldCompleteTask) + } else { + serialTaskQueue.addLast(yieldCompleteTask) + } + + val startedTask = startNextTask() + val otherTasksStarted = startedTask != yieldCompleteTask + + try { + while (currentTask != self) { + taskRunner.condition.await() + } + } finally { + serialTaskQueue.remove(yieldCompleteTask) + } + + // If we're yielding until we're exhausted and a task run, keep going until a task doesn't run. + if (strategy == ResumePriority.AfterOtherTasks && otherTasksStarted) { + return yieldUntil(strategy, condition) + } + } + + private enum class ResumePriority { + /** Resumes as soon as the condition is satisfied. */ + BeforeOtherTasks, + + /** Resumes after the already-enqueued tasks. */ + AfterEnqueuedTasks, + + /** Resumes after all other tasks, including tasks enqueued while yielding. */ + AfterOtherTasks, + } + + /** Returns the task that was started, or null if there were no tasks to start. */ + private fun startNextTask(): SerialTask? { + taskRunner.assertThreadHoldsLock() + + val index = serialTaskQueue.indexOfFirst { it.isReady() } + if (index == -1) return null + + val nextTask = serialTaskQueue.removeAt(index) + currentTask = nextTask + contextSwitchCount++ + nextTask.start() + return nextTask + } + + private interface SerialTask { + /** Returns true if this task is ready to start. */ + fun isReady() = true + + /** Do this task's work, and then start another, such as by calling [startNextTask]. */ + fun start() + } + + private object TestThreadSerialTask : SerialTask { + override fun start() = error("unexpected call") + } + + inner class RunnableSerialTask( + private val runnable: Runnable, + ) : SerialTask { + override fun start() { + taskRunner.assertThreadHoldsLock() + require(currentTask == this) + activeThreads++ + + tasksExecutor.execute { + taskRunner.assertThreadDoesntHoldLock() + require(currentTask == this) + try { + runnable.run() + require(currentTask == this) { "unexpected current task: $currentTask" } + } finally { + taskRunner.lock.withLock { + activeThreads-- + startNextTask() + } + } + } + } } /** @@ -289,28 +353,31 @@ class TaskFaker : Closeable { ) : AbstractQueue(), BlockingQueue { override val size: Int = delegate.size + private var editCount = 0 + override fun poll(): T = delegate.poll() override fun poll( timeout: Long, unit: TimeUnit, ): T? { - taskRunner.assertThreadHoldsLock() - - val waitUntil = nanoTime + unit.toNanos(timeout) - while (true) { - val result = poll() - if (result != null) return result - if (nanoTime >= waitUntil) return null - stall() + taskRunner.lock.withLock { + val waitUntil = nanoTime + unit.toNanos(timeout) + while (true) { + val result = poll() + if (result != null) return result + if (nanoTime >= waitUntil) return null + val editCountBefore = editCount + yieldUntil { nanoTime >= waitUntil || editCount > editCountBefore } + } } } override fun put(element: T) { - taskRunner.assertThreadHoldsLock() - - delegate.put(element) - unstallTasks() + taskRunner.lock.withLock { + delegate.put(element) + editCount++ + } } override fun iterator() = error("unsupported") diff --git a/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt index e6327295a4af..ba969a8159e7 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt @@ -25,10 +25,8 @@ import kotlin.test.assertFailsWith import okhttp3.FakeRoutePlanner import okhttp3.FakeRoutePlanner.ConnectState.TLS_CONNECTED import okhttp3.internal.concurrent.TaskFaker -import okhttp3.testing.Flaky import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test -import org.junitpioneer.jupiter.RetryingTest /** * Unit test for [FastFallbackExchangeFinder] implementation details. @@ -790,8 +788,7 @@ internal class FastFallbackExchangeFinderTest { * * https://github.com/square/okhttp/issues/7152 */ - @RetryingTest(5) - @Flaky + @Test fun reusePlanAndNewConnectRace() { val plan0 = routePlanner.addPlan() plan0.tcpConnectDelayNanos = 250.ms @@ -814,12 +811,8 @@ internal class FastFallbackExchangeFinderTest { taskFaker.advanceUntil(250.ms) assertEvents( "take plan 1", - ) - - taskFaker.runTasks() - assertEvents( - "plan 0 TCP connected", "plan 0 cancel", + "plan 0 TCP connect canceled", ) } diff --git a/okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt b/okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt index 89b06aabe892..640a2230938d 100644 --- a/okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt @@ -70,6 +70,7 @@ class RealWebSocketTest { server.listener.assertExhausted() server.source.close() client.source.close() + taskFaker.runTasks() server.webSocket!!.tearDown() client.webSocket!!.tearDown() taskFaker.close() @@ -78,7 +79,6 @@ class RealWebSocketTest { @Test fun close() { client.webSocket!!.close(1000, "Hello!") - taskFaker.runTasks() // This will trigger a close response. assertThat(server.processNextFrame()).isFalse() server.listener.assertClosing(1000, "Hello!") @@ -132,7 +132,6 @@ class RealWebSocketTest { @Test fun serverCloseThenWritingPingSucceeds() { server.webSocket!!.close(1000, "Hello!") - taskFaker.runTasks() client.processNextFrame() client.listener.assertClosing(1000, "Hello!") assertThat(client.webSocket!!.pong("Pong?".encodeUtf8())).isTrue() @@ -141,7 +140,6 @@ class RealWebSocketTest { @Test fun clientCanWriteMessagesAfterServerClose() { server.webSocket!!.close(1000, "Hello!") - taskFaker.runTasks() client.processNextFrame() client.listener.assertClosing(1000, "Hello!") assertThat(client.webSocket!!.send("Hi!")).isTrue() @@ -152,11 +150,11 @@ class RealWebSocketTest { @Test fun serverCloseThenClientClose() { server.webSocket!!.close(1000, "Hello!") - taskFaker.runTasks() client.processNextFrame() client.listener.assertClosing(1000, "Hello!") assertThat(client.webSocket!!.close(1000, "Bye!")).isTrue() client.webSocket!!.finishReader() + taskFaker.runTasks() client.listener.assertClosed(1000, "Hello!") server.processNextFrame() server.listener.assertClosing(1000, "Bye!") @@ -171,7 +169,6 @@ class RealWebSocketTest { client.listener.assertClosing(1005, "") client.webSocket!!.finishReader() assertThat(client.webSocket!!.close(1000, "Bye!")).isTrue() - taskFaker.runTasks() server.processNextFrame() server.listener.assertClosing(1000, "Bye!") server.webSocket!!.finishReader() @@ -238,7 +235,6 @@ class RealWebSocketTest { @Test fun serverCloseClosesConnection() { server.webSocket!!.close(1000, "Hello!") - taskFaker.runTasks() client.processNextFrame() // Read server close, send client close, close connection. assertThat(client.closed).isFalse() client.listener.assertClosing(1000, "Hello!") @@ -256,7 +252,6 @@ class RealWebSocketTest { fun clientAndServerCloseClosesConnection() { // Send close from both sides at the same time. server.webSocket!!.close(1000, "Hello!") - taskFaker.runTasks() client.processNextFrame() // Read close, close connection close. assertThat(client.closed).isFalse() client.webSocket!!.close(1000, "Hi!") @@ -277,7 +272,6 @@ class RealWebSocketTest { fun serverCloseBreaksReadMessageLoop() { server.webSocket!!.send("Hello!") server.webSocket!!.close(1000, "Bye!") - taskFaker.runTasks() assertThat(client.processNextFrame()).isTrue() client.listener.assertTextMessage("Hello!") assertThat(client.processNextFrame()).isFalse() @@ -303,7 +297,6 @@ class RealWebSocketTest { @Test fun protocolErrorInCloseResponseClosesConnection() { client.webSocket!!.close(1000, "Hello") - taskFaker.runTasks() server.processNextFrame() // Not closed until close reply is received. assertThat(client.closed).isFalse() @@ -324,7 +317,6 @@ class RealWebSocketTest { @Test fun protocolErrorAfterCloseDoesNotSendClose() { client.webSocket!!.close(1000, "Hello!") - taskFaker.runTasks() server.processNextFrame() // Not closed until close reply is received. @@ -402,7 +394,6 @@ class RealWebSocketTest { // At 0ms the server sends 3 unexpected pongs. The client accepts 'em and ignores em. server.webSocket!!.pong("pong 1".encodeUtf8()) - taskFaker.runTasks() client.processNextFrame() server.webSocket!!.pong("pong 2".encodeUtf8()) client.processNextFrame() @@ -527,6 +518,7 @@ class RealWebSocketTest { } fun processNextFrame(): Boolean { + taskFaker.runTasks() return webSocket!!.processNextFrame() } From 822bad8169b003bdc6c793e03c5cc82d3a515989 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Thu, 11 Apr 2024 18:09:35 -0400 Subject: [PATCH 008/134] Extract a test thread factory (#8356) This is different from the production thread factory: - No daemon threads in tests. We don't need 'em. - Threads are numbered in tests. We do need that. --- .../src/main/kotlin/okhttp3/TestUtilJvm.kt | 12 ++++++++++++ .../kotlin/okhttp3/internal/concurrent/TaskFaker.kt | 11 ++--------- .../java/okhttp3/tls/HandshakeCertificatesTest.kt | 3 ++- okhttp/src/test/java/okhttp3/SocksProxy.kt | 4 ++-- .../test/java/okhttp3/internal/cache2/RelayTest.kt | 3 ++- .../java/okhttp3/internal/http2/HttpOverHttp2Test.kt | 3 ++- .../java/okhttp3/internal/http2/MockHttp2Peer.kt | 4 ++-- 7 files changed, 24 insertions(+), 16 deletions(-) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/TestUtilJvm.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/TestUtilJvm.kt index 9bb5bcc6a419..42b4c6e51a93 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/TestUtilJvm.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/TestUtilJvm.kt @@ -20,6 +20,7 @@ import java.net.InetAddress import java.net.InetSocketAddress import java.net.UnknownHostException import java.util.Arrays +import java.util.concurrent.ThreadFactory import okhttp3.internal.http2.Header import okio.Buffer import okio.FileSystem @@ -122,6 +123,17 @@ object TestUtil { if (isGraalVmImage) return block(suppressed.toList()) } + + @JvmStatic + fun threadFactory(name: String): ThreadFactory { + return object : ThreadFactory { + private var nextId = 1 + + override fun newThread(runnable: Runnable): Thread { + return Thread(runnable, "$name-${nextId++}") + } + } + } } fun getEnv(name: String) = System.getenv(name) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt index 894a858d59a4..88dfd7936742 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt @@ -21,11 +21,11 @@ import java.io.Closeable import java.util.AbstractQueue import java.util.concurrent.BlockingQueue import java.util.concurrent.Executors -import java.util.concurrent.ThreadFactory import java.util.concurrent.TimeUnit import java.util.logging.Logger import kotlin.concurrent.withLock import okhttp3.OkHttpClient +import okhttp3.TestUtil.threadFactory /** * Runs a [TaskRunner] in a controlled environment so that everything is sequential and @@ -59,14 +59,7 @@ class TaskFaker : Closeable { val logger = Logger.getLogger("TaskFaker." + instance++) /** Though this executor service may hold many threads, they are not executed concurrently. */ - private val tasksExecutor = - Executors.newCachedThreadPool( - object : ThreadFactory { - private var nextId = 1 - - override fun newThread(runnable: Runnable) = Thread(runnable, "TaskFaker-${nextId++}") - }, - ) + private val tasksExecutor = Executors.newCachedThreadPool(threadFactory("TaskFaker")) /** * True if this task faker has ever had multiple tasks scheduled to run concurrently. Guarded by diff --git a/okhttp-tls/src/test/java/okhttp3/tls/HandshakeCertificatesTest.kt b/okhttp-tls/src/test/java/okhttp3/tls/HandshakeCertificatesTest.kt index 26f4146aa6ce..53d58a43dbc2 100644 --- a/okhttp-tls/src/test/java/okhttp3/tls/HandshakeCertificatesTest.kt +++ b/okhttp-tls/src/test/java/okhttp3/tls/HandshakeCertificatesTest.kt @@ -30,6 +30,7 @@ import javax.net.SocketFactory import javax.net.ssl.SSLSocket import okhttp3.Handshake import okhttp3.Handshake.Companion.handshake +import okhttp3.TestUtil.threadFactory import okhttp3.internal.closeQuietly import okhttp3.testing.PlatformRule import okio.ByteString.Companion.toByteString @@ -47,7 +48,7 @@ class HandshakeCertificatesTest { private var serverSocket: ServerSocket? = null @BeforeEach fun setUp() { - executorService = Executors.newCachedThreadPool() + executorService = Executors.newCachedThreadPool(threadFactory("HandshakeCertificatesTest")) } @AfterEach fun tearDown() { diff --git a/okhttp/src/test/java/okhttp3/SocksProxy.kt b/okhttp/src/test/java/okhttp3/SocksProxy.kt index 6873a0a1c911..b83fa0000a34 100644 --- a/okhttp/src/test/java/okhttp3/SocksProxy.kt +++ b/okhttp/src/test/java/okhttp3/SocksProxy.kt @@ -30,9 +30,9 @@ import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger import java.util.logging.Level import java.util.logging.Logger +import okhttp3.TestUtil.threadFactory import okhttp3.internal.and import okhttp3.internal.closeQuietly -import okhttp3.internal.threadFactory import okhttp3.internal.threadName import okio.Buffer import okio.BufferedSink @@ -47,7 +47,7 @@ import okio.use * See [RFC 1928](https://www.ietf.org/rfc/rfc1928.txt). */ class SocksProxy { - private val executor = Executors.newCachedThreadPool(threadFactory("SocksProxy", false)) + private val executor = Executors.newCachedThreadPool(threadFactory("SocksProxy")) private var serverSocket: ServerSocket? = null private val connectionCount = AtomicInteger() private val openSockets = Collections.newSetFromMap(ConcurrentHashMap()) diff --git a/okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt b/okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt index 597b6c43832c..da28c0c117e2 100644 --- a/okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt @@ -25,6 +25,7 @@ import java.io.IOException import java.util.concurrent.Callable import java.util.concurrent.Executors import kotlin.test.assertFailsWith +import okhttp3.TestUtil.threadFactory import okhttp3.internal.cache2.Relay.Companion.edit import okhttp3.internal.cache2.Relay.Companion.read import okio.Buffer @@ -44,7 +45,7 @@ import org.junit.jupiter.api.io.TempDir class RelayTest { @TempDir var tempDir: File? = null - private val executor = Executors.newCachedThreadPool() + private val executor = Executors.newCachedThreadPool(threadFactory("RelayTest")) private val metadata: ByteString = "great metadata!".encodeUtf8() private lateinit var file: File diff --git a/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt b/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt index 2cc53897fcf8..3edea2595db5 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt @@ -74,6 +74,7 @@ import okhttp3.SimpleProvider import okhttp3.TestLogHandler import okhttp3.TestUtil.assumeNotWindows import okhttp3.TestUtil.repeat +import okhttp3.TestUtil.threadFactory import okhttp3.internal.DoubleInetAddressDns import okhttp3.internal.EMPTY_REQUEST import okhttp3.internal.RecordingOkAuthenticator @@ -509,7 +510,7 @@ class HttpOverHttp2Test { setUp(protocol, mockWebServer) server.enqueue(MockResponse(body = "A")) server.enqueue(MockResponse(body = "A")) - val executor = Executors.newCachedThreadPool() + val executor = Executors.newCachedThreadPool(threadFactory("HttpOverHttp2Test")) val countDownLatch = CountDownLatch(2) executor.execute(AsyncRequest("/r1", countDownLatch)) executor.execute(AsyncRequest("/r2", countDownLatch)) diff --git a/okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt b/okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt index aa7c8cbebd2c..0b65d9876b03 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt @@ -24,8 +24,8 @@ import java.util.concurrent.BlockingQueue import java.util.concurrent.Executors import java.util.concurrent.LinkedBlockingQueue import java.util.logging.Logger +import okhttp3.TestUtil.threadFactory import okhttp3.internal.closeQuietly -import okhttp3.internal.threadFactory import okio.Buffer import okio.BufferedSource import okio.ByteString @@ -41,7 +41,7 @@ class MockHttp2Peer : Closeable { private val outFrames: MutableList = ArrayList() private val inFrames: BlockingQueue = LinkedBlockingQueue() private var port = 0 - private val executor = Executors.newSingleThreadExecutor(threadFactory("MockHttp2Peer", false)) + private val executor = Executors.newSingleThreadExecutor(threadFactory("MockHttp2Peer")) private var serverSocket: ServerSocket? = null private var socket: Socket? = null From 73c3ea5e510bfe6799a4984a413064e73087e9d4 Mon Sep 17 00:00:00 2001 From: Evan Nelson Date: Fri, 12 Apr 2024 11:57:34 -0700 Subject: [PATCH 009/134] Add connection pool pre-warming tests (#8358) 1. The first test just needed to be uncommented now that https://github.com/square/okhttp/pull/8348 is merged 2. A second test was added to exercise http2-specific functionality --- .../src/test/java/okhttp3/FakeRoutePlanner.kt | 8 +- .../internal/connection/ConnectionPoolTest.kt | 179 +++++++++++++----- 2 files changed, 136 insertions(+), 51 deletions(-) diff --git a/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt b/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt index e817d2e09480..e2030cc7946a 100644 --- a/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt +++ b/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt @@ -30,17 +30,15 @@ class FakeRoutePlanner( * Note that we don't use the same [TaskFaker] for this factory. That way off-topic tasks like * connection pool maintenance tasks don't add noise to route planning tests. */ - private val factory = TestValueFactory() - - private val pool = factory.newConnectionPool() - + val factory = TestValueFactory() + val pool = factory.newConnectionPool(routePlanner = this) val events = LinkedBlockingDeque() var canceled = false var autoGeneratePlans = false var defaultConnectionIdleAtNanos = Long.MAX_VALUE private var nextPlanId = 0 private var nextPlanIndex = 0 - private val plans = mutableListOf() + val plans = mutableListOf() override val deferredPlans = ArrayDeque() diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index 6063d99da140..a69bab91757b 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -21,6 +21,7 @@ import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isNotEmpty import assertk.assertions.isTrue +import okhttp3.Address import okhttp3.ConnectionPool import okhttp3.FakeRoutePlanner import okhttp3.OkHttpClient @@ -28,11 +29,17 @@ import okhttp3.Request import okhttp3.TestUtil.awaitGarbageCollection import okhttp3.TestValueFactory import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.http2.Http2 +import okhttp3.internal.http2.Http2Connection +import okhttp3.internal.http2.Http2ConnectionTest +import okhttp3.internal.http2.MockHttp2Peer +import okhttp3.internal.http2.Settings import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test class ConnectionPoolTest { private val factory = TestValueFactory() + private val peer = MockHttp2Peer() /** The fake task runner prevents the cleanup runnable from being started. */ private val addressA = factory.newAddress("a") @@ -46,6 +53,7 @@ class ConnectionPoolTest { @AfterEach fun tearDown() { factory.close() + peer.close() } @Test fun connectionsEvictedWhenIdleLongEnough() { @@ -195,54 +203,133 @@ class ConnectionPoolTest { assertThat(realTaskRunner.activeQueues()).isEmpty() } - @Test fun connectionPreWarming() { - // TODO this test spins forever due to bugs in TaskFaker.runTasks() - - // routePlanner.autoGeneratePlans = true - // routePlanner.defaultConnectionIdleAtNanos = System.nanoTime() + 1_000_000_000_000 - // val address = routePlanner.address - // val pool = factory.newConnectionPool(routePlanner = routePlanner) - // - // // Connections are created as soon as a policy is set - // setPolicy(pool, address, ConnectionPool.AddressPolicy(2)) - // assertThat(pool.connectionCount()).isEqualTo(2) - // - // // Connections are replaced if they idle out or are evicted from the pool - // evictAllConnections(pool) - // assertThat(pool.connectionCount()).isEqualTo(2) - // forceConnectionsToExpire(pool, routePlanner) - // assertThat(pool.connectionCount()).isEqualTo(2) - // - // // Excess connections aren't removed until they idle out, even if no longer needed - // setPolicy(pool, address, ConnectionPool.AddressPolicy(1)) - // assertThat(pool.connectionCount()).isEqualTo(2) - // forceConnectionsToExpire(pool, routePlanner) - // assertThat(pool.connectionCount()).isEqualTo(1) - - // TODO test that http/2 connections will be opened/closed based on concurrent stream settings + @Test fun connectionPreWarmingHttp1() { + val expireTime = System.nanoTime() + 1_000_000_000_000 + + routePlanner.autoGeneratePlans = true + routePlanner.defaultConnectionIdleAtNanos = expireTime + val address = routePlanner.address + val pool = routePlanner.pool + + // Connections are created as soon as a policy is set + setPolicy(pool, address, ConnectionPool.AddressPolicy(2)) + assertThat(pool.connectionCount()).isEqualTo(2) + + // Connections are replaced if they idle out or are evicted from the pool + evictAllConnections(pool) + assertThat(pool.connectionCount()).isEqualTo(2) + forceConnectionsToExpire(pool, routePlanner, expireTime) + assertThat(pool.connectionCount()).isEqualTo(2) + + // Excess connections aren't removed until they idle out, even if no longer needed + setPolicy(pool, address, ConnectionPool.AddressPolicy(1)) + assertThat(pool.connectionCount()).isEqualTo(2) + forceConnectionsToExpire(pool, routePlanner, expireTime) + assertThat(pool.connectionCount()).isEqualTo(1) + } + + @Test fun connectionPreWarmingHttp2() { + val expireSooner = System.nanoTime() + 1_000_000_000_000 + val expireLater = System.nanoTime() + 2_000_000_000_000 + + routePlanner.autoGeneratePlans = true + val address = routePlanner.address + val pool = routePlanner.pool + + // Add a connection to the pool that won't expire for a while + routePlanner.defaultConnectionIdleAtNanos = expireLater + setPolicy(pool, address, ConnectionPool.AddressPolicy(1)) + assertThat(pool.connectionCount()).isEqualTo(1) + + // All other connections created will expire sooner + routePlanner.defaultConnectionIdleAtNanos = expireSooner + + // Turn it into an http/2 connection that supports 5 concurrent streams + // which can satisfy a larger policy + val connection = routePlanner.plans.first().connection + val http2Connection = connectHttp2(peer, connection, 5) + setPolicy(pool, address, ConnectionPool.AddressPolicy(5)) + assertThat(pool.connectionCount()).isEqualTo(1) + + // Decrease the connection's max so that another connection is needed + updateMaxConcurrentStreams(http2Connection, 4) + assertThat(pool.connectionCount()).isEqualTo(2) + + // Increase the connection's max so that the new connection is no longer needed + updateMaxConcurrentStreams(http2Connection, 5) + forceConnectionsToExpire(pool, routePlanner, expireSooner) + assertThat(pool.connectionCount()).isEqualTo(1) + } + + private fun setPolicy( + pool: RealConnectionPool, + address: Address, + policy: ConnectionPool.AddressPolicy, + ) { + pool.setPolicy(address, policy) + routePlanner.factory.taskFaker.runTasks() } - // private fun setPolicy( - // pool: RealConnectionPool, - // address: Address, - // policy: ConnectionPool.AddressPolicy - // ) { - // pool.setPolicy(address, policy) - // factory.taskFaker.runTasks() - // } - // - // private fun evictAllConnections(pool: RealConnectionPool) { - // pool.evictAll() - // assertThat(pool.connectionCount()).isEqualTo(0) - // factory.taskFaker.runTasks() - // } - // - // private fun forceConnectionsToExpire(pool: RealConnectionPool, routePlanner: FakeRoutePlanner) { - // val idleTimeNanos = routePlanner.defaultConnectionIdleAtNanos + pool.keepAliveDurationNs - // repeat(pool.connectionCount()) { pool.cleanup(idleTimeNanos) } - // assertThat(pool.connectionCount()).isEqualTo(0) - // factory.taskFaker.runTasks() - // } + private fun evictAllConnections(pool: RealConnectionPool) { + pool.evictAll() + assertThat(pool.connectionCount()).isEqualTo(0) + routePlanner.factory.taskFaker.runTasks() + } + + private fun forceConnectionsToExpire( + pool: RealConnectionPool, + routePlanner: FakeRoutePlanner, + expireTime: Long, + ) { + val idleTimeNanos = expireTime + pool.keepAliveDurationNs + repeat(pool.connectionCount()) { pool.closeConnections(idleTimeNanos) } + routePlanner.factory.taskFaker.runTasks() + } + + private fun connectHttp2( + peer: MockHttp2Peer, + realConnection: RealConnection, + maxConcurrentStreams: Int, + ): Http2Connection { + // Write the mocking script. + val settings1 = Settings() + settings1[Settings.MAX_CONCURRENT_STREAMS] = maxConcurrentStreams + peer.sendFrame().settings(settings1) + peer.acceptFrame() // ACK + peer.sendFrame().ping(false, 2, 0) + peer.acceptFrame() // PING + peer.play() + + // Play it back. + val connection = + Http2Connection.Builder(true, TaskRunner.INSTANCE) + .socket(peer.openSocket()) + .pushObserver(Http2ConnectionTest.IGNORE) + .listener(realConnection) + .build() + connection.start(sendConnectionPreface = false) + + // verify the peer received the ACK + val ackFrame = peer.takeFrame() + assertThat(ackFrame.type).isEqualTo(Http2.TYPE_SETTINGS) + assertThat(ackFrame.streamId).isEqualTo(0) + assertThat(ackFrame.ack).isTrue() + + routePlanner.factory.taskFaker.runTasks() + + return connection + } + + private fun updateMaxConcurrentStreams( + connection: Http2Connection, + amount: Int, + ) { + val settings = Settings() + settings[Settings.MAX_CONCURRENT_STREAMS] = amount + connection.readerRunnable.applyAndAckSettings(true, settings) + assertThat(connection.peerSettings[Settings.MAX_CONCURRENT_STREAMS]).isEqualTo(amount) + routePlanner.factory.taskFaker.runTasks() + } /** Use a helper method so there's no hidden reference remaining on the stack. */ private fun allocateAndLeakAllocation( From 2b1100eae2fcfc53d56f7fb0a55fd3a55d93f0db Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sun, 14 Apr 2024 00:17:49 -0400 Subject: [PATCH 010/134] Fake time in ConnectionPoolTest (#8360) --- .../java/okhttp3/internal/connection/ConnectionPoolTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index a69bab91757b..240816047d82 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -204,7 +204,7 @@ class ConnectionPoolTest { } @Test fun connectionPreWarmingHttp1() { - val expireTime = System.nanoTime() + 1_000_000_000_000 + val expireTime = factory.taskFaker.nanoTime + 1_000_000_000_000 routePlanner.autoGeneratePlans = true routePlanner.defaultConnectionIdleAtNanos = expireTime @@ -229,8 +229,8 @@ class ConnectionPoolTest { } @Test fun connectionPreWarmingHttp2() { - val expireSooner = System.nanoTime() + 1_000_000_000_000 - val expireLater = System.nanoTime() + 2_000_000_000_000 + val expireSooner = factory.taskFaker.nanoTime + 1_000_000_000_000 + val expireLater = factory.taskFaker.nanoTime + 2_000_000_000_000 routePlanner.autoGeneratePlans = true val address = routePlanner.address From 348a9510a6be82920f303512508a4d30967d1a08 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sun, 14 Apr 2024 15:24:05 +0100 Subject: [PATCH 011/134] Support codespaces (#8347) * Create devcontainer.json * vs code extensions * simplify * Switch to java image * Check for android * Check for android --- .devcontainer/devcontainer.json | 19 +++++++++++++++++++ .vscode/settings.json | 3 +++ settings.gradle.kts | 12 +++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .vscode/settings.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..e356659135f2 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,19 @@ +{ + "image": "mcr.microsoft.com/devcontainers/java:17-bookworm", + "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "17" + } + }, + "customizations": { + "vscode": { + "settings": { + "java.server.launchMode": "Standard" + }, + "extensions": [ + "vscjava.vscode-java-pack", + "vscjava.vscode-gradle" + ] + } + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..849f79e6b5e0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.compile.nullAnalysis.mode": "automatic" +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 212d8251adf2..89ddf571639f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,5 @@ +import java.util.Properties + rootProject.name = "okhttp-parent" plugins { @@ -51,7 +53,15 @@ include(":container-tests") project(":okhttp-logging-interceptor").name = "logging-interceptor" -if (!isKnownBrokenIntelliJ()) { +val androidHome = System.getenv("ANDROID_HOME") +val localProperties = Properties().apply { + val file = File("local.properties") + if (file.exists()) { + load(file.inputStream()) + } +} +val sdkDir = localProperties.getProperty("sdk.dir") +if ((androidHome != null || sdkDir != null) && !isKnownBrokenIntelliJ()) { include(":okhttp-android") include(":android-test") include(":android-test-app") From ce28a31379ad56ec332339249c6a3f7c4aebfe1f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 14 Apr 2024 21:51:50 -0400 Subject: [PATCH 012/134] Update gradle/wrapper-validation-action action to v3 (#8365) * Update gradle/wrapper-validation-action action to v3 * Update build.yml --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Jake Wharton --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 01c62d5f301e..9868d0257e9b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v2 + - uses: gradle/actions/wrapper-validation@v3 - name: Validate Renovate uses: rinchsan/renovate-config-validator@v0.2.0 with: From a673f45ba6de670a0fa1d4e0e06e4e6d9fb2a26f Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Mon, 15 Apr 2024 08:37:21 +0100 Subject: [PATCH 013/134] Move RealCall and RealConnection to loom safe locks (#8290) --- .../main/kotlin/okhttp3/TestValueFactory.kt | 3 +- okhttp/src/main/kotlin/okhttp3/Dispatcher.kt | 76 +++-- .../internal/connection/ConnectPlan.kt | 3 +- .../okhttp3/internal/connection/RealCall.kt | 31 +- .../internal/connection/RealConnection.kt | 56 ++-- .../internal/connection/RealConnectionPool.kt | 33 +- .../internal/connection/RealRoutePlanner.kt | 5 +- .../okhttp3/internal/http2/Http2Connection.kt | 119 ++++---- .../okhttp3/internal/http2/Http2Stream.kt | 157 +++++----- .../okhttp3/internal/http2/Http2Writer.kt | 286 +++++++++--------- .../internal/connection/ConnectionPoolTest.kt | 5 +- 11 files changed, 419 insertions(+), 355 deletions(-) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt index bbc348fa8ab0..adaf9b99420d 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt @@ -31,6 +31,7 @@ import javax.net.SocketFactory import javax.net.ssl.HostnameVerifier import javax.net.ssl.HttpsURLConnection import javax.net.ssl.SSLSocketFactory +import kotlin.concurrent.withLock import okhttp3.internal.RecordingOkAuthenticator import okhttp3.internal.concurrent.TaskFaker import okhttp3.internal.concurrent.TaskRunner @@ -93,7 +94,7 @@ class TestValueFactory : Closeable { socket = Socket(), idleAtNs = idleAtNanos, ) - synchronized(result) { pool.put(result) } + result.lock.withLock { pool.put(result) } return result } diff --git a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt index e869053c1982..0494446a60ad 100644 --- a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt +++ b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt @@ -22,7 +22,9 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.SynchronousQueue import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit -import okhttp3.internal.assertThreadDoesntHoldLock +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock +import okhttp3.internal.assertNotHeld import okhttp3.internal.connection.RealCall import okhttp3.internal.connection.RealCall.AsyncCall import okhttp3.internal.okHttpName @@ -36,6 +38,8 @@ import okhttp3.internal.threadFactory * concurrently. */ class Dispatcher() { + internal val lock: ReentrantLock = ReentrantLock() + /** * The maximum number of requests to execute concurrently. Above this requests queue in memory, * waiting for the running calls to complete. @@ -43,10 +47,11 @@ class Dispatcher() { * If more than [maxRequests] requests are in flight when this is invoked, those requests will * remain in flight. */ - @get:Synchronized var maxRequests = 64 + var maxRequests = 64 + get() = lock.withLock { field } set(maxRequests) { require(maxRequests >= 1) { "max < 1: $maxRequests" } - synchronized(this) { + lock.withLock { field = maxRequests } promoteAndExecute() @@ -62,10 +67,11 @@ class Dispatcher() { * * WebSocket connections to hosts **do not** count against this limit. */ - @get:Synchronized var maxRequestsPerHost = 5 + var maxRequestsPerHost = 5 + get() = lock.withLock { field } set(maxRequestsPerHost) { require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" } - synchronized(this) { + lock.withLock { field = maxRequestsPerHost } promoteAndExecute() @@ -82,29 +88,31 @@ class Dispatcher() { * This means that if you are doing synchronous calls the network layer will not truly be idle * until every returned [Response] has been closed. */ - @set:Synchronized - @get:Synchronized var idleCallback: Runnable? = null + get() = lock.withLock { field } + set(value) { + lock.withLock { field = value } + } private var executorServiceOrNull: ExecutorService? = null - @get:Synchronized @get:JvmName("executorService") val executorService: ExecutorService - get() { - if (executorServiceOrNull == null) { - executorServiceOrNull = - ThreadPoolExecutor( - 0, - Int.MAX_VALUE, - 60, - TimeUnit.SECONDS, - SynchronousQueue(), - threadFactory("$okHttpName Dispatcher", false), - ) + get() = + lock.withLock { + if (executorServiceOrNull == null) { + executorServiceOrNull = + ThreadPoolExecutor( + 0, + Int.MAX_VALUE, + 60, + TimeUnit.SECONDS, + SynchronousQueue(), + threadFactory("$okHttpName Dispatcher", false), + ) + } + return executorServiceOrNull!! } - return executorServiceOrNull!! - } /** Ready async calls in the order they'll be run. */ private val readyAsyncCalls = ArrayDeque() @@ -120,7 +128,7 @@ class Dispatcher() { } internal fun enqueue(call: AsyncCall) { - synchronized(this) { + lock.withLock { readyAsyncCalls.add(call) // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to @@ -147,15 +155,17 @@ class Dispatcher() { * Cancel all calls currently enqueued or executing. Includes calls executed both * [synchronously][Call.execute] and [asynchronously][Call.enqueue]. */ - @Synchronized fun cancelAll() { - for (call in readyAsyncCalls) { - call.call.cancel() - } - for (call in runningAsyncCalls) { - call.call.cancel() - } - for (call in runningSyncCalls) { - call.cancel() + fun cancelAll() { + lock.withLock { + for (call in readyAsyncCalls) { + call.call.cancel() + } + for (call in runningAsyncCalls) { + call.call.cancel() + } + for (call in runningSyncCalls) { + call.cancel() + } } } @@ -167,11 +177,11 @@ class Dispatcher() { * @return true if the dispatcher is currently running calls. */ private fun promoteAndExecute(): Boolean { - this.assertThreadDoesntHoldLock() + lock.assertNotHeld() val executableCalls = mutableListOf() val isRunning: Boolean - synchronized(this) { + lock.withLock { val i = readyAsyncCalls.iterator() while (i.hasNext()) { val asyncCall = i.next() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt index a5c31f9cf03b..b4b5133e07a9 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt @@ -26,6 +26,7 @@ import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.SSLSocket +import kotlin.concurrent.withLock import okhttp3.CertificatePinner import okhttp3.ConnectionSpec import okhttp3.Handshake @@ -503,7 +504,7 @@ class ConnectPlan( val pooled3 = routePlanner.planReusePooledConnection(this, routes) if (pooled3 != null) return pooled3.connection - synchronized(connection) { + connection.lock.withLock { connectionPool.put(connection) user.acquireConnectionNoEvents(connection) } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt index 2f7be64ba69e..20e55f74461d 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt @@ -25,6 +25,8 @@ import java.util.concurrent.RejectedExecutionException import java.util.concurrent.TimeUnit.MILLISECONDS import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock import okhttp3.Call import okhttp3.Callback import okhttp3.EventListener @@ -32,8 +34,9 @@ import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response +import okhttp3.internal.assertHeld +import okhttp3.internal.assertNotHeld import okhttp3.internal.assertThreadDoesntHoldLock -import okhttp3.internal.assertThreadHoldsLock import okhttp3.internal.cache.CacheInterceptor import okhttp3.internal.closeQuietly import okhttp3.internal.http.BridgeInterceptor @@ -60,6 +63,8 @@ class RealCall( val originalRequest: Request, val forWebSocket: Boolean, ) : Call, Cloneable { + internal val lock: ReentrantLock = ReentrantLock() + private val connectionPool: RealConnectionPool = client.connectionPool.delegate internal val eventListener: EventListener = client.eventListenerFactory.create(this) @@ -95,7 +100,7 @@ class RealCall( internal var interceptorScopedExchange: Exchange? = null private set - // These properties are guarded by this. They are typically only accessed by the thread executing + // These properties are guarded by lock. They are typically only accessed by the thread executing // the call, but they may be accessed by other threads for duplex requests. /** True if this call still has a request body open. */ @@ -231,7 +236,7 @@ class RealCall( ) { check(interceptorScopedExchange == null) - synchronized(this) { + lock.withLock { check(!responseBodyOpen) { "cannot make a new request because the previous response is still open: " + "please call response.close()" @@ -265,7 +270,7 @@ class RealCall( /** Finds a new or pooled connection to carry a forthcoming request and response. */ internal fun initExchange(chain: RealInterceptorChain): Exchange { - synchronized(this) { + lock.withLock { check(expectMoreExchanges) { "released" } check(!responseBodyOpen) check(!requestBodyOpen) @@ -277,7 +282,7 @@ class RealCall( val result = Exchange(this, eventListener, exchangeFinder, codec) this.interceptorScopedExchange = result this.exchange = result - synchronized(this) { + lock.withLock { this.requestBodyOpen = true this.responseBodyOpen = true } @@ -287,7 +292,7 @@ class RealCall( } fun acquireConnectionNoEvents(connection: RealConnection) { - connection.assertThreadHoldsLock() + connection.lock.assertHeld() check(this.connection == null) this.connection = connection @@ -312,7 +317,7 @@ class RealCall( var bothStreamsDone = false var callDone = false - synchronized(this) { + lock.withLock { if (requestDone && requestBodyOpen || responseDone && responseBodyOpen) { if (requestDone) requestBodyOpen = false if (responseDone) responseBodyOpen = false @@ -335,7 +340,7 @@ class RealCall( internal fun noMoreExchanges(e: IOException?): IOException? { var callDone = false - synchronized(this) { + lock.withLock { if (expectMoreExchanges) { expectMoreExchanges = false callDone = !requestBodyOpen && !responseBodyOpen @@ -362,13 +367,13 @@ class RealCall( * additional context. Otherwise [e] is returned as-is. */ private fun callDone(e: E): E { - assertThreadDoesntHoldLock() + lock.assertNotHeld() val connection = this.connection if (connection != null) { - connection.assertThreadDoesntHoldLock() + connection.lock.assertNotHeld() val toClose: Socket? = - synchronized(connection) { + connection.lock.withLock { // Sets this.connection to null. releaseConnectionNoEvents() } @@ -399,7 +404,7 @@ class RealCall( */ internal fun releaseConnectionNoEvents(): Socket? { val connection = this.connection!! - connection.assertThreadHoldsLock() + connection.lock.assertHeld() val calls = connection.calls val index = calls.indexOfFirst { it.get() == this@RealCall } @@ -443,7 +448,7 @@ class RealCall( * This is usually due to either an exception or a retry. */ internal fun exitNetworkInterceptorExchange(closeExchange: Boolean) { - synchronized(this) { + lock.withLock { check(expectMoreExchanges) { "released" } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt index f379a4e29efa..abcbb90da1e9 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt @@ -23,8 +23,10 @@ import java.net.Socket import java.net.SocketException import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit.MILLISECONDS +import java.util.concurrent.locks.ReentrantLock import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.SSLSocket +import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.Connection import okhttp3.ConnectionListener @@ -33,8 +35,8 @@ import okhttp3.HttpUrl import okhttp3.OkHttpClient import okhttp3.Protocol import okhttp3.Route -import okhttp3.internal.assertThreadDoesntHoldLock -import okhttp3.internal.assertThreadHoldsLock +import okhttp3.internal.assertHeld +import okhttp3.internal.assertNotHeld import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.TaskRunner import okhttp3.internal.http.ExchangeCodec @@ -80,7 +82,9 @@ class RealConnection( ) : Http2Connection.Listener(), Connection, ExchangeCodec.Carrier { private var http2Connection: Http2Connection? = null - // These properties are guarded by this. + internal val lock: ReentrantLock = ReentrantLock() + + // These properties are guarded by lock. /** * If true, no new exchanges can be created on this connection. It is necessary to set this to @@ -129,19 +133,23 @@ class RealConnection( /** Prevent further exchanges from being created on this connection. */ override fun noNewExchanges() { - synchronized(this) { + lock.withLock { noNewExchanges = true } connectionListener.noNewExchanges(this) } /** Prevent this connection from being used for hosts other than the one in [route]. */ - @Synchronized internal fun noCoalescedConnections() { - noCoalescedConnections = true + internal fun noCoalescedConnections() { + lock.withLock { + noCoalescedConnections = true + } } - @Synchronized internal fun incrementSuccessCount() { - successCount++ + internal fun incrementSuccessCount() { + lock.withLock { + successCount++ + } } @Throws(IOException::class) @@ -179,7 +187,7 @@ class RealConnection( address: Address, routes: List?, ): Boolean { - assertThreadHoldsLock() + lock.assertHeld() // If this connection is not accepting new exchanges, we're done. if (calls.size >= allocationLimit || noNewExchanges) return false @@ -232,7 +240,7 @@ class RealConnection( } private fun supportsUrl(url: HttpUrl): Boolean { - assertThreadHoldsLock() + lock.assertHeld() val routeUrl = route.address.url @@ -308,7 +316,7 @@ class RealConnection( /** Returns true if this connection is ready to host new streams. */ fun isHealthy(doExtensiveChecks: Boolean): Boolean { - assertThreadDoesntHoldLock() + lock.assertNotHeld() val nowNs = System.nanoTime() @@ -326,7 +334,7 @@ class RealConnection( return http2Connection.isHealthy(nowNs) } - val idleDurationNs = synchronized(this) { nowNs - idleAtNs } + val idleDurationNs = lock.withLock { nowNs - idleAtNs } if (idleDurationNs >= IDLE_CONNECTION_HEALTHY_NS && doExtensiveChecks) { return socket.isHealthy(source) } @@ -341,19 +349,21 @@ class RealConnection( } /** When settings are received, adjust the allocation limit. */ - @Synchronized override fun onSettings( + override fun onSettings( connection: Http2Connection, settings: Settings, ) { - val oldLimit = allocationLimit - allocationLimit = settings.getMaxConcurrentStreams() - - if (allocationLimit < oldLimit) { - // We might need new connections to keep policies satisfied - connectionPool.scheduleOpener(route.address) - } else if (allocationLimit > oldLimit) { - // We might no longer need some connections - connectionPool.scheduleCloser() + lock.withLock { + val oldLimit = allocationLimit + allocationLimit = settings.getMaxConcurrentStreams() + + if (allocationLimit < oldLimit) { + // We might need new connections to keep policies satisfied + connectionPool.scheduleOpener(route.address) + } else if (allocationLimit > oldLimit) { + // We might no longer need some connections + connectionPool.scheduleCloser() + } } } @@ -387,7 +397,7 @@ class RealConnection( e: IOException?, ) { var noNewExchangesEvent = false - synchronized(this) { + lock.withLock { if (e is StreamResetException) { when { e.errorCode == ErrorCode.REFUSED_STREAM -> { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt index c4d376c92f11..b154ea493641 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt @@ -21,11 +21,12 @@ import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ThreadLocalRandom import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicReferenceFieldUpdater +import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.ConnectionListener import okhttp3.ConnectionPool import okhttp3.Route -import okhttp3.internal.assertThreadHoldsLock +import okhttp3.internal.assertHeld import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.Task import okhttp3.internal.concurrent.TaskQueue @@ -80,7 +81,7 @@ class RealConnectionPool( fun idleConnectionCount(): Int { return connections.count { - synchronized(it) { it.calls.isEmpty() } + it.lock.withLock { it.calls.isEmpty() } } } @@ -110,7 +111,7 @@ class RealConnectionPool( for (connection in connections) { // In the first synchronized block, acquire the connection if it can satisfy this call. val acquired = - synchronized(connection) { + connection.lock.withLock { when { requireMultiplexed && !connection.isMultiplexed -> false !connection.isEligible(address, routes) -> false @@ -129,7 +130,7 @@ class RealConnectionPool( // the hook to close this connection if it's no longer in use. val noNewExchangesEvent: Boolean val toClose: Socket? = - synchronized(connection) { + connection.lock.withLock { noNewExchangesEvent = !connection.noNewExchanges connection.noNewExchanges = true connectionUser.releaseConnectionNoEvents() @@ -145,7 +146,7 @@ class RealConnectionPool( } fun put(connection: RealConnection) { - connection.assertThreadHoldsLock() + connection.lock.assertHeld() connections.add(connection) // connection.queueEvent { connectionListener.connectEnd(connection) } @@ -157,7 +158,7 @@ class RealConnectionPool( * removed from the pool and should be closed. */ fun connectionBecameIdle(connection: RealConnection): Boolean { - connection.assertThreadHoldsLock() + connection.lock.assertHeld() return if (connection.noNewExchanges || maxIdleConnections == 0) { connection.noNewExchanges = true @@ -176,13 +177,13 @@ class RealConnectionPool( while (i.hasNext()) { val connection = i.next() val socketToClose = - synchronized(connection) { + connection.lock.withLock { if (connection.calls.isEmpty()) { i.remove() connection.noNewExchanges = true - return@synchronized connection.socket() + return@withLock connection.socket() } else { - return@synchronized null + return@withLock null } } if (socketToClose != null) { @@ -214,7 +215,7 @@ class RealConnectionPool( } for (connection in connections) { val addressState = addressStates[connection.route.address] ?: continue - synchronized(connection) { + connection.lock.withLock { addressState.concurrentCallCapacity += connection.allocationLimit } } @@ -237,11 +238,11 @@ class RealConnectionPool( var inUseConnectionCount = 0 var evictableConnectionCount = 0 for (connection in connections) { - synchronized(connection) { + connection.lock.withLock { // If the connection is in use, keep searching. if (pruneAndGetAllocationCount(connection, now) > 0) { inUseConnectionCount++ - return@synchronized + return@withLock } val idleAtNs = connection.idleAtNs @@ -285,7 +286,7 @@ class RealConnectionPool( when { toEvict != null -> { // We've chosen a connection to evict. Confirm it's still okay to be evicted, then close it. - synchronized(toEvict) { + toEvict.lock.withLock { if (toEvict.calls.isNotEmpty()) return 0L // No longer idle. if (toEvict.idleAtNs != toEvictIdleAtNs) return 0L // No longer oldest. toEvict.noNewExchanges = true @@ -336,7 +337,7 @@ class RealConnectionPool( connection: RealConnection, now: Long, ): Int { - connection.assertThreadHoldsLock() + connection.lock.assertHeld() val references = connection.calls var i = 0 @@ -415,7 +416,7 @@ class RealConnectionPool( var concurrentCallCapacity = 0 for (connection in connections) { if (state.address != connection.route.address) continue - synchronized(connection) { + connection.lock.withLock { concurrentCallCapacity += connection.allocationLimit } @@ -430,7 +431,7 @@ class RealConnectionPool( // RealRoutePlanner will add the connection to the pool itself, other RoutePlanners may not // TODO: make all RoutePlanners consistent in this behavior if (connection !in connections) { - synchronized(connection) { put(connection) } + connection.lock.withLock { put(connection) } } return 0L // run again immediately to create more connections if needed diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt index 3684a19da56c..e87b12908b24 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt @@ -19,6 +19,7 @@ import java.io.IOException import java.net.HttpURLConnection import java.net.Socket import java.net.UnknownServiceException +import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.ConnectionSpec import okhttp3.HttpUrl @@ -94,7 +95,7 @@ class RealRoutePlanner( val healthy = candidate.isHealthy(connectionUser.doExtensiveHealthChecks()) var noNewExchangesEvent = false val toClose: Socket? = - synchronized(candidate) { + candidate.lock.withLock { when { !healthy -> { noNewExchangesEvent = !candidate.noNewExchanges @@ -319,7 +320,7 @@ class RealRoutePlanner( * connections. */ private fun retryRoute(connection: RealConnection): Route? { - return synchronized(connection) { + return connection.lock.withLock { when { connection.routeFailureCount != 0 -> null diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt index 686568d3d0fd..5505a46d1f61 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt @@ -20,6 +20,9 @@ import java.io.IOException import java.io.InterruptedIOException import java.net.Socket import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock import okhttp3.internal.EMPTY_BYTE_ARRAY import okhttp3.internal.EMPTY_HEADERS import okhttp3.internal.assertThreadDoesntHoldLock @@ -29,13 +32,11 @@ import okhttp3.internal.http2.ErrorCode.REFUSED_STREAM import okhttp3.internal.http2.Settings.Companion.DEFAULT_INITIAL_WINDOW_SIZE import okhttp3.internal.http2.flowcontrol.WindowCounter import okhttp3.internal.ignoreIoExceptions -import okhttp3.internal.notifyAll import okhttp3.internal.okHttpName import okhttp3.internal.peerName import okhttp3.internal.platform.Platform import okhttp3.internal.platform.Platform.Companion.INFO import okhttp3.internal.toHeaders -import okhttp3.internal.wait import okio.Buffer import okio.BufferedSink import okio.BufferedSource @@ -54,7 +55,10 @@ import okio.source */ @Suppress("NAME_SHADOWING") class Http2Connection internal constructor(builder: Builder) : Closeable { - // Internal state of this connection is guarded by 'this'. No blocking operations may be + internal val lock: ReentrantLock = ReentrantLock() + internal val condition: Condition = lock.newCondition() + + // Internal state of this connection is guarded by 'lock'. No blocking operations may be // performed while holding this lock! // // Socket writes are guarded by frameWriter. @@ -149,12 +153,12 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { val pingIntervalNanos = TimeUnit.MILLISECONDS.toNanos(builder.pingIntervalMillis.toLong()) writerQueue.schedule("$connectionName ping", pingIntervalNanos) { val failDueToMissingPong = - synchronized(this@Http2Connection) { + lock.withLock { if (intervalPongsReceived < intervalPingsSent) { - return@synchronized true + return@withLock true } else { intervalPingsSent++ - return@synchronized false + return@withLock false } } if (failDueToMissingPong) { @@ -171,30 +175,31 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** * Returns the number of [open streams][Http2Stream.isOpen] on this connection. */ - @Synchronized - fun openStreamCount(): Int = streams.size + fun openStreamCount(): Int = lock.withLock { streams.size } - @Synchronized - fun getStream(id: Int): Http2Stream? = streams[id] + fun getStream(id: Int): Http2Stream? = lock.withLock { streams[id] } - @Synchronized internal fun removeStream(streamId: Int): Http2Stream? { - val stream = streams.remove(streamId) + lock.withLock { + val stream = streams.remove(streamId) - // The removed stream may be blocked on a connection-wide window update. - notifyAll() + // The removed stream may be blocked on a connection-wide window update. + condition.signalAll() - return stream + return stream + } } - @Synchronized internal fun updateConnectionFlowControl(read: Long) { - readBytes.update(total = read) - val readBytesToAcknowledge = readBytes.unacknowledged - if (readBytesToAcknowledge >= okHttpSettings.initialWindowSize / 2) { - writeWindowUpdateLater(0, readBytesToAcknowledge) - readBytes.update(acknowledged = readBytesToAcknowledge) + internal fun updateConnectionFlowControl(read: Long) { + lock.withLock { + readBytes.update(total = read) + val readBytesToAcknowledge = readBytes.unacknowledged + if (readBytesToAcknowledge >= okHttpSettings.initialWindowSize / 2) { + writeWindowUpdateLater(0, readBytesToAcknowledge) + readBytes.update(acknowledged = readBytesToAcknowledge) + } + flowControlListener.receivingConnectionWindowChanged(readBytes) } - flowControlListener.receivingConnectionWindowChanged(readBytes) } /** @@ -240,8 +245,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { val stream: Http2Stream val streamId: Int - synchronized(writer) { - synchronized(this) { + writer.lock.withLock { + lock.withLock { if (nextStreamId > Int.MAX_VALUE / 2) { shutdown(REFUSED_STREAM) } @@ -311,7 +316,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { var byteCount = byteCount while (byteCount > 0L) { var toWrite: Int - synchronized(this@Http2Connection) { + lock.withLock { try { while (writeBytesTotal >= writeBytesMaximum) { // Before blocking, confirm that the stream we're writing is still open. It's possible @@ -319,7 +324,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { if (!streams.containsKey(streamId)) { throw IOException("stream closed") } - this@Http2Connection.wait() // Wait until we receive a WINDOW_UPDATE. + condition.await() // Wait until we receive a WINDOW_UPDATE. } } catch (e: InterruptedException) { Thread.currentThread().interrupt() // Retain interrupted status. @@ -392,7 +397,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** For testing: sends a ping to be awaited with [awaitPong]. */ @Throws(InterruptedException::class) fun writePing() { - synchronized(this) { + lock.withLock { awaitPingsSent++ } @@ -401,11 +406,12 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } /** For testing: awaits a pong. */ - @Synchronized @Throws(InterruptedException::class) fun awaitPong() { - while (awaitPongsReceived < awaitPingsSent) { - wait() + lock.withLock { + while (awaitPongsReceived < awaitPingsSent) { + condition.await() + } } } @@ -421,9 +427,9 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { */ @Throws(IOException::class) fun shutdown(statusCode: ErrorCode) { - synchronized(writer) { + writer.lock.withLock { val lastGoodStreamId: Int - synchronized(this) { + lock.withLock { if (isShutdown) { return } @@ -456,7 +462,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } var streamsToClose: Array? = null - synchronized(this) { + lock.withLock { if (streams.isNotEmpty()) { streamsToClose = streams.values.toTypedArray() streams.clear() @@ -516,8 +522,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** Merges [settings] into this peer's settings and sends them to the remote peer. */ @Throws(IOException::class) fun setSettings(settings: Settings) { - synchronized(writer) { - synchronized(this) { + writer.lock.withLock { + lock.withLock { if (isShutdown) { throw ConnectionShutdownException() } @@ -527,14 +533,15 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } } - @Synchronized fun isHealthy(nowNs: Long): Boolean { - if (isShutdown) return false + lock.withLock { + if (isShutdown) return false - // A degraded pong is overdue. - if (degradedPongsReceived < degradedPingsSent && nowNs >= degradedPongDeadlineNs) return false + // A degraded pong is overdue. + if (degradedPongsReceived < degradedPingsSent && nowNs >= degradedPongDeadlineNs) return false - return true + return true + } } /** @@ -553,7 +560,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { * The deadline is currently hardcoded. We may make this configurable in the future! */ internal fun sendDegradedPingLater() { - synchronized(this) { + lock.withLock { if (degradedPongsReceived < degradedPingsSent) return // Already awaiting a degraded pong. degradedPingsSent++ degradedPongDeadlineNs = System.nanoTime() + DEGRADED_PONG_TIMEOUT_NS @@ -682,7 +689,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { return } val stream: Http2Stream? - synchronized(this@Http2Connection) { + lock.withLock { stream = getStream(streamId) if (stream == null) { @@ -761,8 +768,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { var delta: Long var streamsToNotify: Array? var newPeerSettings: Settings - synchronized(writer) { - synchronized(this@Http2Connection) { + writer.lock.withLock { + lock.withLock { val previousPeerSettings = peerSettings newPeerSettings = if (clearPrevious) { @@ -796,7 +803,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } if (streamsToNotify != null) { for (stream in streamsToNotify!!) { - synchronized(stream) { + stream.lock.withLock { stream.addBytesToWriteWindow(delta) } } @@ -813,7 +820,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { payload2: Int, ) { if (ack) { - synchronized(this@Http2Connection) { + lock.withLock { when (payload1) { INTERVAL_PING -> { intervalPongsReceived++ @@ -823,7 +830,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } AWAIT_PING -> { awaitPongsReceived++ - this@Http2Connection.notifyAll() + condition.signalAll() } else -> { // Ignore an unexpected pong. @@ -849,7 +856,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { // Copy the streams first. We don't want to hold a lock when we call receiveRstStream(). val streamsCopy: Array - synchronized(this@Http2Connection) { + lock.withLock { streamsCopy = streams.values.toTypedArray() isShutdown = true } @@ -868,14 +875,14 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { windowSizeIncrement: Long, ) { if (streamId == 0) { - synchronized(this@Http2Connection) { + lock.withLock { writeBytesMaximum += windowSizeIncrement - this@Http2Connection.notifyAll() + condition.signalAll() } } else { val stream = getStream(streamId) if (stream != null) { - synchronized(stream) { + stream.lock.withLock { stream.addBytesToWriteWindow(windowSizeIncrement) } } @@ -918,7 +925,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { streamId: Int, requestHeaders: List
, ) { - synchronized(this) { + lock.withLock { if (streamId in currentPushRequests) { writeSynResetLater(streamId, ErrorCode.PROTOCOL_ERROR) return @@ -930,7 +937,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { ignoreIoExceptions { if (cancel) { writer.rstStream(streamId, ErrorCode.CANCEL) - synchronized(this@Http2Connection) { + lock.withLock { currentPushRequests.remove(streamId) } } @@ -948,7 +955,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { ignoreIoExceptions { if (cancel) writer.rstStream(streamId, ErrorCode.CANCEL) if (cancel || inFinished) { - synchronized(this@Http2Connection) { + lock.withLock { currentPushRequests.remove(streamId) } } @@ -975,7 +982,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { val cancel = pushObserver.onData(streamId, buffer, byteCount, inFinished) if (cancel) writer.rstStream(streamId, ErrorCode.CANCEL) if (cancel || inFinished) { - synchronized(this@Http2Connection) { + lock.withLock { currentPushRequests.remove(streamId) } } @@ -989,7 +996,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { ) { pushQueue.execute("$connectionName[$streamId] onReset") { pushObserver.onReset(streamId, errorCode) - synchronized(this@Http2Connection) { + lock.withLock { currentPushRequests.remove(streamId) } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt index dd1fa1e49584..32a419561505 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt @@ -20,13 +20,14 @@ import java.io.IOException import java.io.InterruptedIOException import java.net.SocketTimeoutException import java.util.ArrayDeque +import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.ReentrantLock +import kotlin.concurrent.withLock import okhttp3.Headers import okhttp3.internal.EMPTY_HEADERS -import okhttp3.internal.assertThreadDoesntHoldLock +import okhttp3.internal.assertNotHeld import okhttp3.internal.http2.flowcontrol.WindowCounter -import okhttp3.internal.notifyAll import okhttp3.internal.toHeaderList -import okhttp3.internal.wait import okio.AsyncTimeout import okio.Buffer import okio.BufferedSource @@ -43,7 +44,10 @@ class Http2Stream internal constructor( inFinished: Boolean, headers: Headers?, ) { - // Internal state is guarded by this. No long-running or potentially blocking operations are + internal val lock: ReentrantLock = ReentrantLock() + val condition: Condition = lock.newCondition() + + // Internal state is guarded by lock. No long-running or potentially blocking operations are // performed while the lock is held. /** The bytes consumed and acknowledged by the stream. */ @@ -82,7 +86,8 @@ class Http2Stream internal constructor( * If there are multiple reasons to abnormally close this stream (such as both peers closing it * near-simultaneously) then this is the first reason known to this peer. */ - @get:Synchronized internal var errorCode: ErrorCode? = null + internal var errorCode: ErrorCode? = null + get() = lock.withLock { field } /** The exception that explains [errorCode]. Null if no exception was provided. */ internal var errorException: IOException? = null @@ -106,17 +111,19 @@ class Http2Stream internal constructor( * not open. This is because input data is buffered. */ val isOpen: Boolean - @Synchronized get() { - if (errorCode != null) { - return false - } - if ((source.finished || source.closed) && - (sink.finished || sink.closed) && - hasResponseHeaders - ) { - return false + get() { + lock.withLock { + if (errorCode != null) { + return false + } + if ((source.finished || source.closed) && + (sink.finished || sink.closed) && + hasResponseHeaders + ) { + return false + } + return true } - return true } /** Returns true if this stream was created by this peer. */ @@ -135,42 +142,44 @@ class Http2Stream internal constructor( * This is true after a `Expect-Continue` request, false for duplex requests, and false for * all other requests. */ - @Synchronized @Throws(IOException::class) fun takeHeaders(callerIsIdle: Boolean = false): Headers { - while (headersQueue.isEmpty() && errorCode == null) { - val doReadTimeout = callerIsIdle || doReadTimeout() - if (doReadTimeout) { - readTimeout.enter() - } - try { - waitForIo() - } finally { + lock.withLock { + while (headersQueue.isEmpty() && errorCode == null) { + val doReadTimeout = callerIsIdle || doReadTimeout() if (doReadTimeout) { - readTimeout.exitAndThrowIfTimedOut() + readTimeout.enter() + } + try { + waitForIo() + } finally { + if (doReadTimeout) { + readTimeout.exitAndThrowIfTimedOut() + } } } + if (headersQueue.isNotEmpty()) { + return headersQueue.removeFirst() + } + throw errorException ?: StreamResetException(errorCode!!) } - if (headersQueue.isNotEmpty()) { - return headersQueue.removeFirst() - } - throw errorException ?: StreamResetException(errorCode!!) } /** * Returns the trailers. It is only safe to call this once the source stream has been completely * exhausted. */ - @Synchronized @Throws(IOException::class) fun trailers(): Headers { - if (source.finished && source.receiveBuffer.exhausted() && source.readBuffer.exhausted()) { - return source.trailers ?: EMPTY_HEADERS - } - if (errorCode != null) { - throw errorException ?: StreamResetException(errorCode!!) + lock.withLock { + if (source.finished && source.receiveBuffer.exhausted() && source.readBuffer.exhausted()) { + return source.trailers ?: EMPTY_HEADERS + } + if (errorCode != null) { + throw errorException ?: StreamResetException(errorCode!!) + } + throw IllegalStateException("too early; can't read the trailers yet") } - throw IllegalStateException("too early; can't read the trailers yet") } /** @@ -187,21 +196,21 @@ class Http2Stream internal constructor( outFinished: Boolean, flushHeaders: Boolean, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() var flushHeaders = flushHeaders - synchronized(this) { + lock.withLock { this.hasResponseHeaders = true if (outFinished) { this.sink.finished = true - this@Http2Stream.notifyAll() // Because doReadTimeout() may have changed. + condition.signalAll() // Because doReadTimeout() may have changed. } } // Only DATA frames are subject to flow-control. Transmit the HEADER frame if the connection // flow-control window is fully depleted. if (!flushHeaders) { - synchronized(connection) { + lock.withLock { flushHeaders = (connection.writeBytesTotal >= connection.writeBytesMaximum) } } @@ -214,7 +223,7 @@ class Http2Stream internal constructor( } fun enqueueTrailers(trailers: Headers) { - synchronized(this) { + lock.withLock { check(!sink.finished) { "already finished" } require(trailers.size != 0) { "trailers.size() == 0" } this.sink.trailers = trailers @@ -235,7 +244,7 @@ class Http2Stream internal constructor( * not yet been sent. */ fun getSink(): Sink { - synchronized(this) { + lock.withLock { check(hasResponseHeaders || isLocallyInitiated) { "reply before requesting the sink" } @@ -273,15 +282,15 @@ class Http2Stream internal constructor( errorCode: ErrorCode, errorException: IOException?, ): Boolean { - this.assertThreadDoesntHoldLock() + lock.assertNotHeld() - synchronized(this) { + lock.withLock { if (this.errorCode != null) { return false } this.errorCode = errorCode this.errorException = errorException - notifyAll() + condition.signalAll() if (source.finished && sink.finished) { return false } @@ -295,7 +304,7 @@ class Http2Stream internal constructor( source: BufferedSource, length: Int, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() this.source.receive(source, length.toLong()) } @@ -305,10 +314,10 @@ class Http2Stream internal constructor( headers: Headers, inFinished: Boolean, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() val open: Boolean - synchronized(this) { + lock.withLock { if (!hasResponseHeaders || headers[Header.RESPONSE_STATUS_UTF8] != null || headers[Header.TARGET_METHOD_UTF8] != null @@ -322,17 +331,19 @@ class Http2Stream internal constructor( this.source.finished = true } open = isOpen - notifyAll() + condition.signalAll() } if (!open) { connection.removeStream(id) } } - @Synchronized fun receiveRstStream(errorCode: ErrorCode) { - if (this.errorCode == null) { - this.errorCode = errorCode - notifyAll() + fun receiveRstStream(errorCode: ErrorCode) { + lock.withLock { + if (this.errorCode == null) { + this.errorCode = errorCode + condition.signalAll() + } } } @@ -389,7 +400,7 @@ class Http2Stream internal constructor( // 1. Decide what to do in a synchronized block. - synchronized(this@Http2Stream) { + lock.withLock { val doReadTimeout = doReadTimeout() if (doReadTimeout) { readTimeout.enter() @@ -452,7 +463,7 @@ class Http2Stream internal constructor( } private fun updateConnectionFlowControl(read: Long) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() connection.updateConnectionFlowControl(read) } @@ -466,14 +477,14 @@ class Http2Stream internal constructor( source: BufferedSource, byteCount: Long, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() var remainingByteCount = byteCount while (remainingByteCount > 0L) { val finished: Boolean val flowControlError: Boolean - synchronized(this@Http2Stream) { + lock.withLock { finished = this.finished flowControlError = remainingByteCount + readBuffer.size > maxByteCount } @@ -499,14 +510,14 @@ class Http2Stream internal constructor( // Move the received data to the read buffer to the reader can read it. If this source has // been closed since this read began we must discard the incoming data and tell the // connection we've done so. - synchronized(this@Http2Stream) { + lock.withLock { if (closed) { receiveBuffer.clear() } else { val wasEmpty = readBuffer.size == 0L readBuffer.writeAll(receiveBuffer) if (wasEmpty) { - this@Http2Stream.notifyAll() + condition.signalAll() } } } @@ -527,11 +538,11 @@ class Http2Stream internal constructor( @Throws(IOException::class) override fun close() { val bytesDiscarded: Long - synchronized(this@Http2Stream) { + lock.withLock { closed = true bytesDiscarded = readBuffer.size readBuffer.clear() - this@Http2Stream.notifyAll() // TODO(jwilson): Unnecessary? + condition.signalAll() // TODO(jwilson): Unnecessary? } if (bytesDiscarded > 0L) { updateConnectionFlowControl(bytesDiscarded) @@ -542,11 +553,11 @@ class Http2Stream internal constructor( @Throws(IOException::class) internal fun cancelStreamIfNecessary() { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() val open: Boolean val cancel: Boolean - synchronized(this) { + lock.withLock { cancel = !source.finished && source.closed && (sink.finished || sink.closed) open = isOpen } @@ -581,7 +592,7 @@ class Http2Stream internal constructor( source: Buffer, byteCount: Long, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() sendBuffer.write(source, byteCount) while (sendBuffer.size >= EMIT_BUFFER_SIZE) { @@ -597,7 +608,7 @@ class Http2Stream internal constructor( private fun emitFrame(outFinishedOnLastFrame: Boolean) { val toWrite: Long val outFinished: Boolean - synchronized(this@Http2Stream) { + lock.withLock { writeTimeout.enter() try { while (writeBytesTotal >= writeBytesMaximum && @@ -627,9 +638,9 @@ class Http2Stream internal constructor( @Throws(IOException::class) override fun flush() { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() - synchronized(this@Http2Stream) { + lock.withLock { checkOutNotClosed() } // TODO(jwilson): flush the connection?! @@ -643,10 +654,10 @@ class Http2Stream internal constructor( @Throws(IOException::class) override fun close() { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() val outFinished: Boolean - synchronized(this@Http2Stream) { + lock.withLock { if (closed) return outFinished = errorCode == null } @@ -675,9 +686,9 @@ class Http2Stream internal constructor( } } } - synchronized(this@Http2Stream) { + lock.withLock { closed = true - this@Http2Stream.notifyAll() // Because doReadTimeout() may have changed. + condition.signalAll() // Because doReadTimeout() may have changed. } connection.flush() cancelStreamIfNecessary() @@ -692,7 +703,7 @@ class Http2Stream internal constructor( fun addBytesToWriteWindow(delta: Long) { writeBytesMaximum += delta if (delta > 0L) { - this@Http2Stream.notifyAll() + condition.signalAll() } } @@ -712,7 +723,7 @@ class Http2Stream internal constructor( @Throws(InterruptedIOException::class) internal fun waitForIo() { try { - wait() + condition.await() } catch (_: InterruptedException) { Thread.currentThread().interrupt() // Retain interrupted status. throw InterruptedIOException() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt index ff72536e9b49..496757427193 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt @@ -17,8 +17,10 @@ package okhttp3.internal.http2 import java.io.Closeable import java.io.IOException +import java.util.concurrent.locks.ReentrantLock import java.util.logging.Level.FINE import java.util.logging.Logger +import kotlin.concurrent.withLock import okhttp3.internal.format import okhttp3.internal.http2.Http2.CONNECTION_PREFACE import okhttp3.internal.http2.Http2.FLAG_ACK @@ -47,39 +49,43 @@ class Http2Writer( private val sink: BufferedSink, private val client: Boolean, ) : Closeable { + internal val lock: ReentrantLock = ReentrantLock() + private val hpackBuffer: Buffer = Buffer() private var maxFrameSize: Int = INITIAL_MAX_FRAME_SIZE private var closed: Boolean = false val hpackWriter: Hpack.Writer = Hpack.Writer(out = hpackBuffer) - @Synchronized @Throws(IOException::class) fun connectionPreface() { - if (closed) throw IOException("closed") - if (!client) return // Nothing to write; servers don't send connection headers! - if (logger.isLoggable(FINE)) { - logger.fine(format(">> CONNECTION ${CONNECTION_PREFACE.hex()}")) + lock.withLock { + if (closed) throw IOException("closed") + if (!client) return // Nothing to write; servers don't send connection headers! + if (logger.isLoggable(FINE)) { + logger.fine(format(">> CONNECTION ${CONNECTION_PREFACE.hex()}")) + } + sink.write(CONNECTION_PREFACE) + sink.flush() } - sink.write(CONNECTION_PREFACE) - sink.flush() } /** Applies `peerSettings` and then sends a settings ACK. */ - @Synchronized @Throws(IOException::class) fun applyAndAckSettings(peerSettings: Settings) { - if (closed) throw IOException("closed") - this.maxFrameSize = peerSettings.getMaxFrameSize(maxFrameSize) - if (peerSettings.headerTableSize != -1) { - hpackWriter.resizeHeaderTable(peerSettings.headerTableSize) + lock.withLock { + if (closed) throw IOException("closed") + this.maxFrameSize = peerSettings.getMaxFrameSize(maxFrameSize) + if (peerSettings.headerTableSize != -1) { + hpackWriter.resizeHeaderTable(peerSettings.headerTableSize) + } + frameHeader( + streamId = 0, + length = 0, + type = TYPE_SETTINGS, + flags = FLAG_ACK, + ) + sink.flush() } - frameHeader( - streamId = 0, - length = 0, - type = TYPE_SETTINGS, - flags = FLAG_ACK, - ) - sink.flush() } /** @@ -94,54 +100,57 @@ class Http2Writer( * @param promisedStreamId server-initiated stream ID. Must be an even number. * @param requestHeaders minimally includes `:method`, `:scheme`, `:authority`, and `:path`. */ - @Synchronized @Throws(IOException::class) fun pushPromise( streamId: Int, promisedStreamId: Int, requestHeaders: List
, ) { - if (closed) throw IOException("closed") - hpackWriter.writeHeaders(requestHeaders) + lock.withLock { + if (closed) throw IOException("closed") + hpackWriter.writeHeaders(requestHeaders) - val byteCount = hpackBuffer.size - val length = minOf(maxFrameSize - 4L, byteCount).toInt() - frameHeader( - streamId = streamId, - length = length + 4, - type = TYPE_PUSH_PROMISE, - flags = if (byteCount == length.toLong()) FLAG_END_HEADERS else 0, - ) - sink.writeInt(promisedStreamId and 0x7fffffff) - sink.write(hpackBuffer, length.toLong()) + val byteCount = hpackBuffer.size + val length = minOf(maxFrameSize - 4L, byteCount).toInt() + frameHeader( + streamId = streamId, + length = length + 4, + type = TYPE_PUSH_PROMISE, + flags = if (byteCount == length.toLong()) FLAG_END_HEADERS else 0, + ) + sink.writeInt(promisedStreamId and 0x7fffffff) + sink.write(hpackBuffer, length.toLong()) - if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) + if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) + } } - @Synchronized @Throws(IOException::class) fun flush() { - if (closed) throw IOException("closed") - sink.flush() + lock.withLock { + if (closed) throw IOException("closed") + sink.flush() + } } - @Synchronized @Throws(IOException::class) fun rstStream( streamId: Int, errorCode: ErrorCode, ) { - if (closed) throw IOException("closed") - require(errorCode.httpCode != -1) + lock.withLock { + if (closed) throw IOException("closed") + require(errorCode.httpCode != -1) - frameHeader( - streamId = streamId, - length = 4, - type = TYPE_RST_STREAM, - flags = FLAG_NONE, - ) - sink.writeInt(errorCode.httpCode) - sink.flush() + frameHeader( + streamId = streamId, + length = 4, + type = TYPE_RST_STREAM, + flags = FLAG_NONE, + ) + sink.writeInt(errorCode.httpCode) + sink.flush() + } } /** The maximum size of bytes that may be sent in a single call to [data]. */ @@ -154,7 +163,6 @@ class Http2Writer( * @param source the buffer to draw bytes from. May be null if byteCount is 0. * @param byteCount must be between 0 and the minimum of `source.length` and [maxDataLength]. */ - @Synchronized @Throws(IOException::class) fun data( outFinished: Boolean, @@ -162,10 +170,12 @@ class Http2Writer( source: Buffer?, byteCount: Int, ) { - if (closed) throw IOException("closed") - var flags = FLAG_NONE - if (outFinished) flags = flags or FLAG_END_STREAM - dataFrame(streamId, flags, source, byteCount) + lock.withLock { + if (closed) throw IOException("closed") + var flags = FLAG_NONE + if (outFinished) flags = flags or FLAG_END_STREAM + dataFrame(streamId, flags, source, byteCount) + } } @Throws(IOException::class) @@ -187,51 +197,53 @@ class Http2Writer( } /** Write okhttp's settings to the peer. */ - @Synchronized @Throws(IOException::class) fun settings(settings: Settings) { - if (closed) throw IOException("closed") - frameHeader( - streamId = 0, - length = settings.size() * 6, - type = TYPE_SETTINGS, - flags = FLAG_NONE, - ) - for (i in 0 until Settings.COUNT) { - if (!settings.isSet(i)) continue - val id = - when (i) { - 4 -> 3 // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. - 7 -> 4 // SETTINGS_INITIAL_WINDOW_SIZE renumbered. - else -> i - } - sink.writeShort(id) - sink.writeInt(settings[i]) + lock.withLock { + if (closed) throw IOException("closed") + frameHeader( + streamId = 0, + length = settings.size() * 6, + type = TYPE_SETTINGS, + flags = FLAG_NONE, + ) + for (i in 0 until Settings.COUNT) { + if (!settings.isSet(i)) continue + val id = + when (i) { + 4 -> 3 // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. + 7 -> 4 // SETTINGS_INITIAL_WINDOW_SIZE renumbered. + else -> i + } + sink.writeShort(id) + sink.writeInt(settings[i]) + } + sink.flush() } - sink.flush() } /** * Send a connection-level ping to the peer. `ack` indicates this is a reply. The data in * `payload1` and `payload2` opaque binary, and there are no rules on the content. */ - @Synchronized @Throws(IOException::class) fun ping( ack: Boolean, payload1: Int, payload2: Int, ) { - if (closed) throw IOException("closed") - frameHeader( - streamId = 0, - length = 8, - type = TYPE_PING, - flags = if (ack) FLAG_ACK else FLAG_NONE, - ) - sink.writeInt(payload1) - sink.writeInt(payload2) - sink.flush() + lock.withLock { + if (closed) throw IOException("closed") + frameHeader( + streamId = 0, + length = 8, + type = TYPE_PING, + flags = if (ack) FLAG_ACK else FLAG_NONE, + ) + sink.writeInt(payload1) + sink.writeInt(payload2) + sink.flush() + } } /** @@ -242,61 +254,63 @@ class Http2Writer( * @param errorCode reason for closing the connection. * @param debugData only valid for HTTP/2; opaque debug data to send. */ - @Synchronized @Throws(IOException::class) fun goAway( lastGoodStreamId: Int, errorCode: ErrorCode, debugData: ByteArray, ) { - if (closed) throw IOException("closed") - require(errorCode.httpCode != -1) { "errorCode.httpCode == -1" } - frameHeader( - streamId = 0, - length = 8 + debugData.size, - type = TYPE_GOAWAY, - flags = FLAG_NONE, - ) - sink.writeInt(lastGoodStreamId) - sink.writeInt(errorCode.httpCode) - if (debugData.isNotEmpty()) { - sink.write(debugData) + lock.withLock { + if (closed) throw IOException("closed") + require(errorCode.httpCode != -1) { "errorCode.httpCode == -1" } + frameHeader( + streamId = 0, + length = 8 + debugData.size, + type = TYPE_GOAWAY, + flags = FLAG_NONE, + ) + sink.writeInt(lastGoodStreamId) + sink.writeInt(errorCode.httpCode) + if (debugData.isNotEmpty()) { + sink.write(debugData) + } + sink.flush() } - sink.flush() } /** * Inform peer that an additional `windowSizeIncrement` bytes can be sent on `streamId`, or the * connection if `streamId` is zero. */ - @Synchronized @Throws(IOException::class) fun windowUpdate( streamId: Int, windowSizeIncrement: Long, ) { - if (closed) throw IOException("closed") - require(windowSizeIncrement != 0L && windowSizeIncrement <= 0x7fffffffL) { - "windowSizeIncrement == 0 || windowSizeIncrement > 0x7fffffffL: $windowSizeIncrement" - } - if (logger.isLoggable(FINE)) { - logger.fine( - frameLogWindowUpdate( - inbound = false, - streamId = streamId, - length = 4, - windowSizeIncrement = windowSizeIncrement, - ), + lock.withLock { + if (closed) throw IOException("closed") + require(windowSizeIncrement != 0L && windowSizeIncrement <= 0x7fffffffL) { + "windowSizeIncrement == 0 || windowSizeIncrement > 0x7fffffffL: $windowSizeIncrement" + } + if (logger.isLoggable(FINE)) { + logger.fine( + frameLogWindowUpdate( + inbound = false, + streamId = streamId, + length = 4, + windowSizeIncrement = windowSizeIncrement, + ), + ) + } + frameHeader( + streamId = streamId, + length = 4, + type = TYPE_WINDOW_UPDATE, + flags = FLAG_NONE, ) + sink.writeInt(windowSizeIncrement.toInt()) + sink.flush() } - frameHeader( - streamId = streamId, - length = 4, - type = TYPE_WINDOW_UPDATE, - flags = FLAG_NONE, - ) - sink.writeInt(windowSizeIncrement.toInt()) - sink.flush() } @Throws(IOException::class) @@ -317,11 +331,12 @@ class Http2Writer( sink.writeInt(streamId and 0x7fffffff) } - @Synchronized @Throws(IOException::class) override fun close() { - closed = true - sink.close() + lock.withLock { + closed = true + sink.close() + } } @Throws(IOException::class) @@ -343,29 +358,30 @@ class Http2Writer( } } - @Synchronized @Throws(IOException::class) fun headers( outFinished: Boolean, streamId: Int, headerBlock: List
, ) { - if (closed) throw IOException("closed") - hpackWriter.writeHeaders(headerBlock) + lock.withLock { + if (closed) throw IOException("closed") + hpackWriter.writeHeaders(headerBlock) - val byteCount = hpackBuffer.size - val length = minOf(maxFrameSize.toLong(), byteCount) - var flags = if (byteCount == length) FLAG_END_HEADERS else 0 - if (outFinished) flags = flags or FLAG_END_STREAM - frameHeader( - streamId = streamId, - length = length.toInt(), - type = TYPE_HEADERS, - flags = flags, - ) - sink.write(hpackBuffer, length) + val byteCount = hpackBuffer.size + val length = minOf(maxFrameSize.toLong(), byteCount) + var flags = if (byteCount == length) FLAG_END_HEADERS else 0 + if (outFinished) flags = flags or FLAG_END_STREAM + frameHeader( + streamId = streamId, + length = length.toInt(), + type = TYPE_HEADERS, + flags = flags, + ) + sink.write(hpackBuffer, length) - if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) + if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) + } } companion object { diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index 240816047d82..8e58158d6e6e 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -21,6 +21,7 @@ import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isNotEmpty import assertk.assertions.isTrue +import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.ConnectionPool import okhttp3.FakeRoutePlanner @@ -96,7 +97,7 @@ class ConnectionPoolTest { .build() val call = client.newCall(Request(addressA.url)) as RealCall call.enterNetworkInterceptorExchange(call.request(), true, factory.newChain(call)) - synchronized(c1) { call.acquireConnectionNoEvents(c1) } + c1.lock.withLock { call.acquireConnectionNoEvents(c1) } // Running at time 50, the pool returns that nothing can be evicted until time 150. assertThat(pool.closeConnections(50L)).isEqualTo(100L) @@ -342,6 +343,6 @@ class ConnectionPoolTest { .build() val call = client.newCall(Request(connection.route().address.url)) as RealCall call.enterNetworkInterceptorExchange(call.request(), true, factory.newChain(call)) - synchronized(connection) { call.acquireConnectionNoEvents(connection) } + connection.lock.withLock { call.acquireConnectionNoEvents(connection) } } } From 360006a96461836783fe7e155d90a396e8a0eac0 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 15 Apr 2024 09:24:48 -0400 Subject: [PATCH 014/134] Don't declare our own HTTP status codes (#8362) These already exist. --- .../okhttp3/internal/-ResponseCommon.kt | 9 +- .../okhttp3/internal/cache/CacheStrategy.kt | 16 +- .../okhttp3/internal/http/HttpStatusCodes.kt | 215 +----------------- .../http/RetryAndFollowUpInterceptor.kt | 8 + 4 files changed, 21 insertions(+), 227 deletions(-) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt index 4f68f6403dd6..f75f4bf8738d 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt @@ -17,7 +17,10 @@ package okhttp3.internal -import kotlin.jvm.JvmOverloads +import java.net.HttpURLConnection.HTTP_MOVED_PERM +import java.net.HttpURLConnection.HTTP_MOVED_TEMP +import java.net.HttpURLConnection.HTTP_MULT_CHOICE +import java.net.HttpURLConnection.HTTP_SEE_OTHER import okhttp3.CacheControl import okhttp3.Headers import okhttp3.MediaType @@ -26,11 +29,7 @@ import okhttp3.Request import okhttp3.Response import okhttp3.ResponseBody import okhttp3.ResponseBody.Companion.asResponseBody -import okhttp3.internal.http.HTTP_MOVED_PERM -import okhttp3.internal.http.HTTP_MOVED_TEMP -import okhttp3.internal.http.HTTP_MULT_CHOICE import okhttp3.internal.http.HTTP_PERM_REDIRECT -import okhttp3.internal.http.HTTP_SEE_OTHER import okhttp3.internal.http.HTTP_TEMP_REDIRECT import okio.Buffer import okio.IOException diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt b/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt index 7e447cc57dfb..0582fcb5028c 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt @@ -16,20 +16,20 @@ package okhttp3.internal.cache import java.net.HttpURLConnection.HTTP_BAD_METHOD +import java.net.HttpURLConnection.HTTP_GONE +import java.net.HttpURLConnection.HTTP_MOVED_PERM +import java.net.HttpURLConnection.HTTP_MOVED_TEMP +import java.net.HttpURLConnection.HTTP_MULT_CHOICE import java.net.HttpURLConnection.HTTP_NOT_AUTHORITATIVE +import java.net.HttpURLConnection.HTTP_NOT_FOUND +import java.net.HttpURLConnection.HTTP_NOT_IMPLEMENTED +import java.net.HttpURLConnection.HTTP_NO_CONTENT +import java.net.HttpURLConnection.HTTP_OK import java.net.HttpURLConnection.HTTP_REQ_TOO_LONG import java.util.Date import java.util.concurrent.TimeUnit.SECONDS import okhttp3.Request import okhttp3.Response -import okhttp3.internal.http.HTTP_GONE -import okhttp3.internal.http.HTTP_MOVED_PERM -import okhttp3.internal.http.HTTP_MOVED_TEMP -import okhttp3.internal.http.HTTP_MULT_CHOICE -import okhttp3.internal.http.HTTP_NOT_FOUND -import okhttp3.internal.http.HTTP_NOT_IMPLEMENTED -import okhttp3.internal.http.HTTP_NO_CONTENT -import okhttp3.internal.http.HTTP_OK import okhttp3.internal.http.HTTP_PERM_REDIRECT import okhttp3.internal.http.HTTP_TEMP_REDIRECT import okhttp3.internal.http.toHttpDateOrNull diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/HttpStatusCodes.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/HttpStatusCodes.kt index 04baa39b8f64..d8a3fcce575d 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/HttpStatusCodes.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/HttpStatusCodes.kt @@ -26,239 +26,26 @@ package okhttp3.internal.http -// HTTP Status Codes +// HTTP Status Codes not offered by HttpUrlConnection. // // https://datatracker.ietf.org/doc/html/rfc7231#page-47 // // From https://github.com/apache/httpcomponents-core/blob/master/httpcore5/src/main/java/org/apache/hc/core5/http/HttpStatus.java -// --- 1xx Informational --- -// /** `100 1xx Informational` (HTTP/1.1 - RFC 7231) */ -// const val HTTP_INFORMATIONAL = 100 - /** `100 Continue` (HTTP/1.1 - RFC 7231) */ const val HTTP_CONTINUE = 100 -/** `101 Switching Protocols` (HTTP/1.1 - RFC 7231) */ -const val HTTP_SWITCHING_PROTOCOLS = 101 - /** `102 Processing` (WebDAV - RFC 2518) */ const val HTTP_PROCESSING = 102 /** `103 Early Hints (Early Hints - RFC 8297)` */ const val HTTP_EARLY_HINTS = 103 -// --- 2xx Success --- -// /** `2xx Success` (HTTP/1.0 - RFC 7231) */ -// const val HTTP_SUCCESS = 200 - -/** `200 OK` (HTTP/1.0 - RFC 7231) */ -const val HTTP_OK = 200 - -/** `201 Created` (HTTP/1.0 - RFC 7231) */ -const val HTTP_CREATED = 201 - -/** `202 Accepted` (HTTP/1.0 - RFC 7231) */ -const val HTTP_ACCEPTED = 202 - -/** `203 Non Authoritative Information` (HTTP/1.1 - RFC 7231) */ -const val HTTP_NOT_AUTHORITATIVE = 203 - -/** `204 No Content` (HTTP/1.0 - RFC 7231) */ -const val HTTP_NO_CONTENT = 204 - -/** `205 Reset Content` (HTTP/1.1 - RFC 7231) */ -const val HTTP_RESET_CONTENT = 205 - -/** `206 Partial Content` (HTTP/1.1 - RFC 7231) */ -const val HTTP_PARTIAL_CONTENT = 206 - -/** - * `207 Multi-Status` (WebDAV - RFC 2518) - * or - * `207 Partial Update OK` (HTTP/1.1 - draft-ietf-http-v11-spec-rev-01?) - */ -const val HTTP_MULTI_STATUS = 207 - -/** - * `208 Already Reported` (WebDAV - RFC 5842, p.30, section 7.1) - */ -const val HTTP_ALREADY_REPORTED = 208 - -/** - * `226 IM Used` (Delta encoding in HTTP - RFC 3229, p. 30, section 10.4.1) - */ -const val HTTP_IM_USED = 226 - -// --- 3xx Redirection --- -// /** `3xx Redirection` (HTTP/1.1 - RFC 7231) */ -// const val HTTP_REDIRECTION = 300 - -/** `300 Multiple Choices` (HTTP/1.1 - RFC 7231) */ -const val HTTP_MULT_CHOICE = 300 - -/** `301 Moved Permanently` (HTTP/1.0 - RFC 7231) */ -const val HTTP_MOVED_PERM = 301 - -/** `302 Moved Temporarily` (Sometimes `Found`) (HTTP/1.0 - RFC 7231) */ -const val HTTP_MOVED_TEMP = 302 - -/** `303 See Other` (HTTP/1.1 - RFC 7231) */ -const val HTTP_SEE_OTHER = 303 - -/** `304 Not Modified` (HTTP/1.0 - RFC 7231) */ -const val HTTP_NOT_MODIFIED = 304 - -/** `305 Use Proxy` (HTTP/1.1 - RFC 7231) */ -const val HTTP_USE_PROXY = 305 - /** `307 Temporary Redirect` (HTTP/1.1 - RFC 7231) */ const val HTTP_TEMP_REDIRECT = 307 /** `308 Permanent Redirect` (HTTP/1.1 - RFC 7538) */ const val HTTP_PERM_REDIRECT = 308 -// --- 4xx Client Error --- -// /** `4xx Client Error` (HTTP/1.1 - RFC 7231) */ -// const val HTTP_CLIENT_ERROR = 400 - -/** `400 Bad Request` (HTTP/1.1 - RFC 7231) */ -const val HTTP_BAD_REQUEST = 400 - -/** `401 Unauthorized` (HTTP/1.0 - RFC 7231) */ -const val HTTP_UNAUTHORIZED = 401 - -/** `402 Payment Required` (HTTP/1.1 - RFC 7231) */ -const val HTTP_PAYMENT_REQUIRED = 402 - -/** `403 Forbidden` (HTTP/1.0 - RFC 7231) */ -const val HTTP_FORBIDDEN = 403 - -/** `404 Not Found` (HTTP/1.0 - RFC 7231) */ -const val HTTP_NOT_FOUND = 404 - -/** `405 Method Not Allowed` (HTTP/1.1 - RFC 7231) */ -const val HTTP_BAD_METHOD = 405 - -/** `406 Not Acceptable` (HTTP/1.1 - RFC 7231) */ -const val HTTP_NOT_ACCEPTABLE = 406 - -/** `407 Proxy Authentication Required` (HTTP/1.1 - RFC 7231) */ -const val HTTP_PROXY_AUTH = 407 - -/** `408 Request Timeout` (HTTP/1.1 - RFC 7231) */ -const val HTTP_CLIENT_TIMEOUT = 408 - -/** `409 Conflict` (HTTP/1.1 - RFC 7231) */ -const val HTTP_CONFLICT = 409 - -/** `410 Gone` (HTTP/1.1 - RFC 7231) */ -const val HTTP_GONE = 410 - -/** `411 Length Required` (HTTP/1.1 - RFC 7231) */ -const val HTTP_LENGTH_REQUIRED = 411 - -/** `412 Precondition Failed` (HTTP/1.1 - RFC 7231) */ -const val HTTP_PRECONDITION_FAILED = 412 - -/** `413 Request Entity Too Large` (HTTP/1.1 - RFC 7231) */ -const val HTTP_REQUEST_TOO_LONG = 413 - -/** `414 Request-URI Too Long` (HTTP/1.1 - RFC 7231) */ -const val HTTP_REQ_TOO_LONG = 414 - -/** `415 Unsupported Media Type` (HTTP/1.1 - RFC 7231) */ -const val HTTP_UNSUPPORTED_MEDIA_TYPE = 415 - -/** `416 Requested Range Not Satisfiable` (HTTP/1.1 - RFC 7231) */ -const val HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416 - -/** `417 Expectation Failed` (HTTP/1.1 - RFC 7231) */ -const val HTTP_EXPECTATION_FAILED = 417 - /** `421 Misdirected Request` (HTTP/2 - RFC 7540) */ const val HTTP_MISDIRECTED_REQUEST = 421 - -/** - * Static constant for a 419 error. - * `419 Insufficient Space on Resource` - * (WebDAV - draft-ietf-webdav-protocol-05?) - * or `419 Proxy Reauthentication Required` - * (HTTP/1.1 drafts?) - */ -const val HTTP_INSUFFICIENT_SPACE_ON_RESOURCE = 419 - -/** - * Static constant for a 420 error. - * `420 Method Failure` - * (WebDAV - draft-ietf-webdav-protocol-05?) - */ -const val HTTP_METHOD_FAILURE = 420 - -/** `422 Unprocessable Entity` (WebDAV - RFC 2518) */ -const val HTTP_UNPROCESSABLE_ENTITY = 422 - -/** `423 Locked` (WebDAV - RFC 2518) */ -const val HTTP_LOCKED = 423 - -/** `424 Failed Dependency` (WebDAV - RFC 2518) */ -const val HTTP_FAILED_DEPENDENCY = 424 - -/** `425 Too Early` (Using Early Data in HTTP - RFC 8470) */ -const val HTTP_TOO_EARLY = 425 - -/** `426 Upgrade Dependency` (HTTP/1.1 - RFC 2817) */ -const val HTTP_UPGRADE_REQUIRED = 426 - -/** `428 Precondition Required` (Additional HTTP Status Codes - RFC 6585) */ -const val HTTP_PRECONDITION_REQUIRED = 428 - -/** `429 Too Many Requests` (Additional HTTP Status Codes - RFC 6585) */ -const val HTTP_TOO_MANY_REQUESTS = 429 - -/** `431 Request Header Fields Too Large` (Additional HTTP Status Codes - RFC 6585) */ -const val HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431 - -/** `451 Unavailable For Legal Reasons` (Legal Obstacles - RFC 7725) */ -const val HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451 - -// --- 5xx Server Error --- -// /** `500 Server Error` (HTTP/1.0 - RFC 7231) */ -// const val HTTP_SERVER_ERROR = 500 - -/** `500 Internal Server Error` (HTTP/1.0 - RFC 7231) */ -const val HTTP_INTERNAL_SERVER_ERROR = 500 - -/** `501 Not Implemented` (HTTP/1.0 - RFC 7231) */ -const val HTTP_NOT_IMPLEMENTED = 501 - -/** `502 Bad Gateway` (HTTP/1.0 - RFC 7231) */ -const val HTTP_BAD_GATEWAY = 502 - -/** `503 Service Unavailable` (HTTP/1.0 - RFC 7231) */ -const val HTTP_UNAVAILABLE = 503 - -/** `504 Gateway Timeout` (HTTP/1.1 - RFC 7231) */ -const val HTTP_GATEWAY_TIMEOUT = 504 - -/** `505 HTTP Version Not Supported` (HTTP/1.1 - RFC 7231) */ -const val HTTP_HTTP_VERSION_NOT_SUPPORTED = 505 - -/** `506 Variant Also Negotiates` ( Transparent Content Negotiation - RFC 2295) */ -const val HTTP_VARIANT_ALSO_NEGOTIATES = 506 - -/** `507 Insufficient Storage` (WebDAV - RFC 2518) */ -const val HTTP_INSUFFICIENT_STORAGE = 507 - -/** - * `508 Loop Detected` (WebDAV - RFC 5842, p.33, section 7.2) - */ -const val HTTP_LOOP_DETECTED = 508 - -/** - * `510 Not Extended` (An HTTP Extension Framework - RFC 2774, p. 10, section 7) - */ -const val HTTP_NOT_EXTENDED = 510 - -/** `511 Network Authentication Required` (Additional HTTP Status Codes - RFC 6585) */ -const val HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511 diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt index c7a3b4c5dea1..5dee0446f853 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt @@ -18,6 +18,14 @@ package okhttp3.internal.http import java.io.FileNotFoundException import java.io.IOException import java.io.InterruptedIOException +import java.net.HttpURLConnection.HTTP_CLIENT_TIMEOUT +import java.net.HttpURLConnection.HTTP_MOVED_PERM +import java.net.HttpURLConnection.HTTP_MOVED_TEMP +import java.net.HttpURLConnection.HTTP_MULT_CHOICE +import java.net.HttpURLConnection.HTTP_PROXY_AUTH +import java.net.HttpURLConnection.HTTP_SEE_OTHER +import java.net.HttpURLConnection.HTTP_UNAUTHORIZED +import java.net.HttpURLConnection.HTTP_UNAVAILABLE import java.net.ProtocolException import java.net.Proxy import java.net.SocketTimeoutException From 06a052939f19c4edd565e4b681f24b15de94aa06 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 15 Apr 2024 09:41:01 -0400 Subject: [PATCH 015/134] Fix public APIs for kotlin.time.Duration (#8355) * Fix public APIs for kotlin.time.Duration Use this as our preferred API for accepting a duration in OkHttpClient and CacheControl. Also hide these functions from the Java API. * Code review feedback * Spotless * apiDump --- okhttp/api/okhttp.api | 6 +-- .../src/main/kotlin/okhttp3/CacheControl.kt | 40 +++++++++---------- .../okhttp3/internal/-CacheControlCommon.kt | 32 +-------------- .../src/test/java/okhttp3/CacheControlTest.kt | 8 ++-- 4 files changed, 29 insertions(+), 57 deletions(-) diff --git a/okhttp/api/okhttp.api b/okhttp/api/okhttp.api index 866cf47a3839..fcc0709091a4 100644 --- a/okhttp/api/okhttp.api +++ b/okhttp/api/okhttp.api @@ -130,11 +130,11 @@ public final class okhttp3/CacheControl$Builder { public final fun build ()Lokhttp3/CacheControl; public final fun immutable ()Lokhttp3/CacheControl$Builder; public final fun maxAge (ILjava/util/concurrent/TimeUnit;)Lokhttp3/CacheControl$Builder; - public final fun maxAge (ILkotlin/time/DurationUnit;)Lokhttp3/CacheControl$Builder; + public final fun maxAge-LRDsOJo (J)Lokhttp3/CacheControl$Builder; public final fun maxStale (ILjava/util/concurrent/TimeUnit;)Lokhttp3/CacheControl$Builder; - public final fun maxStale (ILkotlin/time/DurationUnit;)Lokhttp3/CacheControl$Builder; + public final fun maxStale-LRDsOJo (J)Lokhttp3/CacheControl$Builder; public final fun minFresh (ILjava/util/concurrent/TimeUnit;)Lokhttp3/CacheControl$Builder; - public final fun minFresh (ILkotlin/time/DurationUnit;)Lokhttp3/CacheControl$Builder; + public final fun minFresh-LRDsOJo (J)Lokhttp3/CacheControl$Builder; public final fun noCache ()Lokhttp3/CacheControl$Builder; public final fun noStore ()Lokhttp3/CacheControl$Builder; public final fun noTransform ()Lokhttp3/CacheControl$Builder; diff --git a/okhttp/src/main/kotlin/okhttp3/CacheControl.kt b/okhttp/src/main/kotlin/okhttp3/CacheControl.kt index 9f507bc3525f..652b3398b805 100644 --- a/okhttp/src/main/kotlin/okhttp3/CacheControl.kt +++ b/okhttp/src/main/kotlin/okhttp3/CacheControl.kt @@ -16,15 +16,12 @@ package okhttp3 import java.util.concurrent.TimeUnit -import kotlin.time.DurationUnit +import kotlin.time.Duration import okhttp3.internal.commonBuild import okhttp3.internal.commonClampToInt import okhttp3.internal.commonForceCache import okhttp3.internal.commonForceNetwork import okhttp3.internal.commonImmutable -import okhttp3.internal.commonMaxAge -import okhttp3.internal.commonMaxStale -import okhttp3.internal.commonMinFresh import okhttp3.internal.commonNoCache import okhttp3.internal.commonNoStore import okhttp3.internal.commonNoTransform @@ -186,26 +183,29 @@ class CacheControl internal constructor( * Sets the maximum age of a cached response. If the cache response's age exceeds [maxAge], it * will not be used and a network request will be made. * - * @param maxAge a non-negative integer. This is stored and transmitted with [TimeUnit.SECONDS] + * @param maxAge a non-negative duration. This is stored and transmitted with [TimeUnit.SECONDS] * precision; finer precision will be lost. */ - @ExperimentalOkHttpApi - fun maxAge( - maxAge: Int, - timeUnit: DurationUnit, - ) = commonMaxAge(maxAge, timeUnit) + fun maxAge(maxAge: Duration) = + apply { + val maxAgeSeconds = maxAge.inWholeSeconds + require(maxAgeSeconds >= 0) { "maxAge < 0: $maxAgeSeconds" } + this.maxAgeSeconds = maxAgeSeconds.commonClampToInt() + } - @ExperimentalOkHttpApi - fun maxStale( - maxStale: Int, - timeUnit: DurationUnit, - ) = commonMaxStale(maxStale, timeUnit) + fun maxStale(maxStale: Duration) = + apply { + val maxStaleSeconds = maxStale.inWholeSeconds + require(maxStaleSeconds >= 0) { "maxStale < 0: $maxStaleSeconds" } + this.maxStaleSeconds = maxStaleSeconds.commonClampToInt() + } - @ExperimentalOkHttpApi - fun minFresh( - minFresh: Int, - timeUnit: DurationUnit, - ) = commonMinFresh(minFresh, timeUnit) + fun minFresh(minFresh: Duration) = + apply { + val minFreshSeconds = minFresh.inWholeSeconds + require(minFreshSeconds >= 0) { "minFresh < 0: $minFreshSeconds" } + this.minFreshSeconds = minFreshSeconds.commonClampToInt() + } /** * Sets the maximum age of a cached response. If the cache response's age exceeds [maxAge], it diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt index d35103a34ff3..4b35218be2a2 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt @@ -17,8 +17,7 @@ package okhttp3.internal -import kotlin.time.DurationUnit -import kotlin.time.toDuration +import kotlin.time.Duration.Companion.seconds import okhttp3.CacheControl import okhttp3.Headers @@ -47,33 +46,6 @@ internal fun CacheControl.commonToString(): String { return result } -internal fun CacheControl.Builder.commonMaxAge( - maxAge: Int, - timeUnit: DurationUnit, -) = apply { - require(maxAge >= 0) { "maxAge < 0: $maxAge" } - val maxAgeSecondsLong = maxAge.toDuration(timeUnit).inWholeSeconds - this.maxAgeSeconds = maxAgeSecondsLong.commonClampToInt() -} - -internal fun CacheControl.Builder.commonMaxStale( - maxStale: Int, - timeUnit: DurationUnit, -) = apply { - require(maxStale >= 0) { "maxStale < 0: $maxStale" } - val maxStaleSecondsLong = maxStale.toDuration(timeUnit).inWholeSeconds - this.maxStaleSeconds = maxStaleSecondsLong.commonClampToInt() -} - -internal fun CacheControl.Builder.commonMinFresh( - minFresh: Int, - timeUnit: DurationUnit, -) = apply { - require(minFresh >= 0) { "minFresh < 0: $minFresh" } - val minFreshSecondsLong = minFresh.toDuration(timeUnit).inWholeSeconds - this.minFreshSeconds = minFreshSecondsLong.commonClampToInt() -} - internal fun Long.commonClampToInt(): Int { return when { this > Int.MAX_VALUE -> Int.MAX_VALUE @@ -89,7 +61,7 @@ internal fun CacheControl.Companion.commonForceNetwork() = internal fun CacheControl.Companion.commonForceCache() = CacheControl.Builder() .onlyIfCached() - .maxStale(Int.MAX_VALUE, DurationUnit.SECONDS) + .maxStale(Int.MAX_VALUE.seconds) .build() internal fun CacheControl.Builder.commonBuild(): CacheControl { diff --git a/okhttp/src/test/java/okhttp3/CacheControlTest.kt b/okhttp/src/test/java/okhttp3/CacheControlTest.kt index d7d3e904df0b..a0f04390bd53 100644 --- a/okhttp/src/test/java/okhttp3/CacheControlTest.kt +++ b/okhttp/src/test/java/okhttp3/CacheControlTest.kt @@ -20,7 +20,7 @@ import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isTrue import kotlin.test.Test -import kotlin.time.DurationUnit +import kotlin.time.Duration.Companion.seconds class CacheControlTest { @Test @@ -48,9 +48,9 @@ class CacheControlTest { CacheControl.Builder() .noCache() .noStore() - .maxAge(1, DurationUnit.SECONDS) - .maxStale(2, DurationUnit.SECONDS) - .minFresh(3, DurationUnit.SECONDS) + .maxAge(1.seconds) + .maxStale(2.seconds) + .minFresh(3.seconds) .onlyIfCached() .noTransform() .immutable() From 6bc0862e4e8be59c2f1346bb9cce83b6e5ead4ee Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 15 Apr 2024 10:55:09 -0400 Subject: [PATCH 016/134] Improve some code comments (#8361) --- .../src/test/kotlin/okhttp3/testing/PlatformRuleTest.kt | 2 +- .../kotlin/okhttp3/internal/connection/RouteDatabase.kt | 2 +- .../main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt | 5 ++--- .../test/java/okhttp3/internal/cache/DiskLruCacheTest.kt | 2 +- .../guide/src/main/java/okhttp3/recipes/CheckHandshake.java | 6 +++--- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/okhttp-testing-support/src/test/kotlin/okhttp3/testing/PlatformRuleTest.kt b/okhttp-testing-support/src/test/kotlin/okhttp3/testing/PlatformRuleTest.kt index 15535af42cbc..0479c694e379 100644 --- a/okhttp-testing-support/src/test/kotlin/okhttp3/testing/PlatformRuleTest.kt +++ b/okhttp-testing-support/src/test/kotlin/okhttp3/testing/PlatformRuleTest.kt @@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension /** - * Sanity test for checking which environment and IDE is picking up. + * Validates which environment is used by the IDE. */ class PlatformRuleTest { @RegisterExtension @JvmField diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt index 920ab5920e77..fe9c91bbd901 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt @@ -18,7 +18,7 @@ package okhttp3.internal.connection import okhttp3.Route /** - * A blacklist of failed routes to avoid when creating a new connection to a target address. This is + * A denylist of failed routes to avoid when creating a new connection to a target address. This is * used so that OkHttp can learn from its mistakes: if there was a failure attempting to connect to * a specific IP address or proxy server, that failure is remembered and alternate routes are * preferred. diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt b/okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt index 706721b483e7..0c6263cef3bd 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt @@ -112,19 +112,18 @@ object OkHostnameVerifier : HostnameVerifier { ): Boolean { var hostname = hostname var pattern = pattern - // Basic sanity checks if (hostname.isNullOrEmpty() || hostname.startsWith(".") || hostname.endsWith("..") ) { - // Invalid domain name + // Invalid domain name. return false } if (pattern.isNullOrEmpty() || pattern.startsWith(".") || pattern.endsWith("..") ) { - // Invalid pattern/domain name + // Invalid pattern. return false } diff --git a/okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt b/okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt index 2a0d537b8129..284d2d9fe893 100644 --- a/okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt @@ -840,7 +840,7 @@ class DiskLruCacheTest { } taskFaker.runNextTask() - // Sanity check that a rebuilt journal behaves normally. + // Check that a rebuilt journal behaves normally. assertValue("a", "a", "a") assertValue("b", "b", "b") } diff --git a/samples/guide/src/main/java/okhttp3/recipes/CheckHandshake.java b/samples/guide/src/main/java/okhttp3/recipes/CheckHandshake.java index fcd3ccf5aed5..e852e68d0439 100644 --- a/samples/guide/src/main/java/okhttp3/recipes/CheckHandshake.java +++ b/samples/guide/src/main/java/okhttp3/recipes/CheckHandshake.java @@ -28,14 +28,14 @@ public final class CheckHandshake { /** Rejects otherwise-trusted certificates. */ private static final Interceptor CHECK_HANDSHAKE_INTERCEPTOR = new Interceptor() { - final Set blacklist = Collections.singleton( + final Set denylist = Collections.singleton( "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig="); @Override public Response intercept(Chain chain) throws IOException { for (Certificate certificate : chain.connection().handshake().peerCertificates()) { String pin = CertificatePinner.pin(certificate); - if (blacklist.contains(pin)) { - throw new IOException("Blacklisted peer certificate: " + pin); + if (denylist.contains(pin)) { + throw new IOException("Denylisted peer certificate: " + pin); } } return chain.proceed(chain.request()); From 689d38873fb1165aeb0ece7fea4306126f8ba74b Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 17 Apr 2024 01:15:48 -0400 Subject: [PATCH 017/134] Revert "Move RealCall and RealConnection to loom safe locks (#8290)" (#8367) This reverts commit a673f45ba6de670a0fa1d4e0e06e4e6d9fb2a26f. --- .../main/kotlin/okhttp3/TestValueFactory.kt | 3 +- okhttp/src/main/kotlin/okhttp3/Dispatcher.kt | 76 ++--- .../internal/connection/ConnectPlan.kt | 3 +- .../okhttp3/internal/connection/RealCall.kt | 31 +- .../internal/connection/RealConnection.kt | 56 ++-- .../internal/connection/RealConnectionPool.kt | 33 +- .../internal/connection/RealRoutePlanner.kt | 5 +- .../okhttp3/internal/http2/Http2Connection.kt | 119 ++++---- .../okhttp3/internal/http2/Http2Stream.kt | 157 +++++----- .../okhttp3/internal/http2/Http2Writer.kt | 286 +++++++++--------- .../internal/connection/ConnectionPoolTest.kt | 5 +- 11 files changed, 355 insertions(+), 419 deletions(-) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt index adaf9b99420d..bbc348fa8ab0 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt @@ -31,7 +31,6 @@ import javax.net.SocketFactory import javax.net.ssl.HostnameVerifier import javax.net.ssl.HttpsURLConnection import javax.net.ssl.SSLSocketFactory -import kotlin.concurrent.withLock import okhttp3.internal.RecordingOkAuthenticator import okhttp3.internal.concurrent.TaskFaker import okhttp3.internal.concurrent.TaskRunner @@ -94,7 +93,7 @@ class TestValueFactory : Closeable { socket = Socket(), idleAtNs = idleAtNanos, ) - result.lock.withLock { pool.put(result) } + synchronized(result) { pool.put(result) } return result } diff --git a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt index 0494446a60ad..e869053c1982 100644 --- a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt +++ b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt @@ -22,9 +22,7 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.SynchronousQueue import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit -import java.util.concurrent.locks.ReentrantLock -import kotlin.concurrent.withLock -import okhttp3.internal.assertNotHeld +import okhttp3.internal.assertThreadDoesntHoldLock import okhttp3.internal.connection.RealCall import okhttp3.internal.connection.RealCall.AsyncCall import okhttp3.internal.okHttpName @@ -38,8 +36,6 @@ import okhttp3.internal.threadFactory * concurrently. */ class Dispatcher() { - internal val lock: ReentrantLock = ReentrantLock() - /** * The maximum number of requests to execute concurrently. Above this requests queue in memory, * waiting for the running calls to complete. @@ -47,11 +43,10 @@ class Dispatcher() { * If more than [maxRequests] requests are in flight when this is invoked, those requests will * remain in flight. */ - var maxRequests = 64 - get() = lock.withLock { field } + @get:Synchronized var maxRequests = 64 set(maxRequests) { require(maxRequests >= 1) { "max < 1: $maxRequests" } - lock.withLock { + synchronized(this) { field = maxRequests } promoteAndExecute() @@ -67,11 +62,10 @@ class Dispatcher() { * * WebSocket connections to hosts **do not** count against this limit. */ - var maxRequestsPerHost = 5 - get() = lock.withLock { field } + @get:Synchronized var maxRequestsPerHost = 5 set(maxRequestsPerHost) { require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" } - lock.withLock { + synchronized(this) { field = maxRequestsPerHost } promoteAndExecute() @@ -88,31 +82,29 @@ class Dispatcher() { * This means that if you are doing synchronous calls the network layer will not truly be idle * until every returned [Response] has been closed. */ + @set:Synchronized + @get:Synchronized var idleCallback: Runnable? = null - get() = lock.withLock { field } - set(value) { - lock.withLock { field = value } - } private var executorServiceOrNull: ExecutorService? = null + @get:Synchronized @get:JvmName("executorService") val executorService: ExecutorService - get() = - lock.withLock { - if (executorServiceOrNull == null) { - executorServiceOrNull = - ThreadPoolExecutor( - 0, - Int.MAX_VALUE, - 60, - TimeUnit.SECONDS, - SynchronousQueue(), - threadFactory("$okHttpName Dispatcher", false), - ) - } - return executorServiceOrNull!! + get() { + if (executorServiceOrNull == null) { + executorServiceOrNull = + ThreadPoolExecutor( + 0, + Int.MAX_VALUE, + 60, + TimeUnit.SECONDS, + SynchronousQueue(), + threadFactory("$okHttpName Dispatcher", false), + ) } + return executorServiceOrNull!! + } /** Ready async calls in the order they'll be run. */ private val readyAsyncCalls = ArrayDeque() @@ -128,7 +120,7 @@ class Dispatcher() { } internal fun enqueue(call: AsyncCall) { - lock.withLock { + synchronized(this) { readyAsyncCalls.add(call) // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to @@ -155,17 +147,15 @@ class Dispatcher() { * Cancel all calls currently enqueued or executing. Includes calls executed both * [synchronously][Call.execute] and [asynchronously][Call.enqueue]. */ - fun cancelAll() { - lock.withLock { - for (call in readyAsyncCalls) { - call.call.cancel() - } - for (call in runningAsyncCalls) { - call.call.cancel() - } - for (call in runningSyncCalls) { - call.cancel() - } + @Synchronized fun cancelAll() { + for (call in readyAsyncCalls) { + call.call.cancel() + } + for (call in runningAsyncCalls) { + call.call.cancel() + } + for (call in runningSyncCalls) { + call.cancel() } } @@ -177,11 +167,11 @@ class Dispatcher() { * @return true if the dispatcher is currently running calls. */ private fun promoteAndExecute(): Boolean { - lock.assertNotHeld() + this.assertThreadDoesntHoldLock() val executableCalls = mutableListOf() val isRunning: Boolean - lock.withLock { + synchronized(this) { val i = readyAsyncCalls.iterator() while (i.hasNext()) { val asyncCall = i.next() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt index b4b5133e07a9..a5c31f9cf03b 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt @@ -26,7 +26,6 @@ import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.SSLSocket -import kotlin.concurrent.withLock import okhttp3.CertificatePinner import okhttp3.ConnectionSpec import okhttp3.Handshake @@ -504,7 +503,7 @@ class ConnectPlan( val pooled3 = routePlanner.planReusePooledConnection(this, routes) if (pooled3 != null) return pooled3.connection - connection.lock.withLock { + synchronized(connection) { connectionPool.put(connection) user.acquireConnectionNoEvents(connection) } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt index 20e55f74461d..2f7be64ba69e 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt @@ -25,8 +25,6 @@ import java.util.concurrent.RejectedExecutionException import java.util.concurrent.TimeUnit.MILLISECONDS import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger -import java.util.concurrent.locks.ReentrantLock -import kotlin.concurrent.withLock import okhttp3.Call import okhttp3.Callback import okhttp3.EventListener @@ -34,9 +32,8 @@ import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response -import okhttp3.internal.assertHeld -import okhttp3.internal.assertNotHeld import okhttp3.internal.assertThreadDoesntHoldLock +import okhttp3.internal.assertThreadHoldsLock import okhttp3.internal.cache.CacheInterceptor import okhttp3.internal.closeQuietly import okhttp3.internal.http.BridgeInterceptor @@ -63,8 +60,6 @@ class RealCall( val originalRequest: Request, val forWebSocket: Boolean, ) : Call, Cloneable { - internal val lock: ReentrantLock = ReentrantLock() - private val connectionPool: RealConnectionPool = client.connectionPool.delegate internal val eventListener: EventListener = client.eventListenerFactory.create(this) @@ -100,7 +95,7 @@ class RealCall( internal var interceptorScopedExchange: Exchange? = null private set - // These properties are guarded by lock. They are typically only accessed by the thread executing + // These properties are guarded by this. They are typically only accessed by the thread executing // the call, but they may be accessed by other threads for duplex requests. /** True if this call still has a request body open. */ @@ -236,7 +231,7 @@ class RealCall( ) { check(interceptorScopedExchange == null) - lock.withLock { + synchronized(this) { check(!responseBodyOpen) { "cannot make a new request because the previous response is still open: " + "please call response.close()" @@ -270,7 +265,7 @@ class RealCall( /** Finds a new or pooled connection to carry a forthcoming request and response. */ internal fun initExchange(chain: RealInterceptorChain): Exchange { - lock.withLock { + synchronized(this) { check(expectMoreExchanges) { "released" } check(!responseBodyOpen) check(!requestBodyOpen) @@ -282,7 +277,7 @@ class RealCall( val result = Exchange(this, eventListener, exchangeFinder, codec) this.interceptorScopedExchange = result this.exchange = result - lock.withLock { + synchronized(this) { this.requestBodyOpen = true this.responseBodyOpen = true } @@ -292,7 +287,7 @@ class RealCall( } fun acquireConnectionNoEvents(connection: RealConnection) { - connection.lock.assertHeld() + connection.assertThreadHoldsLock() check(this.connection == null) this.connection = connection @@ -317,7 +312,7 @@ class RealCall( var bothStreamsDone = false var callDone = false - lock.withLock { + synchronized(this) { if (requestDone && requestBodyOpen || responseDone && responseBodyOpen) { if (requestDone) requestBodyOpen = false if (responseDone) responseBodyOpen = false @@ -340,7 +335,7 @@ class RealCall( internal fun noMoreExchanges(e: IOException?): IOException? { var callDone = false - lock.withLock { + synchronized(this) { if (expectMoreExchanges) { expectMoreExchanges = false callDone = !requestBodyOpen && !responseBodyOpen @@ -367,13 +362,13 @@ class RealCall( * additional context. Otherwise [e] is returned as-is. */ private fun callDone(e: E): E { - lock.assertNotHeld() + assertThreadDoesntHoldLock() val connection = this.connection if (connection != null) { - connection.lock.assertNotHeld() + connection.assertThreadDoesntHoldLock() val toClose: Socket? = - connection.lock.withLock { + synchronized(connection) { // Sets this.connection to null. releaseConnectionNoEvents() } @@ -404,7 +399,7 @@ class RealCall( */ internal fun releaseConnectionNoEvents(): Socket? { val connection = this.connection!! - connection.lock.assertHeld() + connection.assertThreadHoldsLock() val calls = connection.calls val index = calls.indexOfFirst { it.get() == this@RealCall } @@ -448,7 +443,7 @@ class RealCall( * This is usually due to either an exception or a retry. */ internal fun exitNetworkInterceptorExchange(closeExchange: Boolean) { - lock.withLock { + synchronized(this) { check(expectMoreExchanges) { "released" } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt index abcbb90da1e9..f379a4e29efa 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt @@ -23,10 +23,8 @@ import java.net.Socket import java.net.SocketException import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit.MILLISECONDS -import java.util.concurrent.locks.ReentrantLock import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.SSLSocket -import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.Connection import okhttp3.ConnectionListener @@ -35,8 +33,8 @@ import okhttp3.HttpUrl import okhttp3.OkHttpClient import okhttp3.Protocol import okhttp3.Route -import okhttp3.internal.assertHeld -import okhttp3.internal.assertNotHeld +import okhttp3.internal.assertThreadDoesntHoldLock +import okhttp3.internal.assertThreadHoldsLock import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.TaskRunner import okhttp3.internal.http.ExchangeCodec @@ -82,9 +80,7 @@ class RealConnection( ) : Http2Connection.Listener(), Connection, ExchangeCodec.Carrier { private var http2Connection: Http2Connection? = null - internal val lock: ReentrantLock = ReentrantLock() - - // These properties are guarded by lock. + // These properties are guarded by this. /** * If true, no new exchanges can be created on this connection. It is necessary to set this to @@ -133,23 +129,19 @@ class RealConnection( /** Prevent further exchanges from being created on this connection. */ override fun noNewExchanges() { - lock.withLock { + synchronized(this) { noNewExchanges = true } connectionListener.noNewExchanges(this) } /** Prevent this connection from being used for hosts other than the one in [route]. */ - internal fun noCoalescedConnections() { - lock.withLock { - noCoalescedConnections = true - } + @Synchronized internal fun noCoalescedConnections() { + noCoalescedConnections = true } - internal fun incrementSuccessCount() { - lock.withLock { - successCount++ - } + @Synchronized internal fun incrementSuccessCount() { + successCount++ } @Throws(IOException::class) @@ -187,7 +179,7 @@ class RealConnection( address: Address, routes: List?, ): Boolean { - lock.assertHeld() + assertThreadHoldsLock() // If this connection is not accepting new exchanges, we're done. if (calls.size >= allocationLimit || noNewExchanges) return false @@ -240,7 +232,7 @@ class RealConnection( } private fun supportsUrl(url: HttpUrl): Boolean { - lock.assertHeld() + assertThreadHoldsLock() val routeUrl = route.address.url @@ -316,7 +308,7 @@ class RealConnection( /** Returns true if this connection is ready to host new streams. */ fun isHealthy(doExtensiveChecks: Boolean): Boolean { - lock.assertNotHeld() + assertThreadDoesntHoldLock() val nowNs = System.nanoTime() @@ -334,7 +326,7 @@ class RealConnection( return http2Connection.isHealthy(nowNs) } - val idleDurationNs = lock.withLock { nowNs - idleAtNs } + val idleDurationNs = synchronized(this) { nowNs - idleAtNs } if (idleDurationNs >= IDLE_CONNECTION_HEALTHY_NS && doExtensiveChecks) { return socket.isHealthy(source) } @@ -349,21 +341,19 @@ class RealConnection( } /** When settings are received, adjust the allocation limit. */ - override fun onSettings( + @Synchronized override fun onSettings( connection: Http2Connection, settings: Settings, ) { - lock.withLock { - val oldLimit = allocationLimit - allocationLimit = settings.getMaxConcurrentStreams() - - if (allocationLimit < oldLimit) { - // We might need new connections to keep policies satisfied - connectionPool.scheduleOpener(route.address) - } else if (allocationLimit > oldLimit) { - // We might no longer need some connections - connectionPool.scheduleCloser() - } + val oldLimit = allocationLimit + allocationLimit = settings.getMaxConcurrentStreams() + + if (allocationLimit < oldLimit) { + // We might need new connections to keep policies satisfied + connectionPool.scheduleOpener(route.address) + } else if (allocationLimit > oldLimit) { + // We might no longer need some connections + connectionPool.scheduleCloser() } } @@ -397,7 +387,7 @@ class RealConnection( e: IOException?, ) { var noNewExchangesEvent = false - lock.withLock { + synchronized(this) { if (e is StreamResetException) { when { e.errorCode == ErrorCode.REFUSED_STREAM -> { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt index b154ea493641..c4d376c92f11 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt @@ -21,12 +21,11 @@ import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ThreadLocalRandom import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicReferenceFieldUpdater -import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.ConnectionListener import okhttp3.ConnectionPool import okhttp3.Route -import okhttp3.internal.assertHeld +import okhttp3.internal.assertThreadHoldsLock import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.Task import okhttp3.internal.concurrent.TaskQueue @@ -81,7 +80,7 @@ class RealConnectionPool( fun idleConnectionCount(): Int { return connections.count { - it.lock.withLock { it.calls.isEmpty() } + synchronized(it) { it.calls.isEmpty() } } } @@ -111,7 +110,7 @@ class RealConnectionPool( for (connection in connections) { // In the first synchronized block, acquire the connection if it can satisfy this call. val acquired = - connection.lock.withLock { + synchronized(connection) { when { requireMultiplexed && !connection.isMultiplexed -> false !connection.isEligible(address, routes) -> false @@ -130,7 +129,7 @@ class RealConnectionPool( // the hook to close this connection if it's no longer in use. val noNewExchangesEvent: Boolean val toClose: Socket? = - connection.lock.withLock { + synchronized(connection) { noNewExchangesEvent = !connection.noNewExchanges connection.noNewExchanges = true connectionUser.releaseConnectionNoEvents() @@ -146,7 +145,7 @@ class RealConnectionPool( } fun put(connection: RealConnection) { - connection.lock.assertHeld() + connection.assertThreadHoldsLock() connections.add(connection) // connection.queueEvent { connectionListener.connectEnd(connection) } @@ -158,7 +157,7 @@ class RealConnectionPool( * removed from the pool and should be closed. */ fun connectionBecameIdle(connection: RealConnection): Boolean { - connection.lock.assertHeld() + connection.assertThreadHoldsLock() return if (connection.noNewExchanges || maxIdleConnections == 0) { connection.noNewExchanges = true @@ -177,13 +176,13 @@ class RealConnectionPool( while (i.hasNext()) { val connection = i.next() val socketToClose = - connection.lock.withLock { + synchronized(connection) { if (connection.calls.isEmpty()) { i.remove() connection.noNewExchanges = true - return@withLock connection.socket() + return@synchronized connection.socket() } else { - return@withLock null + return@synchronized null } } if (socketToClose != null) { @@ -215,7 +214,7 @@ class RealConnectionPool( } for (connection in connections) { val addressState = addressStates[connection.route.address] ?: continue - connection.lock.withLock { + synchronized(connection) { addressState.concurrentCallCapacity += connection.allocationLimit } } @@ -238,11 +237,11 @@ class RealConnectionPool( var inUseConnectionCount = 0 var evictableConnectionCount = 0 for (connection in connections) { - connection.lock.withLock { + synchronized(connection) { // If the connection is in use, keep searching. if (pruneAndGetAllocationCount(connection, now) > 0) { inUseConnectionCount++ - return@withLock + return@synchronized } val idleAtNs = connection.idleAtNs @@ -286,7 +285,7 @@ class RealConnectionPool( when { toEvict != null -> { // We've chosen a connection to evict. Confirm it's still okay to be evicted, then close it. - toEvict.lock.withLock { + synchronized(toEvict) { if (toEvict.calls.isNotEmpty()) return 0L // No longer idle. if (toEvict.idleAtNs != toEvictIdleAtNs) return 0L // No longer oldest. toEvict.noNewExchanges = true @@ -337,7 +336,7 @@ class RealConnectionPool( connection: RealConnection, now: Long, ): Int { - connection.lock.assertHeld() + connection.assertThreadHoldsLock() val references = connection.calls var i = 0 @@ -416,7 +415,7 @@ class RealConnectionPool( var concurrentCallCapacity = 0 for (connection in connections) { if (state.address != connection.route.address) continue - connection.lock.withLock { + synchronized(connection) { concurrentCallCapacity += connection.allocationLimit } @@ -431,7 +430,7 @@ class RealConnectionPool( // RealRoutePlanner will add the connection to the pool itself, other RoutePlanners may not // TODO: make all RoutePlanners consistent in this behavior if (connection !in connections) { - connection.lock.withLock { put(connection) } + synchronized(connection) { put(connection) } } return 0L // run again immediately to create more connections if needed diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt index e87b12908b24..3684a19da56c 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt @@ -19,7 +19,6 @@ import java.io.IOException import java.net.HttpURLConnection import java.net.Socket import java.net.UnknownServiceException -import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.ConnectionSpec import okhttp3.HttpUrl @@ -95,7 +94,7 @@ class RealRoutePlanner( val healthy = candidate.isHealthy(connectionUser.doExtensiveHealthChecks()) var noNewExchangesEvent = false val toClose: Socket? = - candidate.lock.withLock { + synchronized(candidate) { when { !healthy -> { noNewExchangesEvent = !candidate.noNewExchanges @@ -320,7 +319,7 @@ class RealRoutePlanner( * connections. */ private fun retryRoute(connection: RealConnection): Route? { - return connection.lock.withLock { + return synchronized(connection) { when { connection.routeFailureCount != 0 -> null diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt index 5505a46d1f61..686568d3d0fd 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt @@ -20,9 +20,6 @@ import java.io.IOException import java.io.InterruptedIOException import java.net.Socket import java.util.concurrent.TimeUnit -import java.util.concurrent.locks.Condition -import java.util.concurrent.locks.ReentrantLock -import kotlin.concurrent.withLock import okhttp3.internal.EMPTY_BYTE_ARRAY import okhttp3.internal.EMPTY_HEADERS import okhttp3.internal.assertThreadDoesntHoldLock @@ -32,11 +29,13 @@ import okhttp3.internal.http2.ErrorCode.REFUSED_STREAM import okhttp3.internal.http2.Settings.Companion.DEFAULT_INITIAL_WINDOW_SIZE import okhttp3.internal.http2.flowcontrol.WindowCounter import okhttp3.internal.ignoreIoExceptions +import okhttp3.internal.notifyAll import okhttp3.internal.okHttpName import okhttp3.internal.peerName import okhttp3.internal.platform.Platform import okhttp3.internal.platform.Platform.Companion.INFO import okhttp3.internal.toHeaders +import okhttp3.internal.wait import okio.Buffer import okio.BufferedSink import okio.BufferedSource @@ -55,10 +54,7 @@ import okio.source */ @Suppress("NAME_SHADOWING") class Http2Connection internal constructor(builder: Builder) : Closeable { - internal val lock: ReentrantLock = ReentrantLock() - internal val condition: Condition = lock.newCondition() - - // Internal state of this connection is guarded by 'lock'. No blocking operations may be + // Internal state of this connection is guarded by 'this'. No blocking operations may be // performed while holding this lock! // // Socket writes are guarded by frameWriter. @@ -153,12 +149,12 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { val pingIntervalNanos = TimeUnit.MILLISECONDS.toNanos(builder.pingIntervalMillis.toLong()) writerQueue.schedule("$connectionName ping", pingIntervalNanos) { val failDueToMissingPong = - lock.withLock { + synchronized(this@Http2Connection) { if (intervalPongsReceived < intervalPingsSent) { - return@withLock true + return@synchronized true } else { intervalPingsSent++ - return@withLock false + return@synchronized false } } if (failDueToMissingPong) { @@ -175,31 +171,30 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** * Returns the number of [open streams][Http2Stream.isOpen] on this connection. */ - fun openStreamCount(): Int = lock.withLock { streams.size } + @Synchronized + fun openStreamCount(): Int = streams.size - fun getStream(id: Int): Http2Stream? = lock.withLock { streams[id] } + @Synchronized + fun getStream(id: Int): Http2Stream? = streams[id] + @Synchronized internal fun removeStream(streamId: Int): Http2Stream? { - lock.withLock { - val stream = streams.remove(streamId) + val stream = streams.remove(streamId) - // The removed stream may be blocked on a connection-wide window update. - condition.signalAll() + // The removed stream may be blocked on a connection-wide window update. + notifyAll() - return stream - } + return stream } - internal fun updateConnectionFlowControl(read: Long) { - lock.withLock { - readBytes.update(total = read) - val readBytesToAcknowledge = readBytes.unacknowledged - if (readBytesToAcknowledge >= okHttpSettings.initialWindowSize / 2) { - writeWindowUpdateLater(0, readBytesToAcknowledge) - readBytes.update(acknowledged = readBytesToAcknowledge) - } - flowControlListener.receivingConnectionWindowChanged(readBytes) + @Synchronized internal fun updateConnectionFlowControl(read: Long) { + readBytes.update(total = read) + val readBytesToAcknowledge = readBytes.unacknowledged + if (readBytesToAcknowledge >= okHttpSettings.initialWindowSize / 2) { + writeWindowUpdateLater(0, readBytesToAcknowledge) + readBytes.update(acknowledged = readBytesToAcknowledge) } + flowControlListener.receivingConnectionWindowChanged(readBytes) } /** @@ -245,8 +240,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { val stream: Http2Stream val streamId: Int - writer.lock.withLock { - lock.withLock { + synchronized(writer) { + synchronized(this) { if (nextStreamId > Int.MAX_VALUE / 2) { shutdown(REFUSED_STREAM) } @@ -316,7 +311,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { var byteCount = byteCount while (byteCount > 0L) { var toWrite: Int - lock.withLock { + synchronized(this@Http2Connection) { try { while (writeBytesTotal >= writeBytesMaximum) { // Before blocking, confirm that the stream we're writing is still open. It's possible @@ -324,7 +319,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { if (!streams.containsKey(streamId)) { throw IOException("stream closed") } - condition.await() // Wait until we receive a WINDOW_UPDATE. + this@Http2Connection.wait() // Wait until we receive a WINDOW_UPDATE. } } catch (e: InterruptedException) { Thread.currentThread().interrupt() // Retain interrupted status. @@ -397,7 +392,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** For testing: sends a ping to be awaited with [awaitPong]. */ @Throws(InterruptedException::class) fun writePing() { - lock.withLock { + synchronized(this) { awaitPingsSent++ } @@ -406,12 +401,11 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } /** For testing: awaits a pong. */ + @Synchronized @Throws(InterruptedException::class) fun awaitPong() { - lock.withLock { - while (awaitPongsReceived < awaitPingsSent) { - condition.await() - } + while (awaitPongsReceived < awaitPingsSent) { + wait() } } @@ -427,9 +421,9 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { */ @Throws(IOException::class) fun shutdown(statusCode: ErrorCode) { - writer.lock.withLock { + synchronized(writer) { val lastGoodStreamId: Int - lock.withLock { + synchronized(this) { if (isShutdown) { return } @@ -462,7 +456,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } var streamsToClose: Array? = null - lock.withLock { + synchronized(this) { if (streams.isNotEmpty()) { streamsToClose = streams.values.toTypedArray() streams.clear() @@ -522,8 +516,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** Merges [settings] into this peer's settings and sends them to the remote peer. */ @Throws(IOException::class) fun setSettings(settings: Settings) { - writer.lock.withLock { - lock.withLock { + synchronized(writer) { + synchronized(this) { if (isShutdown) { throw ConnectionShutdownException() } @@ -533,15 +527,14 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } } + @Synchronized fun isHealthy(nowNs: Long): Boolean { - lock.withLock { - if (isShutdown) return false + if (isShutdown) return false - // A degraded pong is overdue. - if (degradedPongsReceived < degradedPingsSent && nowNs >= degradedPongDeadlineNs) return false + // A degraded pong is overdue. + if (degradedPongsReceived < degradedPingsSent && nowNs >= degradedPongDeadlineNs) return false - return true - } + return true } /** @@ -560,7 +553,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { * The deadline is currently hardcoded. We may make this configurable in the future! */ internal fun sendDegradedPingLater() { - lock.withLock { + synchronized(this) { if (degradedPongsReceived < degradedPingsSent) return // Already awaiting a degraded pong. degradedPingsSent++ degradedPongDeadlineNs = System.nanoTime() + DEGRADED_PONG_TIMEOUT_NS @@ -689,7 +682,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { return } val stream: Http2Stream? - lock.withLock { + synchronized(this@Http2Connection) { stream = getStream(streamId) if (stream == null) { @@ -768,8 +761,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { var delta: Long var streamsToNotify: Array? var newPeerSettings: Settings - writer.lock.withLock { - lock.withLock { + synchronized(writer) { + synchronized(this@Http2Connection) { val previousPeerSettings = peerSettings newPeerSettings = if (clearPrevious) { @@ -803,7 +796,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } if (streamsToNotify != null) { for (stream in streamsToNotify!!) { - stream.lock.withLock { + synchronized(stream) { stream.addBytesToWriteWindow(delta) } } @@ -820,7 +813,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { payload2: Int, ) { if (ack) { - lock.withLock { + synchronized(this@Http2Connection) { when (payload1) { INTERVAL_PING -> { intervalPongsReceived++ @@ -830,7 +823,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } AWAIT_PING -> { awaitPongsReceived++ - condition.signalAll() + this@Http2Connection.notifyAll() } else -> { // Ignore an unexpected pong. @@ -856,7 +849,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { // Copy the streams first. We don't want to hold a lock when we call receiveRstStream(). val streamsCopy: Array - lock.withLock { + synchronized(this@Http2Connection) { streamsCopy = streams.values.toTypedArray() isShutdown = true } @@ -875,14 +868,14 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { windowSizeIncrement: Long, ) { if (streamId == 0) { - lock.withLock { + synchronized(this@Http2Connection) { writeBytesMaximum += windowSizeIncrement - condition.signalAll() + this@Http2Connection.notifyAll() } } else { val stream = getStream(streamId) if (stream != null) { - stream.lock.withLock { + synchronized(stream) { stream.addBytesToWriteWindow(windowSizeIncrement) } } @@ -925,7 +918,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { streamId: Int, requestHeaders: List
, ) { - lock.withLock { + synchronized(this) { if (streamId in currentPushRequests) { writeSynResetLater(streamId, ErrorCode.PROTOCOL_ERROR) return @@ -937,7 +930,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { ignoreIoExceptions { if (cancel) { writer.rstStream(streamId, ErrorCode.CANCEL) - lock.withLock { + synchronized(this@Http2Connection) { currentPushRequests.remove(streamId) } } @@ -955,7 +948,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { ignoreIoExceptions { if (cancel) writer.rstStream(streamId, ErrorCode.CANCEL) if (cancel || inFinished) { - lock.withLock { + synchronized(this@Http2Connection) { currentPushRequests.remove(streamId) } } @@ -982,7 +975,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { val cancel = pushObserver.onData(streamId, buffer, byteCount, inFinished) if (cancel) writer.rstStream(streamId, ErrorCode.CANCEL) if (cancel || inFinished) { - lock.withLock { + synchronized(this@Http2Connection) { currentPushRequests.remove(streamId) } } @@ -996,7 +989,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { ) { pushQueue.execute("$connectionName[$streamId] onReset") { pushObserver.onReset(streamId, errorCode) - lock.withLock { + synchronized(this@Http2Connection) { currentPushRequests.remove(streamId) } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt index 32a419561505..dd1fa1e49584 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt @@ -20,14 +20,13 @@ import java.io.IOException import java.io.InterruptedIOException import java.net.SocketTimeoutException import java.util.ArrayDeque -import java.util.concurrent.locks.Condition -import java.util.concurrent.locks.ReentrantLock -import kotlin.concurrent.withLock import okhttp3.Headers import okhttp3.internal.EMPTY_HEADERS -import okhttp3.internal.assertNotHeld +import okhttp3.internal.assertThreadDoesntHoldLock import okhttp3.internal.http2.flowcontrol.WindowCounter +import okhttp3.internal.notifyAll import okhttp3.internal.toHeaderList +import okhttp3.internal.wait import okio.AsyncTimeout import okio.Buffer import okio.BufferedSource @@ -44,10 +43,7 @@ class Http2Stream internal constructor( inFinished: Boolean, headers: Headers?, ) { - internal val lock: ReentrantLock = ReentrantLock() - val condition: Condition = lock.newCondition() - - // Internal state is guarded by lock. No long-running or potentially blocking operations are + // Internal state is guarded by this. No long-running or potentially blocking operations are // performed while the lock is held. /** The bytes consumed and acknowledged by the stream. */ @@ -86,8 +82,7 @@ class Http2Stream internal constructor( * If there are multiple reasons to abnormally close this stream (such as both peers closing it * near-simultaneously) then this is the first reason known to this peer. */ - internal var errorCode: ErrorCode? = null - get() = lock.withLock { field } + @get:Synchronized internal var errorCode: ErrorCode? = null /** The exception that explains [errorCode]. Null if no exception was provided. */ internal var errorException: IOException? = null @@ -111,19 +106,17 @@ class Http2Stream internal constructor( * not open. This is because input data is buffered. */ val isOpen: Boolean - get() { - lock.withLock { - if (errorCode != null) { - return false - } - if ((source.finished || source.closed) && - (sink.finished || sink.closed) && - hasResponseHeaders - ) { - return false - } - return true + @Synchronized get() { + if (errorCode != null) { + return false + } + if ((source.finished || source.closed) && + (sink.finished || sink.closed) && + hasResponseHeaders + ) { + return false } + return true } /** Returns true if this stream was created by this peer. */ @@ -142,44 +135,42 @@ class Http2Stream internal constructor( * This is true after a `Expect-Continue` request, false for duplex requests, and false for * all other requests. */ + @Synchronized @Throws(IOException::class) fun takeHeaders(callerIsIdle: Boolean = false): Headers { - lock.withLock { - while (headersQueue.isEmpty() && errorCode == null) { - val doReadTimeout = callerIsIdle || doReadTimeout() + while (headersQueue.isEmpty() && errorCode == null) { + val doReadTimeout = callerIsIdle || doReadTimeout() + if (doReadTimeout) { + readTimeout.enter() + } + try { + waitForIo() + } finally { if (doReadTimeout) { - readTimeout.enter() + readTimeout.exitAndThrowIfTimedOut() } - try { - waitForIo() - } finally { - if (doReadTimeout) { - readTimeout.exitAndThrowIfTimedOut() - } - } - } - if (headersQueue.isNotEmpty()) { - return headersQueue.removeFirst() } - throw errorException ?: StreamResetException(errorCode!!) } + if (headersQueue.isNotEmpty()) { + return headersQueue.removeFirst() + } + throw errorException ?: StreamResetException(errorCode!!) } /** * Returns the trailers. It is only safe to call this once the source stream has been completely * exhausted. */ + @Synchronized @Throws(IOException::class) fun trailers(): Headers { - lock.withLock { - if (source.finished && source.receiveBuffer.exhausted() && source.readBuffer.exhausted()) { - return source.trailers ?: EMPTY_HEADERS - } - if (errorCode != null) { - throw errorException ?: StreamResetException(errorCode!!) - } - throw IllegalStateException("too early; can't read the trailers yet") + if (source.finished && source.receiveBuffer.exhausted() && source.readBuffer.exhausted()) { + return source.trailers ?: EMPTY_HEADERS + } + if (errorCode != null) { + throw errorException ?: StreamResetException(errorCode!!) } + throw IllegalStateException("too early; can't read the trailers yet") } /** @@ -196,21 +187,21 @@ class Http2Stream internal constructor( outFinished: Boolean, flushHeaders: Boolean, ) { - lock.assertNotHeld() + this@Http2Stream.assertThreadDoesntHoldLock() var flushHeaders = flushHeaders - lock.withLock { + synchronized(this) { this.hasResponseHeaders = true if (outFinished) { this.sink.finished = true - condition.signalAll() // Because doReadTimeout() may have changed. + this@Http2Stream.notifyAll() // Because doReadTimeout() may have changed. } } // Only DATA frames are subject to flow-control. Transmit the HEADER frame if the connection // flow-control window is fully depleted. if (!flushHeaders) { - lock.withLock { + synchronized(connection) { flushHeaders = (connection.writeBytesTotal >= connection.writeBytesMaximum) } } @@ -223,7 +214,7 @@ class Http2Stream internal constructor( } fun enqueueTrailers(trailers: Headers) { - lock.withLock { + synchronized(this) { check(!sink.finished) { "already finished" } require(trailers.size != 0) { "trailers.size() == 0" } this.sink.trailers = trailers @@ -244,7 +235,7 @@ class Http2Stream internal constructor( * not yet been sent. */ fun getSink(): Sink { - lock.withLock { + synchronized(this) { check(hasResponseHeaders || isLocallyInitiated) { "reply before requesting the sink" } @@ -282,15 +273,15 @@ class Http2Stream internal constructor( errorCode: ErrorCode, errorException: IOException?, ): Boolean { - lock.assertNotHeld() + this.assertThreadDoesntHoldLock() - lock.withLock { + synchronized(this) { if (this.errorCode != null) { return false } this.errorCode = errorCode this.errorException = errorException - condition.signalAll() + notifyAll() if (source.finished && sink.finished) { return false } @@ -304,7 +295,7 @@ class Http2Stream internal constructor( source: BufferedSource, length: Int, ) { - lock.assertNotHeld() + this@Http2Stream.assertThreadDoesntHoldLock() this.source.receive(source, length.toLong()) } @@ -314,10 +305,10 @@ class Http2Stream internal constructor( headers: Headers, inFinished: Boolean, ) { - lock.assertNotHeld() + this@Http2Stream.assertThreadDoesntHoldLock() val open: Boolean - lock.withLock { + synchronized(this) { if (!hasResponseHeaders || headers[Header.RESPONSE_STATUS_UTF8] != null || headers[Header.TARGET_METHOD_UTF8] != null @@ -331,19 +322,17 @@ class Http2Stream internal constructor( this.source.finished = true } open = isOpen - condition.signalAll() + notifyAll() } if (!open) { connection.removeStream(id) } } - fun receiveRstStream(errorCode: ErrorCode) { - lock.withLock { - if (this.errorCode == null) { - this.errorCode = errorCode - condition.signalAll() - } + @Synchronized fun receiveRstStream(errorCode: ErrorCode) { + if (this.errorCode == null) { + this.errorCode = errorCode + notifyAll() } } @@ -400,7 +389,7 @@ class Http2Stream internal constructor( // 1. Decide what to do in a synchronized block. - lock.withLock { + synchronized(this@Http2Stream) { val doReadTimeout = doReadTimeout() if (doReadTimeout) { readTimeout.enter() @@ -463,7 +452,7 @@ class Http2Stream internal constructor( } private fun updateConnectionFlowControl(read: Long) { - lock.assertNotHeld() + this@Http2Stream.assertThreadDoesntHoldLock() connection.updateConnectionFlowControl(read) } @@ -477,14 +466,14 @@ class Http2Stream internal constructor( source: BufferedSource, byteCount: Long, ) { - lock.assertNotHeld() + this@Http2Stream.assertThreadDoesntHoldLock() var remainingByteCount = byteCount while (remainingByteCount > 0L) { val finished: Boolean val flowControlError: Boolean - lock.withLock { + synchronized(this@Http2Stream) { finished = this.finished flowControlError = remainingByteCount + readBuffer.size > maxByteCount } @@ -510,14 +499,14 @@ class Http2Stream internal constructor( // Move the received data to the read buffer to the reader can read it. If this source has // been closed since this read began we must discard the incoming data and tell the // connection we've done so. - lock.withLock { + synchronized(this@Http2Stream) { if (closed) { receiveBuffer.clear() } else { val wasEmpty = readBuffer.size == 0L readBuffer.writeAll(receiveBuffer) if (wasEmpty) { - condition.signalAll() + this@Http2Stream.notifyAll() } } } @@ -538,11 +527,11 @@ class Http2Stream internal constructor( @Throws(IOException::class) override fun close() { val bytesDiscarded: Long - lock.withLock { + synchronized(this@Http2Stream) { closed = true bytesDiscarded = readBuffer.size readBuffer.clear() - condition.signalAll() // TODO(jwilson): Unnecessary? + this@Http2Stream.notifyAll() // TODO(jwilson): Unnecessary? } if (bytesDiscarded > 0L) { updateConnectionFlowControl(bytesDiscarded) @@ -553,11 +542,11 @@ class Http2Stream internal constructor( @Throws(IOException::class) internal fun cancelStreamIfNecessary() { - lock.assertNotHeld() + this@Http2Stream.assertThreadDoesntHoldLock() val open: Boolean val cancel: Boolean - lock.withLock { + synchronized(this) { cancel = !source.finished && source.closed && (sink.finished || sink.closed) open = isOpen } @@ -592,7 +581,7 @@ class Http2Stream internal constructor( source: Buffer, byteCount: Long, ) { - lock.assertNotHeld() + this@Http2Stream.assertThreadDoesntHoldLock() sendBuffer.write(source, byteCount) while (sendBuffer.size >= EMIT_BUFFER_SIZE) { @@ -608,7 +597,7 @@ class Http2Stream internal constructor( private fun emitFrame(outFinishedOnLastFrame: Boolean) { val toWrite: Long val outFinished: Boolean - lock.withLock { + synchronized(this@Http2Stream) { writeTimeout.enter() try { while (writeBytesTotal >= writeBytesMaximum && @@ -638,9 +627,9 @@ class Http2Stream internal constructor( @Throws(IOException::class) override fun flush() { - lock.assertNotHeld() + this@Http2Stream.assertThreadDoesntHoldLock() - lock.withLock { + synchronized(this@Http2Stream) { checkOutNotClosed() } // TODO(jwilson): flush the connection?! @@ -654,10 +643,10 @@ class Http2Stream internal constructor( @Throws(IOException::class) override fun close() { - lock.assertNotHeld() + this@Http2Stream.assertThreadDoesntHoldLock() val outFinished: Boolean - lock.withLock { + synchronized(this@Http2Stream) { if (closed) return outFinished = errorCode == null } @@ -686,9 +675,9 @@ class Http2Stream internal constructor( } } } - lock.withLock { + synchronized(this@Http2Stream) { closed = true - condition.signalAll() // Because doReadTimeout() may have changed. + this@Http2Stream.notifyAll() // Because doReadTimeout() may have changed. } connection.flush() cancelStreamIfNecessary() @@ -703,7 +692,7 @@ class Http2Stream internal constructor( fun addBytesToWriteWindow(delta: Long) { writeBytesMaximum += delta if (delta > 0L) { - condition.signalAll() + this@Http2Stream.notifyAll() } } @@ -723,7 +712,7 @@ class Http2Stream internal constructor( @Throws(InterruptedIOException::class) internal fun waitForIo() { try { - condition.await() + wait() } catch (_: InterruptedException) { Thread.currentThread().interrupt() // Retain interrupted status. throw InterruptedIOException() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt index 496757427193..ff72536e9b49 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt @@ -17,10 +17,8 @@ package okhttp3.internal.http2 import java.io.Closeable import java.io.IOException -import java.util.concurrent.locks.ReentrantLock import java.util.logging.Level.FINE import java.util.logging.Logger -import kotlin.concurrent.withLock import okhttp3.internal.format import okhttp3.internal.http2.Http2.CONNECTION_PREFACE import okhttp3.internal.http2.Http2.FLAG_ACK @@ -49,43 +47,39 @@ class Http2Writer( private val sink: BufferedSink, private val client: Boolean, ) : Closeable { - internal val lock: ReentrantLock = ReentrantLock() - private val hpackBuffer: Buffer = Buffer() private var maxFrameSize: Int = INITIAL_MAX_FRAME_SIZE private var closed: Boolean = false val hpackWriter: Hpack.Writer = Hpack.Writer(out = hpackBuffer) + @Synchronized @Throws(IOException::class) fun connectionPreface() { - lock.withLock { - if (closed) throw IOException("closed") - if (!client) return // Nothing to write; servers don't send connection headers! - if (logger.isLoggable(FINE)) { - logger.fine(format(">> CONNECTION ${CONNECTION_PREFACE.hex()}")) - } - sink.write(CONNECTION_PREFACE) - sink.flush() + if (closed) throw IOException("closed") + if (!client) return // Nothing to write; servers don't send connection headers! + if (logger.isLoggable(FINE)) { + logger.fine(format(">> CONNECTION ${CONNECTION_PREFACE.hex()}")) } + sink.write(CONNECTION_PREFACE) + sink.flush() } /** Applies `peerSettings` and then sends a settings ACK. */ + @Synchronized @Throws(IOException::class) fun applyAndAckSettings(peerSettings: Settings) { - lock.withLock { - if (closed) throw IOException("closed") - this.maxFrameSize = peerSettings.getMaxFrameSize(maxFrameSize) - if (peerSettings.headerTableSize != -1) { - hpackWriter.resizeHeaderTable(peerSettings.headerTableSize) - } - frameHeader( - streamId = 0, - length = 0, - type = TYPE_SETTINGS, - flags = FLAG_ACK, - ) - sink.flush() + if (closed) throw IOException("closed") + this.maxFrameSize = peerSettings.getMaxFrameSize(maxFrameSize) + if (peerSettings.headerTableSize != -1) { + hpackWriter.resizeHeaderTable(peerSettings.headerTableSize) } + frameHeader( + streamId = 0, + length = 0, + type = TYPE_SETTINGS, + flags = FLAG_ACK, + ) + sink.flush() } /** @@ -100,57 +94,54 @@ class Http2Writer( * @param promisedStreamId server-initiated stream ID. Must be an even number. * @param requestHeaders minimally includes `:method`, `:scheme`, `:authority`, and `:path`. */ + @Synchronized @Throws(IOException::class) fun pushPromise( streamId: Int, promisedStreamId: Int, requestHeaders: List
, ) { - lock.withLock { - if (closed) throw IOException("closed") - hpackWriter.writeHeaders(requestHeaders) + if (closed) throw IOException("closed") + hpackWriter.writeHeaders(requestHeaders) - val byteCount = hpackBuffer.size - val length = minOf(maxFrameSize - 4L, byteCount).toInt() - frameHeader( - streamId = streamId, - length = length + 4, - type = TYPE_PUSH_PROMISE, - flags = if (byteCount == length.toLong()) FLAG_END_HEADERS else 0, - ) - sink.writeInt(promisedStreamId and 0x7fffffff) - sink.write(hpackBuffer, length.toLong()) + val byteCount = hpackBuffer.size + val length = minOf(maxFrameSize - 4L, byteCount).toInt() + frameHeader( + streamId = streamId, + length = length + 4, + type = TYPE_PUSH_PROMISE, + flags = if (byteCount == length.toLong()) FLAG_END_HEADERS else 0, + ) + sink.writeInt(promisedStreamId and 0x7fffffff) + sink.write(hpackBuffer, length.toLong()) - if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) - } + if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) } + @Synchronized @Throws(IOException::class) fun flush() { - lock.withLock { - if (closed) throw IOException("closed") - sink.flush() - } + if (closed) throw IOException("closed") + sink.flush() } + @Synchronized @Throws(IOException::class) fun rstStream( streamId: Int, errorCode: ErrorCode, ) { - lock.withLock { - if (closed) throw IOException("closed") - require(errorCode.httpCode != -1) + if (closed) throw IOException("closed") + require(errorCode.httpCode != -1) - frameHeader( - streamId = streamId, - length = 4, - type = TYPE_RST_STREAM, - flags = FLAG_NONE, - ) - sink.writeInt(errorCode.httpCode) - sink.flush() - } + frameHeader( + streamId = streamId, + length = 4, + type = TYPE_RST_STREAM, + flags = FLAG_NONE, + ) + sink.writeInt(errorCode.httpCode) + sink.flush() } /** The maximum size of bytes that may be sent in a single call to [data]. */ @@ -163,6 +154,7 @@ class Http2Writer( * @param source the buffer to draw bytes from. May be null if byteCount is 0. * @param byteCount must be between 0 and the minimum of `source.length` and [maxDataLength]. */ + @Synchronized @Throws(IOException::class) fun data( outFinished: Boolean, @@ -170,12 +162,10 @@ class Http2Writer( source: Buffer?, byteCount: Int, ) { - lock.withLock { - if (closed) throw IOException("closed") - var flags = FLAG_NONE - if (outFinished) flags = flags or FLAG_END_STREAM - dataFrame(streamId, flags, source, byteCount) - } + if (closed) throw IOException("closed") + var flags = FLAG_NONE + if (outFinished) flags = flags or FLAG_END_STREAM + dataFrame(streamId, flags, source, byteCount) } @Throws(IOException::class) @@ -197,53 +187,51 @@ class Http2Writer( } /** Write okhttp's settings to the peer. */ + @Synchronized @Throws(IOException::class) fun settings(settings: Settings) { - lock.withLock { - if (closed) throw IOException("closed") - frameHeader( - streamId = 0, - length = settings.size() * 6, - type = TYPE_SETTINGS, - flags = FLAG_NONE, - ) - for (i in 0 until Settings.COUNT) { - if (!settings.isSet(i)) continue - val id = - when (i) { - 4 -> 3 // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. - 7 -> 4 // SETTINGS_INITIAL_WINDOW_SIZE renumbered. - else -> i - } - sink.writeShort(id) - sink.writeInt(settings[i]) - } - sink.flush() + if (closed) throw IOException("closed") + frameHeader( + streamId = 0, + length = settings.size() * 6, + type = TYPE_SETTINGS, + flags = FLAG_NONE, + ) + for (i in 0 until Settings.COUNT) { + if (!settings.isSet(i)) continue + val id = + when (i) { + 4 -> 3 // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. + 7 -> 4 // SETTINGS_INITIAL_WINDOW_SIZE renumbered. + else -> i + } + sink.writeShort(id) + sink.writeInt(settings[i]) } + sink.flush() } /** * Send a connection-level ping to the peer. `ack` indicates this is a reply. The data in * `payload1` and `payload2` opaque binary, and there are no rules on the content. */ + @Synchronized @Throws(IOException::class) fun ping( ack: Boolean, payload1: Int, payload2: Int, ) { - lock.withLock { - if (closed) throw IOException("closed") - frameHeader( - streamId = 0, - length = 8, - type = TYPE_PING, - flags = if (ack) FLAG_ACK else FLAG_NONE, - ) - sink.writeInt(payload1) - sink.writeInt(payload2) - sink.flush() - } + if (closed) throw IOException("closed") + frameHeader( + streamId = 0, + length = 8, + type = TYPE_PING, + flags = if (ack) FLAG_ACK else FLAG_NONE, + ) + sink.writeInt(payload1) + sink.writeInt(payload2) + sink.flush() } /** @@ -254,63 +242,61 @@ class Http2Writer( * @param errorCode reason for closing the connection. * @param debugData only valid for HTTP/2; opaque debug data to send. */ + @Synchronized @Throws(IOException::class) fun goAway( lastGoodStreamId: Int, errorCode: ErrorCode, debugData: ByteArray, ) { - lock.withLock { - if (closed) throw IOException("closed") - require(errorCode.httpCode != -1) { "errorCode.httpCode == -1" } - frameHeader( - streamId = 0, - length = 8 + debugData.size, - type = TYPE_GOAWAY, - flags = FLAG_NONE, - ) - sink.writeInt(lastGoodStreamId) - sink.writeInt(errorCode.httpCode) - if (debugData.isNotEmpty()) { - sink.write(debugData) - } - sink.flush() + if (closed) throw IOException("closed") + require(errorCode.httpCode != -1) { "errorCode.httpCode == -1" } + frameHeader( + streamId = 0, + length = 8 + debugData.size, + type = TYPE_GOAWAY, + flags = FLAG_NONE, + ) + sink.writeInt(lastGoodStreamId) + sink.writeInt(errorCode.httpCode) + if (debugData.isNotEmpty()) { + sink.write(debugData) } + sink.flush() } /** * Inform peer that an additional `windowSizeIncrement` bytes can be sent on `streamId`, or the * connection if `streamId` is zero. */ + @Synchronized @Throws(IOException::class) fun windowUpdate( streamId: Int, windowSizeIncrement: Long, ) { - lock.withLock { - if (closed) throw IOException("closed") - require(windowSizeIncrement != 0L && windowSizeIncrement <= 0x7fffffffL) { - "windowSizeIncrement == 0 || windowSizeIncrement > 0x7fffffffL: $windowSizeIncrement" - } - if (logger.isLoggable(FINE)) { - logger.fine( - frameLogWindowUpdate( - inbound = false, - streamId = streamId, - length = 4, - windowSizeIncrement = windowSizeIncrement, - ), - ) - } - frameHeader( - streamId = streamId, - length = 4, - type = TYPE_WINDOW_UPDATE, - flags = FLAG_NONE, + if (closed) throw IOException("closed") + require(windowSizeIncrement != 0L && windowSizeIncrement <= 0x7fffffffL) { + "windowSizeIncrement == 0 || windowSizeIncrement > 0x7fffffffL: $windowSizeIncrement" + } + if (logger.isLoggable(FINE)) { + logger.fine( + frameLogWindowUpdate( + inbound = false, + streamId = streamId, + length = 4, + windowSizeIncrement = windowSizeIncrement, + ), ) - sink.writeInt(windowSizeIncrement.toInt()) - sink.flush() } + frameHeader( + streamId = streamId, + length = 4, + type = TYPE_WINDOW_UPDATE, + flags = FLAG_NONE, + ) + sink.writeInt(windowSizeIncrement.toInt()) + sink.flush() } @Throws(IOException::class) @@ -331,12 +317,11 @@ class Http2Writer( sink.writeInt(streamId and 0x7fffffff) } + @Synchronized @Throws(IOException::class) override fun close() { - lock.withLock { - closed = true - sink.close() - } + closed = true + sink.close() } @Throws(IOException::class) @@ -358,30 +343,29 @@ class Http2Writer( } } + @Synchronized @Throws(IOException::class) fun headers( outFinished: Boolean, streamId: Int, headerBlock: List
, ) { - lock.withLock { - if (closed) throw IOException("closed") - hpackWriter.writeHeaders(headerBlock) + if (closed) throw IOException("closed") + hpackWriter.writeHeaders(headerBlock) - val byteCount = hpackBuffer.size - val length = minOf(maxFrameSize.toLong(), byteCount) - var flags = if (byteCount == length) FLAG_END_HEADERS else 0 - if (outFinished) flags = flags or FLAG_END_STREAM - frameHeader( - streamId = streamId, - length = length.toInt(), - type = TYPE_HEADERS, - flags = flags, - ) - sink.write(hpackBuffer, length) + val byteCount = hpackBuffer.size + val length = minOf(maxFrameSize.toLong(), byteCount) + var flags = if (byteCount == length) FLAG_END_HEADERS else 0 + if (outFinished) flags = flags or FLAG_END_STREAM + frameHeader( + streamId = streamId, + length = length.toInt(), + type = TYPE_HEADERS, + flags = flags, + ) + sink.write(hpackBuffer, length) - if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) - } + if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) } companion object { diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index 8e58158d6e6e..240816047d82 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -21,7 +21,6 @@ import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isNotEmpty import assertk.assertions.isTrue -import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.ConnectionPool import okhttp3.FakeRoutePlanner @@ -97,7 +96,7 @@ class ConnectionPoolTest { .build() val call = client.newCall(Request(addressA.url)) as RealCall call.enterNetworkInterceptorExchange(call.request(), true, factory.newChain(call)) - c1.lock.withLock { call.acquireConnectionNoEvents(c1) } + synchronized(c1) { call.acquireConnectionNoEvents(c1) } // Running at time 50, the pool returns that nothing can be evicted until time 150. assertThat(pool.closeConnections(50L)).isEqualTo(100L) @@ -343,6 +342,6 @@ class ConnectionPoolTest { .build() val call = client.newCall(Request(connection.route().address.url)) as RealCall call.enterNetworkInterceptorExchange(call.request(), true, factory.newChain(call)) - connection.lock.withLock { call.acquireConnectionNoEvents(connection) } + synchronized(connection) { call.acquireConnectionNoEvents(connection) } } } From e274b91f87c113f459826bc0f89853e394b466a8 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 17 Apr 2024 09:25:31 -0400 Subject: [PATCH 018/134] Prepare for release 5.0.0-alpha.13. --- CHANGELOG.md | 71 +++++++++++++++++++++++++++++++++ build.gradle.kts | 2 +- docs/changelogs/changelog_4x.md | 6 +++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a36ad2a9d13e..802ec20a3104 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,72 @@ Change Log See [4.x Change log](https://square.github.io/okhttp/changelogs/changelog_4x/) for the stable version changelogs. +## Version 5.0.0-alpha.13 + +_2024-04-16_ + + * Breaking: Tag unstable new APIs as `@ExperimentalOkHttpApi`. We intend to release OkHttp 5.0 + without stabilizing these new APIs first. + + Do not use these experimental APIs in modules that may be executed using a version of OkHttp + different from the version that the module was compiled with. Do not use them in published + libraries. Do not use them if you aren't willing to track changes to them. + + * Breaking: Drop support for Kotlin Multiplatform. + + We planned to support multiplatform in OkHttp 5.0, but after building it, we weren't happy with + the implementation trade-offs. We can't use our HTTP client engine on Kotlin/JS, and we weren't + prepared to build a TLS API for Kotlin/Native. + + We'd prefer a multiplatform HTTP client API that's backed by OkHttp on Android and JVM, and + other engines on other platforms. [Ktor] does this pretty well today! + + * Breaking: Use `kotlin.time.Duration` in APIs like `OkHttpClient.Builder.callTimeout()`. This + update also drops support for the `DurationUnit` functions introduced in earlier alpha releases + of OkHttp 5. + + * Breaking: Reorder the parameters in the Cache constructor that was introduced in 5.0.0-alpha.3. + + * New: `Request.Builder.cacheUrlOverride()` customizes the cache key used for a request. This can + be used to make canonical URLs for the cache that omit insignificant query parameters or other + irrelevant data. + + This feature may be used with `POST` requests to cache their responses. In such cases the + request body is not used to determine the cache key, so you must manually add cache-relevant + data to the override URL. For example, you could add a `request-body-sha256` query parameter so + requests with the same POST data get the same cache entry. + + * New: `HttpLoggingInterceptor.redactQueryParams()` configures the query parameters to redact + in logs. For best security, don't put sensitive information in query parameters. + + * New: `ConnectionPool.setPolicy()` configures a minimum connection pool size for a target + address. Use this to proactively open HTTP connections. + + Connections opened to fulfill this policy are subject to the connection pool's + `keepAliveDuration` but do not count against the pool-wide `maxIdleConnections` limit. + + This feature increases the client's traffic and the load on the server. Talking to your server's + operators before adopting it. + + * New in okhttp-android: `HttpLoggingInterceptor.androidLogging()` and + `LoggingEventListener.androidLogging()` write HTTP calls or events to Logcat. + + * New: `OkHttpClient.webSocketCloseTimeout` configures how long a web socket connection will wait + for a graceful shutdown before it performs an abrupt shutdown. + + * Fix: Honor `RequestBody.isOneShot()` in `MultipartBody` + + * Fix in `okhttp-coroutines`: Don't leak response bodies in `executeAsync()`. We had a bug where + we didn't call `Response.close()` if the coroutine was canceled before its response was + returned. + + * Upgrade: [Okio 3.9.0][okio_3_9_0]. + + * Upgrade: [Kotlin 1.9.23][kotlin_1_9_23]. + + * Upgrade: [Unicode® IDNA 15.1.0][idna_15_1_0] + + ## Version 5.0.0-alpha.12 _2023-12-17_ @@ -357,20 +423,25 @@ Note that this was originally released on 2020-10-06 as 4.10.0-RC1. The only cha release is the version name. +[Ktor]: https://ktor.io/ [assertk]: https://github.com/willowtreeapps/assertk [graalvm]: https://www.graalvm.org/ [graalvm_21]: https://www.graalvm.org/release-notes/21_0/ [graalvm_22]: https://www.graalvm.org/release-notes/22_2/ +[idna_15_1_0]: https://www.unicode.org/reports/tr46/#Modifications [kotlin_1_4_20]: https://github.com/JetBrains/kotlin/releases/tag/v1.4.20 [kotlin_1_5_31]: https://github.com/JetBrains/kotlin/releases/tag/v1.5.31 [kotlin_1_6_10]: https://github.com/JetBrains/kotlin/releases/tag/v1.6.10 [kotlin_1_6_21]: https://github.com/JetBrains/kotlin/releases/tag/v1.6.21 [kotlin_1_7_10]: https://github.com/JetBrains/kotlin/releases/tag/v1.7.10 [kotlin_1_9_21]: https://github.com/JetBrains/kotlin/releases/tag/v1.9.21 +[kotlin_1_9_23]: https://github.com/JetBrains/kotlin/releases/tag/v1.9.23 +[loom]: https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html [okio_2_9_0]: https://square.github.io/okio/changelog/#version-290 [okio_3_0_0]: https://square.github.io/okio/changelog/#version-300 [okio_3_1_0]: https://square.github.io/okio/changelog/#version-310 [okio_3_2_0]: https://square.github.io/okio/changelog/#version-320 [okio_3_7_0]: https://square.github.io/okio/changelog/#version-370 +[okio_3_9_0]: https://square.github.io/okio/changelog/#version-390 [rfc_8305]: https://tools.ietf.org/html/rfc8305 [uts46]: https://www.unicode.org/reports/tr46 diff --git a/build.gradle.kts b/build.gradle.kts index da74c4002860..d1d7b3c0ecd1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -50,7 +50,7 @@ configure { allprojects { group = "com.squareup.okhttp3" - version = "5.0.0-SNAPSHOT" + version = "5.0.0-alpha.13" repositories { mavenCentral() diff --git a/docs/changelogs/changelog_4x.md b/docs/changelogs/changelog_4x.md index d5bfb30361bd..6019c35da441 100644 --- a/docs/changelogs/changelog_4x.md +++ b/docs/changelogs/changelog_4x.md @@ -6,9 +6,12 @@ OkHttp 4.x Change Log _2023-10-16_ * Fix: Don't hang taking headers for HTTP 103 responses. + * Fix: Recover gracefully when a cache entry's certificate is corrupted. + * Fix: Fail permanently when there's a failure loading the bundled public suffix database. This is the dataset that powers `HttpUrl.topPrivateDomain()`. + * Fix: Immediately update the connection's flow control window instead of waiting for the receiving stream to process it. @@ -16,9 +19,12 @@ _2023-10-16_ calls and that can receive data faster than they can process it. Previously, OkHttp limited HTTP/2 to 16 MiB of unacknowledged data per connection. With this fix there is a limit of 16 MiB of unacknowledged data per stream and no per-connection limit. + * Fix: Don't operate on a connection after it's been returned to the pool. This race occurred on failed web socket connection attempts. + * Upgrade: [Okio 3.6.0][okio_3_6_0]. + * Upgrade: [Kotlin 1.8.21][kotlin_1_8_21]. From 668fce2b393860a7f6f01f282fdc6c7f973e541c Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 17 Apr 2024 09:26:07 -0400 Subject: [PATCH 019/134] Prepare next development version. --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index d1d7b3c0ecd1..da74c4002860 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -50,7 +50,7 @@ configure { allprojects { group = "com.squareup.okhttp3" - version = "5.0.0-alpha.13" + version = "5.0.0-SNAPSHOT" repositories { mavenCentral() From 5e1a3e959fe603a0b11cb9cc4aa6c867e5b8ae8a Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 17 Apr 2024 09:52:16 -0400 Subject: [PATCH 020/134] Don't require a signing key to publish docs (#8368) --- test_docs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_docs.sh b/test_docs.sh index 18fd7389089b..ba482f0bf3bd 100755 --- a/test_docs.sh +++ b/test_docs.sh @@ -9,7 +9,7 @@ set -ex # Test generating the javadoc jars -./gradlew publishToMavenLocal +./gradlew publishToMavenLocal -DRELEASE_SIGNING_ENABLED=false # Generate the API docs ./gradlew dokkaHtmlMultiModule From d6613810ee63c8cdd48885d05975671b7f0540fe Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 17 Apr 2024 21:24:38 -0400 Subject: [PATCH 021/134] Move coroutines extensions to okhttp3.coroutines (#8372) * Move coroutines extensions to okhttp3.coroutines This has the side-effect of fixing our packaging of this module. Previously the okhttp-coroutines.jar contained the code from the :okhttp artifact, not the :okhttp-coroutines artifact. I suspect something in one of our build steps is incorrectly using the package names (only) as a cache key, and it should instead be using the package contents. * apiDump --- build.gradle.kts | 3 --- okhttp-coroutines/api/okhttp-coroutines.api | 2 +- .../ExecuteAsync.kt} | 5 ++++- .../ExecuteAsyncTest.kt} | 15 +++++++++------ .../publicsuffix/PublicSuffixListGenerator.kt | 2 +- .../src/main/kotlin/okhttp3/survey/Iana.kt | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) rename okhttp-coroutines/src/main/kotlin/okhttp3/{JvmCallExtensions.kt => coroutines/ExecuteAsync.kt} (93%) rename okhttp-coroutines/src/test/kotlin/okhttp3/{SuspendCallTest.kt => coroutines/ExecuteAsyncTest.kt} (95%) diff --git a/build.gradle.kts b/build.gradle.kts index da74c4002860..9c4702f37d57 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,5 @@ @file:Suppress("UnstableApiUsage") -import com.diffplug.gradle.spotless.KotlinExtension import com.diffplug.gradle.spotless.SpotlessExtension import com.vanniktech.maven.publish.MavenPublishBaseExtension import com.vanniktech.maven.publish.SonatypeHost @@ -9,9 +8,7 @@ import kotlinx.validation.ApiValidationExtension import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.jetbrains.dokka.gradle.DokkaTaskPartial import org.jetbrains.kotlin.gradle.dsl.kotlinExtension -import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.jetbrains.kotlin.js.translate.context.Namer.kotlin import ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferExtension buildscript { diff --git a/okhttp-coroutines/api/okhttp-coroutines.api b/okhttp-coroutines/api/okhttp-coroutines.api index 4261ec3bb4b7..d8b28b46ce74 100644 --- a/okhttp-coroutines/api/okhttp-coroutines.api +++ b/okhttp-coroutines/api/okhttp-coroutines.api @@ -1,4 +1,4 @@ -public final class okhttp3/JvmCallExtensionsKt { +public final class okhttp3/coroutines/ExecuteAsyncKt { public static final fun executeAsync (Lokhttp3/Call;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } diff --git a/okhttp-coroutines/src/main/kotlin/okhttp3/JvmCallExtensions.kt b/okhttp-coroutines/src/main/kotlin/okhttp3/coroutines/ExecuteAsync.kt similarity index 93% rename from okhttp-coroutines/src/main/kotlin/okhttp3/JvmCallExtensions.kt rename to okhttp-coroutines/src/main/kotlin/okhttp3/coroutines/ExecuteAsync.kt index c301ddbc122d..07b976a2063b 100644 --- a/okhttp-coroutines/src/main/kotlin/okhttp3/JvmCallExtensions.kt +++ b/okhttp-coroutines/src/main/kotlin/okhttp3/coroutines/ExecuteAsync.kt @@ -15,11 +15,14 @@ * */ -package okhttp3 +package okhttp3.coroutines import kotlin.coroutines.resumeWithException import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.suspendCancellableCoroutine +import okhttp3.Call +import okhttp3.Callback +import okhttp3.Response import okhttp3.internal.closeQuietly import okio.IOException diff --git a/okhttp-coroutines/src/test/kotlin/okhttp3/SuspendCallTest.kt b/okhttp-coroutines/src/test/kotlin/okhttp3/coroutines/ExecuteAsyncTest.kt similarity index 95% rename from okhttp-coroutines/src/test/kotlin/okhttp3/SuspendCallTest.kt rename to okhttp-coroutines/src/test/kotlin/okhttp3/coroutines/ExecuteAsyncTest.kt index dcf6080f1e68..6f436ba0bf60 100644 --- a/okhttp-coroutines/src/test/kotlin/okhttp3/SuspendCallTest.kt +++ b/okhttp-coroutines/src/test/kotlin/okhttp3/coroutines/ExecuteAsyncTest.kt @@ -14,10 +14,7 @@ * limitations under the License. * */ - -@file:OptIn(ExperimentalCoroutinesApi::class) - -package okhttp3 +package okhttp3.coroutines import assertk.assertThat import assertk.assertions.isEqualTo @@ -28,7 +25,6 @@ import kotlin.test.assertFailsWith import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.job @@ -39,7 +35,14 @@ import kotlinx.coroutines.withTimeout import mockwebserver3.MockResponse import mockwebserver3.MockWebServer import mockwebserver3.SocketPolicy.DisconnectAfterRequest +import okhttp3.Callback +import okhttp3.FailingCall import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.OkHttpClientTestRule +import okhttp3.Protocol +import okhttp3.Request +import okhttp3.Response +import okhttp3.ResponseBody import okio.Buffer import okio.ForwardingSource import okio.buffer @@ -48,7 +51,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension import org.junit.jupiter.api.fail -class SuspendCallTest { +class ExecuteAsyncTest { @RegisterExtension val clientTestRule = OkHttpClientTestRule() diff --git a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt index f83112e2918a..8d77d56d4a63 100644 --- a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt +++ b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt @@ -22,7 +22,7 @@ import kotlinx.coroutines.withContext import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request -import okhttp3.executeAsync +import okhttp3.coroutines.executeAsync import okhttp3.internal.publicsuffix.PublicSuffixDatabase.Companion.PUBLIC_SUFFIX_RESOURCE import okio.BufferedSink import okio.ByteString diff --git a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Iana.kt b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Iana.kt index 5427864e79b5..ae0541fde032 100644 --- a/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Iana.kt +++ b/samples/tlssurvey/src/main/kotlin/okhttp3/survey/Iana.kt @@ -18,7 +18,7 @@ package okhttp3.survey import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request -import okhttp3.executeAsync +import okhttp3.coroutines.executeAsync import okhttp3.survey.types.SuiteId import okio.ByteString.Companion.decodeHex import okio.IOException From 35f490393f5233680e978354452b51c809ec3d26 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 17 Apr 2024 21:31:39 -0400 Subject: [PATCH 022/134] Prepare for release 5.0.0-alpha.14. --- CHANGELOG.md | 12 ++++++++++++ build.gradle.kts | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 802ec20a3104..f68d7f99177b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ Change Log See [4.x Change log](https://square.github.io/okhttp/changelogs/changelog_4x/) for the stable version changelogs. +## Version 5.0.0-alpha.14 + +_2024-04-17_ + + * Breaking: Move coroutines extensions to okhttp3.coroutines. Previously this artifact shared the + `okhttp3` package name with our core module, which is incompatible with the Java Platform Module + System. + + * Fix in okhttp-coroutines: Publish a valid artifact. The coroutines JAR file in 5.0.0-alpha.13 + was corrupt and should not be used. + + ## Version 5.0.0-alpha.13 _2024-04-16_ diff --git a/build.gradle.kts b/build.gradle.kts index 9c4702f37d57..bbb5d00ca9bb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -47,7 +47,7 @@ configure { allprojects { group = "com.squareup.okhttp3" - version = "5.0.0-SNAPSHOT" + version = "5.0.0-alpha.14" repositories { mavenCentral() From 577d621585f7525d3e98a9161bc26d2965686538 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 17 Apr 2024 21:32:42 -0400 Subject: [PATCH 023/134] Prepare next development version. --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index bbb5d00ca9bb..9c4702f37d57 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -47,7 +47,7 @@ configure { allprojects { group = "com.squareup.okhttp3" - version = "5.0.0-alpha.14" + version = "5.0.0-SNAPSHOT" repositories { mavenCentral() From d0d75578228c5530b5c4ad5b3370d08d7bbeb401 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 20 Apr 2024 18:03:43 +0100 Subject: [PATCH 024/134] Move to centralised loom safe locks (#8371) --- .../main/kotlin/okhttp3/TestValueFactory.kt | 3 +- okhttp/src/main/kotlin/okhttp3/Dispatcher.kt | 105 ++++--- .../internal/connection/ConnectPlan.kt | 4 +- .../okhttp3/internal/connection/Locks.kt | 65 ++++ .../okhttp3/internal/connection/RealCall.kt | 31 +- .../internal/connection/RealConnection.kt | 57 ++-- .../internal/connection/RealConnectionPool.kt | 33 +- .../internal/connection/RealRoutePlanner.kt | 5 +- .../okhttp3/internal/http2/Http2Connection.kt | 119 ++++---- .../okhttp3/internal/http2/Http2Stream.kt | 157 +++++----- .../okhttp3/internal/http2/Http2Writer.kt | 286 +++++++++--------- .../internal/connection/ConnectionPoolTest.kt | 5 +- .../internal/http2/Http2ConnectionTest.kt | 9 +- 13 files changed, 507 insertions(+), 372 deletions(-) create mode 100644 okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt index bbc348fa8ab0..de57c4c5861f 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/TestValueFactory.kt @@ -36,6 +36,7 @@ import okhttp3.internal.concurrent.TaskFaker import okhttp3.internal.concurrent.TaskRunner import okhttp3.internal.connection.CallConnectionUser import okhttp3.internal.connection.FastFallbackExchangeFinder +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.connection.RealCall import okhttp3.internal.connection.RealConnection import okhttp3.internal.connection.RealConnectionPool @@ -93,7 +94,7 @@ class TestValueFactory : Closeable { socket = Socket(), idleAtNs = idleAtNanos, ) - synchronized(result) { pool.put(result) } + result.withLock { pool.put(result) } return result } diff --git a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt index e869053c1982..57d0ab29a4f9 100644 --- a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt +++ b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt @@ -22,7 +22,9 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.SynchronousQueue import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit -import okhttp3.internal.assertThreadDoesntHoldLock +import java.util.concurrent.locks.ReentrantLock +import okhttp3.internal.assertNotHeld +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.connection.RealCall import okhttp3.internal.connection.RealCall.AsyncCall import okhttp3.internal.okHttpName @@ -36,6 +38,8 @@ import okhttp3.internal.threadFactory * concurrently. */ class Dispatcher() { + internal val lock: ReentrantLock = ReentrantLock() + /** * The maximum number of requests to execute concurrently. Above this requests queue in memory, * waiting for the running calls to complete. @@ -43,10 +47,11 @@ class Dispatcher() { * If more than [maxRequests] requests are in flight when this is invoked, those requests will * remain in flight. */ - @get:Synchronized var maxRequests = 64 + var maxRequests = 64 + get() = this.withLock { field } set(maxRequests) { require(maxRequests >= 1) { "max < 1: $maxRequests" } - synchronized(this) { + this.withLock { field = maxRequests } promoteAndExecute() @@ -62,10 +67,11 @@ class Dispatcher() { * * WebSocket connections to hosts **do not** count against this limit. */ - @get:Synchronized var maxRequestsPerHost = 5 + var maxRequestsPerHost = 5 + get() = this.withLock { field } set(maxRequestsPerHost) { require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" } - synchronized(this) { + this.withLock { field = maxRequestsPerHost } promoteAndExecute() @@ -82,29 +88,31 @@ class Dispatcher() { * This means that if you are doing synchronous calls the network layer will not truly be idle * until every returned [Response] has been closed. */ - @set:Synchronized - @get:Synchronized var idleCallback: Runnable? = null + get() = this.withLock { field } + set(value) { + this.withLock { field = value } + } private var executorServiceOrNull: ExecutorService? = null - @get:Synchronized @get:JvmName("executorService") val executorService: ExecutorService - get() { - if (executorServiceOrNull == null) { - executorServiceOrNull = - ThreadPoolExecutor( - 0, - Int.MAX_VALUE, - 60, - TimeUnit.SECONDS, - SynchronousQueue(), - threadFactory("$okHttpName Dispatcher", false), - ) + get() = + this.withLock { + if (executorServiceOrNull == null) { + executorServiceOrNull = + ThreadPoolExecutor( + 0, + Int.MAX_VALUE, + 60, + TimeUnit.SECONDS, + SynchronousQueue(), + threadFactory("$okHttpName Dispatcher", false), + ) + } + return executorServiceOrNull!! } - return executorServiceOrNull!! - } /** Ready async calls in the order they'll be run. */ private val readyAsyncCalls = ArrayDeque() @@ -120,7 +128,7 @@ class Dispatcher() { } internal fun enqueue(call: AsyncCall) { - synchronized(this) { + this.withLock { readyAsyncCalls.add(call) // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to @@ -147,15 +155,17 @@ class Dispatcher() { * Cancel all calls currently enqueued or executing. Includes calls executed both * [synchronously][Call.execute] and [asynchronously][Call.enqueue]. */ - @Synchronized fun cancelAll() { - for (call in readyAsyncCalls) { - call.call.cancel() - } - for (call in runningAsyncCalls) { - call.call.cancel() - } - for (call in runningSyncCalls) { - call.cancel() + fun cancelAll() { + this.withLock { + for (call in readyAsyncCalls) { + call.call.cancel() + } + for (call in runningAsyncCalls) { + call.call.cancel() + } + for (call in runningSyncCalls) { + call.cancel() + } } } @@ -167,11 +177,11 @@ class Dispatcher() { * @return true if the dispatcher is currently running calls. */ private fun promoteAndExecute(): Boolean { - this.assertThreadDoesntHoldLock() + lock.assertNotHeld() val executableCalls = mutableListOf() val isRunning: Boolean - synchronized(this) { + this.withLock { val i = readyAsyncCalls.iterator() while (i.hasNext()) { val asyncCall = i.next() @@ -195,7 +205,7 @@ class Dispatcher() { val asyncCall = executableCalls[i] asyncCall.callsPerHost.decrementAndGet() - synchronized(this) { + this.withLock { runningAsyncCalls.remove(asyncCall) } @@ -213,9 +223,10 @@ class Dispatcher() { } /** Used by [Call.execute] to signal it is in-flight. */ - @Synchronized internal fun executed(call: RealCall) { - runningSyncCalls.add(call) - } + internal fun executed(call: RealCall) = + this.withLock { + runningSyncCalls.add(call) + } /** Used by [AsyncCall.run] to signal completion. */ internal fun finished(call: AsyncCall) { @@ -233,7 +244,7 @@ class Dispatcher() { call: T, ) { val idleCallback: Runnable? - synchronized(this) { + this.withLock { if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!") idleCallback = this.idleCallback } @@ -246,18 +257,20 @@ class Dispatcher() { } /** Returns a snapshot of the calls currently awaiting execution. */ - @Synchronized fun queuedCalls(): List { - return Collections.unmodifiableList(readyAsyncCalls.map { it.call }) - } + fun queuedCalls(): List = + this.withLock { + return Collections.unmodifiableList(readyAsyncCalls.map { it.call }) + } /** Returns a snapshot of the calls currently being executed. */ - @Synchronized fun runningCalls(): List { - return Collections.unmodifiableList(runningSyncCalls + runningAsyncCalls.map { it.call }) - } + fun runningCalls(): List = + this.withLock { + return Collections.unmodifiableList(runningSyncCalls + runningAsyncCalls.map { it.call }) + } - @Synchronized fun queuedCallsCount(): Int = readyAsyncCalls.size + fun queuedCallsCount(): Int = this.withLock { readyAsyncCalls.size } - @Synchronized fun runningCallsCount(): Int = runningAsyncCalls.size + runningSyncCalls.size + fun runningCallsCount(): Int = this.withLock { runningAsyncCalls.size + runningSyncCalls.size } @JvmName("-deprecated_executorService") @Deprecated( diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt index a5c31f9cf03b..625791a5b835 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt @@ -26,6 +26,7 @@ import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.SSLSocket +import kotlin.concurrent.withLock import okhttp3.CertificatePinner import okhttp3.ConnectionSpec import okhttp3.Handshake @@ -35,6 +36,7 @@ import okhttp3.Request import okhttp3.Route import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.connection.RoutePlanner.ConnectResult import okhttp3.internal.http.ExchangeCodec import okhttp3.internal.http1.Http1ExchangeCodec @@ -503,7 +505,7 @@ class ConnectPlan( val pooled3 = routePlanner.planReusePooledConnection(this, routes) if (pooled3 != null) return pooled3.connection - synchronized(connection) { + connection.withLock { connectionPool.put(connection) user.acquireConnectionNoEvents(connection) } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt new file mode 100644 index 000000000000..b09ce9a2d33a --- /dev/null +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 Block, 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:OptIn(ExperimentalContracts::class) + +package okhttp3.internal.connection + +import kotlin.concurrent.withLock +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import okhttp3.Dispatcher +import okhttp3.internal.http2.Http2Connection +import okhttp3.internal.http2.Http2Stream +import okhttp3.internal.http2.Http2Writer + +/** + * Centralisation of central locks according to docs/contribute/concurrency.md + */ +internal object Locks { + inline fun Dispatcher.withLock(action: () -> T): T { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return lock.withLock(action) + } + + inline fun RealConnection.withLock(action: () -> T): T { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return lock.withLock(action) + } + + inline fun RealCall.withLock(action: () -> T): T { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return lock.withLock(action) + } + + inline fun Http2Connection.withLock(action: () -> T): T { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return lock.withLock(action) + } + + inline fun Http2Stream.withLock(action: () -> T): T { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return lock.withLock(action) + } + + inline fun Http2Writer.withLock(action: () -> T): T { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + + // TODO can we assert we don't have the connection lock? + + return lock.withLock(action) + } +} diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt index 2f7be64ba69e..1a83d90309af 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt @@ -25,6 +25,7 @@ import java.util.concurrent.RejectedExecutionException import java.util.concurrent.TimeUnit.MILLISECONDS import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.locks.ReentrantLock import okhttp3.Call import okhttp3.Callback import okhttp3.EventListener @@ -32,10 +33,12 @@ import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response +import okhttp3.internal.assertHeld +import okhttp3.internal.assertNotHeld import okhttp3.internal.assertThreadDoesntHoldLock -import okhttp3.internal.assertThreadHoldsLock import okhttp3.internal.cache.CacheInterceptor import okhttp3.internal.closeQuietly +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.http.BridgeInterceptor import okhttp3.internal.http.CallServerInterceptor import okhttp3.internal.http.RealInterceptorChain @@ -60,6 +63,8 @@ class RealCall( val originalRequest: Request, val forWebSocket: Boolean, ) : Call, Cloneable { + internal val lock: ReentrantLock = ReentrantLock() + private val connectionPool: RealConnectionPool = client.connectionPool.delegate internal val eventListener: EventListener = client.eventListenerFactory.create(this) @@ -95,7 +100,7 @@ class RealCall( internal var interceptorScopedExchange: Exchange? = null private set - // These properties are guarded by this. They are typically only accessed by the thread executing + // These properties are guarded by [lock]. They are typically only accessed by the thread executing // the call, but they may be accessed by other threads for duplex requests. /** True if this call still has a request body open. */ @@ -231,7 +236,7 @@ class RealCall( ) { check(interceptorScopedExchange == null) - synchronized(this) { + this.withLock { check(!responseBodyOpen) { "cannot make a new request because the previous response is still open: " + "please call response.close()" @@ -265,7 +270,7 @@ class RealCall( /** Finds a new or pooled connection to carry a forthcoming request and response. */ internal fun initExchange(chain: RealInterceptorChain): Exchange { - synchronized(this) { + this.withLock { check(expectMoreExchanges) { "released" } check(!responseBodyOpen) check(!requestBodyOpen) @@ -277,7 +282,7 @@ class RealCall( val result = Exchange(this, eventListener, exchangeFinder, codec) this.interceptorScopedExchange = result this.exchange = result - synchronized(this) { + this.withLock { this.requestBodyOpen = true this.responseBodyOpen = true } @@ -287,7 +292,7 @@ class RealCall( } fun acquireConnectionNoEvents(connection: RealConnection) { - connection.assertThreadHoldsLock() + connection.lock.assertHeld() check(this.connection == null) this.connection = connection @@ -312,7 +317,7 @@ class RealCall( var bothStreamsDone = false var callDone = false - synchronized(this) { + this.withLock { if (requestDone && requestBodyOpen || responseDone && responseBodyOpen) { if (requestDone) requestBodyOpen = false if (responseDone) responseBodyOpen = false @@ -335,7 +340,7 @@ class RealCall( internal fun noMoreExchanges(e: IOException?): IOException? { var callDone = false - synchronized(this) { + this.withLock { if (expectMoreExchanges) { expectMoreExchanges = false callDone = !requestBodyOpen && !responseBodyOpen @@ -362,13 +367,13 @@ class RealCall( * additional context. Otherwise [e] is returned as-is. */ private fun callDone(e: E): E { - assertThreadDoesntHoldLock() + lock.assertNotHeld() val connection = this.connection if (connection != null) { - connection.assertThreadDoesntHoldLock() + connection.lock.assertNotHeld() val toClose: Socket? = - synchronized(connection) { + connection.withLock { // Sets this.connection to null. releaseConnectionNoEvents() } @@ -399,7 +404,7 @@ class RealCall( */ internal fun releaseConnectionNoEvents(): Socket? { val connection = this.connection!! - connection.assertThreadHoldsLock() + connection.lock.assertHeld() val calls = connection.calls val index = calls.indexOfFirst { it.get() == this@RealCall } @@ -443,7 +448,7 @@ class RealCall( * This is usually due to either an exception or a retry. */ internal fun exitNetworkInterceptorExchange(closeExchange: Boolean) { - synchronized(this) { + this.withLock { check(expectMoreExchanges) { "released" } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt index f379a4e29efa..432dcc074e7e 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt @@ -23,8 +23,10 @@ import java.net.Socket import java.net.SocketException import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit.MILLISECONDS +import java.util.concurrent.locks.ReentrantLock import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.SSLSocket +import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.Connection import okhttp3.ConnectionListener @@ -33,10 +35,11 @@ import okhttp3.HttpUrl import okhttp3.OkHttpClient import okhttp3.Protocol import okhttp3.Route -import okhttp3.internal.assertThreadDoesntHoldLock -import okhttp3.internal.assertThreadHoldsLock +import okhttp3.internal.assertHeld +import okhttp3.internal.assertNotHeld import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.http.ExchangeCodec import okhttp3.internal.http.RealInterceptorChain import okhttp3.internal.http1.Http1ExchangeCodec @@ -80,7 +83,9 @@ class RealConnection( ) : Http2Connection.Listener(), Connection, ExchangeCodec.Carrier { private var http2Connection: Http2Connection? = null - // These properties are guarded by this. + internal val lock: ReentrantLock = ReentrantLock() + + // These properties are guarded by [lock]. /** * If true, no new exchanges can be created on this connection. It is necessary to set this to @@ -129,19 +134,23 @@ class RealConnection( /** Prevent further exchanges from being created on this connection. */ override fun noNewExchanges() { - synchronized(this) { + this.withLock { noNewExchanges = true } connectionListener.noNewExchanges(this) } /** Prevent this connection from being used for hosts other than the one in [route]. */ - @Synchronized internal fun noCoalescedConnections() { - noCoalescedConnections = true + internal fun noCoalescedConnections() { + this.withLock { + noCoalescedConnections = true + } } - @Synchronized internal fun incrementSuccessCount() { - successCount++ + internal fun incrementSuccessCount() { + this.withLock { + successCount++ + } } @Throws(IOException::class) @@ -179,7 +188,7 @@ class RealConnection( address: Address, routes: List?, ): Boolean { - assertThreadHoldsLock() + lock.assertHeld() // If this connection is not accepting new exchanges, we're done. if (calls.size >= allocationLimit || noNewExchanges) return false @@ -232,7 +241,7 @@ class RealConnection( } private fun supportsUrl(url: HttpUrl): Boolean { - assertThreadHoldsLock() + lock.assertHeld() val routeUrl = route.address.url @@ -308,7 +317,7 @@ class RealConnection( /** Returns true if this connection is ready to host new streams. */ fun isHealthy(doExtensiveChecks: Boolean): Boolean { - assertThreadDoesntHoldLock() + lock.assertNotHeld() val nowNs = System.nanoTime() @@ -326,7 +335,7 @@ class RealConnection( return http2Connection.isHealthy(nowNs) } - val idleDurationNs = synchronized(this) { nowNs - idleAtNs } + val idleDurationNs = lock.withLock { nowNs - idleAtNs } if (idleDurationNs >= IDLE_CONNECTION_HEALTHY_NS && doExtensiveChecks) { return socket.isHealthy(source) } @@ -341,19 +350,21 @@ class RealConnection( } /** When settings are received, adjust the allocation limit. */ - @Synchronized override fun onSettings( + override fun onSettings( connection: Http2Connection, settings: Settings, ) { - val oldLimit = allocationLimit - allocationLimit = settings.getMaxConcurrentStreams() - - if (allocationLimit < oldLimit) { - // We might need new connections to keep policies satisfied - connectionPool.scheduleOpener(route.address) - } else if (allocationLimit > oldLimit) { - // We might no longer need some connections - connectionPool.scheduleCloser() + lock.withLock { + val oldLimit = allocationLimit + allocationLimit = settings.getMaxConcurrentStreams() + + if (allocationLimit < oldLimit) { + // We might need new connections to keep policies satisfied + connectionPool.scheduleOpener(route.address) + } else if (allocationLimit > oldLimit) { + // We might no longer need some connections + connectionPool.scheduleCloser() + } } } @@ -387,7 +398,7 @@ class RealConnection( e: IOException?, ) { var noNewExchangesEvent = false - synchronized(this) { + lock.withLock { if (e is StreamResetException) { when { e.errorCode == ErrorCode.REFUSED_STREAM -> { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt index c4d376c92f11..f4bdfe69d23c 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt @@ -25,11 +25,12 @@ import okhttp3.Address import okhttp3.ConnectionListener import okhttp3.ConnectionPool import okhttp3.Route -import okhttp3.internal.assertThreadHoldsLock +import okhttp3.internal.assertHeld import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.Task import okhttp3.internal.concurrent.TaskQueue import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.connection.RealCall.CallReference import okhttp3.internal.okHttpName import okhttp3.internal.platform.Platform @@ -80,7 +81,7 @@ class RealConnectionPool( fun idleConnectionCount(): Int { return connections.count { - synchronized(it) { it.calls.isEmpty() } + it.withLock { it.calls.isEmpty() } } } @@ -110,7 +111,7 @@ class RealConnectionPool( for (connection in connections) { // In the first synchronized block, acquire the connection if it can satisfy this call. val acquired = - synchronized(connection) { + connection.withLock { when { requireMultiplexed && !connection.isMultiplexed -> false !connection.isEligible(address, routes) -> false @@ -129,7 +130,7 @@ class RealConnectionPool( // the hook to close this connection if it's no longer in use. val noNewExchangesEvent: Boolean val toClose: Socket? = - synchronized(connection) { + connection.withLock { noNewExchangesEvent = !connection.noNewExchanges connection.noNewExchanges = true connectionUser.releaseConnectionNoEvents() @@ -145,7 +146,7 @@ class RealConnectionPool( } fun put(connection: RealConnection) { - connection.assertThreadHoldsLock() + connection.lock.assertHeld() connections.add(connection) // connection.queueEvent { connectionListener.connectEnd(connection) } @@ -157,7 +158,7 @@ class RealConnectionPool( * removed from the pool and should be closed. */ fun connectionBecameIdle(connection: RealConnection): Boolean { - connection.assertThreadHoldsLock() + connection.lock.assertHeld() return if (connection.noNewExchanges || maxIdleConnections == 0) { connection.noNewExchanges = true @@ -176,13 +177,13 @@ class RealConnectionPool( while (i.hasNext()) { val connection = i.next() val socketToClose = - synchronized(connection) { + connection.withLock { if (connection.calls.isEmpty()) { i.remove() connection.noNewExchanges = true - return@synchronized connection.socket() + return@withLock connection.socket() } else { - return@synchronized null + return@withLock null } } if (socketToClose != null) { @@ -214,7 +215,7 @@ class RealConnectionPool( } for (connection in connections) { val addressState = addressStates[connection.route.address] ?: continue - synchronized(connection) { + connection.withLock { addressState.concurrentCallCapacity += connection.allocationLimit } } @@ -237,11 +238,11 @@ class RealConnectionPool( var inUseConnectionCount = 0 var evictableConnectionCount = 0 for (connection in connections) { - synchronized(connection) { + connection.withLock { // If the connection is in use, keep searching. if (pruneAndGetAllocationCount(connection, now) > 0) { inUseConnectionCount++ - return@synchronized + return@withLock } val idleAtNs = connection.idleAtNs @@ -285,7 +286,7 @@ class RealConnectionPool( when { toEvict != null -> { // We've chosen a connection to evict. Confirm it's still okay to be evicted, then close it. - synchronized(toEvict) { + toEvict.withLock { if (toEvict.calls.isNotEmpty()) return 0L // No longer idle. if (toEvict.idleAtNs != toEvictIdleAtNs) return 0L // No longer oldest. toEvict.noNewExchanges = true @@ -336,7 +337,7 @@ class RealConnectionPool( connection: RealConnection, now: Long, ): Int { - connection.assertThreadHoldsLock() + connection.lock.assertHeld() val references = connection.calls var i = 0 @@ -415,7 +416,7 @@ class RealConnectionPool( var concurrentCallCapacity = 0 for (connection in connections) { if (state.address != connection.route.address) continue - synchronized(connection) { + connection.withLock { concurrentCallCapacity += connection.allocationLimit } @@ -430,7 +431,7 @@ class RealConnectionPool( // RealRoutePlanner will add the connection to the pool itself, other RoutePlanners may not // TODO: make all RoutePlanners consistent in this behavior if (connection !in connections) { - synchronized(connection) { put(connection) } + connection.withLock { put(connection) } } return 0L // run again immediately to create more connections if needed diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt index 3684a19da56c..e49564bcd722 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt @@ -30,6 +30,7 @@ import okhttp3.internal.USER_AGENT import okhttp3.internal.canReuseConnectionFor import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.connection.RoutePlanner.Plan import okhttp3.internal.platform.Platform import okhttp3.internal.toHostHeader @@ -94,7 +95,7 @@ class RealRoutePlanner( val healthy = candidate.isHealthy(connectionUser.doExtensiveHealthChecks()) var noNewExchangesEvent = false val toClose: Socket? = - synchronized(candidate) { + candidate.withLock { when { !healthy -> { noNewExchangesEvent = !candidate.noNewExchanges @@ -319,7 +320,7 @@ class RealRoutePlanner( * connections. */ private fun retryRoute(connection: RealConnection): Route? { - return synchronized(connection) { + return connection.withLock { when { connection.routeFailureCount != 0 -> null diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt index 686568d3d0fd..7339f4fcf8df 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt @@ -20,22 +20,23 @@ import java.io.IOException import java.io.InterruptedIOException import java.net.Socket import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.ReentrantLock import okhttp3.internal.EMPTY_BYTE_ARRAY import okhttp3.internal.EMPTY_HEADERS import okhttp3.internal.assertThreadDoesntHoldLock import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.http2.ErrorCode.REFUSED_STREAM import okhttp3.internal.http2.Settings.Companion.DEFAULT_INITIAL_WINDOW_SIZE import okhttp3.internal.http2.flowcontrol.WindowCounter import okhttp3.internal.ignoreIoExceptions -import okhttp3.internal.notifyAll import okhttp3.internal.okHttpName import okhttp3.internal.peerName import okhttp3.internal.platform.Platform import okhttp3.internal.platform.Platform.Companion.INFO import okhttp3.internal.toHeaders -import okhttp3.internal.wait import okio.Buffer import okio.BufferedSink import okio.BufferedSource @@ -54,7 +55,10 @@ import okio.source */ @Suppress("NAME_SHADOWING") class Http2Connection internal constructor(builder: Builder) : Closeable { - // Internal state of this connection is guarded by 'this'. No blocking operations may be + internal val lock: ReentrantLock = ReentrantLock() + internal val condition: Condition = lock.newCondition() + + // Internal state of this connection is guarded by 'lock'. No blocking operations may be // performed while holding this lock! // // Socket writes are guarded by frameWriter. @@ -149,12 +153,12 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { val pingIntervalNanos = TimeUnit.MILLISECONDS.toNanos(builder.pingIntervalMillis.toLong()) writerQueue.schedule("$connectionName ping", pingIntervalNanos) { val failDueToMissingPong = - synchronized(this@Http2Connection) { + this.withLock { if (intervalPongsReceived < intervalPingsSent) { - return@synchronized true + return@withLock true } else { intervalPingsSent++ - return@synchronized false + return@withLock false } } if (failDueToMissingPong) { @@ -171,30 +175,31 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** * Returns the number of [open streams][Http2Stream.isOpen] on this connection. */ - @Synchronized - fun openStreamCount(): Int = streams.size + fun openStreamCount(): Int = this.withLock { streams.size } - @Synchronized - fun getStream(id: Int): Http2Stream? = streams[id] + fun getStream(id: Int): Http2Stream? = this.withLock { streams[id] } - @Synchronized internal fun removeStream(streamId: Int): Http2Stream? { - val stream = streams.remove(streamId) + this.withLock { + val stream = streams.remove(streamId) - // The removed stream may be blocked on a connection-wide window update. - notifyAll() + // The removed stream may be blocked on a connection-wide window update. + condition.signalAll() - return stream + return stream + } } - @Synchronized internal fun updateConnectionFlowControl(read: Long) { - readBytes.update(total = read) - val readBytesToAcknowledge = readBytes.unacknowledged - if (readBytesToAcknowledge >= okHttpSettings.initialWindowSize / 2) { - writeWindowUpdateLater(0, readBytesToAcknowledge) - readBytes.update(acknowledged = readBytesToAcknowledge) + internal fun updateConnectionFlowControl(read: Long) { + this.withLock { + readBytes.update(total = read) + val readBytesToAcknowledge = readBytes.unacknowledged + if (readBytesToAcknowledge >= okHttpSettings.initialWindowSize / 2) { + writeWindowUpdateLater(0, readBytesToAcknowledge) + readBytes.update(acknowledged = readBytesToAcknowledge) + } + flowControlListener.receivingConnectionWindowChanged(readBytes) } - flowControlListener.receivingConnectionWindowChanged(readBytes) } /** @@ -240,8 +245,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { val stream: Http2Stream val streamId: Int - synchronized(writer) { - synchronized(this) { + writer.withLock { + this.withLock { if (nextStreamId > Int.MAX_VALUE / 2) { shutdown(REFUSED_STREAM) } @@ -311,7 +316,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { var byteCount = byteCount while (byteCount > 0L) { var toWrite: Int - synchronized(this@Http2Connection) { + this.withLock { try { while (writeBytesTotal >= writeBytesMaximum) { // Before blocking, confirm that the stream we're writing is still open. It's possible @@ -319,7 +324,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { if (!streams.containsKey(streamId)) { throw IOException("stream closed") } - this@Http2Connection.wait() // Wait until we receive a WINDOW_UPDATE. + condition.await() // Wait until we receive a WINDOW_UPDATE. } } catch (e: InterruptedException) { Thread.currentThread().interrupt() // Retain interrupted status. @@ -392,7 +397,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** For testing: sends a ping to be awaited with [awaitPong]. */ @Throws(InterruptedException::class) fun writePing() { - synchronized(this) { + this.withLock { awaitPingsSent++ } @@ -401,11 +406,12 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } /** For testing: awaits a pong. */ - @Synchronized @Throws(InterruptedException::class) fun awaitPong() { - while (awaitPongsReceived < awaitPingsSent) { - wait() + this.withLock { + while (awaitPongsReceived < awaitPingsSent) { + condition.await() + } } } @@ -421,9 +427,9 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { */ @Throws(IOException::class) fun shutdown(statusCode: ErrorCode) { - synchronized(writer) { + writer.withLock { val lastGoodStreamId: Int - synchronized(this) { + this.withLock { if (isShutdown) { return } @@ -456,7 +462,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } var streamsToClose: Array? = null - synchronized(this) { + this.withLock { if (streams.isNotEmpty()) { streamsToClose = streams.values.toTypedArray() streams.clear() @@ -516,8 +522,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { /** Merges [settings] into this peer's settings and sends them to the remote peer. */ @Throws(IOException::class) fun setSettings(settings: Settings) { - synchronized(writer) { - synchronized(this) { + writer.withLock { + this.withLock { if (isShutdown) { throw ConnectionShutdownException() } @@ -527,14 +533,15 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } } - @Synchronized fun isHealthy(nowNs: Long): Boolean { - if (isShutdown) return false + this.withLock { + if (isShutdown) return false - // A degraded pong is overdue. - if (degradedPongsReceived < degradedPingsSent && nowNs >= degradedPongDeadlineNs) return false + // A degraded pong is overdue. + if (degradedPongsReceived < degradedPingsSent && nowNs >= degradedPongDeadlineNs) return false - return true + return true + } } /** @@ -553,7 +560,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { * The deadline is currently hardcoded. We may make this configurable in the future! */ internal fun sendDegradedPingLater() { - synchronized(this) { + this.withLock { if (degradedPongsReceived < degradedPingsSent) return // Already awaiting a degraded pong. degradedPingsSent++ degradedPongDeadlineNs = System.nanoTime() + DEGRADED_PONG_TIMEOUT_NS @@ -682,7 +689,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { return } val stream: Http2Stream? - synchronized(this@Http2Connection) { + this@Http2Connection.withLock { stream = getStream(streamId) if (stream == null) { @@ -761,8 +768,8 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { var delta: Long var streamsToNotify: Array? var newPeerSettings: Settings - synchronized(writer) { - synchronized(this@Http2Connection) { + writer.withLock { + this@Http2Connection.withLock { val previousPeerSettings = peerSettings newPeerSettings = if (clearPrevious) { @@ -796,7 +803,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } if (streamsToNotify != null) { for (stream in streamsToNotify!!) { - synchronized(stream) { + stream.withLock { stream.addBytesToWriteWindow(delta) } } @@ -813,7 +820,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { payload2: Int, ) { if (ack) { - synchronized(this@Http2Connection) { + this@Http2Connection.withLock { when (payload1) { INTERVAL_PING -> { intervalPongsReceived++ @@ -823,7 +830,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { } AWAIT_PING -> { awaitPongsReceived++ - this@Http2Connection.notifyAll() + condition.signalAll() } else -> { // Ignore an unexpected pong. @@ -849,7 +856,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { // Copy the streams first. We don't want to hold a lock when we call receiveRstStream(). val streamsCopy: Array - synchronized(this@Http2Connection) { + this@Http2Connection.withLock { streamsCopy = streams.values.toTypedArray() isShutdown = true } @@ -868,14 +875,14 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { windowSizeIncrement: Long, ) { if (streamId == 0) { - synchronized(this@Http2Connection) { + this@Http2Connection.withLock { writeBytesMaximum += windowSizeIncrement - this@Http2Connection.notifyAll() + condition.signalAll() } } else { val stream = getStream(streamId) if (stream != null) { - synchronized(stream) { + stream.withLock { stream.addBytesToWriteWindow(windowSizeIncrement) } } @@ -918,7 +925,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { streamId: Int, requestHeaders: List
, ) { - synchronized(this) { + this.withLock { if (streamId in currentPushRequests) { writeSynResetLater(streamId, ErrorCode.PROTOCOL_ERROR) return @@ -930,7 +937,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { ignoreIoExceptions { if (cancel) { writer.rstStream(streamId, ErrorCode.CANCEL) - synchronized(this@Http2Connection) { + this.withLock { currentPushRequests.remove(streamId) } } @@ -948,7 +955,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { ignoreIoExceptions { if (cancel) writer.rstStream(streamId, ErrorCode.CANCEL) if (cancel || inFinished) { - synchronized(this@Http2Connection) { + this.withLock { currentPushRequests.remove(streamId) } } @@ -975,7 +982,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { val cancel = pushObserver.onData(streamId, buffer, byteCount, inFinished) if (cancel) writer.rstStream(streamId, ErrorCode.CANCEL) if (cancel || inFinished) { - synchronized(this@Http2Connection) { + this.withLock { currentPushRequests.remove(streamId) } } @@ -989,7 +996,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable { ) { pushQueue.execute("$connectionName[$streamId] onReset") { pushObserver.onReset(streamId, errorCode) - synchronized(this@Http2Connection) { + this.withLock { currentPushRequests.remove(streamId) } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt index dd1fa1e49584..ea27c00ecf5e 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt @@ -20,13 +20,14 @@ import java.io.IOException import java.io.InterruptedIOException import java.net.SocketTimeoutException import java.util.ArrayDeque +import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.ReentrantLock import okhttp3.Headers import okhttp3.internal.EMPTY_HEADERS -import okhttp3.internal.assertThreadDoesntHoldLock +import okhttp3.internal.assertNotHeld +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.http2.flowcontrol.WindowCounter -import okhttp3.internal.notifyAll import okhttp3.internal.toHeaderList -import okhttp3.internal.wait import okio.AsyncTimeout import okio.Buffer import okio.BufferedSource @@ -43,7 +44,10 @@ class Http2Stream internal constructor( inFinished: Boolean, headers: Headers?, ) { - // Internal state is guarded by this. No long-running or potentially blocking operations are + internal val lock: ReentrantLock = ReentrantLock() + val condition: Condition = lock.newCondition() + + // Internal state is guarded by [lock]. No long-running or potentially blocking operations are // performed while the lock is held. /** The bytes consumed and acknowledged by the stream. */ @@ -82,7 +86,8 @@ class Http2Stream internal constructor( * If there are multiple reasons to abnormally close this stream (such as both peers closing it * near-simultaneously) then this is the first reason known to this peer. */ - @get:Synchronized internal var errorCode: ErrorCode? = null + internal var errorCode: ErrorCode? = null + get() = this.withLock { field } /** The exception that explains [errorCode]. Null if no exception was provided. */ internal var errorException: IOException? = null @@ -106,17 +111,19 @@ class Http2Stream internal constructor( * not open. This is because input data is buffered. */ val isOpen: Boolean - @Synchronized get() { - if (errorCode != null) { - return false - } - if ((source.finished || source.closed) && - (sink.finished || sink.closed) && - hasResponseHeaders - ) { - return false + get() { + this.withLock { + if (errorCode != null) { + return false + } + if ((source.finished || source.closed) && + (sink.finished || sink.closed) && + hasResponseHeaders + ) { + return false + } + return true } - return true } /** Returns true if this stream was created by this peer. */ @@ -135,42 +142,44 @@ class Http2Stream internal constructor( * This is true after a `Expect-Continue` request, false for duplex requests, and false for * all other requests. */ - @Synchronized @Throws(IOException::class) fun takeHeaders(callerIsIdle: Boolean = false): Headers { - while (headersQueue.isEmpty() && errorCode == null) { - val doReadTimeout = callerIsIdle || doReadTimeout() - if (doReadTimeout) { - readTimeout.enter() - } - try { - waitForIo() - } finally { + this.withLock { + while (headersQueue.isEmpty() && errorCode == null) { + val doReadTimeout = callerIsIdle || doReadTimeout() if (doReadTimeout) { - readTimeout.exitAndThrowIfTimedOut() + readTimeout.enter() + } + try { + waitForIo() + } finally { + if (doReadTimeout) { + readTimeout.exitAndThrowIfTimedOut() + } } } + if (headersQueue.isNotEmpty()) { + return headersQueue.removeFirst() + } + throw errorException ?: StreamResetException(errorCode!!) } - if (headersQueue.isNotEmpty()) { - return headersQueue.removeFirst() - } - throw errorException ?: StreamResetException(errorCode!!) } /** * Returns the trailers. It is only safe to call this once the source stream has been completely * exhausted. */ - @Synchronized @Throws(IOException::class) fun trailers(): Headers { - if (source.finished && source.receiveBuffer.exhausted() && source.readBuffer.exhausted()) { - return source.trailers ?: EMPTY_HEADERS - } - if (errorCode != null) { - throw errorException ?: StreamResetException(errorCode!!) + this.withLock { + if (source.finished && source.receiveBuffer.exhausted() && source.readBuffer.exhausted()) { + return source.trailers ?: EMPTY_HEADERS + } + if (errorCode != null) { + throw errorException ?: StreamResetException(errorCode!!) + } + throw IllegalStateException("too early; can't read the trailers yet") } - throw IllegalStateException("too early; can't read the trailers yet") } /** @@ -187,21 +196,21 @@ class Http2Stream internal constructor( outFinished: Boolean, flushHeaders: Boolean, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() var flushHeaders = flushHeaders - synchronized(this) { + this.withLock { this.hasResponseHeaders = true if (outFinished) { this.sink.finished = true - this@Http2Stream.notifyAll() // Because doReadTimeout() may have changed. + condition.signalAll() // Because doReadTimeout() may have changed. } } // Only DATA frames are subject to flow-control. Transmit the HEADER frame if the connection // flow-control window is fully depleted. if (!flushHeaders) { - synchronized(connection) { + this.withLock { flushHeaders = (connection.writeBytesTotal >= connection.writeBytesMaximum) } } @@ -214,7 +223,7 @@ class Http2Stream internal constructor( } fun enqueueTrailers(trailers: Headers) { - synchronized(this) { + this.withLock { check(!sink.finished) { "already finished" } require(trailers.size != 0) { "trailers.size() == 0" } this.sink.trailers = trailers @@ -235,7 +244,7 @@ class Http2Stream internal constructor( * not yet been sent. */ fun getSink(): Sink { - synchronized(this) { + this.withLock { check(hasResponseHeaders || isLocallyInitiated) { "reply before requesting the sink" } @@ -273,15 +282,15 @@ class Http2Stream internal constructor( errorCode: ErrorCode, errorException: IOException?, ): Boolean { - this.assertThreadDoesntHoldLock() + lock.assertNotHeld() - synchronized(this) { + this.withLock { if (this.errorCode != null) { return false } this.errorCode = errorCode this.errorException = errorException - notifyAll() + condition.signalAll() if (source.finished && sink.finished) { return false } @@ -295,7 +304,7 @@ class Http2Stream internal constructor( source: BufferedSource, length: Int, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() this.source.receive(source, length.toLong()) } @@ -305,10 +314,10 @@ class Http2Stream internal constructor( headers: Headers, inFinished: Boolean, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() val open: Boolean - synchronized(this) { + this.withLock { if (!hasResponseHeaders || headers[Header.RESPONSE_STATUS_UTF8] != null || headers[Header.TARGET_METHOD_UTF8] != null @@ -322,17 +331,19 @@ class Http2Stream internal constructor( this.source.finished = true } open = isOpen - notifyAll() + condition.signalAll() } if (!open) { connection.removeStream(id) } } - @Synchronized fun receiveRstStream(errorCode: ErrorCode) { - if (this.errorCode == null) { - this.errorCode = errorCode - notifyAll() + fun receiveRstStream(errorCode: ErrorCode) { + this.withLock { + if (this.errorCode == null) { + this.errorCode = errorCode + condition.signalAll() + } } } @@ -389,7 +400,7 @@ class Http2Stream internal constructor( // 1. Decide what to do in a synchronized block. - synchronized(this@Http2Stream) { + this@Http2Stream.withLock { val doReadTimeout = doReadTimeout() if (doReadTimeout) { readTimeout.enter() @@ -452,7 +463,7 @@ class Http2Stream internal constructor( } private fun updateConnectionFlowControl(read: Long) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() connection.updateConnectionFlowControl(read) } @@ -466,14 +477,14 @@ class Http2Stream internal constructor( source: BufferedSource, byteCount: Long, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() var remainingByteCount = byteCount while (remainingByteCount > 0L) { val finished: Boolean val flowControlError: Boolean - synchronized(this@Http2Stream) { + this@Http2Stream.withLock { finished = this.finished flowControlError = remainingByteCount + readBuffer.size > maxByteCount } @@ -499,14 +510,14 @@ class Http2Stream internal constructor( // Move the received data to the read buffer to the reader can read it. If this source has // been closed since this read began we must discard the incoming data and tell the // connection we've done so. - synchronized(this@Http2Stream) { + this@Http2Stream.withLock { if (closed) { receiveBuffer.clear() } else { val wasEmpty = readBuffer.size == 0L readBuffer.writeAll(receiveBuffer) if (wasEmpty) { - this@Http2Stream.notifyAll() + condition.signalAll() } } } @@ -527,11 +538,11 @@ class Http2Stream internal constructor( @Throws(IOException::class) override fun close() { val bytesDiscarded: Long - synchronized(this@Http2Stream) { + this@Http2Stream.withLock { closed = true bytesDiscarded = readBuffer.size readBuffer.clear() - this@Http2Stream.notifyAll() // TODO(jwilson): Unnecessary? + condition.signalAll() // TODO(jwilson): Unnecessary? } if (bytesDiscarded > 0L) { updateConnectionFlowControl(bytesDiscarded) @@ -542,11 +553,11 @@ class Http2Stream internal constructor( @Throws(IOException::class) internal fun cancelStreamIfNecessary() { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() val open: Boolean val cancel: Boolean - synchronized(this) { + this.withLock { cancel = !source.finished && source.closed && (sink.finished || sink.closed) open = isOpen } @@ -581,7 +592,7 @@ class Http2Stream internal constructor( source: Buffer, byteCount: Long, ) { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() sendBuffer.write(source, byteCount) while (sendBuffer.size >= EMIT_BUFFER_SIZE) { @@ -597,7 +608,7 @@ class Http2Stream internal constructor( private fun emitFrame(outFinishedOnLastFrame: Boolean) { val toWrite: Long val outFinished: Boolean - synchronized(this@Http2Stream) { + this@Http2Stream.withLock { writeTimeout.enter() try { while (writeBytesTotal >= writeBytesMaximum && @@ -627,9 +638,9 @@ class Http2Stream internal constructor( @Throws(IOException::class) override fun flush() { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() - synchronized(this@Http2Stream) { + this@Http2Stream.withLock { checkOutNotClosed() } // TODO(jwilson): flush the connection?! @@ -643,10 +654,10 @@ class Http2Stream internal constructor( @Throws(IOException::class) override fun close() { - this@Http2Stream.assertThreadDoesntHoldLock() + lock.assertNotHeld() val outFinished: Boolean - synchronized(this@Http2Stream) { + this@Http2Stream.withLock { if (closed) return outFinished = errorCode == null } @@ -675,9 +686,9 @@ class Http2Stream internal constructor( } } } - synchronized(this@Http2Stream) { + this@Http2Stream.withLock { closed = true - this@Http2Stream.notifyAll() // Because doReadTimeout() may have changed. + condition.signalAll() // Because doReadTimeout() may have changed. } connection.flush() cancelStreamIfNecessary() @@ -692,7 +703,7 @@ class Http2Stream internal constructor( fun addBytesToWriteWindow(delta: Long) { writeBytesMaximum += delta if (delta > 0L) { - this@Http2Stream.notifyAll() + condition.signalAll() } } @@ -712,7 +723,7 @@ class Http2Stream internal constructor( @Throws(InterruptedIOException::class) internal fun waitForIo() { try { - wait() + condition.await() } catch (_: InterruptedException) { Thread.currentThread().interrupt() // Retain interrupted status. throw InterruptedIOException() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt index ff72536e9b49..6c63ef263300 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt @@ -17,8 +17,10 @@ package okhttp3.internal.http2 import java.io.Closeable import java.io.IOException +import java.util.concurrent.locks.ReentrantLock import java.util.logging.Level.FINE import java.util.logging.Logger +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.format import okhttp3.internal.http2.Http2.CONNECTION_PREFACE import okhttp3.internal.http2.Http2.FLAG_ACK @@ -47,39 +49,43 @@ class Http2Writer( private val sink: BufferedSink, private val client: Boolean, ) : Closeable { + internal val lock: ReentrantLock = ReentrantLock() + private val hpackBuffer: Buffer = Buffer() private var maxFrameSize: Int = INITIAL_MAX_FRAME_SIZE private var closed: Boolean = false val hpackWriter: Hpack.Writer = Hpack.Writer(out = hpackBuffer) - @Synchronized @Throws(IOException::class) fun connectionPreface() { - if (closed) throw IOException("closed") - if (!client) return // Nothing to write; servers don't send connection headers! - if (logger.isLoggable(FINE)) { - logger.fine(format(">> CONNECTION ${CONNECTION_PREFACE.hex()}")) + this.withLock { + if (closed) throw IOException("closed") + if (!client) return // Nothing to write; servers don't send connection headers! + if (logger.isLoggable(FINE)) { + logger.fine(format(">> CONNECTION ${CONNECTION_PREFACE.hex()}")) + } + sink.write(CONNECTION_PREFACE) + sink.flush() } - sink.write(CONNECTION_PREFACE) - sink.flush() } /** Applies `peerSettings` and then sends a settings ACK. */ - @Synchronized @Throws(IOException::class) fun applyAndAckSettings(peerSettings: Settings) { - if (closed) throw IOException("closed") - this.maxFrameSize = peerSettings.getMaxFrameSize(maxFrameSize) - if (peerSettings.headerTableSize != -1) { - hpackWriter.resizeHeaderTable(peerSettings.headerTableSize) + this.withLock { + if (closed) throw IOException("closed") + this.maxFrameSize = peerSettings.getMaxFrameSize(maxFrameSize) + if (peerSettings.headerTableSize != -1) { + hpackWriter.resizeHeaderTable(peerSettings.headerTableSize) + } + frameHeader( + streamId = 0, + length = 0, + type = TYPE_SETTINGS, + flags = FLAG_ACK, + ) + sink.flush() } - frameHeader( - streamId = 0, - length = 0, - type = TYPE_SETTINGS, - flags = FLAG_ACK, - ) - sink.flush() } /** @@ -94,54 +100,57 @@ class Http2Writer( * @param promisedStreamId server-initiated stream ID. Must be an even number. * @param requestHeaders minimally includes `:method`, `:scheme`, `:authority`, and `:path`. */ - @Synchronized @Throws(IOException::class) fun pushPromise( streamId: Int, promisedStreamId: Int, requestHeaders: List
, ) { - if (closed) throw IOException("closed") - hpackWriter.writeHeaders(requestHeaders) + this.withLock { + if (closed) throw IOException("closed") + hpackWriter.writeHeaders(requestHeaders) - val byteCount = hpackBuffer.size - val length = minOf(maxFrameSize - 4L, byteCount).toInt() - frameHeader( - streamId = streamId, - length = length + 4, - type = TYPE_PUSH_PROMISE, - flags = if (byteCount == length.toLong()) FLAG_END_HEADERS else 0, - ) - sink.writeInt(promisedStreamId and 0x7fffffff) - sink.write(hpackBuffer, length.toLong()) + val byteCount = hpackBuffer.size + val length = minOf(maxFrameSize - 4L, byteCount).toInt() + frameHeader( + streamId = streamId, + length = length + 4, + type = TYPE_PUSH_PROMISE, + flags = if (byteCount == length.toLong()) FLAG_END_HEADERS else 0, + ) + sink.writeInt(promisedStreamId and 0x7fffffff) + sink.write(hpackBuffer, length.toLong()) - if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) + if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) + } } - @Synchronized @Throws(IOException::class) fun flush() { - if (closed) throw IOException("closed") - sink.flush() + this.withLock { + if (closed) throw IOException("closed") + sink.flush() + } } - @Synchronized @Throws(IOException::class) fun rstStream( streamId: Int, errorCode: ErrorCode, ) { - if (closed) throw IOException("closed") - require(errorCode.httpCode != -1) + this.withLock { + if (closed) throw IOException("closed") + require(errorCode.httpCode != -1) - frameHeader( - streamId = streamId, - length = 4, - type = TYPE_RST_STREAM, - flags = FLAG_NONE, - ) - sink.writeInt(errorCode.httpCode) - sink.flush() + frameHeader( + streamId = streamId, + length = 4, + type = TYPE_RST_STREAM, + flags = FLAG_NONE, + ) + sink.writeInt(errorCode.httpCode) + sink.flush() + } } /** The maximum size of bytes that may be sent in a single call to [data]. */ @@ -154,7 +163,6 @@ class Http2Writer( * @param source the buffer to draw bytes from. May be null if byteCount is 0. * @param byteCount must be between 0 and the minimum of `source.length` and [maxDataLength]. */ - @Synchronized @Throws(IOException::class) fun data( outFinished: Boolean, @@ -162,10 +170,12 @@ class Http2Writer( source: Buffer?, byteCount: Int, ) { - if (closed) throw IOException("closed") - var flags = FLAG_NONE - if (outFinished) flags = flags or FLAG_END_STREAM - dataFrame(streamId, flags, source, byteCount) + this.withLock { + if (closed) throw IOException("closed") + var flags = FLAG_NONE + if (outFinished) flags = flags or FLAG_END_STREAM + dataFrame(streamId, flags, source, byteCount) + } } @Throws(IOException::class) @@ -187,51 +197,53 @@ class Http2Writer( } /** Write okhttp's settings to the peer. */ - @Synchronized @Throws(IOException::class) fun settings(settings: Settings) { - if (closed) throw IOException("closed") - frameHeader( - streamId = 0, - length = settings.size() * 6, - type = TYPE_SETTINGS, - flags = FLAG_NONE, - ) - for (i in 0 until Settings.COUNT) { - if (!settings.isSet(i)) continue - val id = - when (i) { - 4 -> 3 // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. - 7 -> 4 // SETTINGS_INITIAL_WINDOW_SIZE renumbered. - else -> i - } - sink.writeShort(id) - sink.writeInt(settings[i]) + this.withLock { + if (closed) throw IOException("closed") + frameHeader( + streamId = 0, + length = settings.size() * 6, + type = TYPE_SETTINGS, + flags = FLAG_NONE, + ) + for (i in 0 until Settings.COUNT) { + if (!settings.isSet(i)) continue + val id = + when (i) { + 4 -> 3 // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. + 7 -> 4 // SETTINGS_INITIAL_WINDOW_SIZE renumbered. + else -> i + } + sink.writeShort(id) + sink.writeInt(settings[i]) + } + sink.flush() } - sink.flush() } /** * Send a connection-level ping to the peer. `ack` indicates this is a reply. The data in * `payload1` and `payload2` opaque binary, and there are no rules on the content. */ - @Synchronized @Throws(IOException::class) fun ping( ack: Boolean, payload1: Int, payload2: Int, ) { - if (closed) throw IOException("closed") - frameHeader( - streamId = 0, - length = 8, - type = TYPE_PING, - flags = if (ack) FLAG_ACK else FLAG_NONE, - ) - sink.writeInt(payload1) - sink.writeInt(payload2) - sink.flush() + this.withLock { + if (closed) throw IOException("closed") + frameHeader( + streamId = 0, + length = 8, + type = TYPE_PING, + flags = if (ack) FLAG_ACK else FLAG_NONE, + ) + sink.writeInt(payload1) + sink.writeInt(payload2) + sink.flush() + } } /** @@ -242,61 +254,63 @@ class Http2Writer( * @param errorCode reason for closing the connection. * @param debugData only valid for HTTP/2; opaque debug data to send. */ - @Synchronized @Throws(IOException::class) fun goAway( lastGoodStreamId: Int, errorCode: ErrorCode, debugData: ByteArray, ) { - if (closed) throw IOException("closed") - require(errorCode.httpCode != -1) { "errorCode.httpCode == -1" } - frameHeader( - streamId = 0, - length = 8 + debugData.size, - type = TYPE_GOAWAY, - flags = FLAG_NONE, - ) - sink.writeInt(lastGoodStreamId) - sink.writeInt(errorCode.httpCode) - if (debugData.isNotEmpty()) { - sink.write(debugData) + this.withLock { + if (closed) throw IOException("closed") + require(errorCode.httpCode != -1) { "errorCode.httpCode == -1" } + frameHeader( + streamId = 0, + length = 8 + debugData.size, + type = TYPE_GOAWAY, + flags = FLAG_NONE, + ) + sink.writeInt(lastGoodStreamId) + sink.writeInt(errorCode.httpCode) + if (debugData.isNotEmpty()) { + sink.write(debugData) + } + sink.flush() } - sink.flush() } /** * Inform peer that an additional `windowSizeIncrement` bytes can be sent on `streamId`, or the * connection if `streamId` is zero. */ - @Synchronized @Throws(IOException::class) fun windowUpdate( streamId: Int, windowSizeIncrement: Long, ) { - if (closed) throw IOException("closed") - require(windowSizeIncrement != 0L && windowSizeIncrement <= 0x7fffffffL) { - "windowSizeIncrement == 0 || windowSizeIncrement > 0x7fffffffL: $windowSizeIncrement" - } - if (logger.isLoggable(FINE)) { - logger.fine( - frameLogWindowUpdate( - inbound = false, - streamId = streamId, - length = 4, - windowSizeIncrement = windowSizeIncrement, - ), + this.withLock { + if (closed) throw IOException("closed") + require(windowSizeIncrement != 0L && windowSizeIncrement <= 0x7fffffffL) { + "windowSizeIncrement == 0 || windowSizeIncrement > 0x7fffffffL: $windowSizeIncrement" + } + if (logger.isLoggable(FINE)) { + logger.fine( + frameLogWindowUpdate( + inbound = false, + streamId = streamId, + length = 4, + windowSizeIncrement = windowSizeIncrement, + ), + ) + } + frameHeader( + streamId = streamId, + length = 4, + type = TYPE_WINDOW_UPDATE, + flags = FLAG_NONE, ) + sink.writeInt(windowSizeIncrement.toInt()) + sink.flush() } - frameHeader( - streamId = streamId, - length = 4, - type = TYPE_WINDOW_UPDATE, - flags = FLAG_NONE, - ) - sink.writeInt(windowSizeIncrement.toInt()) - sink.flush() } @Throws(IOException::class) @@ -317,11 +331,12 @@ class Http2Writer( sink.writeInt(streamId and 0x7fffffff) } - @Synchronized @Throws(IOException::class) override fun close() { - closed = true - sink.close() + this.withLock { + closed = true + sink.close() + } } @Throws(IOException::class) @@ -343,29 +358,30 @@ class Http2Writer( } } - @Synchronized @Throws(IOException::class) fun headers( outFinished: Boolean, streamId: Int, headerBlock: List
, ) { - if (closed) throw IOException("closed") - hpackWriter.writeHeaders(headerBlock) + this.withLock { + if (closed) throw IOException("closed") + hpackWriter.writeHeaders(headerBlock) - val byteCount = hpackBuffer.size - val length = minOf(maxFrameSize.toLong(), byteCount) - var flags = if (byteCount == length) FLAG_END_HEADERS else 0 - if (outFinished) flags = flags or FLAG_END_STREAM - frameHeader( - streamId = streamId, - length = length.toInt(), - type = TYPE_HEADERS, - flags = flags, - ) - sink.write(hpackBuffer, length) + val byteCount = hpackBuffer.size + val length = minOf(maxFrameSize.toLong(), byteCount) + var flags = if (byteCount == length) FLAG_END_HEADERS else 0 + if (outFinished) flags = flags or FLAG_END_STREAM + frameHeader( + streamId = streamId, + length = length.toInt(), + type = TYPE_HEADERS, + flags = flags, + ) + sink.write(hpackBuffer, length) - if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) + if (byteCount > length) writeContinuationFrames(streamId, byteCount - length) + } } companion object { diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index 240816047d82..0908b22f98ac 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -29,6 +29,7 @@ import okhttp3.Request import okhttp3.TestUtil.awaitGarbageCollection import okhttp3.TestValueFactory import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.http2.Http2 import okhttp3.internal.http2.Http2Connection import okhttp3.internal.http2.Http2ConnectionTest @@ -96,7 +97,7 @@ class ConnectionPoolTest { .build() val call = client.newCall(Request(addressA.url)) as RealCall call.enterNetworkInterceptorExchange(call.request(), true, factory.newChain(call)) - synchronized(c1) { call.acquireConnectionNoEvents(c1) } + c1.withLock { call.acquireConnectionNoEvents(c1) } // Running at time 50, the pool returns that nothing can be evicted until time 150. assertThat(pool.closeConnections(50L)).isEqualTo(100L) @@ -342,6 +343,6 @@ class ConnectionPoolTest { .build() val call = client.newCall(Request(connection.route().address.url)) as RealCall call.enterNetworkInterceptorExchange(call.request(), true, factory.newChain(call)) - synchronized(connection) { call.acquireConnectionNoEvents(connection) } + connection.withLock { call.acquireConnectionNoEvents(connection) } } } diff --git a/okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt b/okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt index faeb3f041104..923522e32503 100644 --- a/okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt @@ -38,6 +38,7 @@ import okhttp3.internal.EMPTY_BYTE_ARRAY import okhttp3.internal.EMPTY_HEADERS import okhttp3.internal.concurrent.TaskFaker import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.notifyAll import okhttp3.internal.wait import okio.AsyncTimeout @@ -968,7 +969,7 @@ class Http2ConnectionTest { } } val connection = connect(peer, IGNORE, listener) - synchronized(connection) { + connection.withLock { assertThat(connection.peerSettings.getMaxConcurrentStreams()).isEqualTo(10) } maxConcurrentStreamsUpdated.await() @@ -997,7 +998,7 @@ class Http2ConnectionTest { val connection = connect(peer) assertThat(peer.takeFrame().type).isEqualTo(Http2.TYPE_SETTINGS) assertThat(peer.takeFrame().type).isEqualTo(Http2.TYPE_PING) - synchronized(connection) { + connection.withLock { assertThat(connection.peerSettings.headerTableSize).isEqualTo(10000) assertThat(connection.peerSettings.initialWindowSize).isEqualTo(40000) assertThat(connection.peerSettings.getMaxFrameSize(-1)).isEqualTo(50000) @@ -1024,7 +1025,7 @@ class Http2ConnectionTest { val settings2 = Settings() settings2[Settings.MAX_CONCURRENT_STREAMS] = 60000 connection.readerRunnable.applyAndAckSettings(true, settings2) - synchronized(connection) { + connection.withLock { assertThat(connection.peerSettings.headerTableSize).isEqualTo(-1) assertThat(connection.peerSettings.initialWindowSize) .isEqualTo(Settings.DEFAULT_INITIAL_WINDOW_SIZE) @@ -1393,7 +1394,7 @@ class Http2ConnectionTest { // Play it back. val connection = connect(peer) connection.newStream(headerEntries("a", "android"), false) - synchronized(connection) { + connection.withLock { if (!connection.isHealthy(System.nanoTime())) { throw ConnectionShutdownException() } From 8d83f921ebd3783149512cb2ed68724cbf3c7a1d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 20:34:32 +0100 Subject: [PATCH 025/134] Update dependency androidx.activity:activity-ktx to v1.9.0 (#8382) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 58cce71a1722..f263e7c25b39 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,7 @@ testcontainers = "1.19.7" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.3.3" -androidx-activity = "androidx.activity:activity-ktx:1.8.2" +androidx-activity = "androidx.activity:activity-ktx:1.9.0" androidx-annotation = "androidx.annotation:annotation:1.7.1" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.5.1" androidx-junit = "androidx.test.ext:junit:1.1.5" From aede7c57f3e03fa1c8338268675ccc711eeeeefa Mon Sep 17 00:00:00 2001 From: Evan Nelson Date: Tue, 23 Apr 2024 21:40:49 -0700 Subject: [PATCH 026/134] Fix ConnectionPoolTest bug (#8384) 1. Advance taskFaker time forward to the present when the test starts. 2. Stop having multiple factories and taskfakers floating around. --- .../src/test/java/okhttp3/FakeRoutePlanner.kt | 8 ++--- .../internal/connection/ConnectionPoolTest.kt | 32 +++++++++---------- .../FastFallbackExchangeFinderTest.kt | 7 +++- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt b/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt index e2030cc7946a..56fe78b9e246 100644 --- a/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt +++ b/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt @@ -24,13 +24,9 @@ import okhttp3.internal.connection.RoutePlanner import okhttp3.internal.connection.RoutePlanner.ConnectResult class FakeRoutePlanner( - private val taskFaker: TaskFaker, + val factory: TestValueFactory = TestValueFactory(), + val taskFaker: TaskFaker = factory.taskFaker, ) : RoutePlanner, Closeable { - /** - * Note that we don't use the same [TaskFaker] for this factory. That way off-topic tasks like - * connection pool maintenance tasks don't add noise to route planning tests. - */ - val factory = TestValueFactory() val pool = factory.newConnectionPool(routePlanner = this) val events = LinkedBlockingDeque() var canceled = false diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index 0908b22f98ac..b9b4f5354258 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -27,7 +27,6 @@ import okhttp3.FakeRoutePlanner import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.TestUtil.awaitGarbageCollection -import okhttp3.TestValueFactory import okhttp3.internal.concurrent.TaskRunner import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.http2.Http2 @@ -39,7 +38,9 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test class ConnectionPoolTest { - private val factory = TestValueFactory() + private val routePlanner = FakeRoutePlanner() + private val factory = routePlanner.factory + private val taskFaker = routePlanner.taskFaker private val peer = MockHttp2Peer() /** The fake task runner prevents the cleanup runnable from being started. */ @@ -50,8 +51,6 @@ class ConnectionPoolTest { private val addressC = factory.newAddress("c") private val routeC1 = factory.newRoute(addressC) - private val routePlanner = FakeRoutePlanner(factory.taskFaker) - @AfterEach fun tearDown() { factory.close() peer.close() @@ -205,7 +204,8 @@ class ConnectionPoolTest { } @Test fun connectionPreWarmingHttp1() { - val expireTime = factory.taskFaker.nanoTime + 1_000_000_000_000 + taskFaker.advanceUntil(System.nanoTime()) + val expireTime = taskFaker.nanoTime + 1_000_000_000_000 routePlanner.autoGeneratePlans = true routePlanner.defaultConnectionIdleAtNanos = expireTime @@ -219,19 +219,20 @@ class ConnectionPoolTest { // Connections are replaced if they idle out or are evicted from the pool evictAllConnections(pool) assertThat(pool.connectionCount()).isEqualTo(2) - forceConnectionsToExpire(pool, routePlanner, expireTime) + forceConnectionsToExpire(pool, expireTime) assertThat(pool.connectionCount()).isEqualTo(2) // Excess connections aren't removed until they idle out, even if no longer needed setPolicy(pool, address, ConnectionPool.AddressPolicy(1)) assertThat(pool.connectionCount()).isEqualTo(2) - forceConnectionsToExpire(pool, routePlanner, expireTime) + forceConnectionsToExpire(pool, expireTime) assertThat(pool.connectionCount()).isEqualTo(1) } @Test fun connectionPreWarmingHttp2() { - val expireSooner = factory.taskFaker.nanoTime + 1_000_000_000_000 - val expireLater = factory.taskFaker.nanoTime + 2_000_000_000_000 + taskFaker.advanceUntil(System.nanoTime()) + val expireSooner = taskFaker.nanoTime + 1_000_000_000_000 + val expireLater = taskFaker.nanoTime + 2_000_000_000_000 routePlanner.autoGeneratePlans = true val address = routePlanner.address @@ -258,7 +259,7 @@ class ConnectionPoolTest { // Increase the connection's max so that the new connection is no longer needed updateMaxConcurrentStreams(http2Connection, 5) - forceConnectionsToExpire(pool, routePlanner, expireSooner) + forceConnectionsToExpire(pool, expireSooner) assertThat(pool.connectionCount()).isEqualTo(1) } @@ -268,23 +269,22 @@ class ConnectionPoolTest { policy: ConnectionPool.AddressPolicy, ) { pool.setPolicy(address, policy) - routePlanner.factory.taskFaker.runTasks() + taskFaker.runTasks() } private fun evictAllConnections(pool: RealConnectionPool) { pool.evictAll() assertThat(pool.connectionCount()).isEqualTo(0) - routePlanner.factory.taskFaker.runTasks() + taskFaker.runTasks() } private fun forceConnectionsToExpire( pool: RealConnectionPool, - routePlanner: FakeRoutePlanner, expireTime: Long, ) { val idleTimeNanos = expireTime + pool.keepAliveDurationNs repeat(pool.connectionCount()) { pool.closeConnections(idleTimeNanos) } - routePlanner.factory.taskFaker.runTasks() + taskFaker.runTasks() } private fun connectHttp2( @@ -316,7 +316,7 @@ class ConnectionPoolTest { assertThat(ackFrame.streamId).isEqualTo(0) assertThat(ackFrame.ack).isTrue() - routePlanner.factory.taskFaker.runTasks() + taskFaker.runTasks() return connection } @@ -329,7 +329,7 @@ class ConnectionPoolTest { settings[Settings.MAX_CONCURRENT_STREAMS] = amount connection.readerRunnable.applyAndAckSettings(true, settings) assertThat(connection.peerSettings[Settings.MAX_CONCURRENT_STREAMS]).isEqualTo(amount) - routePlanner.factory.taskFaker.runTasks() + taskFaker.runTasks() } /** Use a helper method so there's no hidden reference remaining on the stack. */ diff --git a/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt index ba969a8159e7..1d41ccd14b03 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt @@ -41,7 +41,12 @@ import org.junit.jupiter.api.Test internal class FastFallbackExchangeFinderTest { private val taskFaker = TaskFaker() private val taskRunner = taskFaker.taskRunner - private val routePlanner = FakeRoutePlanner(taskFaker) + + /** + * Note that we don't use the same [TaskFaker] for this factory. That way off-topic tasks like + * connection pool maintenance tasks don't add noise to route planning tests. + */ + private val routePlanner = FakeRoutePlanner(taskFaker = taskFaker) private val finder = FastFallbackExchangeFinder(routePlanner, taskRunner) @AfterEach From d0b6a464d8f660941a47b40fb8ed67508550921c Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sun, 28 Apr 2024 20:33:04 -0400 Subject: [PATCH 027/134] Start fewer threads in TaskRunner (#8391) We've got a race where we'll start a thread when we need one, even if we've already started a thread. This changes TaskRunner's behavior to never add a thread if we're still waiting for a recently-added one to start running. This is intended to reduce the number of threads contenting for the TaskRunner lock as reported in this issue: https://github.com/square/okhttp/issues/8388 --- .../okhttp3/internal/concurrent/TaskFaker.kt | 16 ++-- .../okhttp3/internal/concurrent/TaskRunner.kt | 33 ++++++- .../internal/concurrent/TaskRunnerTest.kt | 90 +++++++++++++++++++ 3 files changed, 129 insertions(+), 10 deletions(-) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt index 88dfd7936742..1874cd9ca8e0 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt @@ -63,29 +63,32 @@ class TaskFaker : Closeable { /** * True if this task faker has ever had multiple tasks scheduled to run concurrently. Guarded by - * [taskRunner]. + * [TaskRunner.lock]. */ var isParallel = false + /** Number of calls to [TaskRunner.Backend.execute]. Guarded by [TaskRunner.lock]. */ + var executeCallCount = 0 + /** Guarded by [taskRunner]. */ var nanoTime = 0L private set - /** Backlog of tasks to run. Only one task runs at a time. Guarded by [taskRunner]. */ + /** Backlog of tasks to run. Only one task runs at a time. Guarded by [TaskRunner.lock]. */ private val serialTaskQueue = ArrayDeque() - /** The task that's currently executing. Guarded by [taskRunner]. */ + /** The task that's currently executing. Guarded by [TaskRunner.lock]. */ private var currentTask: SerialTask = TestThreadSerialTask - /** The coordinator task if it's waiting, and how it will resume. Guarded by [taskRunner]. */ + /** The coordinator task if it's waiting, and how it will resume. Guarded by [TaskRunner.lock]. */ private var waitingCoordinatorTask: SerialTask? = null private var waitingCoordinatorInterrupted = false private var waitingCoordinatorNotified = false - /** How many times a new task has been started. Guarded by [taskRunner]. */ + /** How many times a new task has been started. Guarded by [TaskRunner.lock]. */ private var contextSwitchCount = 0 - /** Guarded by [taskRunner]. */ + /** Guarded by [TaskRunner.lock]. */ private var activeThreads = 0 /** A task runner that posts tasks to this fake. Tasks won't be executed until requested. */ @@ -100,6 +103,7 @@ class TaskFaker : Closeable { val queuedTask = RunnableSerialTask(runnable) serialTaskQueue += queuedTask + executeCallCount++ isParallel = serialTaskQueue.size > 1 } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt index 6acc7b24e774..60143b3c40f8 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt @@ -52,6 +52,17 @@ class TaskRunner( private var coordinatorWaiting = false private var coordinatorWakeUpAt = 0L + /** + * When we need a new thread to run tasks, we call [Backend.execute]. A few microseconds later we + * expect a newly-started thread to call [Runnable.run]. We shouldn't request new threads until + * the already-requested ones are in service, otherwise we might create more threads than we need. + * + * We use [executeCallCount] and [runCallCount] to defend against starting more threads than we + * need. Both fields are guarded by [lock]. + */ + private var executeCallCount = 0 + private var runCallCount = 0 + /** Queues with tasks that are currently executing their [TaskQueue.activeTask]. */ private val busyQueues = mutableListOf() @@ -61,9 +72,14 @@ class TaskRunner( private val runnable: Runnable = object : Runnable { override fun run() { + var incrementedRunCallCount = false while (true) { val task = this@TaskRunner.lock.withLock { + if (!incrementedRunCallCount) { + incrementedRunCallCount = true + runCallCount++ + } awaitTaskToRun() } ?: return @@ -76,7 +92,7 @@ class TaskRunner( // If the task is crashing start another thread to service the queues. if (!completedNormally) { lock.withLock { - backend.execute(this@TaskRunner, this) + startAnotherThread() } } } @@ -99,7 +115,7 @@ class TaskRunner( if (coordinatorWaiting) { backend.coordinatorNotify(this@TaskRunner) } else { - backend.execute(this@TaskRunner, runnable) + startAnotherThread() } } @@ -157,7 +173,7 @@ class TaskRunner( * Returns an immediately-executable task for the calling thread to execute, sleeping as necessary * until one is ready. If there are no ready queues, or if other threads have everything under * control this will return null. If there is more than a single task ready to execute immediately - * this will launch another thread to handle that work. + * this will start another thread to handle that work. */ fun awaitTaskToRun(): Task? { lock.assertHeld() @@ -207,7 +223,7 @@ class TaskRunner( // Also start another thread if there's more work or scheduling to do. if (multipleReadyTasks || !coordinatorWaiting && readyQueues.isNotEmpty()) { - backend.execute(this@TaskRunner, runnable) + startAnotherThread() } return readyTask @@ -238,6 +254,15 @@ class TaskRunner( } } + /** Start another thread, unless a new thread is already scheduled to start. */ + private fun startAnotherThread() { + lock.assertHeld() + if (executeCallCount > runCallCount) return // A thread is still starting. + + executeCallCount++ + backend.execute(this@TaskRunner, runnable) + } + fun newQueue(): TaskQueue { val name = lock.withLock { nextQueueName++ } return TaskQueue(this, "Q$name") diff --git a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt index 5f343b5632c7..36b0c4c72b00 100644 --- a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt @@ -680,6 +680,96 @@ class TaskRunnerTest { assertThat(idleLatch2).isSameAs(idleLatch1) } + @Test fun cancelAllWhenEmptyDoesNotStartWorkerThread() { + redQueue.execute("red task", 100.µs) { + error("expected to be canceled") + } + assertThat(taskFaker.executeCallCount).isEqualTo(1) + + blueQueue.execute("task", 100.µs) { + error("expected to be canceled") + } + assertThat(taskFaker.executeCallCount).isEqualTo(1) + + redQueue.cancelAll() + assertThat(taskFaker.executeCallCount).isEqualTo(1) + + blueQueue.cancelAll() + assertThat(taskFaker.executeCallCount).isEqualTo(1) + } + + @Test fun noMoreThanOneWorkerThreadWaitingToStartAtATime() { + // Enqueueing the red task starts a thread because the head of the queue changed. + redQueue.execute("red task") { + log += "red:starting@${taskFaker.nanoTime}" + taskFaker.sleep(100.µs) + log += "red:finishing@${taskFaker.nanoTime}" + } + assertThat(taskFaker.executeCallCount).isEqualTo(1) + + // Enqueueing the blue task doesn't start a thread because the red one is still starting. + blueQueue.execute("blue task") { + log += "blue:starting@${taskFaker.nanoTime}" + taskFaker.sleep(100.µs) + log += "blue:finishing@${taskFaker.nanoTime}" + } + assertThat(taskFaker.executeCallCount).isEqualTo(1) + + // Running the red task starts another thread, so the two can run in parallel. + taskFaker.runNextTask() + assertThat(log).containsExactly("red:starting@0") + assertThat(taskFaker.executeCallCount).isEqualTo(2) + + // Next the blue task starts. + taskFaker.runNextTask() + assertThat(log).containsExactly( + "red:starting@0", + "blue:starting@0", + ) + assertThat(taskFaker.executeCallCount).isEqualTo(2) + + // Advance time until the tasks complete. + taskFaker.advanceUntil(100.µs) + assertThat(log).containsExactly( + "red:starting@0", + "blue:starting@0", + "red:finishing@100000", + "blue:finishing@100000", + ) + taskFaker.assertNoMoreTasks() + assertThat(taskFaker.executeCallCount).isEqualTo(2) + } + + @Test fun onlyOneCoordinatorWaitingToStartFutureTasks() { + // Enqueueing the red task starts a coordinator thread. + redQueue.execute("red task", 100.µs) { + log += "red:run@${taskFaker.nanoTime}" + } + assertThat(taskFaker.executeCallCount).isEqualTo(1) + + // Enqueueing the blue task doesn't need a 2nd coordinator yet. + blueQueue.execute("blue task", 200.µs) { + log += "blue:run@${taskFaker.nanoTime}" + } + assertThat(taskFaker.executeCallCount).isEqualTo(1) + + // Nothing to do. + taskFaker.runTasks() + assertThat(log).isEmpty() + + // At 100.µs, the coordinator runs the red task and starts a thread for the new coordinator. + taskFaker.advanceUntil(100.µs) + assertThat(log).containsExactly("red:run@100000") + assertThat(taskFaker.executeCallCount).isEqualTo(2) + + // At 200.µs, the blue task runs. + taskFaker.advanceUntil(200.µs) + assertThat(log).containsExactly("red:run@100000", "blue:run@200000") + assertThat(taskFaker.executeCallCount).isEqualTo(2) + + taskFaker.assertNoMoreTasks() + } + private val Int.µs: Long get() = this * 1_000L } From 2f618f76a7ad3864284790edce167ebb309df1bf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 06:06:52 +0100 Subject: [PATCH 028/134] Update dependency com.google.guava:guava to v33.2.0-jre (#8397) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f263e7c25b39..32ee29a32ef4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -48,7 +48,7 @@ gradlePlugin-kotlinSerialization = { module = "org.jetbrains.kotlin:kotlin-seria gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.28.0" gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" -guava-jre = "com.google.guava:guava:33.1.0-jre" +guava-jre = "com.google.guava:guava:33.2.0-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:2.2" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3" jettyClient = "org.eclipse.jetty:jetty-client:9.4.54.v20240208" From 62031cd8f4a04600c11a4b294a6f786581ff6069 Mon Sep 17 00:00:00 2001 From: Endeavour233 <43426962+Endeavour233@users.noreply.github.com> Date: Mon, 13 May 2024 21:42:37 +0800 Subject: [PATCH 029/134] fix UTF-32 BOM (#8407) --- okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt | 6 +++--- okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt | 10 +++++++--- okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt | 10 +++++----- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt b/okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt index 3db8d43a9c2a..16d1321b5afb 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt @@ -55,12 +55,12 @@ internal val UNICODE_BOMS = "efbbbf".decodeHex(), // UTF-16BE. "feff".decodeHex(), + // UTF-32LE. + "fffe0000".decodeHex(), // UTF-16LE. "fffe".decodeHex(), // UTF-32BE. - "0000ffff".decodeHex(), - // UTF-32LE. - "ffff0000".decodeHex(), + "0000feff".decodeHex(), ) /** diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt b/okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt index 1f1c4f4e3a1f..71014a703f3f 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt @@ -94,14 +94,18 @@ internal fun format( return String.format(Locale.US, format, *args) } +/** + * will also strip BOM from the source + */ @Throws(IOException::class) internal fun BufferedSource.readBomAsCharset(default: Charset): Charset { return when (select(UNICODE_BOMS)) { + // a mapping from the index of encoding methods in UNICODE_BOMS to its corresponding encoding method 0 -> UTF_8 1 -> UTF_16BE - 2 -> UTF_16LE - 3 -> UTF_32BE - 4 -> UTF_32LE + 2 -> UTF_32LE + 3 -> UTF_16LE + 4 -> UTF_32BE -1 -> default else -> throw AssertionError() } diff --git a/okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt b/okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt index a7967e92f3f1..730a77bed562 100644 --- a/okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt +++ b/okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt @@ -62,7 +62,7 @@ class ResponseBodyJvmTest { @Test fun stringBomOverridesExplicitCharset() { - val body = body("0000ffff00000068000000650000006c0000006c0000006f", "utf-8") + val body = body("0000feff00000068000000650000006c0000006c0000006f", "utf-8") assertThat(body.string()).isEqualTo("hello") } @@ -86,13 +86,13 @@ class ResponseBodyJvmTest { @Test fun stringBomUtf32Be() { - val body = body("0000ffff00000068000000650000006c0000006c0000006f") + val body = body("0000feff00000068000000650000006c0000006c0000006f") assertThat(body.string()).isEqualTo("hello") } @Test fun stringBomUtf32Le() { - val body = body("ffff000068000000650000006c0000006c0000006f000000") + val body = body("fffe000068000000650000006c0000006c0000006f000000") assertThat(body.string()).isEqualTo("hello") } @@ -168,13 +168,13 @@ class ResponseBodyJvmTest { @Test fun readerBomUtf32Be() { - val body = body("0000ffff00000068000000650000006c0000006c0000006f") + val body = body("0000feff00000068000000650000006c0000006c0000006f") assertThat(exhaust(body.charStream())).isEqualTo("hello") } @Test fun readerBomUtf32Le() { - val body = body("ffff000068000000650000006c0000006c0000006f000000") + val body = body("fffe000068000000650000006c0000006c0000006f000000") assertThat(exhaust(body.charStream())).isEqualTo("hello") } From bd611089c2f07ab0d9a7eae610d9f7383139a5a3 Mon Sep 17 00:00:00 2001 From: Evan Nelson Date: Tue, 14 May 2024 10:48:07 -0700 Subject: [PATCH 030/134] Fix an environment-specific bug in RouteFailureTest (#8409) InetSocketAddress's constructor will try to resolve the host to an IP address. As a result, if you're on a network that happens to have a resolvable `myproxy` host, this test would fail -- and as it turns out, my home network does. Instead, use InetSocketAddress.createUnresolved(). --- okhttp/src/test/java/okhttp3/RouteFailureTest.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/okhttp/src/test/java/okhttp3/RouteFailureTest.kt b/okhttp/src/test/java/okhttp3/RouteFailureTest.kt index 4ced615788da..c0884a454d02 100644 --- a/okhttp/src/test/java/okhttp3/RouteFailureTest.kt +++ b/okhttp/src/test/java/okhttp3/RouteFailureTest.kt @@ -316,7 +316,8 @@ class RouteFailureTest { fun proxyMoveTest(cleanShutdown: Boolean) { // Define a single Proxy at myproxy:8008 that will artificially move during the test val proxySelector = RecordingProxySelector() - proxySelector.proxies.add(Proxy(Proxy.Type.HTTP, InetSocketAddress("myproxy", 8008))) + val socketAddress = InetSocketAddress.createUnresolved("myproxy", 8008) + proxySelector.proxies.add(Proxy(Proxy.Type.HTTP, socketAddress)) // Define two host names for the DNS routing of fake proxy servers val proxyServer1 = InetAddress.getByAddress("proxyServer1", byteArrayOf(127, 0, 0, 2)) From 54238b4c713080c3fd32fb1a070fb5d6814c9a09 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 00:34:57 +0100 Subject: [PATCH 031/134] Update mcr.microsoft.com/devcontainers/java Docker tag to v21 (#8398) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e356659135f2..8ade6e48f023 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "image": "mcr.microsoft.com/devcontainers/java:17-bookworm", + "image": "mcr.microsoft.com/devcontainers/java:21-bookworm", "features": { "ghcr.io/devcontainers/features/java:1": { "version": "17" From 60de813ea55b0aba7b2d5df73c6e07ca8c2a5ee2 Mon Sep 17 00:00:00 2001 From: Leo Lin Date: Thu, 20 Jun 2024 09:10:53 -0500 Subject: [PATCH 032/134] Allow Nullable ExecutorService Parameter in Dispatcher Constructor (#8401) Allow Nullable ExecutorService Parameter in Dispatcher Constructor to maintain backwards compatibility with OkHttp3 3.x migration to 4.x and beyond --- okhttp/src/main/kotlin/okhttp3/Dispatcher.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt index 57d0ab29a4f9..9e012a7907d5 100644 --- a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt +++ b/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt @@ -123,7 +123,7 @@ class Dispatcher() { /** Running synchronous calls. Includes canceled calls that haven't finished yet. */ private val runningSyncCalls = ArrayDeque() - constructor(executorService: ExecutorService) : this() { + constructor(executorService: ExecutorService?) : this() { this.executorServiceOrNull = executorService } From db291df7628c3a89479fb538d0ae7f50eae4c0ce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 10:05:16 +0100 Subject: [PATCH 033/134] Update dependency net.ltgt.gradle:gradle-errorprone-plugin to v4 (#8444) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 32ee29a32ef4..d695d1895c4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,7 +41,7 @@ gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.1" gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.14.0" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } gradlePlugin-dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.20" -gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:3.1.0" +gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.0.1" gradlePlugin-graal = "com.palantir.graal:gradle-graal:0.12.0" gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } gradlePlugin-kotlinSerialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } From b4d1ffd36bd585cf8a2c01a50cfcaafb14b03b97 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:54:10 +0100 Subject: [PATCH 034/134] Update dependency org.robolectric:robolectric to v4.12.2 (#8422) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d695d1895c4a..1959b37ef7c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -82,7 +82,7 @@ nativeImageSvm = { module = "org.graalvm.nativeimage:svm", version.ref = "graalv openjsse = "org.openjsse:openjsse:1.1.14" playservices-safetynet = "com.google.android.gms:play-services-safetynet:18.0.1" robolectric-android = "org.robolectric:android-all:14-robolectric-10818077" -robolectric = "org.robolectric:robolectric:4.12.1" +robolectric = "org.robolectric:robolectric:4.12.2" signature-android-apilevel21 = "net.sf.androidscents.signature:android-api-level-21:5.0.1_r2" signature-android-apilevel24 = "net.sf.androidscents.signature:android-api-level-24:7.0_r2" squareup-moshi = { module = "com.squareup.moshi:moshi", version.ref = "com-squareup-moshi" } From b38dda707c904ad25dba59f3be87746b7bdb399a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:58:02 +0100 Subject: [PATCH 035/134] Update dependency androidx.annotation:annotation to v1.8.0 (#8425) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1959b37ef7c0..d91cf8be4be9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ testcontainers = "1.19.7" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.3.3" androidx-activity = "androidx.activity:activity-ktx:1.9.0" -androidx-annotation = "androidx.annotation:annotation:1.7.1" +androidx-annotation = "androidx.annotation:annotation:1.8.0" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.5.1" androidx-junit = "androidx.test.ext:junit:1.1.5" androidx-test-runner = "androidx.test:runner:1.5.2" From 7b3b7566e57ec93faf61b7d1dfc4e7ebf6840f14 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:04:09 +0100 Subject: [PATCH 036/134] Update testcontainers-java monorepo to v1.19.8 (#8424) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d91cf8be4be9..572bdaff3873 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ org-conscrypt = "2.5.2" org-jetbrains-coroutines = "1.8.0" org-jetbrains-kotlin = "1.9.23" org-junit-jupiter = "5.10.2" -testcontainers = "1.19.7" +testcontainers = "1.19.8" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.3.3" From c624cafbe7115741013fc651ee1e0ad51b496314 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:04:27 +0100 Subject: [PATCH 037/134] Update dependency com.google.guava:guava to v33.2.1-jre (#8435) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 572bdaff3873..b2cc55b75b98 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -48,7 +48,7 @@ gradlePlugin-kotlinSerialization = { module = "org.jetbrains.kotlin:kotlin-seria gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.28.0" gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" -guava-jre = "com.google.guava:guava:33.2.0-jre" +guava-jre = "com.google.guava:guava:33.2.1-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:2.2" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3" jettyClient = "org.eclipse.jetty:jetty-client:9.4.54.v20240208" From 45c470a1fd1b299898d4b97bf541286b8653656a Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 22 Jun 2024 17:06:35 +0100 Subject: [PATCH 038/134] Disable connectionPreWarmingHttp2 for now (#8452) --- .../java/okhttp3/internal/connection/ConnectionPoolTest.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index b9b4f5354258..7ecceb09f3ea 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -35,6 +35,7 @@ import okhttp3.internal.http2.Http2ConnectionTest import okhttp3.internal.http2.MockHttp2Peer import okhttp3.internal.http2.Settings import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test class ConnectionPoolTest { @@ -229,7 +230,9 @@ class ConnectionPoolTest { assertThat(pool.connectionCount()).isEqualTo(1) } - @Test fun connectionPreWarmingHttp2() { + @Disabled("https://github.com/square/okhttp/issues/8451") + @Test + fun connectionPreWarmingHttp2() { taskFaker.advanceUntil(System.nanoTime()) val expireSooner = taskFaker.nanoTime + 1_000_000_000_000 val expireLater = taskFaker.nanoTime + 2_000_000_000_000 From dd7bbf4098633e3b0b749e29ffdd74ff7ff63d26 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 22 Jun 2024 17:18:31 +0100 Subject: [PATCH 039/134] Update renovate rules --- .github/renovate.json | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index 36df25c9d60b..6774ca1bbcf4 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -12,6 +12,18 @@ "com.squareup.okhttp3:mockwebserver" ], "packageRules": [ + { + "matchPackagePatterns": [ + "biz.*" + ], + "groupName": "bnd" + }, + { + "matchPackagePatterns": [ + "org.graalvm.*" + ], + "groupName": "graalvm" + }, { "matchPackageNames": ["org.objenesis:objenesis"], "allowedVersions": "<=2.6" @@ -25,16 +37,6 @@ "matchPackageNames": ["org.junit-pioneer:junit-pioneer"], "allowedVersions": "<2.0.0", "description": "JDK 11 requirement" - }, - { - "matchPackageNames": ["gradle"], - "allowedVersions": "<8.0", - "description": "Recent release, not compatible with pinned AGP and Kotlin versions yet. Wait for AGP 8?" - }, - { - "matchPackageNames": ["com.android.tools.build:gradle"], - "allowedVersions": "<7.4", - "description": "Recent release, no compatible Intellij stable release (2023.1)" } ] } From d3ab47f7520b759667c4ec97e1b08b1deaa4c729 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:21:54 +0100 Subject: [PATCH 040/134] Update dependency com.google.android.gms:play-services-safetynet to v18.1.0 (#8438) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b2cc55b75b98..b78c9d2a1c37 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -80,7 +80,7 @@ mockserver = { module = "org.testcontainers:mockserver", version.ref = "testcont mockserver-client = { module = "org.mock-server:mockserver-client-java-no-dependencies", version.ref = "mockserverClient" } nativeImageSvm = { module = "org.graalvm.nativeimage:svm", version.ref = "graalvm" } openjsse = "org.openjsse:openjsse:1.1.14" -playservices-safetynet = "com.google.android.gms:play-services-safetynet:18.0.1" +playservices-safetynet = "com.google.android.gms:play-services-safetynet:18.1.0" robolectric-android = "org.robolectric:android-all:14-robolectric-10818077" robolectric = "org.robolectric:robolectric:4.12.2" signature-android-apilevel21 = "net.sf.androidscents.signature:android-api-level-21:5.0.1_r2" From d596eee060fa4e610abb13faef04896bbc20cbd1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:22:22 +0100 Subject: [PATCH 041/134] Update dependency com.puppycrawl.tools:checkstyle to v10.17.0 (#8393) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b78c9d2a1c37..a61638da97d8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] biz-aQute-bnd = "6.4.0" -checkStyle = "10.15.0" +checkStyle = "10.17.0" com-squareup-moshi = "1.15.1" com-squareup-okio = "3.9.0" de-mannodermaus-junit5 = "1.4.0" From 182324bd7a6378d40f99a0e786cb9afcccdd044f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:22:31 +0100 Subject: [PATCH 042/134] Update dependency com.github.ajalt.clikt:clikt to v4.4.0 (#8392) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a61638da97d8..fe36acc85946 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ bouncycastle-bcprov = { module = "org.bouncycastle:bcprov-jdk15to18", version.re bouncycastle-bctls = { module = "org.bouncycastle:bctls-jdk15to18", version.ref = "org-bouncycastle" } brotli-dec = "org.brotli:dec:0.1.2" checkStyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkStyle" } -clikt = "com.github.ajalt.clikt:clikt:4.3.0" +clikt = "com.github.ajalt.clikt:clikt:4.4.0" codehaus-signature-java18 = "org.codehaus.mojo.signature:java18:1.0" conscrypt-android = { module = "org.conscrypt:conscrypt-android", version.ref = "org-conscrypt" } conscrypt-openjdk = { module = "org.conscrypt:conscrypt-openjdk-uber", version.ref = "org-conscrypt" } From aa302d2db6175d6c9e2e8bfe546f29170630ed9b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:22:42 +0100 Subject: [PATCH 043/134] Update dependency com.willowtreeapps.assertk:assertk to v0.28.1 (#8381) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fe36acc85946..3bfdd0fd59e2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ androidx-junit = "androidx.test.ext:junit:1.1.5" androidx-test-runner = "androidx.test:runner:1.5.2" animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.23" aqute-resolve = { module = "biz.aQute.bnd:biz.aQute.resolve", version.ref = "biz-aQute-bnd" } -assertk = "com.willowtreeapps.assertk:assertk:0.28.0" +assertk = "com.willowtreeapps.assertk:assertk:0.28.1" bouncycastle-bcpkix = { module = "org.bouncycastle:bcpkix-jdk15to18", version.ref = "org-bouncycastle" } bouncycastle-bcprov = { module = "org.bouncycastle:bcprov-jdk15to18", version.ref = "org-bouncycastle" } bouncycastle-bctls = { module = "org.bouncycastle:bctls-jdk15to18", version.ref = "org-bouncycastle" } From af40263b7beb35188aaae420a8079ac1c9ad9350 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:22:52 +0100 Subject: [PATCH 044/134] Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.3.1 (#8436) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3bfdd0fd59e2..5d63f1d9c8e4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,7 +50,7 @@ gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" guava-jre = "com.google.guava:guava:33.2.1-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:2.2" -httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3" +httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" jettyClient = "org.eclipse.jetty:jetty-client:9.4.54.v20240208" jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.22" jsoup = "org.jsoup:jsoup:1.17.2" From 1c2d31f0d2c7b02cd81efdd96e0dcdb63c63a352 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:23:03 +0100 Subject: [PATCH 045/134] Update dependency com.squareup:kotlinpoet to v1.17.0 (#8439) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5d63f1d9c8e4..e5fb9bfe6d1e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -89,7 +89,7 @@ squareup-moshi = { module = "com.squareup.moshi:moshi", version.ref = "com-squar squareup-moshi-compiler = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "com-squareup-moshi" } squareup-moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "com-squareup-moshi" } squareup-okhttp-icu = "com.squareup.okhttpicu:okhttp-icu:0.2.0" -squareup-kotlinPoet = "com.squareup:kotlinpoet:1.16.0" +squareup-kotlinPoet = "com.squareup:kotlinpoet:1.17.0" squareup-okio = { module = "com.squareup.okio:okio", version.ref = "com-squareup-okio" } squareup-okio-fakefilesystem = { module = "com.squareup.okio:okio-fakefilesystem", version.ref = "com-squareup-okio" } squareup-okio-nodefilesystem = { module = "com.squareup.okio:okio-nodefilesystem", version.ref = "com-squareup-okio" } From 3c0697d97d6abbe046f489c8c259960d54eb56b8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:24:52 +0100 Subject: [PATCH 046/134] Update dependency org.eclipse.platform:org.eclipse.osgi to v3.20.0 (#8454) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e5fb9bfe6d1e..629631f38d75 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,7 +33,7 @@ clikt = "com.github.ajalt.clikt:clikt:4.4.0" codehaus-signature-java18 = "org.codehaus.mojo.signature:java18:1.0" conscrypt-android = { module = "org.conscrypt:conscrypt-android", version.ref = "org-conscrypt" } conscrypt-openjdk = { module = "org.conscrypt:conscrypt-openjdk-uber", version.ref = "org-conscrypt" } -eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.19.0" +eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.20.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" gradlePlugin-android = "com.android.tools.build:gradle:8.2.0" gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.10.0.0" From 821ac849ea4ed6e002ade97314d54384356924f9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:25:07 +0100 Subject: [PATCH 047/134] Update org.jetbrains.coroutines to v1.8.1 (#8406) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 629631f38d75..2440f1a86292 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ kotlinx-serialization = "1.6.3" mockserverClient = "5.15.0" org-bouncycastle = "1.76" org-conscrypt = "2.5.2" -org-jetbrains-coroutines = "1.8.0" +org-jetbrains-coroutines = "1.8.1" org-jetbrains-kotlin = "1.9.23" org-junit-jupiter = "5.10.2" testcontainers = "1.19.8" From 717aea70482dbff08d6eacafd1c8e6376f461a9c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:25:15 +0100 Subject: [PATCH 048/134] Update dependency com.vanniktech:gradle-maven-publish-plugin to v0.29.0 (#8453) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2440f1a86292..07c7bf25c3e7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,7 +45,7 @@ gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.0.1" gradlePlugin-graal = "com.palantir.graal:gradle-graal:0.12.0" gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } gradlePlugin-kotlinSerialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } -gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.28.0" +gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.29.0" gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" guava-jre = "com.google.guava:guava:33.2.1-jre" From ad4c4f02860565e7217f23713f22c215f3bfce75 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sun, 23 Jun 2024 18:02:02 +0100 Subject: [PATCH 049/134] Maven dependency checks (#8431) * Testing maven dependency checks * Bump to 1.9.24 --- build.gradle.kts | 2 ++ gradle/libs.versions.toml | 7 ++++++- samples/tlssurvey/build.gradle.kts | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9c4702f37d57..befab1665954 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -26,6 +26,7 @@ buildscript { classpath(libs.gradlePlugin.spotless) classpath(libs.gradlePlugin.mavenPublish) classpath(libs.gradlePlugin.binaryCompatibilityValidator) + classpath(libs.gradlePlugin.mavenSympathy) } repositories { @@ -88,6 +89,7 @@ subprojects { apply(plugin = "checkstyle") apply(plugin = "ru.vyarus.animalsniffer") apply(plugin = "biz.aQute.bnd.builder") + apply(plugin = "io.github.usefulness.maven-sympathy") tasks.withType { options.encoding = Charsets.UTF_8.toString() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 07c7bf25c3e7..e6c01abf22d8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,12 +6,14 @@ com-squareup-okio = "3.9.0" de-mannodermaus-junit5 = "1.4.0" graalvm = "22.3.2" kotlinx-serialization = "1.6.3" +ksp = "1.9.24-1.0.20" mockserverClient = "5.15.0" org-bouncycastle = "1.76" org-conscrypt = "2.5.2" org-jetbrains-coroutines = "1.8.1" -org-jetbrains-kotlin = "1.9.23" +org-jetbrains-kotlin = "1.9.24" org-junit-jupiter = "5.10.2" +retrofit = "2.11.0" testcontainers = "1.19.8" [libraries] @@ -33,6 +35,7 @@ clikt = "com.github.ajalt.clikt:clikt:4.4.0" codehaus-signature-java18 = "org.codehaus.mojo.signature:java18:1.0" conscrypt-android = { module = "org.conscrypt:conscrypt-android", version.ref = "org-conscrypt" } conscrypt-openjdk = { module = "org.conscrypt:conscrypt-openjdk-uber", version.ref = "org-conscrypt" } +converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" } eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.20.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" gradlePlugin-android = "com.android.tools.build:gradle:8.2.0" @@ -46,6 +49,7 @@ gradlePlugin-graal = "com.palantir.graal:gradle-graal:0.12.0" gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } gradlePlugin-kotlinSerialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.29.0" +gradlePlugin-mavenSympathy = "io.github.usefulness.maven-sympathy:io.github.usefulness.maven-sympathy.gradle.plugin:0.3.0" gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" guava-jre = "com.google.guava:guava:33.2.1-jre" @@ -81,6 +85,7 @@ mockserver-client = { module = "org.mock-server:mockserver-client-java-no-depend nativeImageSvm = { module = "org.graalvm.nativeimage:svm", version.ref = "graalvm" } openjsse = "org.openjsse:openjsse:1.1.14" playservices-safetynet = "com.google.android.gms:play-services-safetynet:18.1.0" +retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } robolectric-android = "org.robolectric:android-all:14-robolectric-10818077" robolectric = "org.robolectric:robolectric:4.12.2" signature-android-apilevel21 = "net.sf.androidscents.signature:android-api-level-21:5.0.1_r2" diff --git a/samples/tlssurvey/build.gradle.kts b/samples/tlssurvey/build.gradle.kts index aa1c1192a297..37400b86988c 100644 --- a/samples/tlssurvey/build.gradle.kts +++ b/samples/tlssurvey/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("jvm") application - id("com.google.devtools.ksp").version("1.9.23-1.0.20") + id("com.google.devtools.ksp").version(libs.versions.ksp) } application { @@ -13,12 +13,12 @@ dependencies { implementation(projects.okhttpCoroutines) implementation(libs.conscrypt.openjdk) - implementation("com.squareup.retrofit2:retrofit:2.11.0") - implementation("com.squareup.retrofit2:converter-moshi:2.11.0") + implementation(libs.retrofit) + implementation(libs.converter.moshi) implementation(libs.squareup.moshi) implementation(libs.squareup.moshi.kotlin) - ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.1") + ksp(libs.squareup.moshi.compiler) } tasks.compileJava { From defcfc7c74b8004beb7403557f87b50a3556c4da Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 06:33:36 +0100 Subject: [PATCH 050/134] Update dependency androidx.test.espresso:espresso-core to v3.6.1 (#8465) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e6c01abf22d8..f6fd905f4ebb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,7 +20,7 @@ testcontainers = "1.19.8" amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.3.3" androidx-activity = "androidx.activity:activity-ktx:1.9.0" androidx-annotation = "androidx.annotation:annotation:1.8.0" -androidx-espresso-core = "androidx.test.espresso:espresso-core:3.5.1" +androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.1.5" androidx-test-runner = "androidx.test:runner:1.5.2" animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.23" From c85c3dbbee94e2bb8ed86ed29da0148842bb493e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 06:33:49 +0100 Subject: [PATCH 051/134] Update junit5 monorepo (#8464) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f6fd905f4ebb..20f8b7a69755 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ org-bouncycastle = "1.76" org-conscrypt = "2.5.2" org-jetbrains-coroutines = "1.8.1" org-jetbrains-kotlin = "1.9.24" -org-junit-jupiter = "5.10.2" +org-junit-jupiter = "5.10.3" retrofit = "2.11.0" testcontainers = "1.19.8" @@ -63,8 +63,8 @@ junit-ktx = "androidx.test.ext:junit-ktx:1.1.5" junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "org-junit-jupiter" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "org-junit-jupiter" } junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "org-junit-jupiter" } -junit-platform-console = "org.junit.platform:junit-platform-console:1.10.2" -junit-vintage-engine = "org.junit.vintage:junit-vintage-engine:5.10.2" +junit-platform-console = "org.junit.platform:junit-platform-console:1.10.3" +junit-vintage-engine = "org.junit.vintage:junit-vintage-engine:5.10.3" junit-pioneer = "org.junit-pioneer:junit-pioneer:1.9.1" junit5android-core = { module = "de.mannodermaus.junit5:android-test-core", version.ref = "de-mannodermaus-junit5" } junit5android-runner = { module = "de.mannodermaus.junit5:android-test-runner", version.ref = "de-mannodermaus-junit5" } From bc1bb4be120a653ef08e8d64d102c9d178545a91 Mon Sep 17 00:00:00 2001 From: Endeavour233 <43426962+Endeavour233@users.noreply.github.com> Date: Sat, 6 Jul 2024 17:38:30 +0800 Subject: [PATCH 052/134] update doc for body field (#8420) --- okhttp/src/main/kotlin/okhttp3/Response.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/okhttp/src/main/kotlin/okhttp3/Response.kt b/okhttp/src/main/kotlin/okhttp3/Response.kt index 517c1047f987..6fd6fdf9567a 100644 --- a/okhttp/src/main/kotlin/okhttp3/Response.kt +++ b/okhttp/src/main/kotlin/okhttp3/Response.kt @@ -84,7 +84,7 @@ class Response internal constructor( * from [Call.execute]. Response bodies must be [closed][ResponseBody] and may * be consumed only once. * - * This always returns null on responses returned from [cacheResponse], [networkResponse], + * This always returns an unreadable [ResponseBody], which may implement [ResponseBody.contentType] and [ResponseBody.contentLength], on responses returned from [cacheResponse], [networkResponse], * and [priorResponse]. */ @get:JvmName("body") val body: ResponseBody, From d03a2c139350f0f3fd8fe1166d371f72b9f6f505 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 06:17:32 +0100 Subject: [PATCH 053/134] Update dependency androidx.test.ext:junit to v1.2.1 (#8469) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 20f8b7a69755..db4ee373a412 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,7 +21,7 @@ amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.3.3" androidx-activity = "androidx.activity:activity-ktx:1.9.0" androidx-annotation = "androidx.annotation:annotation:1.8.0" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" -androidx-junit = "androidx.test.ext:junit:1.1.5" +androidx-junit = "androidx.test.ext:junit:1.2.1" androidx-test-runner = "androidx.test:runner:1.5.2" animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.23" aqute-resolve = { module = "biz.aQute.bnd:biz.aQute.resolve", version.ref = "biz-aQute-bnd" } From 4f9cb44a89d040a0e6d8c268e08447323b0b2d64 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 06:18:17 +0100 Subject: [PATCH 054/134] Update dependency org.eclipse.jetty:jetty-client to v9.4.55.v20240627 (#8468) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index db4ee373a412..27ba9e4483ef 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -55,7 +55,7 @@ gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" guava-jre = "com.google.guava:guava:33.2.1-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:2.2" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" -jettyClient = "org.eclipse.jetty:jetty-client:9.4.54.v20240208" +jettyClient = "org.eclipse.jetty:jetty-client:9.4.55.v20240627" jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.22" jsoup = "org.jsoup:jsoup:1.17.2" junit = "junit:junit:4.13.2" From 571c41df11aeae737b87b1e99defb85ea239d859 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 14 Jul 2024 22:34:56 -0400 Subject: [PATCH 055/134] Update dependency androidx.test:runner to v1.6.1 (#8475) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 27ba9e4483ef..e6b2b13bc205 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ androidx-activity = "androidx.activity:activity-ktx:1.9.0" androidx-annotation = "androidx.annotation:annotation:1.8.0" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" -androidx-test-runner = "androidx.test:runner:1.5.2" +androidx-test-runner = "androidx.test:runner:1.6.1" animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.23" aqute-resolve = { module = "biz.aQute.bnd:biz.aQute.resolve", version.ref = "biz-aQute-bnd" } assertk = "com.willowtreeapps.assertk:assertk:0.28.1" From 51eacac4c6cde93c2cbad21dd841be50bbe078be Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 14 Jul 2024 22:35:06 -0400 Subject: [PATCH 056/134] Update dependency androidx.test.ext:junit-ktx to v1.2.1 (#8474) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e6b2b13bc205..6a3b2e0644c6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -59,7 +59,7 @@ jettyClient = "org.eclipse.jetty:jetty-client:9.4.55.v20240627" jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.22" jsoup = "org.jsoup:jsoup:1.17.2" junit = "junit:junit:4.13.2" -junit-ktx = "androidx.test.ext:junit-ktx:1.1.5" +junit-ktx = "androidx.test.ext:junit-ktx:1.2.1" junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "org-junit-jupiter" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "org-junit-jupiter" } junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "org-junit-jupiter" } From 366e6f8cba1cc381df6d2cf1d8e2c4c6ad127e4b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 19:59:11 -0400 Subject: [PATCH 057/134] Update dependency org.codehaus.mojo:animal-sniffer-annotations to v1.24 (#8479) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6a3b2e0644c6..312710320d7e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ androidx-annotation = "androidx.annotation:annotation:1.8.0" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" androidx-test-runner = "androidx.test:runner:1.6.1" -animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.23" +animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.24" aqute-resolve = { module = "biz.aQute.bnd:biz.aQute.resolve", version.ref = "biz-aQute-bnd" } assertk = "com.willowtreeapps.assertk:assertk:0.28.1" bouncycastle-bcpkix = { module = "org.bouncycastle:bcpkix-jdk15to18", version.ref = "org-bouncycastle" } From 8f1f19c7c96afc5391d2b6320baf180e28cc7d2b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 21:00:33 -0400 Subject: [PATCH 058/134] Update dependency org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin to v0.16.2 (#8484) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 312710320d7e..b71253a677a2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,7 +41,7 @@ findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" gradlePlugin-android = "com.android.tools.build:gradle:8.2.0" gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.10.0.0" gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.1" -gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.14.0" +gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.16.2" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } gradlePlugin-dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.20" gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.0.1" From ec6479c15a4d76e8dceb2fd9d8bda78aa9a6bdae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 21:00:42 -0400 Subject: [PATCH 059/134] Update kotlin monorepo to v1.9.25 (#8483) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b71253a677a2..0eae6c7021c7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ mockserverClient = "5.15.0" org-bouncycastle = "1.76" org-conscrypt = "2.5.2" org-jetbrains-coroutines = "1.8.1" -org-jetbrains-kotlin = "1.9.24" +org-jetbrains-kotlin = "1.9.25" org-junit-jupiter = "5.10.3" retrofit = "2.11.0" testcontainers = "1.19.8" From 49a811aa08344b91b2c2a01b2f4743b82bc22396 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 21:53:06 -0400 Subject: [PATCH 060/134] Update dependency org.jsoup:jsoup to v1.18.1 (#8485) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0eae6c7021c7..eda6a9fefc05 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,7 +57,7 @@ hamcrestLibrary = "org.hamcrest:hamcrest-library:2.2" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" jettyClient = "org.eclipse.jetty:jetty-client:9.4.55.v20240627" jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.22" -jsoup = "org.jsoup:jsoup:1.17.2" +jsoup = "org.jsoup:jsoup:1.18.1" junit = "junit:junit:4.13.2" junit-ktx = "androidx.test.ext:junit-ktx:1.2.1" junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "org-junit-jupiter" } From e20610ea241e04b96d06c260cb73f42a7b564e12 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:18:03 -0400 Subject: [PATCH 061/134] Update dependency androidx.annotation:annotation to v1.8.1 (#8495) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eda6a9fefc05..2b5a8599756b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ testcontainers = "1.19.8" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.3.3" androidx-activity = "androidx.activity:activity-ktx:1.9.0" -androidx-annotation = "androidx.annotation:annotation:1.8.0" +androidx-annotation = "androidx.annotation:annotation:1.8.1" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" androidx-test-runner = "androidx.test:runner:1.6.1" From 3830bbe8a0387612c91c95c981275305d5abf5cb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:44:18 -0400 Subject: [PATCH 062/134] Update dependency androidx.activity:activity-ktx to v1.9.1 (#8494) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2b5a8599756b..1ed8c846e9ed 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ testcontainers = "1.19.8" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.3.3" -androidx-activity = "androidx.activity:activity-ktx:1.9.0" +androidx-activity = "androidx.activity:activity-ktx:1.9.1" androidx-annotation = "androidx.annotation:annotation:1.8.1" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" From eb01b1072bf93204b53eb73d40b60ee58d482a51 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 4 Aug 2024 20:38:40 -0400 Subject: [PATCH 063/134] Update dependency org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin to v0.16.3 (#8499) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1ed8c846e9ed..061736b97627 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,7 +41,7 @@ findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" gradlePlugin-android = "com.android.tools.build:gradle:8.2.0" gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.10.0.0" gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.1" -gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.16.2" +gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.16.3" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } gradlePlugin-dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.20" gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.0.1" From 34aa13644978028bceeb269ba48dc10d90da1350 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 Aug 2024 22:42:10 -0400 Subject: [PATCH 064/134] Update dependency androidx.annotation:annotation to v1.8.2 (#8505) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 061736b97627..59cd3a4409ac 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ testcontainers = "1.19.8" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.3.3" androidx-activity = "androidx.activity:activity-ktx:1.9.1" -androidx-annotation = "androidx.annotation:annotation:1.8.1" +androidx-annotation = "androidx.annotation:annotation:1.8.2" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" androidx-test-runner = "androidx.test:runner:1.6.1" From babbf643cdf28df52022868996d2af9e91fc1c77 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Aug 2024 19:18:20 +0100 Subject: [PATCH 065/134] Update dependency de.mannodermaus.gradle.plugins:android-junit5 to v1.11.0.0 (#8498) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 59cd3a4409ac..a15c71e175e8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.r eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.20.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" gradlePlugin-android = "com.android.tools.build:gradle:8.2.0" -gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.10.0.0" +gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.0.0" gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.1" gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.16.3" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } From c99c5e736c773bcd1f1fc0e89cdd87b80dd5ec41 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:37:49 +0100 Subject: [PATCH 066/134] Update de.mannodermaus.junit5 to v1.5.0 (#8500) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a15c71e175e8..55faf5e59dbc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ biz-aQute-bnd = "6.4.0" checkStyle = "10.17.0" com-squareup-moshi = "1.15.1" com-squareup-okio = "3.9.0" -de-mannodermaus-junit5 = "1.4.0" +de-mannodermaus-junit5 = "1.5.0" graalvm = "22.3.2" kotlinx-serialization = "1.6.3" ksp = "1.9.24-1.0.20" From ee03fc254a9207e47dfc3c2bab1c354eeb7c4003 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:39:41 +0100 Subject: [PATCH 067/134] Update dependency software.amazon.cryptools:AmazonCorrettoCryptoProvider to v2.4.1 (#8487) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 55faf5e59dbc..92f60224c708 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ retrofit = "2.11.0" testcontainers = "1.19.8" [libraries] -amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.3.3" +amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.4.1" androidx-activity = "androidx.activity:activity-ktx:1.9.1" androidx-annotation = "androidx.annotation:annotation:1.8.2" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" From f7b70f06d82ee0e0a25c1569fa028a2877b48de2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:48:19 +0100 Subject: [PATCH 068/134] Update testcontainers-java monorepo to v1.20.1 (#8501) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 92f60224c708..c22b2678199b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-coroutines = "1.8.1" org-jetbrains-kotlin = "1.9.25" org-junit-jupiter = "5.10.3" retrofit = "2.11.0" -testcontainers = "1.19.8" +testcontainers = "1.20.1" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.4.1" From c4fc47cc0075987c6fd76aa74478e1315a189d5f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:48:56 +0100 Subject: [PATCH 069/134] Update dependency com.google.guava:guava to v33.3.0-jre (#8515) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c22b2678199b..9fadab38bb03 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -52,7 +52,7 @@ gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.29.0" gradlePlugin-mavenSympathy = "io.github.usefulness.maven-sympathy:io.github.usefulness.maven-sympathy.gradle.plugin:0.3.0" gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" -guava-jre = "com.google.guava:guava:33.2.1-jre" +guava-jre = "com.google.guava:guava:33.3.0-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:2.2" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" jettyClient = "org.eclipse.jetty:jetty-client:9.4.55.v20240627" From 35ead6cd093bca5c409467eee62e8c47d4669790 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 17 Aug 2024 11:04:53 +0100 Subject: [PATCH 070/134] Update dependency org.hamcrest:hamcrest-library to v3 (#8517) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9fadab38bb03..53c078655ae0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -53,7 +53,7 @@ gradlePlugin-mavenSympathy = "io.github.usefulness.maven-sympathy:io.github.usef gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" guava-jre = "com.google.guava:guava:33.3.0-jre" -hamcrestLibrary = "org.hamcrest:hamcrest-library:2.2" +hamcrestLibrary = "org.hamcrest:hamcrest-library:3.0" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" jettyClient = "org.eclipse.jetty:jetty-client:9.4.55.v20240627" jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.22" From e10d8d3f08b82f90c9f57513b2322acd0d131dc3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 17 Aug 2024 11:05:29 +0100 Subject: [PATCH 071/134] Update gradle/actions action to v4 (#8518) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 38 ++++++++++++++++---------------- .github/workflows/containers.yml | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9868d0257e9b..72cc4c33c378 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Upload Artifacts run: ./gradlew clean publish --stacktrace @@ -49,7 +49,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: gradle/actions/wrapper-validation@v3 + - uses: gradle/actions/wrapper-validation@v4 - name: Validate Renovate uses: rinchsan/renovate-config-validator@v0.2.0 with: @@ -79,7 +79,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew check -PandroidBuild=true -PgraalBuild=true -x test -x test @@ -108,7 +108,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dtest.java.version=11 @@ -150,7 +150,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dtest.java.version=11 @@ -178,7 +178,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dtest.java.version=8 @@ -212,7 +212,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dtest.java.version=8 -Dokhttp.platform=jdk8alpn -Dalpn.boot.version=8.1.13.v20181017 -Dorg.gradle.java.installations.paths=/opt/hostedtoolcache/Java_Adopt_jdk/8.0.242-8.1/x64 @@ -240,7 +240,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dtest.java.version=8 -Dokhttp.platform=openjsse @@ -268,7 +268,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dokhttp.platform=conscrypt @@ -296,7 +296,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dokhttp.platform=bouncycastle @@ -325,7 +325,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dokhttp.platform=corretto @@ -354,7 +354,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dtest.java.version=17 @@ -389,7 +389,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dtest.java.version=21 @@ -418,7 +418,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Test run: ./gradlew test @@ -447,13 +447,13 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Build okcurl run: ./gradlew okcurl:nativeImage - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Build ConsoleLauncher run: ./gradlew -PgraalBuild=true native-image-tests:nativeImage @@ -500,7 +500,7 @@ jobs: sudo udevadm trigger --name-match=kvm - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Gradle cache run: ./gradlew -PandroidBuild=true :okhttp-android:test @@ -572,7 +572,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Checks run: ./gradlew test -Dokhttp.platform=loom -Dtest.java.version=21 -PcontainerTests=true @@ -616,7 +616,7 @@ jobs: sudo udevadm trigger --name-match=kvm - name: Gradle cache - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: AVD cache uses: actions/cache@v4 diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml index 0b058c3dd2df..580d67493f1c 100644 --- a/.github/workflows/containers.yml +++ b/.github/workflows/containers.yml @@ -33,7 +33,7 @@ jobs: java-version: 17 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Run Container Tests run: ./gradlew container-tests:test -PcontainerTests=true From 7da99460f0bea3d6c217f37eb27ae66616d7bdd2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 18 Aug 2024 22:57:01 -0400 Subject: [PATCH 072/134] Update dependency androidx.test:runner to v1.6.2 (#8520) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 53c078655ae0..cf00722d278b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ androidx-activity = "androidx.activity:activity-ktx:1.9.1" androidx-annotation = "androidx.annotation:annotation:1.8.2" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" -androidx-test-runner = "androidx.test:runner:1.6.1" +androidx-test-runner = "androidx.test:runner:1.6.2" animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.24" aqute-resolve = { module = "biz.aQute.bnd:biz.aQute.resolve", version.ref = "biz-aQute-bnd" } assertk = "com.willowtreeapps.assertk:assertk:0.28.1" From 9ed9dfe317169020fbbf54507cb672ea55fc5c9d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:46:51 -0400 Subject: [PATCH 073/134] Update dependency com.puppycrawl.tools:checkstyle to v10.18.0 (#8525) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cf00722d278b..a53df3d2becc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] biz-aQute-bnd = "6.4.0" -checkStyle = "10.17.0" +checkStyle = "10.18.0" com-squareup-moshi = "1.15.1" com-squareup-okio = "3.9.0" de-mannodermaus-junit5 = "1.5.0" From 28075d78310e895b4673cd5433a69b80d42433c2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:08:43 +0100 Subject: [PATCH 074/134] Update junit5 monorepo (#8526) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a53df3d2becc..43a1783884eb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ org-bouncycastle = "1.76" org-conscrypt = "2.5.2" org-jetbrains-coroutines = "1.8.1" org-jetbrains-kotlin = "1.9.25" -org-junit-jupiter = "5.10.3" +org-junit-jupiter = "5.11.0" retrofit = "2.11.0" testcontainers = "1.20.1" @@ -63,8 +63,8 @@ junit-ktx = "androidx.test.ext:junit-ktx:1.2.1" junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "org-junit-jupiter" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "org-junit-jupiter" } junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "org-junit-jupiter" } -junit-platform-console = "org.junit.platform:junit-platform-console:1.10.3" -junit-vintage-engine = "org.junit.vintage:junit-vintage-engine:5.10.3" +junit-platform-console = "org.junit.platform:junit-platform-console:1.11.0" +junit-vintage-engine = "org.junit.vintage:junit-vintage-engine:5.11.0" junit-pioneer = "org.junit-pioneer:junit-pioneer:1.9.1" junit5android-core = { module = "de.mannodermaus.junit5:android-test-core", version.ref = "de-mannodermaus-junit5" } junit5android-runner = { module = "de.mannodermaus.junit5:android-test-runner", version.ref = "de-mannodermaus-junit5" } From e8c3e0b9244285c03bb0187689be347769d8d489 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 23:19:34 -0400 Subject: [PATCH 075/134] Update dependency com.puppycrawl.tools:checkstyle to v10.18.1 (#8528) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 43a1783884eb..1fcbd12088db 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] biz-aQute-bnd = "6.4.0" -checkStyle = "10.18.0" +checkStyle = "10.18.1" com-squareup-moshi = "1.15.1" com-squareup-okio = "3.9.0" de-mannodermaus-junit5 = "1.5.0" From a91675e32cdddb0f918514ab4c3c0d457b6559ac Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 8 Sep 2024 21:10:18 -0400 Subject: [PATCH 076/134] Update dependency androidx.activity:activity-ktx to v1.9.2 (#8532) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1fcbd12088db..175cff855b4e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ testcontainers = "1.20.1" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.4.1" -androidx-activity = "androidx.activity:activity-ktx:1.9.1" +androidx-activity = "androidx.activity:activity-ktx:1.9.2" androidx-annotation = "androidx.annotation:annotation:1.8.2" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" From d58da0a65b7f9cdbdf25b198e804153164ae729f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 8 Sep 2024 21:33:57 -0400 Subject: [PATCH 077/134] Update dependency org.eclipse.jetty:jetty-client to v9.4.56.v20240826 (#8533) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 175cff855b4e..93743969df6a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -55,7 +55,7 @@ gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" guava-jre = "com.google.guava:guava:33.3.0-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:3.0" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" -jettyClient = "org.eclipse.jetty:jetty-client:9.4.55.v20240627" +jettyClient = "org.eclipse.jetty:jetty-client:9.4.56.v20240826" jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.22" jsoup = "org.jsoup:jsoup:1.18.1" junit = "junit:junit:4.13.2" From 2806e624afab96e26e84277a9f789004b622953f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 21:20:56 -0400 Subject: [PATCH 078/134] Update com.squareup.okio to v3.9.1 (#8535) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 93743969df6a..f047e6756380 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ biz-aQute-bnd = "6.4.0" checkStyle = "10.18.1" com-squareup-moshi = "1.15.1" -com-squareup-okio = "3.9.0" +com-squareup-okio = "3.9.1" de-mannodermaus-junit5 = "1.5.0" graalvm = "22.3.2" kotlinx-serialization = "1.6.3" From f2771425cb714a5b0b27238bd081b2516b4d640f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 21:25:34 -0400 Subject: [PATCH 079/134] Update dependency org.eclipse.platform:org.eclipse.osgi to v3.21.0 (#8536) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f047e6756380..c8b5cf682637 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,7 +36,7 @@ codehaus-signature-java18 = "org.codehaus.mojo.signature:java18:1.0" conscrypt-android = { module = "org.conscrypt:conscrypt-android", version.ref = "org-conscrypt" } conscrypt-openjdk = { module = "org.conscrypt:conscrypt-openjdk-uber", version.ref = "org-conscrypt" } converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" } -eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.20.0" +eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.21.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" gradlePlugin-android = "com.android.tools.build:gradle:8.2.0" gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.0.0" From dbedfd000c8e84bc914c619714b8c9bf7f3e06d4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 15:04:41 -0700 Subject: [PATCH 080/134] Update dependency com.puppycrawl.tools:checkstyle to v10.19.0 (#8547) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c8b5cf682637..c646fca354b9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] biz-aQute-bnd = "6.4.0" -checkStyle = "10.18.1" +checkStyle = "10.19.0" com-squareup-moshi = "1.15.1" com-squareup-okio = "3.9.1" de-mannodermaus-junit5 = "1.5.0" From 43c7eb62421b1c750acda9983bbb19668e8b0861 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 27 Oct 2024 20:31:35 -0700 Subject: [PATCH 081/134] Update dependency androidx.activity:activity-ktx to v1.9.3 (#8561) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c646fca354b9..134fe7894587 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ testcontainers = "1.20.1" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.4.1" -androidx-activity = "androidx.activity:activity-ktx:1.9.2" +androidx-activity = "androidx.activity:activity-ktx:1.9.3" androidx-annotation = "androidx.annotation:annotation:1.8.2" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" From 90d2c07566ba552c5320b00249f61a9469270117 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 04:53:44 -0700 Subject: [PATCH 082/134] Update dependency com.github.jnr:jnr-unixsocket to v0.38.23 (#8562) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 134fe7894587..cf1d761a0f5a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -56,7 +56,7 @@ guava-jre = "com.google.guava:guava:33.3.0-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:3.0" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" jettyClient = "org.eclipse.jetty:jetty-client:9.4.56.v20240826" -jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.22" +jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.23" jsoup = "org.jsoup:jsoup:1.18.1" junit = "junit:junit:4.13.2" junit-ktx = "androidx.test.ext:junit-ktx:1.2.1" From ce9fc58b8da2c22a3adab8055334284badbfc33e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=A1=A0=E1=A0=B5=E1=A1=A0=E1=A1=B3=20=E1=A1=A0=E1=A0=B5?= =?UTF-8?q?=E1=A1=A0=20=E1=A0=AE=E1=A0=A0=E1=A0=A8=E1=A1=A9=E1=A0=8B?= =?UTF-8?q?=E1=A0=A0=E1=A0=A8?= <125150101+UjuiUjuMandan@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:27:31 +0800 Subject: [PATCH 083/134] Skip protocol warning since QUIC supports multiplexing too (#8563) --- .../src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt index cc3872e5e194..2dc4741e901a 100644 --- a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt +++ b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt @@ -223,7 +223,7 @@ class DnsOverHttps internal constructor( hostname: String, response: Response, ): List { - if (response.cacheResponse == null && response.protocol !== Protocol.HTTP_2) { + if (response.cacheResponse == null && response.protocol !== Protocol.HTTP_2 && response.protocol !== Protocol.QUIC) { Platform.get().log("Incorrect protocol: ${response.protocol}", Platform.WARN) } From f1e6d01aea30844f0ddc7394208ec13d59d5e6f8 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Tue, 5 Nov 2024 06:50:55 +0000 Subject: [PATCH 084/134] Fix: Handle multiple 1xx responses (#8569) This change updates the client to handle multiple 1xx (Processing etc) responses from the server. The client now waits for the final response with a status code other than 1xx before proceeding. From https://datatracker.ietf.org/doc/html/rfc7231#section-6.2 > A client MUST be able to parse one or more 1xx responses received prior to a final response, even if the client does not expect one. A user agent MAY ignore unexpected 1xx responses. fixes #8568 --- .../internal/http/CallServerInterceptor.kt | 2 +- okhttp/src/test/java/okhttp3/CallTest.kt | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt b/okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt index 9c7a60d49d15..324324f17a5e 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt @@ -105,7 +105,7 @@ class CallServerInterceptor(private val forWebSocket: Boolean) : Interceptor { .build() var code = response.code - if (shouldIgnoreAndWaitForRealResponse(code, exchange)) { + while (shouldIgnoreAndWaitForRealResponse(code, exchange)) { responseBuilder = exchange.readResponseHeaders(expectContinue = false)!! if (invokeStartEvent) { exchange.responseHeadersStart() diff --git a/okhttp/src/test/java/okhttp3/CallTest.kt b/okhttp/src/test/java/okhttp3/CallTest.kt index e59e0de7b6ee..a43d76d7dae9 100644 --- a/okhttp/src/test/java/okhttp3/CallTest.kt +++ b/okhttp/src/test/java/okhttp3/CallTest.kt @@ -3234,6 +3234,33 @@ open class CallTest { assertThat(recordedRequest.body.readUtf8()).isEqualTo("abc") } + @Test + fun serverRespondsWithProcessingMultiple() { + server.enqueue( + MockResponse.Builder() + .apply { + repeat(10) { + addInformationalResponse( + MockResponse( + code = HTTP_PROCESSING, + ), + ) + } + } + .build(), + ) + val request = + Request( + url = server.url("/"), + body = "abc".toRequestBody("text/plain".toMediaType()), + ) + executeSynchronously(request) + .assertCode(200) + .assertSuccessful() + val recordedRequest = server.takeRequest() + assertThat(recordedRequest.body.readUtf8()).isEqualTo("abc") + } + @Test fun serverRespondsWithUnsolicited100Continue_HTTP2() { enableProtocol(Protocol.HTTP_2) From d056e608a0cc85c50ddd2bd4653832d409ec7c3a Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Mon, 11 Nov 2024 17:46:15 +0000 Subject: [PATCH 085/134] Update README.md to describe philosophy (#8572) --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index e70c426cc535..f3ffebb74f45 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,27 @@ configured to fall back for broad connectivity. Using OkHttp is easy. Its request/response API is designed with fluent builders and immutability. It supports both synchronous blocking calls and async calls with callbacks. +A well behaved user agent +------------------------- + +OkHttp follows modern HTTP specifications such as + +* HTTP/1.1 - [RFC 7231](https://datatracker.ietf.org/doc/html/rfc7231) +* HTTP/2 - [RFC 9113](https://datatracker.ietf.org/doc/html/rfc9113) +* Websockets - [RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455) +* SSE - [Server-sent events](https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events) + +Where the spec is ambiguous, OkHttp follows modern user agents such as popular Browsers or common HTTP Libraries. + +OkHttp is principled and avoids being overly configurable, especially when such configuration is +to workaround a buggy server, test invalid scenarios or that contradict the relevant RFC. +Other HTTP libraries exist that fill that gap allowing extensive customisation including potentially +invalid requests. + +Example Limitations + +* Does not allow GET with a body. +* Cache is not an interface with alternative implementations. Get a URL --------- @@ -129,6 +150,11 @@ The latest release is available on [Maven Central](https://search.maven.org/arti testImplementation("com.squareup.okhttp3:mockwebserver:4.12.0") ``` +MockWebServer is used for firstly for internal testing, and for basic testing of apps using OkHttp client. +It is not a full featured HTTP testing library that is developed standalone. It is not being actively developed +for new features. As such you might find your needs outgrow MockWebServer and you may which to use a +more full featured testing library such as [MockServer](https://www.mock-server.com/). + GraalVM Native Image -------------------- From 02d69bf883c47905d0ad3fd9d2ad75b8ede75bb9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 19:51:31 +0000 Subject: [PATCH 086/134] Update dependency de.mannodermaus.gradle.plugins:android-junit5 to v1.11.2.0 (#8567) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cf1d761a0f5a..c79b8d4cef5a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.r eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.21.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" gradlePlugin-android = "com.android.tools.build:gradle:8.2.0" -gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.0.0" +gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.2.0" gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.1" gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.16.3" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } From 3e560892d40a1d4059a750e70929cccadc11733d Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sun, 17 Nov 2024 19:04:37 +0000 Subject: [PATCH 087/134] Centralise more locks (#8389) Refactor: Centralize lock management This change centralizes the management of locks and conditions by introducing a centralised Locks registry. This allows for easier debugging and potential future improvements to lock usage. The `withLock` and `newLockCondition` functions are now invoked through the `Locks` object, providing a central point of access. --- .../kotlin/okhttp3/OkHttpClientTestRule.kt | 4 +- .../okhttp3/internal/concurrent/TaskFaker.kt | 20 ++++---- .../okhttp3/internal/concurrent/TaskQueue.kt | 14 +++--- .../okhttp3/internal/concurrent/TaskRunner.kt | 17 +++---- .../internal/connection/ConnectPlan.kt | 1 - .../okhttp3/internal/connection/Locks.kt | 46 ++++++++++++++++--- .../internal/connection/RealConnection.kt | 7 ++- .../okhttp3/internal/http2/Http2Connection.kt | 3 +- .../okhttp3/internal/http2/Http2Stream.kt | 3 +- 9 files changed, 75 insertions(+), 40 deletions(-) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpClientTestRule.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpClientTestRule.kt index 275d09f6a0a7..8d222346e88e 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpClientTestRule.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpClientTestRule.kt @@ -25,9 +25,9 @@ import java.util.logging.Level import java.util.logging.LogManager import java.util.logging.LogRecord import java.util.logging.Logger -import kotlin.concurrent.withLock import okhttp3.internal.buildConnectionPool import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.connection.RealConnectionPool import okhttp3.internal.http2.Http2 import okhttp3.internal.taskRunnerInternal @@ -234,7 +234,7 @@ class OkHttpClientTestRule : BeforeEachCallback, AfterEachCallback { // a test timeout failure. val waitTime = (entryTime + 1_000_000_000L - System.nanoTime()) if (!queue.idleLatch().await(waitTime, TimeUnit.NANOSECONDS)) { - TaskRunner.INSTANCE.lock.withLock { + TaskRunner.INSTANCE.withLock { TaskRunner.INSTANCE.cancelAll() } fail("Queue still active after 1000 ms") diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt index 1874cd9ca8e0..e9be10d078cd 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + package okhttp3.internal.concurrent import assertk.assertThat @@ -23,9 +25,9 @@ import java.util.concurrent.BlockingQueue import java.util.concurrent.Executors import java.util.concurrent.TimeUnit import java.util.logging.Logger -import kotlin.concurrent.withLock import okhttp3.OkHttpClient import okhttp3.TestUtil.threadFactory +import okhttp3.internal.connection.Locks.withLock /** * Runs a [TaskRunner] in a controlled environment so that everything is sequential and @@ -170,7 +172,7 @@ class TaskFaker : Closeable { fun advanceUntil(newTime: Long) { taskRunner.assertThreadDoesntHoldLock() - taskRunner.lock.withLock { + taskRunner.withLock { check(currentTask == TestThreadSerialTask) nanoTime = newTime yieldUntil(ResumePriority.AfterOtherTasks) @@ -181,7 +183,7 @@ class TaskFaker : Closeable { fun assertNoMoreTasks() { taskRunner.assertThreadDoesntHoldLock() - taskRunner.lock.withLock { + taskRunner.withLock { assertThat(activeThreads).isEqualTo(0) } } @@ -211,7 +213,7 @@ class TaskFaker : Closeable { fun runNextTask() { taskRunner.assertThreadDoesntHoldLock() - taskRunner.lock.withLock { + taskRunner.withLock { val contextSwitchCountBefore = contextSwitchCount yieldUntil(ResumePriority.BeforeOtherTasks) { contextSwitchCount > contextSwitchCountBefore @@ -221,7 +223,7 @@ class TaskFaker : Closeable { /** Sleep until [durationNanos] elapses. For use by the task threads. */ fun sleep(durationNanos: Long) { - taskRunner.lock.withLock { + taskRunner.withLock { val sleepUntil = nanoTime + durationNanos yieldUntil { nanoTime >= sleepUntil } } @@ -233,7 +235,7 @@ class TaskFaker : Closeable { */ fun yield() { taskRunner.assertThreadDoesntHoldLock() - taskRunner.lock.withLock { + taskRunner.withLock { yieldUntil() } } @@ -332,7 +334,7 @@ class TaskFaker : Closeable { runnable.run() require(currentTask == this) { "unexpected current task: $currentTask" } } finally { - taskRunner.lock.withLock { + taskRunner.withLock { activeThreads-- startNextTask() } @@ -358,7 +360,7 @@ class TaskFaker : Closeable { timeout: Long, unit: TimeUnit, ): T? { - taskRunner.lock.withLock { + taskRunner.withLock { val waitUntil = nanoTime + unit.toNanos(timeout) while (true) { val result = poll() @@ -371,7 +373,7 @@ class TaskFaker : Closeable { } override fun put(element: T) { - taskRunner.lock.withLock { + taskRunner.withLock { delegate.put(element) editCount++ } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt index 788fc0f44321..99d5b600b265 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt @@ -18,8 +18,8 @@ package okhttp3.internal.concurrent import java.util.concurrent.CountDownLatch import java.util.concurrent.RejectedExecutionException import java.util.concurrent.locks.ReentrantLock -import kotlin.concurrent.withLock import okhttp3.internal.assertNotHeld +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.okHttpName /** @@ -32,7 +32,7 @@ class TaskQueue internal constructor( internal val taskRunner: TaskRunner, internal val name: String, ) { - val lock: ReentrantLock = ReentrantLock() + internal val lock: ReentrantLock = ReentrantLock() internal var shutdown = false @@ -50,7 +50,7 @@ class TaskQueue internal constructor( * currently-executing task unless it is also scheduled for future execution. */ val scheduledTasks: List - get() = taskRunner.lock.withLock { futureTasks.toList() } + get() = taskRunner.withLock { futureTasks.toList() } /** * Schedules [task] for execution in [delayNanos]. A task may only have one future execution @@ -66,7 +66,7 @@ class TaskQueue internal constructor( task: Task, delayNanos: Long = 0L, ) { - taskRunner.lock.withLock { + taskRunner.withLock { if (shutdown) { if (task.cancelable) { taskRunner.logger.taskLog(task, this) { "schedule canceled (queue is shutdown)" } @@ -126,7 +126,7 @@ class TaskQueue internal constructor( /** Returns a latch that reaches 0 when the queue is next idle. */ fun idleLatch(): CountDownLatch { - taskRunner.lock.withLock { + taskRunner.withLock { // If the queue is already idle, that's easy. if (activeTask == null && futureTasks.isEmpty()) { return CountDownLatch(0) @@ -208,7 +208,7 @@ class TaskQueue internal constructor( fun cancelAll() { lock.assertNotHeld() - taskRunner.lock.withLock { + taskRunner.withLock { if (cancelAllAndDecide()) { taskRunner.kickCoordinator(this) } @@ -218,7 +218,7 @@ class TaskQueue internal constructor( fun shutdown() { lock.assertNotHeld() - taskRunner.lock.withLock { + taskRunner.withLock { shutdown = true if (cancelAllAndDecide()) { taskRunner.kickCoordinator(this) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt index 60143b3c40f8..0ae5ee90d404 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt @@ -23,10 +23,11 @@ import java.util.concurrent.TimeUnit import java.util.concurrent.locks.Condition import java.util.concurrent.locks.ReentrantLock import java.util.logging.Logger -import kotlin.concurrent.withLock import okhttp3.internal.addIfAbsent import okhttp3.internal.assertHeld import okhttp3.internal.concurrent.TaskRunner.Companion.INSTANCE +import okhttp3.internal.connection.Locks.newLockCondition +import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.okHttpName import okhttp3.internal.threadFactory @@ -45,8 +46,8 @@ class TaskRunner( val backend: Backend, internal val logger: Logger = TaskRunner.logger, ) { - val lock: ReentrantLock = ReentrantLock() - val condition: Condition = lock.newCondition() + internal val lock: ReentrantLock = ReentrantLock() + val condition: Condition = lock.newLockCondition() private var nextQueueName = 10000 private var coordinatorWaiting = false @@ -75,7 +76,7 @@ class TaskRunner( var incrementedRunCallCount = false while (true) { val task = - this@TaskRunner.lock.withLock { + this@TaskRunner.withLock { if (!incrementedRunCallCount) { incrementedRunCallCount = true runCallCount++ @@ -91,7 +92,7 @@ class TaskRunner( } finally { // If the task is crashing start another thread to service the queues. if (!completedNormally) { - lock.withLock { + this@TaskRunner.withLock { startAnotherThread() } } @@ -139,7 +140,7 @@ class TaskRunner( try { delayNanos = task.runOnce() } finally { - lock.withLock { + this.withLock { afterRun(task, delayNanos) } currentThread.name = oldName @@ -264,7 +265,7 @@ class TaskRunner( } fun newQueue(): TaskQueue { - val name = lock.withLock { nextQueueName++ } + val name = this.withLock { nextQueueName++ } return TaskQueue(this, "Q$name") } @@ -273,7 +274,7 @@ class TaskRunner( * necessarily track queues that have no tasks scheduled. */ fun activeQueues(): List { - lock.withLock { + this.withLock { return busyQueues + readyQueues } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt index 625791a5b835..90ecf50a8ab0 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt @@ -26,7 +26,6 @@ import java.security.cert.X509Certificate import java.util.concurrent.TimeUnit import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.SSLSocket -import kotlin.concurrent.withLock import okhttp3.CertificatePinner import okhttp3.ConnectionSpec import okhttp3.Handshake diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt index b09ce9a2d33a..0a765eb8a820 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt @@ -17,11 +17,15 @@ package okhttp3.internal.connection +import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.ReentrantLock import kotlin.concurrent.withLock import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract import okhttp3.Dispatcher +import okhttp3.internal.concurrent.TaskQueue +import okhttp3.internal.concurrent.TaskRunner import okhttp3.internal.http2.Http2Connection import okhttp3.internal.http2.Http2Stream import okhttp3.internal.http2.Http2Writer @@ -32,34 +36,62 @@ import okhttp3.internal.http2.Http2Writer internal object Locks { inline fun Dispatcher.withLock(action: () -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return lock.withLock(action) + return lock.runWithLock(action) } inline fun RealConnection.withLock(action: () -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return lock.withLock(action) + return lock.runWithLock(action) } inline fun RealCall.withLock(action: () -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return lock.withLock(action) + return lock.runWithLock(action) } inline fun Http2Connection.withLock(action: () -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return lock.withLock(action) + return lock.runWithLock(action) } inline fun Http2Stream.withLock(action: () -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return lock.withLock(action) + return lock.runWithLock(action) } - inline fun Http2Writer.withLock(action: () -> T): T { + inline fun TaskRunner.withLock(action: () -> T): T { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return lock.runWithLock(action) + } + + inline fun TaskQueue.withLock(action: () -> T): T { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return lock.runWithLock(action) + } + inline fun Http2Writer.withLock(action: () -> T): T { // TODO can we assert we don't have the connection lock? - return lock.withLock(action) + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return lock.runWithLock(action) + } + + /** + * A no cost (inlined) alias to [ReentrantLock#newCondition] for an OkHttp Lock. + * No function on its own but places a central place that all conditions go through to allow + * temporary debugging. + */ + internal fun ReentrantLock.newLockCondition(): Condition { + return this.newCondition() + } + + /** + * A no cost (inlined) alias to [ReentrantLock#withLock] for an OkHttp Lock. + * No function on its own but places a central place that all locks go through to allow + * temporary debugging. + */ + inline fun ReentrantLock.runWithLock(action: () -> T): T { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return withLock(action) } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt index 432dcc074e7e..89c0bb30bd26 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt @@ -26,7 +26,6 @@ import java.util.concurrent.TimeUnit.MILLISECONDS import java.util.concurrent.locks.ReentrantLock import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.SSLSocket -import kotlin.concurrent.withLock import okhttp3.Address import okhttp3.Connection import okhttp3.ConnectionListener @@ -335,7 +334,7 @@ class RealConnection( return http2Connection.isHealthy(nowNs) } - val idleDurationNs = lock.withLock { nowNs - idleAtNs } + val idleDurationNs = this.withLock { nowNs - idleAtNs } if (idleDurationNs >= IDLE_CONNECTION_HEALTHY_NS && doExtensiveChecks) { return socket.isHealthy(source) } @@ -354,7 +353,7 @@ class RealConnection( connection: Http2Connection, settings: Settings, ) { - lock.withLock { + this.withLock { val oldLimit = allocationLimit allocationLimit = settings.getMaxConcurrentStreams() @@ -398,7 +397,7 @@ class RealConnection( e: IOException?, ) { var noNewExchangesEvent = false - lock.withLock { + this.withLock { if (e is StreamResetException) { when { e.errorCode == ErrorCode.REFUSED_STREAM -> { diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt index 7339f4fcf8df..eac412033736 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt @@ -27,6 +27,7 @@ import okhttp3.internal.EMPTY_HEADERS import okhttp3.internal.assertThreadDoesntHoldLock import okhttp3.internal.closeQuietly import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.connection.Locks.newLockCondition import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.http2.ErrorCode.REFUSED_STREAM import okhttp3.internal.http2.Settings.Companion.DEFAULT_INITIAL_WINDOW_SIZE @@ -56,7 +57,7 @@ import okio.source @Suppress("NAME_SHADOWING") class Http2Connection internal constructor(builder: Builder) : Closeable { internal val lock: ReentrantLock = ReentrantLock() - internal val condition: Condition = lock.newCondition() + internal val condition: Condition = lock.newLockCondition() // Internal state of this connection is guarded by 'lock'. No blocking operations may be // performed while holding this lock! diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt index ea27c00ecf5e..fcabc4d2ca5c 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt @@ -25,6 +25,7 @@ import java.util.concurrent.locks.ReentrantLock import okhttp3.Headers import okhttp3.internal.EMPTY_HEADERS import okhttp3.internal.assertNotHeld +import okhttp3.internal.connection.Locks.newLockCondition import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.http2.flowcontrol.WindowCounter import okhttp3.internal.toHeaderList @@ -45,7 +46,7 @@ class Http2Stream internal constructor( headers: Headers?, ) { internal val lock: ReentrantLock = ReentrantLock() - val condition: Condition = lock.newCondition() + val condition: Condition = lock.newLockCondition() // Internal state is guarded by [lock]. No long-running or potentially blocking operations are // performed while the lock is held. From bafad870fa125e38923aa3f14cef61bdfb8dd586 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:32:12 +0000 Subject: [PATCH 088/134] Update junit5 monorepo (#8579) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c79b8d4cef5a..16c1ae6181ae 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ org-bouncycastle = "1.76" org-conscrypt = "2.5.2" org-jetbrains-coroutines = "1.8.1" org-jetbrains-kotlin = "1.9.25" -org-junit-jupiter = "5.11.0" +org-junit-jupiter = "5.11.3" retrofit = "2.11.0" testcontainers = "1.20.1" @@ -63,8 +63,8 @@ junit-ktx = "androidx.test.ext:junit-ktx:1.2.1" junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "org-junit-jupiter" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "org-junit-jupiter" } junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "org-junit-jupiter" } -junit-platform-console = "org.junit.platform:junit-platform-console:1.11.0" -junit-vintage-engine = "org.junit.vintage:junit-vintage-engine:5.11.0" +junit-platform-console = "org.junit.platform:junit-platform-console:1.11.3" +junit-vintage-engine = "org.junit.vintage:junit-vintage-engine:5.11.3" junit-pioneer = "org.junit-pioneer:junit-pioneer:1.9.1" junit5android-core = { module = "de.mannodermaus.junit5:android-test-core", version.ref = "de-mannodermaus-junit5" } junit5android-runner = { module = "de.mannodermaus.junit5:android-test-runner", version.ref = "de-mannodermaus-junit5" } From 61ab31ab1deb941d28f40892611474091fbd3634 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Tue, 19 Nov 2024 01:00:37 +0000 Subject: [PATCH 089/134] Simplify the DnsOverHttps logic (#8383) * Simplify the logic. Rely on OkHttpClient caching, instead of a cache only request. * Simplify the logic. Rely on OkHttpClient caching, instead of a cache only request. --- .../okhttp3/dnsoverhttps/DnsOverHttps.kt | 66 +++---------------- .../okhttp3/dnsoverhttps/DnsOverHttpsTest.kt | 26 ++++++++ 2 files changed, 35 insertions(+), 57 deletions(-) diff --git a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt index 2dc4741e901a..f164e23b863f 100644 --- a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt +++ b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/DnsOverHttps.kt @@ -16,11 +16,9 @@ package okhttp3.dnsoverhttps import java.io.IOException -import java.net.HttpURLConnection import java.net.InetAddress import java.net.UnknownHostException import java.util.concurrent.CountDownLatch -import okhttp3.CacheControl import okhttp3.Call import okhttp3.Callback import okhttp3.Dns @@ -72,16 +70,17 @@ class DnsOverHttps internal constructor( @Throws(UnknownHostException::class) private fun lookupHttps(hostname: String): List { - val networkRequests = ArrayList(2) - val failures = ArrayList(2) - val results = ArrayList(5) + val networkRequests = + buildList { + add(client.newCall(buildRequest(hostname, DnsRecordCodec.TYPE_A))) - buildRequest(hostname, networkRequests, results, failures, DnsRecordCodec.TYPE_A) - - if (includeIPv6) { - buildRequest(hostname, networkRequests, results, failures, DnsRecordCodec.TYPE_AAAA) - } + if (includeIPv6) { + add(client.newCall(buildRequest(hostname, DnsRecordCodec.TYPE_AAAA))) + } + } + val failures = ArrayList(2) + val results = ArrayList(5) executeRequests(hostname, networkRequests, results, failures) return results.ifEmpty { @@ -89,21 +88,6 @@ class DnsOverHttps internal constructor( } } - private fun buildRequest( - hostname: String, - networkRequests: MutableList, - results: MutableList, - failures: MutableList, - type: Int, - ) { - val request = buildRequest(hostname, type) - val response = getCacheOnlyResponse(request) - - response?.let { processResponse(it, hostname, results, failures) } ?: networkRequests.add( - client.newCall(request), - ) - } - private fun executeRequests( hostname: String, networkRequests: List, @@ -186,38 +170,6 @@ class DnsOverHttps internal constructor( throw unknownHostException } - private fun getCacheOnlyResponse(request: Request): Response? { - if (client.cache != null) { - try { - // Use the cache without hitting the network first - // 504 code indicates that the Cache is stale - val onlyIfCached = - CacheControl.Builder() - .onlyIfCached() - .build() - - var cacheUrl = request.url - - val cacheRequest = - request.newBuilder() - .cacheControl(onlyIfCached) - .cacheUrlOverride(cacheUrl) - .build() - - val cacheResponse = client.newCall(cacheRequest).execute() - - if (cacheResponse.code != HttpURLConnection.HTTP_GATEWAY_TIMEOUT) { - return cacheResponse - } - } catch (ioe: IOException) { - // Failures are ignored as we can fallback to the network - // and hopefully repopulate the cache. - } - } - - return null - } - @Throws(Exception::class) private fun readResponse( hostname: String, diff --git a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt index bfe84cb34800..34d602b36fe9 100644 --- a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt +++ b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt @@ -35,6 +35,7 @@ import okhttp3.Cache import okhttp3.Dns import okhttp3.OkHttpClient import okhttp3.Protocol +import okhttp3.RecordingEventListener import okhttp3.testing.PlatformRule import okio.Buffer import okio.ByteString.Companion.decodeHex @@ -53,9 +54,11 @@ class DnsOverHttpsTest { private lateinit var server: MockWebServer private lateinit var dns: Dns private val cacheFs = FakeFileSystem() + private val eventListener = RecordingEventListener() private val bootstrapClient = OkHttpClient.Builder() .protocols(listOf(Protocol.HTTP_2, Protocol.HTTP_1_1)) + .eventListener(eventListener) .build() @BeforeEach @@ -194,16 +197,22 @@ class DnsOverHttpsTest { assertThat(recordedRequest.path) .isEqualTo("/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ") + assertThat(cacheEvents()).containsExactly("CacheMiss") + result = cachedDns.lookup("google.com") assertThat(server.takeRequest(1, TimeUnit.MILLISECONDS)).isNull() assertThat(result).isEqualTo(listOf(address("157.240.1.18"))) + assertThat(cacheEvents()).containsExactly("CacheHit") + result = cachedDns.lookup("www.google.com") assertThat(result).containsExactly(address("157.240.1.18")) recordedRequest = server.takeRequest() assertThat(recordedRequest.method).isEqualTo("GET") assertThat(recordedRequest.path) .isEqualTo("/lookup?ct&dns=AAABAAABAAAAAAAAA3d3dwZnb29nbGUDY29tAAABAAE") + + assertThat(cacheEvents()).containsExactly("CacheMiss") } @Test @@ -231,16 +240,22 @@ class DnsOverHttpsTest { assertThat(recordedRequest.path) .isEqualTo("/lookup?ct") + assertThat(cacheEvents()).containsExactly("CacheMiss") + result = cachedDns.lookup("google.com") assertThat(server.takeRequest(0, TimeUnit.MILLISECONDS)).isNull() assertThat(result).isEqualTo(listOf(address("157.240.1.18"))) + assertThat(cacheEvents()).containsExactly("CacheHit") + result = cachedDns.lookup("www.google.com") assertThat(result).containsExactly(address("157.240.1.18")) recordedRequest = server.takeRequest(0, TimeUnit.MILLISECONDS)!! assertThat(recordedRequest.method).isEqualTo("POST") assertThat(recordedRequest.path) .isEqualTo("/lookup?ct") + + assertThat(cacheEvents()).containsExactly("CacheMiss") } @Test @@ -265,6 +280,9 @@ class DnsOverHttpsTest { assertThat(recordedRequest.path).isEqualTo( "/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ", ) + + assertThat(cacheEvents()).containsExactly("CacheMiss") + Thread.sleep(2000) server.enqueue( dnsResponse( @@ -282,6 +300,14 @@ class DnsOverHttpsTest { assertThat(recordedRequest!!.method).isEqualTo("GET") assertThat(recordedRequest.path) .isEqualTo("/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ") + + assertThat(cacheEvents()).containsExactly("CacheMiss") + } + + private fun cacheEvents(): List { + return eventListener.recordedEventTypes().filter { it.contains("Cache") }.also { + eventListener.clearAllEvents() + } } private fun dnsResponse(s: String): MockResponse { From 8da74400a4c7b41dc247b646d4a3f5ccf3480ea0 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 18 Nov 2024 20:02:00 -0500 Subject: [PATCH 090/134] Remove renumbering indirection in settings frames (#8385) This makes the code difficult to understand. Co-authored-by: Jesse Wilson Co-authored-by: Yuri Schimke --- .../src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt | 6 +++--- .../src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt | 8 +------- okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt | 8 ++++---- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt index 38e7c685ba0a..cc8a4cc11486 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt @@ -261,7 +261,7 @@ class Http2Reader( if (length % 6 != 0) throw IOException("TYPE_SETTINGS length % 6 != 0: $length") val settings = Settings() for (i in 0 until length step 6) { - var id = source.readShort() and 0xffff + val id = source.readShort() and 0xffff val value = source.readInt() when (id) { @@ -277,11 +277,11 @@ class Http2Reader( } // SETTINGS_MAX_CONCURRENT_STREAMS - 3 -> id = 4 // Renumbered in draft 10. + 3 -> { + } // SETTINGS_INITIAL_WINDOW_SIZE 4 -> { - id = 7 // Renumbered in draft 10. if (value < 0) { throw IOException("PROTOCOL_ERROR SETTINGS_INITIAL_WINDOW_SIZE > 2^31 - 1") } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt index 6c63ef263300..ca8de63c9598 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt @@ -209,13 +209,7 @@ class Http2Writer( ) for (i in 0 until Settings.COUNT) { if (!settings.isSet(i)) continue - val id = - when (i) { - 4 -> 3 // SETTINGS_MAX_CONCURRENT_STREAMS renumbered. - 7 -> 4 // SETTINGS_INITIAL_WINDOW_SIZE renumbered. - else -> i - } - sink.writeShort(id) + sink.writeShort(i) sink.writeInt(settings[i]) } sink.flush() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt b/okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt index ef704cdfde5d..a52bd3321037 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt @@ -116,7 +116,10 @@ class Settings { const val ENABLE_PUSH = 2 /** Sender's maximum number of concurrent streams. */ - const val MAX_CONCURRENT_STREAMS = 4 + const val MAX_CONCURRENT_STREAMS = 3 + + /** Window size in bytes. */ + const val INITIAL_WINDOW_SIZE = 4 /** HTTP/2: Size in bytes of the largest frame payload the sender will accept. */ const val MAX_FRAME_SIZE = 5 @@ -124,9 +127,6 @@ class Settings { /** HTTP/2: Advisory only. Size in bytes of the largest header list the sender will accept. */ const val MAX_HEADER_LIST_SIZE = 6 - /** Window size in bytes. */ - const val INITIAL_WINDOW_SIZE = 7 - /** Total number of settings. */ const val COUNT = 10 } From aac6c7055d710204cabd6e3ccec33b70447db648 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Tue, 19 Nov 2024 01:14:19 +0000 Subject: [PATCH 091/134] Avoid NPE in ConnectPlan (#8514) * Avoid NPE in ConnectPlan * Avoid NPE in ConnectPlan * Avoid NPE in ConnectPlan * cleanup --- .../internal/connection/ConnectPlan.kt | 16 ++-- .../internal/connection/RealConnection.kt | 75 ++++++++++++------- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt index 90ecf50a8ab0..b143092ccde0 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt @@ -93,8 +93,8 @@ class ConnectPlan( internal var socket: Socket? = null private var handshake: Handshake? = null private var protocol: Protocol? = null - private var source: BufferedSource? = null - private var sink: BufferedSink? = null + private lateinit var source: BufferedSource + private lateinit var sink: BufferedSink private var connection: RealConnection? = null /** True if this connection is ready for use, including TCP, tunnels, and TLS. */ @@ -152,7 +152,7 @@ class ConnectPlan( } override fun connectTlsEtc(): ConnectResult { - check(rawSocket != null) { "TCP not connected" } + val rawSocket = requireNotNull(rawSocket) { "TCP not connected" } check(!isReady) { "already connected" } val connectionSpecs = route.address.connectionSpecs @@ -176,7 +176,7 @@ class ConnectPlan( // that happens, then we will have buffered bytes that are needed by the SSLSocket! // This check is imperfect: it doesn't tell us whether a handshake will succeed, just // that it will almost certainly fail because the proxy has sent unexpected data. - if (source?.buffer?.exhausted() == false || sink?.buffer?.exhausted() == false) { + if (!source.buffer.exhausted() || !sink.buffer.exhausted()) { throw IOException("TLS tunnel buffered too many bytes!") } @@ -216,9 +216,9 @@ class ConnectPlan( connectionPool = connectionPool, route = route, rawSocket = rawSocket, - socket = socket, + socket = socket!!, handshake = handshake, - protocol = protocol, + protocol = protocol!!, source = source, sink = sink, pingIntervalMillis = pingIntervalMillis, @@ -247,7 +247,7 @@ class ConnectPlan( user.removePlanToCancel(this) if (!success) { socket?.closeQuietly() - rawSocket?.closeQuietly() + rawSocket.closeQuietly() } } } @@ -420,8 +420,6 @@ class ConnectPlan( val url = route.address.url val requestLine = "CONNECT ${url.toHostHeader(includeDefaultPort = true)} HTTP/1.1" while (true) { - val source = this.source!! - val sink = this.sink!! val tunnelCodec = Http1ExchangeCodec( // No client for CONNECT tunnels: diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt index 89c0bb30bd26..b2048715f906 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt @@ -53,8 +53,13 @@ import okhttp3.internal.http2.StreamResetException import okhttp3.internal.isHealthy import okhttp3.internal.tls.OkHostnameVerifier import okhttp3.internal.ws.RealWebSocket +import okio.Buffer import okio.BufferedSink import okio.BufferedSource +import okio.Sink +import okio.Source +import okio.Timeout +import okio.buffer /** * A connection to a remote web server capable of carrying 1 or more concurrent streams. @@ -67,16 +72,16 @@ class RealConnection( val connectionPool: RealConnectionPool, override val route: Route, /** The low-level TCP socket. */ - private var rawSocket: Socket?, + private val rawSocket: Socket, /** * The application layer socket. Either an [SSLSocket] layered over [rawSocket], or [rawSocket] * itself if this connection does not use SSL. */ - private var socket: Socket?, - private var handshake: Handshake?, - private var protocol: Protocol?, - private var source: BufferedSource?, - private var sink: BufferedSink?, + private val socket: Socket, + private val handshake: Handshake?, + private val protocol: Protocol, + private val source: BufferedSource, + private val sink: BufferedSink, private val pingIntervalMillis: Int, internal val connectionListener: ConnectionListener, ) : Http2Connection.Listener(), Connection, ExchangeCodec.Carrier { @@ -162,9 +167,6 @@ class RealConnection( @Throws(IOException::class) private fun startHttp2() { - val socket = this.socket!! - val source = this.source!! - val sink = this.sink!! socket.soTimeout = 0 // HTTP/2 connection timeouts are set per-stream. val flowControlListener = connectionListener as? FlowControlListener ?: FlowControlListener.None val http2Connection = @@ -253,7 +255,7 @@ class RealConnection( } // We have a host mismatch. But if the certificate matches, we're still good. - return !noCoalescedConnections && handshake != null && certificateSupportHost(url, handshake!!) + return !noCoalescedConnections && handshake != null && certificateSupportHost(url, handshake) } private fun certificateSupportHost( @@ -271,9 +273,9 @@ class RealConnection( client: OkHttpClient, chain: RealInterceptorChain, ): ExchangeCodec { - val socket = this.socket!! - val source = this.source!! - val sink = this.sink!! + val socket = this.socket + val source = this.source + val sink = this.sink val http2Connection = this.http2Connection return if (http2Connection != null) { @@ -288,10 +290,6 @@ class RealConnection( @Throws(SocketException::class) internal fun newWebSocketStreams(exchange: Exchange): RealWebSocket.Streams { - val socket = this.socket!! - val source = this.source!! - val sink = this.sink!! - socket.soTimeout = 0 noNewExchanges() return object : RealWebSocket.Streams(true, source, sink) { @@ -309,10 +307,10 @@ class RealConnection( override fun cancel() { // Close the raw socket so we don't end up doing synchronous I/O. - rawSocket?.closeQuietly() + rawSocket.closeQuietly() } - override fun socket(): Socket = socket!! + override fun socket(): Socket = socket /** Returns true if this connection is ready to host new streams. */ fun isHealthy(doExtensiveChecks: Boolean): Boolean { @@ -320,9 +318,6 @@ class RealConnection( val nowNs = System.nanoTime() - val rawSocket = this.rawSocket!! - val socket = this.socket!! - val source = this.source!! if (rawSocket.isClosed || socket.isClosed || socket.isInputShutdown || socket.isOutputShutdown ) { @@ -442,7 +437,7 @@ class RealConnection( } } - override fun protocol(): Protocol = protocol!! + override fun protocol(): Protocol = protocol override fun toString(): String { return "Connection{${route.address.url.host}:${route.address.url.port}," + @@ -467,12 +462,38 @@ class RealConnection( taskRunner = taskRunner, connectionPool = connectionPool, route = route, - rawSocket = null, + rawSocket = Socket(), socket = socket, handshake = null, - protocol = null, - source = null, - sink = null, + protocol = Protocol.HTTP_2, + source = + object : Source { + override fun close() = Unit + + override fun read( + sink: Buffer, + byteCount: Long, + ): Long { + throw UnsupportedOperationException() + } + + override fun timeout(): Timeout = Timeout.NONE + }.buffer(), + sink = + object : Sink { + override fun close() = Unit + + override fun flush() = Unit + + override fun timeout(): Timeout = Timeout.NONE + + override fun write( + source: Buffer, + byteCount: Long, + ) { + throw UnsupportedOperationException() + } + }.buffer(), pingIntervalMillis = 0, ConnectionListener.NONE, ) From 27521ef9cb24909c96d53bd7761de9fd21ae3b4b Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Wed, 20 Nov 2024 08:59:58 +0000 Subject: [PATCH 092/134] Centralise thread name logic (#8513) --- .../okhttp3/internal/concurrent/TaskRunner.kt | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt index 0ae5ee90d404..dc62f8c1a528 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt @@ -30,6 +30,7 @@ import okhttp3.internal.connection.Locks.newLockCondition import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.okHttpName import okhttp3.internal.threadFactory +import okhttp3.internal.threadName /** * A set of worker threads that are shared among a set of task queues. @@ -132,18 +133,15 @@ class TaskRunner( } private fun runTask(task: Task) { - val currentThread = Thread.currentThread() - val oldName = currentThread.name - currentThread.name = task.name - - var delayNanos = -1L - try { - delayNanos = task.runOnce() - } finally { - this.withLock { - afterRun(task, delayNanos) + threadName(task.name) { + var delayNanos = -1L + try { + delayNanos = task.runOnce() + } finally { + this.withLock { + afterRun(task, delayNanos) + } } - currentThread.name = oldName } } From 7ef4fb4bfdcd6b2567cc7aff5ec3e7b45a7d13af Mon Sep 17 00:00:00 2001 From: Jesse Wilson at Work Date: Wed, 20 Nov 2024 15:18:17 -0500 Subject: [PATCH 093/134] Add another test for headers' size limit (#8584) --- okhttp/src/test/java/okhttp3/CallTest.kt | 25 ++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/okhttp/src/test/java/okhttp3/CallTest.kt b/okhttp/src/test/java/okhttp3/CallTest.kt index a43d76d7dae9..47d1dc91d4d3 100644 --- a/okhttp/src/test/java/okhttp3/CallTest.kt +++ b/okhttp/src/test/java/okhttp3/CallTest.kt @@ -2619,8 +2619,8 @@ open class CallTest { } @Test - fun httpWithExcessiveHeaders() { - val longLine = "HTTP/1.1 200 " + stringFill('O', 256 * 1024) + "K" + fun httpWithExcessiveStatusLine() { + val longLine = "HTTP/1.1 200 " + "O".repeat(256 * 1024) + "K" server.protocols = listOf(Protocol.HTTP_1_1) server.enqueue( MockResponse.Builder() @@ -2629,16 +2629,21 @@ open class CallTest { .build(), ) executeSynchronously("/") - .assertFailureMatches(".*unexpected end of stream on " + server.url("/").redact()) + .assertFailureMatches(".*unexpected end of stream on ${server.url("/").redact()}") } - private fun stringFill( - fillChar: Char, - length: Int, - ): String { - val value = CharArray(length) - Arrays.fill(value, fillChar) - return String(value) + @Test + fun httpWithExcessiveHeaders() { + server.protocols = listOf(Protocol.HTTP_1_1) + server.enqueue( + MockResponse.Builder() + .addHeader("Set-Cookie", "a=${"A".repeat(255 * 1024)}") + .addHeader("Set-Cookie", "b=${"B".repeat(1 * 1024)}") + .body("I'm not even supposed to be here today.") + .build(), + ) + executeSynchronously("/") + .assertFailureMatches(".*unexpected end of stream on ${server.url("/").redact()}") } @Test From 4ba74c7f9cd0d939fc1194323a534cb253829f95 Mon Sep 17 00:00:00 2001 From: Jared Burrows Date: Thu, 21 Nov 2024 02:19:31 -0500 Subject: [PATCH 094/134] Fix pymdownx.emoji extension warning (#8559) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description - Fix pymdownx.emoji extension warning ## Repro - `mkdocs build` ## Warning ``` ❯ mkdocs build INFO - DeprecationWarning: 'materialx.emoji.twemoji' is deprecated. Material emoji logic has been officially moved into mkdocs-material version 9.4. Please use Material's 'material.extensions.emoji.twemoji' instead of 'materialx.emoji.twemoji' in your 'mkdocs.yml' file. ``` markdown_extensions: - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg ``` 'mkdocs_material_extensions' is deprecated and will no longer be supported moving forward. This is the last release. File "/opt/homebrew/lib/python3.12/site-packages/materialx/emoji.py", line 118, in twemoji return _patch_index(options) File "/opt/homebrew/lib/python3.12/site-packages/materialx/emoji.py", line 68, in _deprecated_func warnings.warn( WARNING - Material emoji logic has been officially moved into mkdocs-material version 9.4. Please use Material's 'material.extensions.emoji.twemoji' instead of 'materialx.emoji.twemoji' in your 'mkdocs.yml' file. ``` markdown_extensions: - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg ``` 'mkdocs_material_extensions' is deprecated and will no longer be supported moving forward. This is the last release. INFO - Cleaning site directory INFO - Building documentation to directory: /Users/<>/Downloads/site INFO - Documentation built in 0.13 seconds ``` Co-authored-by: Jesse Wilson --- mkdocs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 00b136820e2f..2490b3e5dd3b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,8 +45,8 @@ markdown_extensions: smart_enable: all - pymdownx.caret - pymdownx.emoji: - emoji_index: !!python/name:materialx.emoji.twemoji - emoji_generator: !!python/name:materialx.emoji.to_svg + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg - pymdownx.inlinehilite - pymdownx.magiclink - pymdownx.smartsymbols From f07f4ccbd4be1f94d3b17b0fffb77f558ef56f4b Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 23 Nov 2024 19:12:40 +0000 Subject: [PATCH 095/134] Call proxy selector on failure (#8415) * Call proxy selector on failure --------- Co-authored-by: Jesse Wilson --- .../okhttp3/internal/http/RecordingProxySelector.kt | 4 ++-- .../kotlin/okhttp3/internal/connection/ConnectPlan.kt | 8 ++++++++ okhttp/src/test/java/okhttp3/CallTest.kt | 10 ++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http/RecordingProxySelector.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http/RecordingProxySelector.kt index b81d99857a18..a51e8afb74de 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http/RecordingProxySelector.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/http/RecordingProxySelector.kt @@ -30,8 +30,8 @@ import okhttp3.internal.format class RecordingProxySelector : ProxySelector() { @JvmField val proxies = mutableListOf() - private val requestedUris = mutableListOf() - private val failures = mutableListOf() + val requestedUris = mutableListOf() + val failures = mutableListOf() override fun select(uri: URI): List { requestedUris.add(uri) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt index b143092ccde0..a2815f5c1de3 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt @@ -141,6 +141,14 @@ class ConnectPlan( success = true return ConnectResult(plan = this) } catch (e: IOException) { + // If we used the ProxySelector, and got a IOException during connect, report the failure. + if (route.address.proxy == null && route.proxy.type() != Proxy.Type.DIRECT) { + route.address.proxySelector.connectFailed( + route.address.url.toUri(), + route.proxy.address(), + e, + ) + } user.connectFailed(route, null, e) return ConnectResult(plan = this, throwable = e) } finally { diff --git a/okhttp/src/test/java/okhttp3/CallTest.kt b/okhttp/src/test/java/okhttp3/CallTest.kt index 47d1dc91d4d3..c483e5843194 100644 --- a/okhttp/src/test/java/okhttp3/CallTest.kt +++ b/okhttp/src/test/java/okhttp3/CallTest.kt @@ -15,11 +15,14 @@ */ package okhttp3 +import assertk.all import assertk.assertThat import assertk.assertions.contains import assertk.assertions.containsExactly import assertk.assertions.doesNotContain import assertk.assertions.hasMessage +import assertk.assertions.hasSize +import assertk.assertions.index import assertk.assertions.isCloseTo import assertk.assertions.isEmpty import assertk.assertions.isEqualTo @@ -30,6 +33,7 @@ import assertk.assertions.isNotNull import assertk.assertions.isNotSameAs import assertk.assertions.isNull import assertk.assertions.isTrue +import assertk.assertions.matches import assertk.assertions.startsWith import assertk.fail import java.io.FileNotFoundException @@ -1017,6 +1021,12 @@ open class CallTest { executeSynchronously(request) .assertCode(200) .assertBody("success!") + + assertThat(proxySelector.failures) + .all { + hasSize(1) + index(0).matches(".* Connect timed out".toRegex(RegexOption.IGNORE_CASE)) + } } /** https://github.com/square/okhttp/issues/4875 */ From 2832a9e532ecbc6f1f84b3a07e8e64b75372789c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 16:33:21 +0000 Subject: [PATCH 096/134] Update dependency com.google.guava:guava to v33.3.1-jre (#8546) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 16c1ae6181ae..f5f70c72bc09 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -52,7 +52,7 @@ gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.29.0" gradlePlugin-mavenSympathy = "io.github.usefulness.maven-sympathy:io.github.usefulness.maven-sympathy.gradle.plugin:0.3.0" gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" -guava-jre = "com.google.guava:guava:33.3.0-jre" +guava-jre = "com.google.guava:guava:33.3.1-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:3.0" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" jettyClient = "org.eclipse.jetty:jetty-client:9.4.56.v20240826" From 7c942799982e97cfcce04d87019412344187dfe6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 22:01:40 -0500 Subject: [PATCH 097/134] Update testcontainers-java monorepo to v1.20.4 (#8591) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f5f70c72bc09..254e87522346 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ org-jetbrains-coroutines = "1.8.1" org-jetbrains-kotlin = "1.9.25" org-junit-jupiter = "5.11.3" retrofit = "2.11.0" -testcontainers = "1.20.1" +testcontainers = "1.20.4" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.4.1" From d3123b371538aa3290fd324d9348917207ab4410 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 22:53:32 -0500 Subject: [PATCH 098/134] Update dependency ru.vyarus:gradle-animalsniffer-plugin to v1.7.2 (#8590) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 254e87522346..7bd6949c5bb3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,7 +40,7 @@ eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.21.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" gradlePlugin-android = "com.android.tools.build:gradle:8.2.0" gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.2.0" -gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.1" +gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.2" gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.16.3" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } gradlePlugin-dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.20" From 6459eddf2a3299300ad426391ccf4d91cfc765df Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 23:03:59 -0500 Subject: [PATCH 099/134] Update dependency androidx.annotation:annotation to v1.9.1 (#8593) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7bd6949c5bb3..86280bbabc39 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ testcontainers = "1.20.4" [libraries] amazonCorretto = "software.amazon.cryptools:AmazonCorrettoCryptoProvider:2.4.1" androidx-activity = "androidx.activity:activity-ktx:1.9.3" -androidx-annotation = "androidx.annotation:annotation:1.8.2" +androidx-annotation = "androidx.annotation:annotation:1.9.1" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" androidx-test-runner = "androidx.test:runner:1.6.2" From 290a19b5dcfbef46afcd7a71e43dc6efb29187d9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 08:16:12 +0000 Subject: [PATCH 100/134] Update de.mannodermaus.junit5 to v1.6.0 (#8592) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 86280bbabc39..33f1eadb6a96 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ biz-aQute-bnd = "6.4.0" checkStyle = "10.19.0" com-squareup-moshi = "1.15.1" com-squareup-okio = "3.9.1" -de-mannodermaus-junit5 = "1.5.0" +de-mannodermaus-junit5 = "1.6.0" graalvm = "22.3.2" kotlinx-serialization = "1.6.3" ksp = "1.9.24-1.0.20" From 54b64fe5d1c11daa95f317e03f7eddd58d6013e5 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Wed, 27 Nov 2024 08:50:25 +0000 Subject: [PATCH 101/134] Embed the public suffix database list directly inside a class (#8589) During build time embed the database as a base64 encoded string, parsed the first time a cookie is used, using the class init as the mutex. --- build.gradle.kts | 1 + .../okhttp3/PublicSuffixDatabaseTest.kt | 11 -- okhttp/build.gradle.kts | 23 +++- .../publicsuffix/PublicSuffixDatabase.kt | 125 ++---------------- .../internal/publicsuffix/PublicSuffixList.kt | 28 ++++ .../publicsuffix/EmbeddedPublicSuffixList.kt | 54 ++++++++ .../resources/META-INF/proguard/okhttp3.pro | 4 - .../publicsuffix/PublicSuffixDatabaseTest.kt | 29 ++-- .../publicsuffix/PublicSuffixListGenerator.kt | 24 +++- .../publicsuffix/ResourcePublicSuffixList.kt | 115 ++++++++++++++++ .../okhttp3/internal/publicsuffix/NOTICE | 0 .../publicsuffix/PublicSuffixDatabase.gz | Bin 12 files changed, 269 insertions(+), 145 deletions(-) create mode 100644 okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.kt create mode 100644 okhttp/src/main/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt create mode 100644 okhttp/src/test/java/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt rename okhttp/src/{main => test}/resources/okhttp3/internal/publicsuffix/NOTICE (100%) rename okhttp/src/{main => test}/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz (100%) diff --git a/build.gradle.kts b/build.gradle.kts index befab1665954..42c6bdee9feb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -42,6 +42,7 @@ apply(plugin = "com.diffplug.spotless") configure { kotlin { target("**/*.kt") + targetExclude("**/kotlinTemplates/**/*.kt") ktlint() } } diff --git a/native-image-tests/src/main/kotlin/okhttp3/PublicSuffixDatabaseTest.kt b/native-image-tests/src/main/kotlin/okhttp3/PublicSuffixDatabaseTest.kt index 98a452cd40dc..175de8da30fc 100644 --- a/native-image-tests/src/main/kotlin/okhttp3/PublicSuffixDatabaseTest.kt +++ b/native-image-tests/src/main/kotlin/okhttp3/PublicSuffixDatabaseTest.kt @@ -17,11 +17,8 @@ package okhttp3 import assertk.assertThat import assertk.assertions.isEqualTo -import assertk.assertions.isGreaterThan import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.internal.publicsuffix.PublicSuffixDatabase import okhttp3.testing.PlatformRule -import okio.FileSystem import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @@ -36,12 +33,4 @@ class PublicSuffixDatabaseTest { assertThat(url.topPrivateDomain()).isEqualTo("twitter.com") } - - @Test - fun testPublicSuffixes() { - platform.assumeNotGraalVMImage() - - val metadata = FileSystem.RESOURCES.metadata(PublicSuffixDatabase.PUBLIC_SUFFIX_RESOURCE) - assertThat(metadata.size!!).isGreaterThan(30000) - } } diff --git a/okhttp/build.gradle.kts b/okhttp/build.gradle.kts index 5c3f2fb4e8df..9c9ea07c776f 100644 --- a/okhttp/build.gradle.kts +++ b/okhttp/build.gradle.kts @@ -1,5 +1,9 @@ import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.KotlinJvm +import java.io.DataInputStream +import java.io.FileInputStream +import java.util.Base64 +import java.util.zip.GZIPInputStream plugins { kotlin("jvm") @@ -9,12 +13,27 @@ plugins { id("binary-compatibility-validator") } -// Build & use okhttp3/internal/-InternalVersion.kt +fun ByteArray.toByteStringExpression(): String { + return "\"${Base64.getEncoder().encodeToString(this@toByteStringExpression)}\".decodeBase64()!!" +} + val copyKotlinTemplates = tasks.register("copyKotlinTemplates") { from("src/main/kotlinTemplates") into("$buildDir/generated/sources/kotlinTemplates") - expand("projectVersion" to project.version) + filteringCharset = Charsets.UTF_8.toString() + + // TODO replace with KotlinPoet? + val databaseGz = project.file("src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") + val listBytes = databaseGz.readBytes().toByteStringExpression() + + expand( + // Build & use okhttp3/internal/-InternalVersion.kt + "projectVersion" to project.version, + + // Build okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt + "publicSuffixListBytes" to listBytes + ) } // Build & use okhttp3/internal/idn/IdnaMappingTableInstance.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt b/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt index fef4fd01df79..88094ad1c600 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt @@ -15,18 +15,10 @@ */ package okhttp3.internal.publicsuffix -import java.io.IOException -import java.io.InterruptedIOException import java.net.IDN -import java.util.concurrent.CountDownLatch -import java.util.concurrent.atomic.AtomicBoolean import okhttp3.internal.and -import okhttp3.internal.platform.Platform -import okio.FileSystem -import okio.GzipSource -import okio.Path -import okio.Path.Companion.toPath -import okio.buffer +import okio.ByteString +import okio.ByteString.Companion.encodeUtf8 /** * A database of public suffixes provided by [publicsuffix.org][publicsuffix_org]. @@ -34,22 +26,8 @@ import okio.buffer * [publicsuffix_org]: https://publicsuffix.org/ */ class PublicSuffixDatabase internal constructor( - val path: Path = PUBLIC_SUFFIX_RESOURCE, - val fileSystem: FileSystem = FileSystem.RESOURCES, + private val publicSuffixList: PublicSuffixList, ) { - /** True after we've attempted to read the list for the first time. */ - private val listRead = AtomicBoolean(false) - - /** Used for concurrent threads reading the list for the first time. */ - private val readCompleteLatch = CountDownLatch(1) - - // The lists are held as a large array of UTF-8 bytes. This is to avoid allocating lots of strings - // that will likely never be used. Each rule is separated by '\n'. Please see the - // PublicSuffixListGenerator class for how these lists are generated. - // Guarded by this. - private lateinit var publicSuffixListBytes: ByteArray - private lateinit var publicSuffixExceptionListBytes: ByteArray - /** * Returns the effective top-level domain plus one (eTLD+1) by referencing the public suffix list. * Returns null if the domain is a public suffix or a private address. @@ -101,29 +79,16 @@ class PublicSuffixDatabase internal constructor( } private fun findMatchingRule(domainLabels: List): List { - if (!listRead.get() && listRead.compareAndSet(false, true)) { - readTheListUninterruptibly() - } else { - try { - readCompleteLatch.await() - } catch (_: InterruptedException) { - Thread.currentThread().interrupt() // Retain interrupted status. - } - } - - check(::publicSuffixListBytes.isInitialized) { - // May have failed with an IOException - "Unable to load $PUBLIC_SUFFIX_RESOURCE resource from the classpath." - } + publicSuffixList.ensureLoaded() // Break apart the domain into UTF-8 labels, i.e. foo.bar.com turns into [foo, bar, com]. - val domainLabelsUtf8Bytes = Array(domainLabels.size) { i -> domainLabels[i].toByteArray() } + val domainLabelsUtf8Bytes = Array(domainLabels.size) { i -> domainLabels[i].encodeUtf8() } // Start by looking for exact matches. We start at the leftmost label. For example, foo.bar.com // will look like: [foo, bar, com], [bar, com], [com]. The longest matching rule wins. var exactMatch: String? = null for (i in domainLabelsUtf8Bytes.indices) { - val rule = publicSuffixListBytes.binarySearch(domainLabelsUtf8Bytes, i) + val rule = publicSuffixList.bytes.binarySearch(domainLabelsUtf8Bytes, i) if (rule != null) { exactMatch = rule break @@ -140,7 +105,7 @@ class PublicSuffixDatabase internal constructor( val labelsWithWildcard = domainLabelsUtf8Bytes.clone() for (labelIndex in 0 until labelsWithWildcard.size - 1) { labelsWithWildcard[labelIndex] = WILDCARD_LABEL - val rule = publicSuffixListBytes.binarySearch(labelsWithWildcard, labelIndex) + val rule = publicSuffixList.bytes.binarySearch(labelsWithWildcard, labelIndex) if (rule != null) { wildcardMatch = rule break @@ -153,7 +118,7 @@ class PublicSuffixDatabase internal constructor( if (wildcardMatch != null) { for (labelIndex in 0 until domainLabelsUtf8Bytes.size - 1) { val rule = - publicSuffixExceptionListBytes.binarySearch( + publicSuffixList.exceptionBytes.binarySearch( domainLabelsUtf8Bytes, labelIndex, ) @@ -182,84 +147,20 @@ class PublicSuffixDatabase internal constructor( } } - /** - * Reads the public suffix list treating the operation as uninterruptible. We always want to read - * the list otherwise we'll be left in a bad state. If the thread was interrupted prior to this - * operation, it will be re-interrupted after the list is read. - */ - private fun readTheListUninterruptibly() { - var interrupted = false - try { - while (true) { - try { - readTheList() - return - } catch (_: InterruptedIOException) { - Thread.interrupted() // Temporarily clear the interrupted state. - interrupted = true - } catch (e: IOException) { - Platform.get().log("Failed to read public suffix list", Platform.WARN, e) - return - } - } - } finally { - if (interrupted) { - Thread.currentThread().interrupt() // Retain interrupted status. - } - } - } - - @Throws(IOException::class) - private fun readTheList() { - var publicSuffixListBytes: ByteArray? - var publicSuffixExceptionListBytes: ByteArray? - - try { - GzipSource(fileSystem.source(path)).buffer().use { bufferedSource -> - val totalBytes = bufferedSource.readInt() - publicSuffixListBytes = bufferedSource.readByteArray(totalBytes.toLong()) - - val totalExceptionBytes = bufferedSource.readInt() - publicSuffixExceptionListBytes = bufferedSource.readByteArray(totalExceptionBytes.toLong()) - } - - synchronized(this) { - this.publicSuffixListBytes = publicSuffixListBytes!! - this.publicSuffixExceptionListBytes = publicSuffixExceptionListBytes!! - } - } finally { - readCompleteLatch.countDown() - } - } - - /** Visible for testing. */ - fun setListBytes( - publicSuffixListBytes: ByteArray, - publicSuffixExceptionListBytes: ByteArray, - ) { - this.publicSuffixListBytes = publicSuffixListBytes - this.publicSuffixExceptionListBytes = publicSuffixExceptionListBytes - listRead.set(true) - readCompleteLatch.countDown() - } - companion object { - @JvmField - val PUBLIC_SUFFIX_RESOURCE = "/okhttp3/internal/publicsuffix/${PublicSuffixDatabase::class.java.simpleName}.gz".toPath() - - private val WILDCARD_LABEL = byteArrayOf('*'.code.toByte()) + private val WILDCARD_LABEL = ByteString.of('*'.code.toByte()) private val PREVAILING_RULE = listOf("*") private const val EXCEPTION_MARKER = '!' - private val instance = PublicSuffixDatabase() + private val instance = PublicSuffixDatabase(EmbeddedPublicSuffixList) fun get(): PublicSuffixDatabase { return instance } - private fun ByteArray.binarySearch( - labels: Array, + private fun ByteString.binarySearch( + labels: Array, labelIndex: Int, ): String? { var low = 0 @@ -338,7 +239,7 @@ class PublicSuffixDatabase internal constructor( low = mid + end + 1 } else { // Found a match. - match = String(this, mid, publicSuffixLength) + match = this.substring(mid, mid + publicSuffixLength).string(Charsets.UTF_8) break } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.kt b/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.kt new file mode 100644 index 000000000000..3fdfaa659edc --- /dev/null +++ b/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 Block, 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.internal.publicsuffix + +import okio.ByteString + +/** + * Basic I/O for the PublicSuffixDatabase.gz. + */ +internal interface PublicSuffixList { + fun ensureLoaded() + + val bytes: ByteString + val exceptionBytes: ByteString +} diff --git a/okhttp/src/main/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt b/okhttp/src/main/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt new file mode 100644 index 000000000000..93f14cff3d26 --- /dev/null +++ b/okhttp/src/main/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 Block, 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.internal.publicsuffix + +//Note that PublicSuffixDatabase.gz is compiled from The Public Suffix List: +//https://publicsuffix.org/list/public_suffix_list.dat +// +//It is subject to the terms of the Mozilla Public License, v. 2.0: +//https://mozilla.org/MPL/2.0/ + +import okio.Buffer +import okio.ByteString +import okio.ByteString.Companion.decodeBase64 +import okio.GzipSource +import okio.buffer + +/** + * A implementation of I/O for PublicSuffixDatabase.gz by directly encoding + * the relevant byte arrays in a class file. + */ +internal object EmbeddedPublicSuffixList: PublicSuffixList { + override fun ensureLoaded() { + } + + override val bytes: ByteString + + override val exceptionBytes: ByteString + + init { + Buffer().use { buffer -> + buffer.write($publicSuffixListBytes) + GzipSource(buffer).buffer().use { source -> + val totalBytes = source.readInt() + bytes = source.readByteString(totalBytes.toLong()) + + val totalExceptionBytes = source.readInt() + exceptionBytes = source.readByteString(totalExceptionBytes.toLong()) + } + } + } +} diff --git a/okhttp/src/main/resources/META-INF/proguard/okhttp3.pro b/okhttp/src/main/resources/META-INF/proguard/okhttp3.pro index 74fc3168014a..280a52749be2 100644 --- a/okhttp/src/main/resources/META-INF/proguard/okhttp3.pro +++ b/okhttp/src/main/resources/META-INF/proguard/okhttp3.pro @@ -1,10 +1,6 @@ # JSR 305 annotations are for embedding nullability information. -dontwarn javax.annotation.** -# A resource is loaded with a relative path so the package of this class must be preserved. --keeppackagenames okhttp3.internal.publicsuffix.* --adaptresourcefilenames okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz - # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. -dontwarn org.codehaus.mojo.animal_sniffer.* diff --git a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt index e264cb34e36c..02ef95e947a3 100644 --- a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt @@ -23,6 +23,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith import okhttp3.internal.toCanonicalHost import okio.Buffer +import okio.ByteString import okio.FileSystem import okio.GzipSource import okio.Path.Companion.toPath @@ -31,7 +32,8 @@ import okio.use import org.junit.jupiter.api.Test class PublicSuffixDatabaseTest { - private val publicSuffixDatabase = PublicSuffixDatabase() + private val list = ResourcePublicSuffixList() + private val publicSuffixDatabase = PublicSuffixDatabase(list) @Test fun longestMatchWins() { val buffer = @@ -39,7 +41,7 @@ class PublicSuffixDatabaseTest { .writeUtf8("com\n") .writeUtf8("my.square.com\n") .writeUtf8("square.com\n") - publicSuffixDatabase.setListBytes(buffer.readByteArray(), byteArrayOf()) + list.setListBytes(buffer.readByteString(), ByteString.of()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("example.com")) .isEqualTo("example.com") assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("foo.example.com")) @@ -56,7 +58,7 @@ class PublicSuffixDatabaseTest { .writeUtf8("*.square.com\n") .writeUtf8("com\n") .writeUtf8("example.com\n") - publicSuffixDatabase.setListBytes(buffer.readByteArray(), byteArrayOf()) + list.setListBytes(buffer.readByteString(), ByteString.of()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("my.square.com")).isNull() assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("foo.my.square.com")) .isEqualTo("foo.my.square.com") @@ -70,7 +72,7 @@ class PublicSuffixDatabaseTest { .writeUtf8("bbb\n") .writeUtf8("ddd\n") .writeUtf8("fff\n") - publicSuffixDatabase.setListBytes(buffer.readByteArray(), byteArrayOf()) + list.setListBytes(buffer.readByteString(), ByteString.of()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("aaa")).isNull() assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("ggg")).isNull() assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("ccc")).isNull() @@ -87,7 +89,7 @@ class PublicSuffixDatabaseTest { .writeUtf8("*.square.jp\n") .writeUtf8("example.com\n") .writeUtf8("square.com\n") - publicSuffixDatabase.setListBytes(buffer.readByteArray(), exception.readByteArray()) + list.setListBytes(buffer.readByteString(), exception.readByteString()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("my.square.jp")) .isEqualTo("my.square.jp") assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("foo.my.square.jp")) @@ -105,14 +107,14 @@ class PublicSuffixDatabaseTest { .writeUtf8("*.square.jp\n") .writeUtf8("example.com\n") .writeUtf8("square.com\n") - publicSuffixDatabase.setListBytes(buffer.readByteArray(), exception.readByteArray()) + list.setListBytes(buffer.readByteString(), exception.readByteString()) assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("example.com")).isNull() assertThat(publicSuffixDatabase.getEffectiveTldPlusOne("foo.square.jp")).isNull() } @Test fun allPublicSuffixes() { val buffer = Buffer() - FileSystem.RESOURCES.source(PublicSuffixDatabase.PUBLIC_SUFFIX_RESOURCE).use { resource -> + FileSystem.RESOURCES.source(ResourcePublicSuffixList.PUBLIC_SUFFIX_RESOURCE).use { resource -> GzipSource(resource).buffer().use { source -> val length = source.readInt() buffer.write(source, length.toLong()) @@ -132,7 +134,7 @@ class PublicSuffixDatabaseTest { @Test fun publicSuffixExceptions() { val buffer = Buffer() - FileSystem.RESOURCES.source(PublicSuffixDatabase.PUBLIC_SUFFIX_RESOURCE).use { resource -> + FileSystem.RESOURCES.source(ResourcePublicSuffixList.PUBLIC_SUFFIX_RESOURCE).use { resource -> GzipSource(resource).buffer().use { source -> var length = source.readInt() source.skip(length.toLong()) @@ -163,7 +165,9 @@ class PublicSuffixDatabaseTest { @Test fun secondReadFailsSameAsFirst() { val badPublicSuffixDatabase = PublicSuffixDatabase( - path = "/xxx.gz".toPath(), + ResourcePublicSuffixList( + path = "/xxx.gz".toPath(), + ), ) lateinit var firstFailure: Exception assertFailsWith { @@ -278,6 +282,13 @@ class PublicSuffixDatabaseTest { checkPublicSuffix("xn--fiqs8s", null) } + @Test fun contentsMatch() { + list.ensureLoaded() + + assertEquals(list.bytes, EmbeddedPublicSuffixList.bytes) + assertEquals(list.exceptionBytes, EmbeddedPublicSuffixList.exceptionBytes) + } + private fun checkPublicSuffix( domain: String, registrablePart: String?, diff --git a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt index 8d77d56d4a63..174dc49171e8 100644 --- a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt +++ b/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt @@ -13,17 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package okhttp3.internal.publicsuffix import java.util.SortedSet import java.util.TreeSet import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.withContext import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.coroutines.executeAsync -import okhttp3.internal.publicsuffix.PublicSuffixDatabase.Companion.PUBLIC_SUFFIX_RESOURCE +import okhttp3.internal.publicsuffix.ResourcePublicSuffixList.Companion.PUBLIC_SUFFIX_RESOURCE import okio.BufferedSink import okio.ByteString import okio.ByteString.Companion.encodeUtf8 @@ -49,15 +52,13 @@ class PublicSuffixListGenerator( val fileSystem: FileSystem = FileSystem.SYSTEM, val client: OkHttpClient = OkHttpClient(), ) { - private val resources = projectRoot / "okhttp/src/main/resources/okhttp3/internal/publicsuffix" - private val testResources = projectRoot / "okhttp/src/test/resources/okhttp3/internal/publicsuffix" - private val publicSuffixListDotDat = testResources / "public_suffix_list.dat" - private val outputFile = resources / PUBLIC_SUFFIX_RESOURCE + private val testResources = projectRoot / "okhttp/src/test/resources" + private val publicSuffixListDotDat = testResources / "okhttp3/internal/publicsuffix/public_suffix_list.dat" + private val outputFile = testResources / PUBLIC_SUFFIX_RESOURCE val request = Request("https://publicsuffix.org/list/public_suffix_list.dat".toHttpUrl()) suspend fun import() { - check(fileSystem.metadata(resources).isDirectory) check(fileSystem.metadata(testResources).isDirectory) updateLocalFile() @@ -167,5 +168,14 @@ A wildcard rule was added that wildcards the first level! We'll need to change t } suspend fun main() { - PublicSuffixListGenerator().import() + val publicSuffixListGenerator = PublicSuffixListGenerator() + + try { + publicSuffixListGenerator.import() + } finally { + publicSuffixListGenerator.client.run { + connectionPool.evictAll() + dispatcher.executorService.shutdownNow() + } + } } diff --git a/okhttp/src/test/java/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt b/okhttp/src/test/java/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt new file mode 100644 index 000000000000..3efacb9e66d1 --- /dev/null +++ b/okhttp/src/test/java/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt @@ -0,0 +1,115 @@ +package okhttp3.internal.publicsuffix + +import java.io.IOException +import java.io.InterruptedIOException +import java.util.concurrent.CountDownLatch +import java.util.concurrent.atomic.AtomicBoolean +import okhttp3.internal.platform.Platform +import okio.ByteString +import okio.FileSystem +import okio.GzipSource +import okio.Path +import okio.Path.Companion.toPath +import okio.buffer + +internal class ResourcePublicSuffixList( + val path: Path = PUBLIC_SUFFIX_RESOURCE, + val fileSystem: FileSystem = FileSystem.RESOURCES, +) : PublicSuffixList { + /** True after we've attempted to read the list for the first time. */ + private val listRead = AtomicBoolean(false) + + /** Used for concurrent threads reading the list for the first time. */ + private val readCompleteLatch = CountDownLatch(1) + + // The lists are held as a large array of UTF-8 bytes. This is to avoid allocating lots of strings + // that will likely never be used. Each rule is separated by '\n'. Please see the + // PublicSuffixListGenerator class for how these lists are generated. + // Guarded by this. + override lateinit var bytes: ByteString + override lateinit var exceptionBytes: ByteString + + @Throws(IOException::class) + private fun readTheList() { + var publicSuffixListBytes: ByteString? + var publicSuffixExceptionListBytes: ByteString? + + try { + GzipSource(fileSystem.source(path)).buffer().use { bufferedSource -> + val totalBytes = bufferedSource.readInt() + publicSuffixListBytes = bufferedSource.readByteString(totalBytes.toLong()) + + val totalExceptionBytes = bufferedSource.readInt() + publicSuffixExceptionListBytes = bufferedSource.readByteString(totalExceptionBytes.toLong()) + } + + synchronized(this) { + this.bytes = publicSuffixListBytes!! + this.exceptionBytes = publicSuffixExceptionListBytes!! + } + } finally { + readCompleteLatch.countDown() + } + } + + override fun ensureLoaded() { + if (!listRead.get() && listRead.compareAndSet(false, true)) { + readTheListUninterruptibly() + } else { + try { + readCompleteLatch.await() + } catch (_: InterruptedException) { + Thread.currentThread().interrupt() // Retain interrupted status. + } + } + + check(::bytes.isInitialized) { + // May have failed with an IOException + "Unable to load $PUBLIC_SUFFIX_RESOURCE resource from the classpath." + } + } + + /** + * Reads the public suffix list treating the operation as uninterruptible. We always want to read + * the list otherwise we'll be left in a bad state. If the thread was interrupted prior to this + * operation, it will be re-interrupted after the list is read. + */ + private fun readTheListUninterruptibly() { + var interrupted = false + try { + while (true) { + try { + readTheList() + return + } catch (_: InterruptedIOException) { + Thread.interrupted() // Temporarily clear the interrupted state. + interrupted = true + } catch (e: IOException) { + Platform.get().log("Failed to read public suffix list", Platform.WARN, e) + return + } + } + } finally { + if (interrupted) { + Thread.currentThread().interrupt() // Retain interrupted status. + } + } + } + + /** Visible for testing. */ + fun setListBytes( + publicSuffixListBytes: ByteString, + publicSuffixExceptionListBytes: ByteString, + ) { + this.bytes = publicSuffixListBytes + this.exceptionBytes = publicSuffixExceptionListBytes + listRead.set(true) + readCompleteLatch.countDown() + } + + companion object { + @JvmField + val PUBLIC_SUFFIX_RESOURCE = + "okhttp3/internal/publicsuffix/${PublicSuffixDatabase::class.java.simpleName}.gz".toPath() + } +} diff --git a/okhttp/src/main/resources/okhttp3/internal/publicsuffix/NOTICE b/okhttp/src/test/resources/okhttp3/internal/publicsuffix/NOTICE similarity index 100% rename from okhttp/src/main/resources/okhttp3/internal/publicsuffix/NOTICE rename to okhttp/src/test/resources/okhttp3/internal/publicsuffix/NOTICE diff --git a/okhttp/src/main/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz b/okhttp/src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz similarity index 100% rename from okhttp/src/main/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz rename to okhttp/src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz From 1e9f44ee90bdadf3a0c1f730c528f525ff621ab1 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Wed, 27 Nov 2024 13:31:11 +0000 Subject: [PATCH 102/134] Update the public suffix DB (#8595) * Update the public suffix db --- okhttp/build.gradle.kts | 4 +- .../publicsuffix/PublicSuffixDatabase.gz | Bin 41394 -> 42502 bytes .../publicsuffix/public_suffix_list.dat | 7622 ++++++++++------- 3 files changed, 4571 insertions(+), 3055 deletions(-) diff --git a/okhttp/build.gradle.kts b/okhttp/build.gradle.kts index 9c9ea07c776f..084db6e649d4 100644 --- a/okhttp/build.gradle.kts +++ b/okhttp/build.gradle.kts @@ -21,9 +21,11 @@ val copyKotlinTemplates = tasks.register("copyKotlinTemplates") { from("src/main/kotlinTemplates") into("$buildDir/generated/sources/kotlinTemplates") + // Tag as an input to regenerate after an update + inputs.file("src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") + filteringCharset = Charsets.UTF_8.toString() - // TODO replace with KotlinPoet? val databaseGz = project.file("src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") val listBytes = databaseGz.readBytes().toByteStringExpression() diff --git a/okhttp/src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz b/okhttp/src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz index 1e552b5aacf7a4dae8e7b51e1446bc7ab5100df0..9102bd41409915327142e519e474c307c0dead7c 100644 GIT binary patch literal 42502 zcmV)6K*+xziwFP!000000F=F7j_j(^FW9;d{ZK<`DNARsz0Wyc4~Mi#o3ssHfHTWE zg&xJ0dLOB!JAnOg-%5909lr>`*p*eaK2@cO2xI;e1P}!O$N%_0|HuFJ`j3D7_8N7F zuZ?T<>AaY+)&3M>_d1U%UYws^gBo=psL|wUdZBOhG$l~AHxrzHy$2wdQ*cY{Prtn? z<1eGTzp6<+oK^Rb{f~_fuU5yq^8@htq*aJteKDV`^RfT$c>D2d-hThe+qXH%UcQWs zy?mea&D$@A_I=XX+aI5MySMuG+9(EtnrFXQt9^d^SiEkWjmm&%9MR4#9=g+!;+O%W zvAoiE8RpO1+)A3)$Tba6of>VUSK}AOK%VaU%YtgqVw%w{?dznY;vg4liH}UyUcCkr zHE=5x{aJA2q4M=r#Mx(fy}Fg6%!xrxCG$j>m#7iIF~#!c*XSvt^omlXBqx5IqqA-@ zO)kzQL^n}4b&W{@w&ZPkr78uiqB^UPQ%A(plj=eBtJa;h(vy^Fq3hAju4-0MUUqXdHg_={ArKJ@(T^3^7MJHAWvV`vv~QgGZ!ykM)Xbd z%s##kTHOLuxw1L}>L@x^#e z&E>V}fuNEuehI@$6%2SEaz{<=uGZ9mdKaQ@Q~d)mwtJn{tFeySR7G>QJ~c_xzRt@T z!1xO_YwR%rSC9vFS3wQt^@@lGBzz#R&guk76a%%#VO>JMB#+dH6SUY?+e0CZ%C^T0 zjLn$xN)UClPG^+7wA!7ox`{cp6TP<4fw2gi0ZsoxHp$a>4R11?SJ60|I_tzl=WJ+b z)D^}%t;8Gct+2L?OM>u~Rh?UvlmXIzR+Q<6nu25}#YHUS_3Rm-4s#(dL#kto2Q!n8 zoW(Wsb8>h}wkOp%Zzbh~4Znv1drDLfE|dxpB;(R+ubNTw8%k3y9-(&b_6si-v~d>| zC6@!dJ7#z23$t49z42rEc<%5>;!Wstxz66)s2{v~JyZKm-6#>k=U#(#cPh3)r(*lL zm|2fn`kw^NTr?Tb24p(Eeta9goDa z{i$Z+$CQSd+B3$=x)Wf4F{s8=9VGNU8z>+PO6MS`?kiOJqf50LZq1(Kgf+bWY~JK8 zm7hMF`1-bDsHR?H!$P%j)-|S=8nYu~hDN^Ehj4&Mm6EDzIcv{@k#MtR4yBxz@Lkbn zAD{DS^6?F?&py5igNpG|AR0g+`}&v)4@3x95GXq5&?0Zti0k^fEo1b1R&=k1`McU7 z?f4oU3gCXO=}nE)Qo>#DkaMrR-mqDzP_g&>rSkkXnJ9g1b%X0E<7klocs+M7G@H2J z@0{3wsENt?_13)nqx%OVS8*aczloSB&5*k=BKr;D{PyGb{z|h99SpU@b~q5MV*>G> z8O_l|po5DhnA<|_5a?tq`6Z^Q1%tFg%z$9}#!y8OKJ$lYQ@}1B7(qdUv#Pj5Tb)s0 z=N(2ZzQV?(#;76x_M@TF4P1N~<}?d9dt|4dB}Q^NIC2r?@4x^1bv6wKOG^B|PG|n| zzy2YT`fmf38$&-%Ez0!A(=z>mGX3$7fBfUMU&#IaztAmzm^Z`-ha!YS@%{ev``_{X z?>{8+->tF2u-%tJj8~*xC-IkTswf`&osnp@!{teb;e8!LOG2>hQy~~P^M+(uFhxtT#RsT zhT=Up_;K>inwWtjnMjFWGti*cn{!5KzOxT(=+(ne$`^u1gym@PgVT|$Pp(H%k+VD= zPQc}Lr5@ZZ6s!cXv^|CVq9_&3tJ3_8c%B(<3_mSDJwI1GFIPM}rqj60$!|z5aWelhYoVvUL395N@2-2Z#CK)IShHs_#a%dZNNUXBg!GsgN2VLxF_2i9{8I z*bv{c@nr0c8mH+*=2M!(N$+M)qjI5YVSb@n4kfx_bqSv%nhuYqsx=d&C@zkcrN@s`#yy2Q3Mj^% zq!-pC5{DwqR}zWx($W|w&(|J+v>S3zwe8wz5^GU+2}HZ5veiG3+<*gbP{3b`4V^M80m>gGU`7WB-HrBlgQ=ec-k%Hc5*5I}vN=|-A40X)}{WKhW=iR?OY zXUapjSo7)zjG>Z_p4maq38B7dxQ|Q7hWn5?Yb0*Rs!V1$m^xCZhO%!k1Egsna*@KO zSnR9r(P$WT#6DNor7-4KP4#U2iDbr`HX~1aQf7%t&7NwdIYH3!ZY(d(OMuhR>sW}q z!U+KLOBy*&O2(*-azsgDC5)y9Ta?^vGD2c6JCce_4pb;r?nCchX;|n|c8LR2UCTU{ zv$7=OT$X_*yk<(i9?Qg?_DBng>h6QzJB=UGJoc}yG6oK>D30ODa5AXY$_PqeXI}YJ ztJ6C}RpbV>CIOHmG3fLirrYT&B2}PnJN?85$Q9bRPyF<4g*a-b#y;^SFDk-AKMRbg z8KXQ^Eox|~xen%aaJhm8Lrlw69C9#Hf;ELYq&y4Cz@RzwU6EQhE^de-KG1Mp#qBi- z(^g)@bvcs+J21-|7AkbA0k_p1wJc1Tgb|Kq#2vZkj%6GjIkb^$cvQVsEmb;`lx-m? zV{JbW>}eq5Pc==YgkO!FN}OvnD(LXrkKd$KjwFDb6OCNw_(UJhrXOi%# z>0)+7vLE5SI!)_OtLCbSk3pf^;mckvoy3QA1#;pmcrQ5*cBIV4h>0(GPkE2-MB|i9 z1AtY?t<42+S8Kq!sMI=zErZ!q3T|SiHI;&c;95E{Tp=3%YVncmfe*08}C1U#d}!}`$ez6o{-%R$~WHk ztIywi&T9eR_^ehQe$nUmNv+lyjy@;i?62TOLmn$JR8|52(ES)e6vM6C(ugSi-L@($ zZgkvoY^%>pf`~#5O+IVgnyADkPSgNL9izhVO5sT;c)@siy}ihkgMUVkz8z)^wtfFQ z#n>78u@GT9lBzg4S6B5-Yfn7gdZoSrE@v%fOC+P@JkKoQcIL7O{&Rsa1$IT@i=;!d zqg`(%{K(@;-l@yh5&v})jW(~zVd4f6dpg~S4eC`Q2q}jE_HP)66oa|&Tr-I>qydO$_r

%vwG5!`;y7d7r>*Dh*jM1;xlSQUTMf2Qw3&$9GTDA3r3}Zq&TW zLEL80*dj~mKofyfTx3^Jc+PR4Mpb=DL`Jv5{kdMqD-NvCa5jSWGryS zP||AwGbmz&+wu{kwK&0q$>zkCkNekT#*-fLdNW3lstt>)@iv!Oar}z*yXX+s)#lJ;Ie(-0RecYm zjuLy$VC+d^pn{I$>opA<*gH9a+ofP9?p6_6BEs3I5YY*#>N~SvU?9?TXtFUnZ#8vk zs+OgsYN^JVr9sBYZ4Ezot(9E7YN>mwQKoTAhb_`Or)C+vFo?zL#i0^f3cNoPl23w;C$+U5uHPK1YeDL+-J6|-E?q%Xn zef~FmeHQCZtLzgW^VivXKCk)O*XPMOXpnvC>-$6(m6NZ1e4FZzbDyt$eVgj6JNDey zUYqMvKVR1UvpLvTem>1ut^f0>k8i4?*8cg_$G6$}x)oQdKhHhv6=$CN*=wDA>gSv6 zR>}v@J$%P5zU36(cKvUAeW#T#>vlD9TZbhAb~4yWL(mfCA^bKv8m4YMmfT(=dA*Sw zYm$&~qYq^KB`6QYH`gdx^%sbDSr`;~^X3*Bo$>xo|LR)L8Smjm6e&~k?x7nU6mgnH zk0gxHm?AG|1bd^=i)4w31d2x%zE*YCuOt_z;eM47YS;#<6)JtZp^FCf2g`X6?a#_w zX}%93=V2xkaghtLFpQmpO_qD`4i%m!%!hc)WNdP0GwO}7EzAPDv>SZbVP#s{@=lcZ z|1a&LkPvb{@!}hek7w+-o-r7ou@QGZZnB;g{pVTVnWr1{Omn@nIvYj94-KSL!-TE; zIFAd=hQ8XDY%Y>n*&Y*pJ{d89t8zEQWuMO)B4PLl?o zp@p8;wh%_hhd0y*;FyTosuN9TOxB_VDPSF>O&&(fFla(rvL_RH=gMC8yK2UcFmd+L39} zdUBW3VBLL``I5c3^x~5@VdcijK%+7+F6RvLMySB8F2F58dPzX%6JTrsN(?3glP-YG zU!wmdP&xx3XR*bU5ua0-iW*Q!VIldD0BVJE2BABZK;lLPUZ81~Bg+}YIFnW`7?(uU zMNlYvA6sq`A*W!`-bg2gA{y6!kh&tirWa)Xc3DSa5YP_j_;AQ!QzW-U_sr_q844z9QKBn6TG+ZgkTF=R)RA{5T z@B=+^vS`M$yv}z3nl~{B7#A7U&f2mHK}O=JS9WQ}fnKENnUb8gr_S1U5-|0?DShHI z_tDg^ZmQeh_rD5)X02&<+pdz%5czRl5EXptI!|KP6(5>{Z;=qQsW&2k#U5an}(zIdu?Z)mYogp9;1)1s2J}l zNGd;RHU?`uE)m0{d8m{_Lq#DhoS^qV6G&`P9YXD~E@lB7*9OjJKw9$J6hR$780_0T z`T$;B8ny_T`^7aGiT#p>F*GydB=?>>hhYihm`guo4S}KICpU*FwXV^Iy>xmc4moTmM~`_ z1_>ofd{Kx|60suY1O4x95s9R>^A#&%=d1E*8HT|m@|~~R4?azp&)21s z)-S^*$!>!@iBq&qEBne!xM0DMazr8?aX{)`cdA-<56Oq4PcSd{fIEI*QBPbUVrQLs zXM)p*40FdIm=y>Mf@NBzD|oEnX@em`6}a+$uEIgNWVosPHugb|(;iKCYxXPQU@`X;6;h_q1tkN@9{>Lh= zscIKfmA2`vf~zvIRl~7WUCmXR=PItBRb%m$A76dzt9qUb0rmyc6@Hx2y}^!060f0;(Q)Ml zh*F~&0Qt+ZkY7U35E}fdlFAc-R_3Gr{cmgYXq}M~3wRb-c{1x>p3J(JGV7*^EKTLzCVGPq zpj~QXfAUb$$v>!(@=jmnb~f~c$;?kn{4x)~LTigI9z2sC$Wl#;FhfX2i|o$(v7me%Si z1#>~vmupDjchoOsrK3@Oql*GgLn2)xI(+1)b6U;7$)RP0e9t?44JNh?^x>?bj+2yU zh;TEO>Wfp1SSBG)vV=lFd-EwhllCZyY37Hb{*v`07`HjzX(ln3SoNe^<94Jy#X_gp zwis=ZX$J9)=qX91NC-pxmL=BN_#X-0rK&IM!lI-m3+#kp~*!j}PhhuX%w$H#d15*ZW8ORB9*|W=~>T+Su zIjM7|_?*I!V-Gp@nA05J5gj+ZQ+=$ zJz-5%1|UqCnOR;&oG$!GQg)>#9G|>t>=UBwsFW9cY)eJr;nX257S{8tfB*Z0eT51m z=82<%+|6~~UuanLq-WY+XmryXpM7Bg^d*fIOL%&)tkKksuy%-(o#uiS$f6KId>zaE z7w1P|^&9^FKR3eRef9c6|0gqF5_2LcytzM|SJRo#d!WX8uxMvPZ|0QNURgb|Q@H^H24}N}D%8qu%(5RLU`#z2Pp{Q1Pv#~h z_zhGkE4Ma53TzFJG#Tklh1?>^pBZz6rLU645&ahSnoy>6imOXq6oiAnu4(oi3~VcPYhw@Dp61-;Y15?T+2e*E?z z#}RF$YK;k=259qZB%?oun(FEnYK2Xt9d(_cn=@9Sg+Dc0|6N>Z;Rmp|W7?VnE)4R)3zjsh?u9}8JY3}fT zkKbEa@+5HG>sB>1)eVuxV?YjKVjunM@Y|0(E{LTGa%@L)0|?~|TNPSZm>4J@>W4(c+IOZGf9dT-}q*v$Zd_0T0jsF#bfXJ1@lNmFRw-0a zX=-r~1!Q9dVwHlAfU>ca9YHc9W-E3`$i{YFwjr+?01g8wqg11@LKoXeiVNv#E|+yf z=@n}!W+dkfU@jz^swjc|296cDoHyjHfO;t)<{<^VxPsU%no|A*&s#j$*(~tAfJ-W5 zIe?$1?@U@LJy>o}8RfL)!<`JpJG(S%d1JUp1g0;@NrB$EkEQYN4sYSNH;(_tiG8ro2Z!)L%nDu3H3LmwX?#7+G>;0+JqvQ_g&j|d<{uwl z%;V{TeBMY}nwvP1q((k(wK(!!D<8BHrj|@=@uDTuS`wip5f@4IMLxes zIy?EGll*m(vQA2=lazI{IOziktdn$hlCpjfM?UDqXD>dD#AoE4kyM+X>|6yKB)Nmc zKF9}yL_0_k3=+{GxgDi)MyZ@p@;*u;Mu~lt5*+2bNn)79%Ov@mB=$*4X_DkllCeoX zpCtC_O&kf#O6*n|n3bTdB;HEwsVUClbCyD$<%3zudX}`zl9pM%n;M+91&e$$OC4qcoc+Ig0XKl<%UX zI?8uZ3Tu%hEfVb_p)68yH%Z`4Qg)LvyGfWg$x+fS$Z#lEG}l~ zL<4r}A{D_(<4>F)tBR|*QkpPw$ax6dfo$s#yS)fcAeWmFxm=d^qG?i_Ps|c-g{xW; zYLhZPkY!YD;@Lo8Fr$0{oMpoTmRC_VQQS@^K7v_4Ol5?Zo$&xdZu(6Y%A2&=MDEBB z-ri?6>*OJ9&dm}ex!f_y7)yzrb zijkkpKgl<5K+zMek1Z--%%*wcz*}Pk$)Z472XY<5jBLM%AW%E?(UHG%FBfmTa1Up&pG@_T=i#q9;wby;v_n|>JGLBets&sJJs z;Lc1n!RzM93tsH{NcNf5eOZ5^7Y-N49rgR@mUqi$78Kiw^mBnh}`XA?MK_KMj~f@dspL5OV?c0Dn7 zT{buXHr-CQl?c?kHroz_$7(j;vJH&g@w8SABh9#pv9_@FAbS(7nrzi|S{%eqFNmkT zVB-;rzo;eXN#mjUu~)riO1+Lk1Tdf$hnNspghf8=ZAdHyMdM}EQ^Bs=TkZmk+(_WR zLJb#Eb3)($tnpxQXp*rNKWn-^N+KQ#hpVeK4_U)+8x$Tr(rVvj~i%AKK4DjMm ztF0?1FTlS*$Ux-s;>AC5XDO%Ir8BFo4pIi#*FqTw^OAPs#SwnqiehMs!+Bu43`hk0 z`(PskoRU9a%f!%#VQZ;bk=|3-Hm4Zne#z_m1f`Yz_G0|R`krmqq#fI~r`bW2Eo5Py zZBOqFOnK#IViXk%TA0yeOTBe*-m@An5$u_M+=~q=*mN{7aq~!vIIY1U=CX=JIC1uv z92gI61_&}-RrV=4xzBiR!poKPEDcXinp!^soF$+XXQ8B)tio>dx(h&zMBMkIGG1$u+}5XXBzm4(SkiSpaVx!nw&2*_Nca z(P4m}Ic=<5O;4Kqv|de<=&BQFJDrq?2wBUBLvUM?03_3?Bd~1*pWnf7Tnh_vg9PHS zmeKl!mzmi`yYlaUXCFbD5*AG}j9Shh&T+J1T5Zm0g1MLy%!NUPB`Ym$B<8oA6@9lf zLn*9<3V=!layosvc$$vEfvqnI_@>C$&Ev-^AKYASz67xH(6HK*Xzp|V2{ZGLKQc`G zUM;EZ6MCDoFCqn#3ysii_$36*`NZZ?S+Egm)p0VyS&|g(NF)0O~NLc!-NjwXy@J*}`{1`;$T7pe5lvv>orrUP@XSSKV;h3_-osU}7 z6G{=Z5^4ss!}nQ`RwW?z1=xnSafMXXLS2Sil{1L;BoNK(1^O+0WlIK-)cnzs%lh`O z0_CQV4oeb{RPkC$A(Zi$DQF1i8bZ1L?FW_^^l$(AV9&Www0mlxI-YQ(vSGm7KH@h?fGh@A&JXC=;AoL(Fw&Q+XA z94n3lc9y`-L7XU#gxSdFjeO9^2aQBalT~)^?6eYeD_&apTuUCb7N-+OBGM935>x4vhWT2A(J4s!)veOUZ$OpZ6F@hOMtNAI8yt@iT6v$VNcihhA4DmTMPgs%yPL#*lic1UzMG`;F7d7M?jhejIEJ*NCr~~nPZ&*5xGm8qWulA; zH##$UImy0#I(Q07fyrM-VpGz;)}1q9;?J^)R&C^sX^R>!!6BbE1U$F`X2T`g)S=SE z$y`mvSqI{uI5JIz@l0b^kLOW!T;FmXgUgppR5+Fe^f-tw8lOe6SYyDa=b1ajMDo`g zw6alo(~}_rtb1UG&FiKDouFuc@+3{CqYgsZ5qJ@p9FN&C_}Jv-1r#3^a}s5?qpg!{ z@9*Gker{>-gRjr6Iey{wXlw8bufKoi^%rxqH^1?5Nu!%sWSCtiO&i(j(Uue|?y7C&RJ2k&3A z*pHq+Yj8)OU$fdze1E}i4_|!EazFR{eQ|%qdOv#o)zl;@6-1je5*%vJP6Q57g8zO8Ze$TUa{yt~e z2X9|;>refDm&|YY^uh11X6e&D^~~Qd=IKk`{Hfnx%+qIFx%T@tOFsDgtTpYtea(!Y zdHsSD*WSNo!=L#4rdYpXzz2W7)J(o&y$654QkY*b-DlpuX%}C!+uG;Xy!PPpmkQq#!WvwPrm6 ziFyuLB*S%{AZ}24&D)N+lOwP{k4v$3iSt;Y^bY$I(1>Sn5Rf7asNFZk<(O8bLRoYR zSyzFefuBiZLF4%UE|#E8x4E*g*NKbtoSfcrcBQA zzS*MFJ|JsdA!NSK1#Kj%D|A_Q%1%1+HFY?2$Bvk6fSc=`N?^hHi5pd5zEYGZKR!@? z|3LZU1Ld1@`xXEF?ERNF8*F^^%h#XWXRz_jPhMvS-4a)Oq^5wi{Rn5$QR8gVoIMtE z)48oI`*x1i>&WNeRJv2O3@3z_aSj~{sCXC6O{aC?ux zl!s3S=qH|jB@LEjm*@7LzHca>OLBWp-xk`ZGTakCU$u;{q_@i3SEAeA+xKPgsnAyW`BY+i;^(U( z_)=E;=NlzzxvEA#FZi_Hv}=!lj@#(6B2B3sGlP>x+((x>(AbO|D-0)3lHr z9mRs~rRR3i^B_;oAn1)93fhRgQUs7h^LQrtEi@~u$m~`); zFObm$PyB$me1T%3VMjOYkg$&^8-eNvoOUs(?6sx zjZX&80NvF%mb=!n&mFOS;*pCr5p|pF7&RRCgfq45_EB78#kH5@cH;Wv|HctaBrpRY zxegD*z7RsZipea3_^|KgO8*%5E?20n^Q)_tO>{Aoa~YK&3c9;(f@87&b{SiLlgy5K zpnjjX=?N{{^cOyS4@Zn95CC<5Y4;2xA_E^{(v;j;Ji2*a6Xa7$oSfZ4h6pyZN?*Y2 z0=q8z6YGPx6pIYS1$KD>j~c}a_hl3tVi(F8pW?c(1uS}A zLF8Aq`FN!EV%g;4#omX+7|5gRIT(f{*4TW@aR3gzwS!|9LtRcK8&ST{$1Pxx!66g#;xk1r($6%Op?k(EuJfclmas zi;LoySdyryTpTjQ$IrlhJ&m=jCJZZC=B7JuL~mPakKV$1JkBzWbxq34AD_G|jEXfc zh)@4^!sK#qCV|K}^Q26H(98sc(KD5ixp%l>B4O$7gMykN2f!xFQVn?}3X>O4e8X)0 z6GuZ>Pqp{#o*fTJ@=ZZ6<>mg}_NvV~palU#0Ib6hsfXrw)0)&?fv`aZ86OFYW2i4= zAd*RGtXKd#bU&ED)?)~xHexs`vrrqmojSPEY7$95qdg&6{lFa$pS<`;KTa@FNvC!RbzLfn7z98@+8RSa0y9 z3cstu>CFb4ik?n)3S51g4hb-vSq#JL1}Cek3{O>7X(}7%pRr3-RKE z#jxeNzYh)s-Kq~X12KI&qzRJTM0xPX#6$c-?Qj?2;6A>b>MIcwp)x=w6ncB0L9KiJ zm;hH_R0{%M-(C)z3Wd^G6&%)3rBls zx)wimRy(6%Ao1;%^);6u_Uy0DK(@Q|T)-qL2M?IkgR!K`;&70T``6+E?wnxIqhaln z?yZTqtcjoncRU@sCsW;h}Fpt|FWnsdH82*Y^Djgc6e7|V+W4WrP*h8yGw zS(dL!2{0{~g1MPNqOhI18Ep9^>@H`}I|Xl)BTLRQ%1n-+oZU`Qs?YS#gHQ)SzvJ6x zx|aSi%j;S`^GFU1V>1Ne3Nx?3C?m|yX*T`BN2cwAUCO>nHp)6pZ5;=hInmm{PTt^h zS!gy|1xL=s@cl2HI1hG++mkb>t#1?Rl*DS?Ekp7srg?!F2`P^J!sHixD25!*$tOqd z^yzdgVkyDpOk;O>=_nk^7Cm^wk(`UX>goSAcs5Mh8TzMu^WnwL=sv;}waP8UTp~Z< z@v@X%(#1HzBw**Q?7d{`&rR28S8zg&j4bo|GRNA4oEh!Lr9;oh zsqc=`#-{+f=}hejmk#rH6M387UOH+_*64@jL&;q+$JVitwT>;S(X%>$M_Ag_?btS2 z#|w5cbaia^tYf=p^h}$*9h)KR*r-^?M#VZdB-XJBvCf@wehLn9hAU@AaTa!3A?ik) zz)lz0=`B0R2RYWTGb?elI0HN3#?Fn2Zg&xO=Wr?B3fFC|-*xh-VWZQW3+laSv+jyD zj3UT%xUUI52VC)0AE)b_G%Po^{Fog!LkYU@19ryHoM5{H-&>o)v#zJ`-IR=jb`D{< zcGX-=uHy%qA3GcCVYJCx%ALcf(tIhThs@_XSr(DX4)T(cZL!$Oals;pH6{xL9ps2w zI_Vq&iOG0khB&^sHIazJCObK&gDh1KvP76+2VJL~dctYU<-s{|bGOX6uknIhFE?qA zcmSY z$;I#iN8;-wxt-*;llc099V6cvNvDwyj3mPR6h}Tc675yq4U(2YA{r#|gM2>B;@riN ztc+5+qm=F_85<=Lqr@;ud5#j%D3v-&awqwGlH^Vj`y`)FlK4qtpCo~kggHr=ljMDp zFegdbl!BH7T8V*#-YB11iNs3iR)|h=I!igvl7Lyf%#wgve9jW{EV-E_uAdT#mv>%L z6vkaiU$#wg7siq9y?kCM_T-=+LUi6}~H z7D>$_IlM_~Zc_X=`TQ>NtwMar2M>wi!J%khsU{H~SrDVAzpc!Pn*oBL~S2i`R-zY#DQf@8OWz_r|47$y#YJ%tp8cp($>GtytvlRyW`p=-SA4_uwGj|Ey<^?|+Wr{m%sc@BgQs z#l8P8OOx3S7hCEPSwk5l;%M}Rx+zFK=Bd1Q+ABoR^VhvPlSp7IQ(;7zWdDtzXO zYMSH=w&*Jh;Y>J4J4|y|bMS>FXjoLrQWp_%Pg5l?_X;<+>=uuR6!a*`(zuzmu9Y71 zz3TE*!ZohUl78G{ae-GxmNc0JB^fsB6)#5ZRVL8{f^+7PNhMU>uh3{h8(P(04B_rcSwm$$(j-)MlA5vXTC$FH2>tsir2uhY6 zvm6G>q>^w}<#$r4#tD#}YJj}9mgmw;aQ5R-V_ev<5Pv6^zP_-bj1&SjBy8~~Z1JjY z3Frb`s02WcEQ^OsFhgM2*G2T0&9-cIheiir6e3M?`}WfCgALFU0|Z^Gk!Hx^ zoN(6?ZV>mfwpoO@^t=Yt5dv->j;L(S69@>XLnvMp&djFmW*NWo! zx}>gd(Ilg>BN|<(p?1GS1rnNeEoX2&#$EYA?`1cz8rEIh^+%uOzbbw&gVSE#GiaE# zRKTL|{m2@KRc6_ybVdJRw=B`>)VqUlj!us3?vh`Z666YOwgTe#cX7tL%5bHx$!@)2 zn@AQ#_K__6$4}_-NEMa4-jKA<*2#*TNwc+>`CuE7tq!t9JTU{h?G^y%J7|+UjjJ{F?4m%Gr%O!pj|68rR=xv6X7ex_yS$|W z&)EK5{#-r{nvIvQlWNLWnKsuX8zeJf7&Y6k1F~4NMaD>uixG(mETEW)>YvVeu)u>S zNp(TwD4HX>!#L~gwbGIhv>v~RuaM}E?%qU@Hv`t4a)Ao3FPvz1g@x12kbIcjI{v!+;E(sWi1jL5` zK^$CNoYZqAlE|A`d=D@^@AO-X@-M;Y_o5Tt)3m#+BleIsl6>uhl?4Mnlh}tdN#c~A z7-#C#;+s-cEaCNHIkI269<6CHAsFpX*9FJmcy|J~rKJfAL93We?w5Q#v|rN3V}Hv^ z&HYN#4| z?)m=z4m2LYq9c7Ps>J>Ke|AeA?|)ZK6FO3*TnX6<)?iV{U@_ca)!Sfs$o%;I541eF zsnk$o9Y>W^=47p;nj&SMUh(!PU>RV|xfGH)%M?EgQRa-`p(1MHi)r$bt7)iCsd8S7 ztOZ0@jfsXYO7zt_0VvP_s1}2SbpPP#UQNa`WfIM%9m_R&VXF+iLgA6F$Zr*G7msy8 z*NYpbS@0vtl(Clnu~P-r#v7i`)b&Beyv);hgN8!5@pz8>$++SP@5yue67%>CLpPB- zXX#0e+EA-3f~ILN*d;O)X_SW1@+K0Tcz-ce{KfnpL5rfNCgO#`3)Nh@Z1|LKALd$2 z#2t<1W;=OGto0We2}*H0`P>*j&RhG4A1)j)A~@Hc9uUVW`34lb^FsX7;px#Yv#e}b zA}rir+DT#2W`G`F(Ge50v|z?+)+>}cO5j^>poT$R7)~v!l7Kzc30l~H6$(|<_}v*} zGnV?|!xm;lM$n-~qgv6$Ms9G63#qfF}9KWgE zn2GPWH&c72hun`@7{)X?ew+=iNhFY1WNI3O*^_EpFYrp0Rp(>W`GO^1UaXNGC0_hyG^R9(#r#a09y@M?0VfgP@C+>{Z~2+&pN zfsG(>AL5?R$-O2w`D@<9)lG8KcbDX^Tg2@Xy-zq7@r9Lf#FfagehE7_c1n+q zQkqc;FG5mlL-`0N zbs`bUV{J9X3KBL8x^&)E2#y95O})9M`Gx8@U)?CAWgNo^q~fa~mTq|4t@vuNsb7cG z=#d7-eNe>BE|m{poYjJDJ{?<~$BkyX`XZgI5M()$GRmu>Zo?PBl&tckEW^907;#ytnw8c>UP%| zf_vMg19p^39|a+5)$F3iy{@LpTg2|nTnAdJngpqauh~&mh#=ODj&VMyUr|2vTB7;5 zClrfFH7S`Z+NkH1M3xy3KE3<2omm&sOGA=$tM2qk3}`vYGZ2s_$?lMCa_D zD7x^8GHP8?FBgra=*Fy9Pq1}yD?cC~QXQz1my`w^JkDixG;-^&f=MIl2pbW zf%|4nuvmqt3E{4FNg&owP~|MlNy9IM0XpLO8y`2P!9KVw-$KCHpf~8Ahy7M5=$Dm~7h%CK8Jo+q0%ogQbyZav*NE zw@A3G_EhS~M4R?!5=`W~_DrN!aidh6a141c>1r${-5m7bXh6=J0_N5&;yS;kvm@qC zQs#bwbXON#3tKM>-H-c01Pq7$Sdeg_f48j9#Cq?J2-AMh zFGgIc{uG?)ypCu?1c`Zvo$@0gY&oM^G`p&sq6ancbh6@#OM1kL;k7x_4_y!Z`gEO} zS2NT`UF79+;_!I6QUu%ef!CI2o>xu(Ew$eZwXp3aNy&ITxJ0z58demSh6UP!R0IvZwD|$(+_r8jRKIxxpNrHKq=^PT(RaP>2WscIs#1E zjaQN^dTn^Y{Ho&v!QQMIWF`8l?|Sr9Vt)p>d6=fb$IF6{X7)kXaDxQt7#7`ML~(5fW4-ru&0H*|K3XH{qL$Y26S;YuE^vF=73gikDGbGo%0@4jTmlAAOJ{0X@K&H@S!JMHnIfY;|G?erVYlg-W z#I!*rut^ul6sUwZl^jeZ&RZrdC7HJp#LXn95Q?XJ@pLb5?~=y<3LlRrgJ{Q-qGH(-=kat`_XDxQV4tO< z_C;dBeh?&zXk^seav)CCGX0>6@L@S5hDr7A3HHKvyIDkl;^0ocOSD>G8k8Krt>pOuV#b~?4@$OKs-hZLb(bdt zd0&Kxx;xr6AR-mVuv0A}n%l3069pQpn|L&U1M-F21WoHeUDYoe92mxa4nru1dP5Er zuA9R2L1AHTpVLVrnT45xz$KHWJHw&QC$mf9WH?kzr7FFC(4QQg=K_N~U1geDP_sL? z&m@+{Dq#;q-Ww~T9w;BQ?lxi_fhcsog8 zkPloRC3X<^s_FZdvr{bx%F}>-FSR;NqN`?Tby3Kwx>us^i;${g>spptWSNK%$}`!m z{%{br%=8$Y%%LAzXRqe9W=5#EBlEF-AJ8%#>f18=+*-vPcyp7c>8f#~^hb~VuvTRx zkSHaGSQ0iAcu5+aRRmtnEtCkn9&?ZPWTD8j>LQ0emc8_BnjxH2 z5F@`EhKcH6+Q1KjiHz8x+L(@++((_%!R!`O32H|Tr{lvwQc8AkhrX7D zw|$KD@+M=uBywQ{gy)CDn;{$OC)nMvd)7*ML*aR2eDCsVk@Ii?!%(;x5Qovva~!*1obEiG6KdliXHeMSEAeQMgOt44F^{UnbnElR|~E zZ(EUA_u;$h;LfgsqwwF2sWasRug%nBJkzn+Mrp1!U&8Xg!kHc#zL#T;aVF-RIq5Dw z42s9-xHavYRcv|;jpn{hrOe&%1MAjDmOl1xGyDl#xSua$)q$C1}c=AUwr~*aKtX@na&$*b9;9X(ty{37HofN zQwP-Poy>p_%gG+XoORV~iMZr>vDaMyqdWVD?j-$_s_Ouk3bW~kt#`>r+g2@(1>x-O z`gOrGg+OQP$Q$Kvte*|H>!*+ql%@`I2#u}?o7~n(VVq9q za0lnjlPRL}>vqs)9M9k~k+nB>J&mXznjOjh`bdlQ z2;!ovBdrg!0mDhDdIn0QT}UFtGg-dV-^PMFL4LhSdfrUx{UL0mZgB z!GjnEBPdui6wtxA2)d0YfzWGyj3e}7nAN~oIU(8Nb-|a6yEc?#y#s8QKr3$)1000U z>#Y{X{3=Y)zyDRI`Tg%Yl)zp@-db4g{b-003whGZcbloO#`$reSPno&b^fQrNl@&Gb_ZJ|piM`PK{PJ$t$1uY!?(46klb-52CJX*eCX`U{@?>f7BN(V zHB-@v*d^O%&HT)M7O#&bgv};yy-Q+f`xrgWFI6j_MCi;ROvf|4O%FjxZns{vco{%G z2^e5Z*d9^#lb&bX%7IMHUbC zq|WUr?xjZS;~awS3U-y1pfb*oQ2PF-$5mt7V&(f^C4=M1ow}1bv1-qVP0SGj#i;22 z6lR@F^~rYNNK*?PZi_~B;bV1%2{UrE7=qegBSvY^6YrL*`)9s>eBmo!b@YvoZ)2-3 z`})M!?z*i{{Os<$`rJ>tzvvqepQdEHnduu3Uxn~V6pb=(s94xp<$-@x{X83~N|JTd z0ts)#vIxYxk=iQ_{4^LEz-_W3G~%uWdfKx&OIxvx!mc==mLI1-PPn&1+Kg>IY^?$6 z^i6dV9pLxB3WAjt4%@!r@|97!M$F5OYUTx~QT<%Zm>Od~&PY&_E=L-t#}SFC8!i8g z&6r`25geLaN{R{c?X7h2QQh(5t$(-=lozyt$$3aH55q>##`DYA&_Bb?axP|#(UDrp z0-FmSwQ9xaY~z5`_KOKc@zJx`_#tFx9Bb5P9nNb4aWM*tLZ73VvbFY6H%*GFXdtIZ> z=^aAxFv|BM<|t6|7`0tG3=aepPo*k#xTYX(RWjbtg!DsQ#VGUGWuveo8||Sd@!GLF zQ?99z^1VnSHA_*zU}!9mFHk7ZBSWHq!H_FZ%#bKxFr+i2H9MCQL05thRSZC4tp$)N zZ$&ACq4KS0V*naT;$%PpG?s6t4Jx5bB}r3>Z7ShSB|B3Ic`6yRC1bXPXG?gZm%-4r zKvRKk1u7|ZYw-U;&yuFvV_wx3h zQ#${cUt8mKg9g)5%QC6S8612O=%V?to#X));tD=vI%#WN&nL|ZSkf`T(F~d&;WQ^@ zcgAqwV@)WrDlso65#j80n(Y8t={eDeWa5hBSsT*y6@qS85LVb{{Plr5w*bLrHg_7V zztSv=T!e2MH(I!@684AFX8FD#An$)=aNx&^a}`OEuP>A|8yU?Uklq;i{5acOV(S%r z9ZXt%XEOe9x3B?WN4{Bko-0hk%9wE# zg3$n%KGh`VfDW>OUU-bh zT%;BgDGc#$o`v<}`m#XtSV4kb9d)W)A~DxYY z%ptvLJQh#+rpA9O8R2Qqc$4W5c-U&YJh-o=U#<4-$z_Y< z`=3P;eg9993Euy%dL&G$ZLQ<|@6;Y9Oj;%gqLZTkY!IHHB<{$NIg#`$`qBhx<1)m? zkf=C$>#(g>*(RLygh^cPwS-Y4Cr8WqgfgR^)CH@dX#H50d6e7Nr_C^DmwcKF9^>ik z-jb$2TjQf@A=f4xO>sLcDwmAIdEl&DnFvCxU)ag^rRr5v(Fx=E{BAXIQY8M~7Gf1# z)P!c4l0Y}RF$^kUK~sf_pCqeIuz)GLL-pP?jWhURs)4I10E)`&q_X<(ggGrg*U;1S z0x}?B=Dt%Inb?lywu(x4OqX6v3JWFnK>+A;eG9>crmIO|3zWa{O|KJ#TJeiOU1|kB z>2Wg@lY>!7AQ~;UN&o?E$lEgaAjBKuLI6TflMjBs@Qo&QCj7#yJlj6~Buk2Ap^k7C zuv2s9WvTss{FIie>eV};?Usy)Bpn!R8K+6hy`@apZGESO4Qj4UuhwOJR#n^ zC4XT#?=*0Pgw>&XMUtuQe(OtUZd(*#feUU~;rGz;D!ZZ}OoHP0~>b1D<;ZtyeWIpAB^e8&?(;Q&5nD8q})Qznu`>Bp^& z9Nmbc+36!YG9KXJ-@#9g^H2)WD(XhWO{j7jWP&jgn{T#SHdK0wg$Se?*)? z&6YozhI6X8GGRj?=mBetSYiN-lbh3Q*wiy;o=8UuHM47Ap>fh+GBAl+Z64uJ-6@|X z6zm3V+KkEVp3K!W*yT3t=xPsoqNz4_)KSZL3X43O-8q8JIDCO1vyEAT`XwYNaSc7D zVSm!oS(BtG$L~|IaH9Y#Qz*D8=$O)l%D0Hm=aVtGi*u0Y#P#EY1_u^j?|&6<(9xqw zyA%(JlCn|*5NAcRU4ThPjk}$51&IN)iJD$lM*FUe_WjGm(mYI#FpM^5)MW4sJHBGr zI29TK?2p!*)HL2z7x6M4+y$YwJI%a=Z}no@yf{r@^!kMRsB)pF>N0xNjl`=*SqFz| zHH>)F9NzRhI|~V~qV9KkdkHU*^v7MPNfa=5+Zl;g_Uaj5_IolDbd9QQcqm_o{j&44 z-SJoCg56aulR+Lw+=9Z67AFzCI1hHfzTh}<A&-lxP?E?k1&llSHiI zJS5tO1oq(Xl$FjjW}fyzodJ}CvJR23CC!i(ou8_QSkbTCw{@sio@kC9_WSTj=d#+< zN|a3!&gO-7NdoPl8kLAFj~@<9q*u@)t(z=}XB=~@`W$EqQgzx7`d}1351rnu+UoF*-gC zQGatRuE>v&XJW?75*HsIEf{yf1oJ>5o6|K@4Lb{gz{5`UV>;Y6n((?RjweVmrIL$< zvS;UfL+Q4QOoYbS%My~22R?;zRJh5+eLD+FXSTM8{6ht=t}?=PRh-;#sw~CB2oc>u zPXeTMH@$;S=ozVbNvB%!J~pFJ)2LftjCVD*NjgqgYAuO&JOzaUZufP*mH3M6Y!R+7 zGO%MZOex#Yf?Ib`terNErs~6b5MEPv*;Ve!is;AB>Odb^wR=ab=l{u4cO@MN;V`-j zaUZ)&1{Ri`zql`|$I|b*Y}%OLr5OeZCsVbG$FjdhcakH-X=ZzU|GUCSKpe^(f|r&i z8Ux2Oe%Y+dgh@4)btYW5#K(ar;ufd_QQqJj)uPW&sc zMFnUQRnU#MyR+fPYbOZLW#D2Mhl?Q;cK<*IuV40z8P+Z55Rp8D&TE3?D1PK@lR!Og zwXYscnM<+KRze0^Vd6;t)MT9(D(eCKzSb`TEhxjS|e*rp%5QZkU94 zrjPp9lLI@2(uAY4-tZ;&0ee>lr>7)v5cCO|{P>~(#~1nofdkl4 zQyM8|*hi4Lhx4tw$q~u|2ZpsQGJ`b=3)&d8!#yT^0HtPuLmXhh2=X<=V z$7EX{wAT`r>OLt_B3vb3(gVFNgj4F|8k!Z0W zE?Jr&m|+sMK>M2ugrKyOH7!Mv2)9AVA*DJ(pC#;6k@?Dq-GpoL6R-Cp_ltM_pmPOU ztgISNX_*$gOEOC)?j4@pN0DCC*B%f_FH>@O@*@yuh9SpqO(RdmlRSaW?xh$)1E=IW zuPZTT;dQh6+#it^CG$jzi8@KS(Qdl4Y-XM1TWq<}yuDx+ww|&nVrc>^&BP!H_ zxqj~dG84O6IUN2u=x%g3rU4XK1#}PkNg}0{R?^<=)!wANaF?VgtuCalLrS6^#(wpo zPJ~0G{W1<}Nb%U`Kb-tBtAHx>4Wkn?jmk{a9d*g7%F2X+Sqt+aVphkK3G`P=jMzB0 z9IwD)X(p>Xbtn5!BNk0hO4RN|C*?{sE;__USr#%;*G_eQRkxd19^BUDMS*_;5&F8Ex;=*OFz^2#|waNPM4AgWI zobdKRU6^AV<)xgWmpJnfwKOpG+PvVy^4OI_q63oWVT%g3QM ze0nuJFr)DryZ5J8+wJ?)>+M2)VXn*Gc3_Q)#7`DBh<<(>o zLD%0=+zM9a(Gb5#H;b}7Vh!*1~;ix`wVNvy_RX}DA+mhu1$exHp#sU zOV!=3V(O;V48Jf{V4@*+-6rfC^W-SJdP<~}8Pz;W(e0#@3TOakkarcI*%)W#B2f;^ z+TtNF<_C7Q*^Q^xEybN2i96Hc(t=prg>`Fja~rP6tZV&Wio`8#Jf)?VHh!B4E@sd$ zGpo$T??^Nwt$$DqJ;B~l&U#mT^8!RM%Gk0S!x!`f%cE|W$)oO<&iT}(*(ei2r}aS^ zzLN=#Qxf|t~^>`@_^EO-svD* zCDMCZv%mzSmDg+EgO9WGA^k=Jv3V|nsv@MCQ&Q6W_`DfUjc2*SvziV>f;Eq$@}Sb9 zw>gg~CKx3-h!cDMn8#QWg$c)cOyBNMEoOj&Yj;>^!&pWTy4RzTII%brai-!V;-uo(09u?%oE1B$L^wln zX5t))BjJX*I7%FeWoX1H#gWKHlI%#rjU?Pi!i^-^(L$W1I5j(C2{0C)V~H%5^2Jgj zsROs>0yvROP9*G9s$nYcrc&^!_}vZB$SAk zMDm(k5=Wvwl1v=QySe0LE|oHuaC0g6T#}tjQB(N{seFV~3Z6=qQi(d1`c9?#QVE_( zxJ;7GBtRzF%_I|q;s~K2E?4COLXOTmufO%$5Pg0l!N`@+_&u5_Y`-Slj=e>X1w+y-kn&jE@zef zs!4tX|KYXR+*$q#RtSlfMOw&t(CV4%*o4-Ah0r!UppaSZ@NP_IR>xgX6q40Q9n=`; ztH`_T&!jbWFmZ~-f+b`_^%+GFyJzgVu%uA??)A<=ObgTZVyoaQNy zQjN{8TvE!I#o!A^K-EDady4`gga9&DFwBR+0&>C(ag?fwoX-PcXHsVo34a)4i$109`K-B9|b!O)~0$c z2Gzkw;9iMyxn7~5D#ym(lpTzTFh`r3;YK{Kd5DG)8ajU3F_JL5 z$)g>CWd+(vK?ygm%82H9BOk-U{3*&9_JS%r;L_qKEvC3CglH8(jtA1&-npq$O8>ewZ)#E-22$|NYT za7_Z23NbHvL9UjO#w8z~?Ux#hWwk6ZndAH(=I3(%M1ZC*O>;jM{f4W{juE^&#cA7cjIuZ-Vc|F4KFhjgX>awmNN9^rC zQ^l@`aW->oCZs7a$IPBy_4ZRwub*D;o+X~%aMwBW(-X7^izysTD(u^;AE+N786}F# zvFRl<%WBzp<+YD zS9=w=-G*r+blH_Jr%uY>2b_K+VPfMTzKRORQ$(sl8`5fm3lQ`?it$8DlL_{K$$@Qg zaSjw43+Cp=lms#}qi7swbxVjx1XnDP-7H*anGq>Gsi8yXVp|xtT;|Tt)U+e%4VyAj z+Gdwr)+l}i%i#P;bP5gN(QUOj9oxz z`_0^$;_>IVd9n$(<%!X|jHFvr* z6n*`!l`w^-74BFOsSL#H6t5eVGjL7-%@WoTZFMRgCa|8F6{35HaUYFGqWo2*l+a3` z6mgnWDcZ3yc!}7nSMOF1*7dC{ir4O|64A613>N8azHyRF&*>rbQK&48I*?#gSrQtZ zP`GF|;(BTs7M00Y^oI-HJ@Y?rmM2TguJ9&WcSBHR-MhI&3AasXoQ#Sx0l&qAy4YBU zbQke1gaM+pw#uEdAt^olJt18dQiZ0BF#p67(i4g!y(-O-Cny@R4o*T~%PeTtx$=goyjyp; zr{s1D<+?+VtP%l{K=MW5I31FdxlxQk>nM%D(B}>yn94X3FBAZGEr;?@FTpS576E8FI zl1OBUB%6qrL^7XT5=Wvwk}Ms`ySe0SE?JsO@VNw^OP1zRFLTMnTxuefPnF82N~K;> z$zUo8rBW}c)NU%lGYOYTCNfDqlW>`oA(PZI$zUe2WK!BpN}EZXndB@x7RRO_8O$Z2 zTvEuTe7WQ-7cWXmTZqp>vQ$VDF62`clCwf`R!GhYiKUR76_T?;QokgTY0116FIsY~ zCA&tv7^ylVRcFTHNG6Qr+DImhq;4d2BT*ZP+DPg~D#S=8jFhjGrdUcbrPJalnjI-a zDZxw0StU8EB=t(lUP+vl#JP~{E+n4|sn&%=y^vxqC1Kl`w^kdKU>c z#0Sl`I0MFVfj-d}Lt?zK9~RC>CNd*gQ<>3BH*=a*&2S=&0AWcp!eNL|!X6 z3S>p%?GnnQO5#_wwotSC!k}Ar8)yY6ojNO^O14lKWKD_=Stg< zMfv+0%C``q_}XSzKV_f=+^G<5rqwbEwNI;ZO=&xkbSI1s56p15iHQOR-XUUwwUy6F zl&WKLhA5M2zD7&dbvi4#N7}3<0(Hi~M!tPKxrHT85{Bv?Z9|ujsse_%8n>r2s%qC) zRo2Nb@y;qo=F-Y{vx};-V=-J7l*X$om-Y#5b|Qti2mKpt)f}`7QEIk8UPwm8LI!51=>tLvRj>G{kZVn(-w~V`dHVZWL`ah;<10-oV41B)P0jMKH8)EH zev}Ef5d!kqQsjvW#MLO8oM1HxtbHqMT0mVD-!m(sMPgGxh#DK$qvJs_1p7-**S3aD zTVkzA1&_MLh&a(=%mnOw%h$#~R)a;{gyws-1xumQ)5U~+b?#^Mk(RO4N}T5oSn*ZW zg2uO43rT|)gp)?>(6~vCblw8Sr@(3oKrDy=r2v#z=>`G9tEnw@Y^Y`rDm_eOLKi}S zkL*c6fo4W2PSBJF1@o>2?+6yt$cbJR(}{>A5VYic&FCMWag@ZYfvLs#jM}19`Li*8 zT*O%dt)b*%)ytQ%#Ce7@H7O$yg5V1hq2rMW=UZ3ZqQDX=3B7XH9g%| zNYMY~4sk(CYg)MZ%@HQW=uyV}wydZZ6F@ml(691Rg2e#kBPY|Lib^gyw6q0riRlz_ zl~o&5$o*Kk>s6pWlYH2WVpx|JxT01-TZIgZ)P!Tye$t)w3WytU2280E2d*TdWgF+Q zN?EWRUx+2^h;hb?MzV$=;x1Xa9iHVx>Ffu*1p%x?ce09>e4Gm?I7^K{9T`7}(?h@W z;e&P#EYgwHlnE%U*+H?%sgN-!BA0Fj(CT|4xITnrB+^k}?~9c0)}tI%Hsp#+D<~2j zQF{nuBUS0#6L+#JP&2McnEojQm|Gur@(FGRdjBW2SKsZdcV*;+v)6HtMz2YS*9 ztq{JT;IbCdi}Bxd@rI`_c!!0auCw#rNul{V3x;UTryTGS9n|a$7t6&)-fw*5Bj%;VtRhs-p$~swm=qH0GS66ODYUy$SiRiF-<>aDBX=F zhZtUoMUrRf)VKl7M+wa(s9v2cu+7BotP(eYD!zOa`*LLbLgM1vi0pDLB@619t9TYi zDYaau%~~2b7esOGYbBMaq)-aGEN~`A?9A9Ve`#{E1v~i6zqt81DmV&>Eaj!BYx%Y165 z8oZV8FVNm}MO~tVUONKK%4*6j^kP)o!HN3R61|M+6ss9=O_@ZT=JI}lZ{5IF6G%ao z(%fq(WJ;;zImB=C$0WLm;H20VW4GWSG-Mnk`K2n+HIE$CuuSEIzNq41%E}muN+#|K zhhqZ4iUDV<%4j4h7_@^Hn^L%hMZl$q{-0s$C7i+v7kg<07VFZ8FIiujVY~2B zI>tf+j+Foah!Ox~$q4dFBi-PV;k!%HtrO+uGs5$!lZs{}kFpk?ioFRzd|$*%3LFoq zLy$wAlB$0+H?`aQAau0?d_2%76cu8e|HD6U57QVB^fNq$2&Y9nHKs6f=BzsaF*FDV zi9~4&xru#Z*H!>3nE(@}h^!@m+6J-v3_6-j(ikE*wNnU9yt_=!2gGdiI;he%b^D@A zt&Gj_Y)&&;v^c6H>KRQ(0wpl-!OFJ@7LiCDk!N?^j+O_F3TLOJM?*8PGf1a#eXpzV zL__aO?r%frNMo~$Rv2hpI%4%?2)&5&vC~uAV2#YIqu_9Y;oKHzfu3zIi0fz>9Z>Ca zP4WT&YSED>CCD?SX67DO%=vKuaUSV(K(l%XJ@F2uCDd4rMEW@vM#v+hnF6h$U|JH1 zSap6Gdmv|pFd9Qw4A6p5Tq;vMtU}cuI_3ch4lNqsXvGd{jOOE#uT~J0Ok(SiW)}mO z;%rA?*kaRAs=9!~cS|zcB;&Ecs0pBg>~2bn6ius7e~Q#J4Ugw=rmP%QH26sUF)7ZH z)F-Ta@qNsq;Q(^Bu{?7)pwCn4w=@${CNL?%;o5?V+;{?Few4+2R0DX*vM+`gV-VjrUU?cWF5mUwvmU3;FzZD*+BE8 zrl-7I*0Xk*p?T3KhD0E~pJ=gNLrmb7`v~-A#t&K$rU@VgJT7fa6JJ%LPLerTHO+f> z{-;Xj)%s-tP*-Rbe5<6{iPRWqptsQ`;gq98Be`p7Y?d<-B}zby)2OQx{z;+K5d51% zh_5Uyj6@*6)fr2LHh~Gk4qe&EjUBiXYTA}m`W7#VgT$3u>hVX83n$2O-CBylb|!S* zyw5G}e36&t28LFRH|Edj*?5x+Z4oylA zbwiS)1ufQ5ud0sH158`=EifEowpR7r4o0eW_qlbm4ARZA2lZfZW~&=rS=zKO50~)} z%C>lqP7~`Yyb0$7m>9pH3F5f^N1ko4m|>Mi+AJsp-zW*0@DUS)RY^s3`` zPOm!F=JdK{%}%d3JkaS4kHtAXX&A86leU>rzp_p2^u)F?@-}Y*H6Pf3f8<4^`O(1- zJNnRwDaPOm+cPpg4-|v_>Xpv{RU?M@l?~z<9)%|@!J#*1ep8WUs2>JcW_x};9 zPx&rVgBPi{i`Ldf>*yji)2}}KD?YpZ6@7};z3$WB@4jq?SAX{T?OP;wTcnr2o@Mf{ z1oijZvrP7SP=CLFzuRx`p{wUuFj1_64v<1L}~ zeElt<_Oyc_)Ws{IS9@O%ap79%-3PXWx^OM@=@(lmTA`AE&(>c)4jO+3v;6v=zsltUEjXew}x`~_Ni&-T5mRqx=i_VH5txTbyl(JoGC9|yCCSJ^%1kK;neqX_31`&bIk z>z*mz^SPr-dA@cuunoR86f*R+?F;W7t9Fe#JBqPmG}ti$#K&c<^UWE-;`d-rFY*0s z%UO@@qkUUO7uqK3zcti=k}p^&Ew92d57-}McLtdLl<82-M?^KxslC2dzWtKM6knm z@6v5sr0(#&VI~QE?;cdv{BCQf9gn+bsLh^tEIz{kyC;&Ze)oQqT~pAS&z{X~7xTO3 zvtQ-znDRDz+}pl(Gr^(X-E8oh-=5X9gB1=v?ijK+d)!+~dj|21p8I{M9mD!&j~nv3 zqhfZHa8H@`lwwD|cjR;#4{<$VFSqXb+c~^$^tU739sS37*-@F!%Z~QtdD&Hap0~bU zwwG$>tljw8K3{uY`h1kVbM!`k8^#yUU!Ux69U{AadgQ-PW7#|ZZuGZd=H2LT!<_5< z?VfEtUwfL)z8SXbZO7c|y!JaD+2Ffp)9Qc9u_wfi&(-gAV~6j)x#`sy`=4m+32~tk z?`x|4Pcha*^lQGo7NHwF_iNI94)M&Fo<0);;fL=GOi1X6V-a z@1I2b?JaEg+^YijPp|zp0-Wc5jj3M~+O?4I{OoO9eVSB{hO}eB(DkyTg{>)F_TKet zbNyP{u0@0Mv!>&=i|NPMI(*VdO?>n9r0kC*Gm!}a3bdWm}U zV(j`dbbT4Qexe(_*t}lsT`#t-_kmIGv!Y%MVlT#UPdnY+I(N0nT`h4}``gj#cC@t} zEo=irx2LToX8r@H--dQoSYpNg z*(q-}Yy;M-#d)aITL_KDHAb_9^+bC%vp^2?g&Dc#7S>~^?iaV%rd?&==!s!8)l78= zIS~`BYOB*&a9C-Pb_&cXSTdotV*`bC_LdLe(gHC*wCK|z zQ04qoxeeqDViH)5ah;KX1$|4_Q*WF#)BNDcnkGI%ush zYK)o>tb-a{xo&m40v$!Ak$#qsX;EwK*x+tllVg5yda~usf`*2PO2-Xla-?*FS*6Gp zG)Kx+oyAX2T7ul^1GGry&K)US;LA(K?VT#a_F&tu2UD=Y0FXnWh+oXk?LZ?oiM9gNjSX~q<#u49X_5;?D~)eurTT6DM*I#v0|hNNbbu>ubh!Kaqyp~vww zj~txjiGz_eUs&|7XcDO~LnRmG38^Mk_qM5t41UqH3N@b_r$f=J3=*SG>(;m@^7RO(zL$l^Li43P+<#RNNCVi*;n1!6N2|5e3W8w&Ny{g>uz!43D9@ zM~esX*Pd!(L!DrV%YtS|-wsMIm`F7-8sJJ}j;Fl}NzgpzC&TtyBp`T);$3=HQ+|R% zc@)zl?F>Gm|>~=ZfA-Z7B2i@352RcseJ|_KFVt; z^L+e6r^OJ8OE5mio(TpZ(};N#pTyHZ5WkGmaVj^<34onYawgVZ(osSm+R$BdW*YD5PqD@Br6EvfSG#ML1owW{H$YXwDux|&AIHxa$Yx6bxFQ%gHCWKw8BEM|;D zG(~1?ky|js+AkQU*=H1)tO*E}5$NYKqIiUA-k{JzVqpw$%Y^ucW&53oY#P9hPjN}T zwf6MlvJ&7%&nhrh{OV7BafzwcYh8d0~8<`m`_Sxog1$eH&lLqrV+KNun2vA4E11NaL@yaRABP6A)%o6w~2DtR? z6gY}MU=S&$_SlJcgDp%Dh3#xq4l^mJ-WjTP9+?>|6a)#w3~z@enoEQlQ=f3XDO1S+7~gG>j#OH1o1kaN)Y+^)G zJQoIUYc0etfhcVMGqP-R3-XMw@_L>Rq$ox zjVnZ2H=+URk@715s0xD}sc;1i68cw=aj3(Xs*Z|t)?Uum*n+Gvc|-rstsPRY7tlH= z_!v1>muulln0@JV*}PV4mpDs0HKnF&J(Ajt?o_!bv-Urtj@SZsr&4t^UtdQz!941I7@ctY?1ooKm@*q`3ah}sHNz#&obAlGTmisv92tvg?xDPd)) zPD5AnAg-Gho@sqJ(;=>n;Iq=YmAIIC;bOvvTh7>xC|KlPCZ%yUUx2a>UI4-$+bLNU zwC2IkYI7o(@VPTp9VKv<{ILAROszLP70!@q*|8)}b0gT-&S19WNsv-Vnw5_%&y$gL zoPIP0Yk{DRO|-`(v0YXtScJ1iJCjV^woQ^W<{C_r9*L?Yf{3|FvLcNSDxKQ5K-;d1fNabgdF6EgLuZFPxhD(-Ub0Sk> zJi%ntuSR3LN1L6VSTa>)&b)JenAP;Xd6mK6otmDJir^(91EUE&5?Zr13)oyWFHf&G z0Zy-5BL16Nmfc;ofgM&OD0YT}ZbXjJBisDcXoPht@5Y*HAO@)5puw`W7Nf?rfD3oH zRXh$48`Pv6M){lpj71G#KdG8JU2*`W7z(4JItmQwneObR=50V*r`Tu0v$8FKAW_I` zRM!d!QF0q7_syd-n%D|Mo1jOdR}rQMS~f>fQ=qZL@K%bhA6Hv>FjJ&Mi{u#&|oyWt(kno3}EOXu$X?YA((ki=hSmnAWW&k2tDx z#Gt4sMYCH~a6J^wo)vlw>ni5wL8%U)K~kDFD090GDxkBJ9kd*_KY;x>24Y9yu2c|@ zb-cl{nkkOrbRIdqVg*#F`=czYndB!=p#@glMLmw4Vpc0vw4e4St)UYR$9*XH9(MxwAJ9APrdM%?;8QIT(Gw~U< z`U6UHskA+8v(*_j%fenWJ1`Drv|DdEr7@n*~ZcHPh)H)F`6vfAdV!fP>;MW`M z_AR4>r4oJrgy*7+j-Z04xe|S-WZM~y#%thgM9#uAhb`OTrHouT%UJq4ph={;a3vP= zE{T%9vfNmgdS}YvY+_YlTf8-W3!TbV$DgaLMcYRRp=nFN5q@HD(v)%H&bkQ9F&_ys zJB&t9M{dd^)$~XU(;7H6F4WQKiT7TRzyp1unM#o%8cuELs0+vGq6x;w^v)$#DIdqj zt!_oo$Ihb{Mnc3eUnjtLZh?Ga0d0Nq`3wUK8)}G&ppB)SEpP&AwZC)2Q2OZ5ejx3J z5QZWL7D+SBmO75+2Qzl~Ane)eV6m$uvQXM0|J3A>Gc0y((N zK3d_n_Pvu=3%#s;pU_(%D6}yxPaJ65`<*rCi3M$YzpD+k;z2uKZ>h>aBxs|LK*VR8 zkDUc<#a%YOZsm4%zTQ&4{k^eIM{MPIcD~+}hZ@hxA{h zNghOh>4VczbA1EV!F zRXCfKFpDT1T8p}75huz5sbf|b`2qBx3(rd*13c(5j!SDUiyP=N8RsyWgZwZ&w_rR} z<5iMdELYVL&Z{j7#`Bo|d3dDSsmFN?XFjjfg=J0ZT$l{xw9eJRSn@$&s;2e9I5Bf0 zwvIx2;EmS?Via&7mLmB3(Nb|WTE!!qKZ5I0EDxKNJw{s19cy`d)yWwVbb8f-CvK5< zdg4}KrzhbOjMy!I#RRljG67Nkn_$sIgl5%5aJy6@#IBD{zi2yk33bIK)D@S!ty4zU z8R92P&tTh&s0r9Lo}^%Wfe6I-g!^D6w%#KhZXPmm9_-YEi^tn$d?+C#XB!=0tkzq3 z9h?FlDQ~~EWQjlj9ITAGvVNtUwl}+`Wkf?%eqa}5gdHWpUUbQle}2CgN|UPuTcAOb zNf9S-SeDI;hfk>8Xk&4&sKE1ZBrI8!(5s&$Fi>7bM@iNS69Cmgl=H|>aE@SYCkJ5$ zk~cmJEeq<$QW{Z1q39|&84#ig4_$@W5hnz(TXY=eb-yjqa4_Q!#|<$oM2_RZZf5d$ zC2gxYYXB9E!2c$5DmjmAK{e5gs=5>iZMf}Urtmjv&NrD%&u26@oa5>A5=`sN!g+};PKA;%E)i?Rzjsy+9VHa z4P$lO^)&a7+{)nari2WsJ1K$a@qqaVulZ*iPK8Q2Yi;sI&85;o)nurVpjmQjn?uAd zX!}`ISN;(!QHDX&km0$M7S{*}Sv(vya)|J)Wwn(9C3tRWY8F_QC?hqD;6X=TZD^LL z^FIhoZYUX@i8T<1r*i^wHPowkYOw-)CM}l)^S=J5K@$NEm4nT?GBOY>gJWgP09r9` z0%voqM-AYT`=>Sx>VfQe)I1h=AAx2}oWlkUw2ZmFyar$?eix-L6}BrO1o4y#^|e^r z94V=?vkF(<~O7 z1InGq#+O*);}O_NEybV@oQ%zylw!<>oEble1wzYUSojTq42k8_GEVV>nL(V04DI%T zgA@3GY$vjp6+E3ucCvyN|0*5IDU;v;#7UF6w8adW|`iY4W$NK&aqW;Lgs5e3Ve1p8h*GZTg_RCdcFb`4DAl<|UM zm<&o{T&7C1++9hvI*Sr#9Sm?jbw)=C%V#qcHE=OgGfWd%Vr7U_@?Sh`<$gYo$Ls13R!)Y+vb$O{IZhEN4|jUgCU4LnG2kBFa65jZ5QP{+bEI zblIU6Ag2o@zRv(xgky!?T%tfMfeM)9h6j_3`4J~n1XPt7p6 z$_(PHB@U11$tIRc$|4(=p=WFQnhTc%XQW<|mV$QuEka>Kz6(GqFJ zEor&996T9oHxmk>~>kM!TgO*=V=~O0cMJxjSI()p!x{`M+b#v!bL3?gf76=Vr2xt;omz!D$c$3PNcI%vN^{pV4)p6zB!+q7VH&rY;0 z`^dIngNWw5Y!X;`Y=)9H;_=)nH}15EX4G^->vGvW0*2m51A*7c_!q70b_#a&`CZGm z5(WK3C*w|@w6#~=F^di^!rIUwu;L|ksf_qE-W4QZP8QB5jv^74z}*K*P~3opRK{a5 z6)~9u?>3YJ0}^qGCWA#Y2Xdwa#Mnh3s%8l>K##Lk%bXv1yfg>y+=-_Hh(Lvnt_B<2 zCAqKMWr$R*{4&=HlDb}(s+Fw60us;J0VR)ug*GUiXmS<4SHUug2;8c@uTA`LWSuak za;=|&bUOXP!CDt(r&!)3rDd&niqnu`FDiSw`x*?&^8l0?hRdDbX zS(XhJH&g3iE7L-Sqrrq*12u+;ndDe2J?5z!hvZ3qV5;#!yZ6)*H_+mZKI08uPrumY zHQ416qB@|89VgQ`q-`LjrP}0^$m>+ImN?NikTw)uZ7RFkTzIvy^lEeQ)#md1@P?{b zuZhhSv9TUDRKt2LY^;P$b+EY#HrBxA3fNTsO{s54d}G?1lHQo|dcv;S7m2Z8LTedY zdAOdK$PB2})L5QUzMmgmdH>>)#{flf~>n2%?1BK)_mu&&dz0M+#YBwmVCEoBzc zH4jyjG_ppViDD92Q|QwhZlF3nX)_@cv21*o22x&XimQRh6=e=1uBjT1+*Csr;PUuK zkjhZHAGCE|-C(A`$nSFvrkaNPc_8S@pL9(H?$n<_u#?8=cjBKXJi)bG8rZsFH$m)p z`nPeJl(iSZS^Rvek{}+4frh2d{TZ9lU{8+5$*Qxf4${=$a}|Q!bo6*-rYGGh)m;8y zdIYhI!piEdha4qXiQt?_PLi5!F(bUUzokYkqC8Bf718IU$EagkwX72Qr4hH4DvhH8 zsvt@>CCQDi%CT~-^0~~{mBz&|I74<~J`5rtk)>iqjkT=jkx;?+)j~I50IG#e=y*ar zb6VRtY5mU@zWHAN)KWDhUqt4uX0JsT!%53}A=1*$O5k32vznK{g>hKU8-jH&iv!%LGxIqbGljxwjEQNTI2^u=&?e zbUaEU%9tbk;Bc5s7uYxA8|~ha3E{Kg45CWYIByIQ3kCr)!3@>GoT}BG+*WPjv*^e> zU#_wtS9|8{eOKXy5JKBJ%yGuzuU)HrED}ytE+cZ4Cx0(x&y(iHFksYD-WW6|&?sW& z+;u=({ybS=fyS=M*#!ey)&w3wPLGR{ADv!pU<}gUkXA8~*7i|~19>IF$yL6>YSbGI zD@EB-Ia{l5hxkgZD!+6Ee@q(u_=^;(F-2QB$u6Aiw?u;<)shtftL!Zof69WI8x{K- z0z|1g^Cq-i1k(c%Y8*>7TMv~Uf*UMwQhmAII~-JF>%-fZ)SMi%#rXzp~mETZ&ad=SxM%O*sqkA?4oSM;4{ z@i>e0+(rb^oK`0c5z;saP3U-y5aLb1klYQ{2_?zI9zO0;I_NmSPv7pu0K#~U)W!Ws za(pV87U5Qr#^=i$siH-s#ABgsYZusx8o>kf$m9aJFG!=SjbBfvA`3*I{fIoHE=Kgv zz*y=drhfq@MpBM#J0MpZTI)H);CXu8qooT`kAXaM6nQMmPe7~0CXhp>T_EBmQyX~> zwi{9EVU#x=*X)+(pVr_jI(SrhgMY4+q$a28|b$npb1X_MtLa9po-3X_Sqndz=)9X{a*G093 z9~et=pnD=pG!zjB=sY8o>ej7`7ZZ6}cH|$ot3LJpY*Bm~dfBe_beq4fYPW6vy6X8t ze|@sQU6JWFe>?KFLyf5CYlnu!(AQ>Nh@qdoW!$F!aD$f}CEKPC(etuH2cqX|tL8$_ z&o<43o|kRx(*`d)O0`YN;07;iu}~kLN?%RrpZh$^L@bi%2m?+sR0o)R^3skvLlmQ@Wo*pDYiwz(Ebnqu@M7K?u4s99ZO+d5UU zV*t3ARU-?ttSaVq0&C(pEK=Zicx3rIH!&oIe}8t7=qV?qOImLnFoQLY9qv~8$`RW4 z1}PZg56GeMXedK@0-x4`L~f0%9HK0LQe#Ud*Evq$qsUSTsv?^9nH2 z6(6-PvO{PvV%A`!puGi^kaLk$A#lNj+6GZNRagnx>QP48 z1G({{(aN`=AsY|=RK(lSqsCFiLZopPMGh$!u&4wUR85EQQy9KbZ0Y7O8;xzb_zY-a z>~sBs-J;}I%!4k-zt87#Y`i11z#?*Lg?BM`*vX0@ zxjYytT^z`zuVI>$E6y2_bv)({kU}BT1`lf#FrQ0o>nvGy=d#h(xoos`E}8x0gUfca zWEnws876dzhuGqIM=^nAmHj=NCCf;*`;`{=4pM#TxCZVJV}DDLaBRJXs{kTa!O{6L zN{4z?k7nS$mrzKDCtpV<7u?2@8WcaK3PsLEHIO^5$JWd+PzghnEQusKZTOs#VKbwa z5G}0$*AlAsvZ|B0l7*b@(wWgD$SVZj`N`QVjcApGf>}<2B~hDwqUCtTtkyC<9Fq4K z_Xf3d?GD}mH?YOi5c`;L#^OvXc9O9;IXmf`oqQrr!cHN?@<<%b4vn~c&ywMoomB(} zx-J_{0)&qub~tOp3C>zYA3u0NzpeP3zvY!+hw~n~9 z)FFr&8+u)s?R$GVShg|CqAlZip4KU`(Xr-ZY^=SO@l=b7pk0}K>&iT{`5p0%Gw7VkDSdEF zvuxd}1Bh#;6qdxu(QmL6?m3B55$_}@=LfAF^7$mLa5zB;B@?%$zD$x?3(pgNFt5ul zm7G@ZNtDgVAsDgc!!`hG6NMY&0f7T@m1#YcV-KD|I4-rkEul5FLmYGqzHEIS3v-+t zx2!P1_8NbHfn7YBa&665O$4bLr40}*MZRH~3CqeXEx6)rl15fd?J|##<<7?v*I`X+ z7Y($^&gAkbfly03Ppc)Eal$C@!8p!rj+7dk1e~nWlc1eIt{)EwV>kjeK2{wf=dMhF z=5i;*3WAYm<0Bp8Y2pK1s({Y^rCJV_#WQldWLZ$uQap~Jz{Q3_S%~GRH5_@h~b1!=*KAtN@bNw<%8Ey?!ETL4ZfvrAjz~zX3 z)Xpo_el6By-y=(PB?@< zyz_FRC`C^k`*{a*MCj-?t#M~H*cBiObOZRyZcFk`^Xn*0Hhc^sm%L4f$U>!Dmg41^ z@%Bt#WT}F4#zwr#?IkpXppse{tOjm(TN=`uKPOdF^Yz9uvh2@LtVVTB9(KNc8D$wJ$qjS)i1`Ck4*8zMJ##I${}@ zW)D8YVs&B_>SR^M0WGn|;!YOIDR_5gPy>5+6bsMdV!?+**X4Fh0_j6dxt zWK|A(e#Dd8b0dO6z8T;V#yw_T4} zvPR0=yR#ObqC(vz8m0vop7uS~c za@DG1#bJdxd4)Ndybf1*qBX4|9%9G=pSPk}wSbT=s%pie9t_MObyb#f&P1px(98K% z7FGrb;pP2R&7~B)l7II*&wrzdp-KvkjhRCgpK{^h5qS7#$C1T7_i|Jx`3_BlQN*NcPu zx9;CP{QCK?pSyp1aR2uGkMQ{9{^xK`?tgap^>bfe`TF_6{g3Z|^7ZBWCj)YRHn@NH z{w>1p-T$2Y+y#2?{ukD1Lfj?bRS*B-{>j(RdDz|iAH%tK|4Vkhex4{F-oHf%z{caf z`?nFyX7Jwqk3INH%D}DrcM!upqJ3nYHmqRQ|5t51)&n^&3@9~<X069e{+*aZw?rI{hME|(Jc5!`g{AEH-pzVzWG&$@)kw$hrxrl9^8ER@`Dq4 zz5?X-gSQ^O`0&cZmkD|J0uw%X_+vqCK6vlJ?T4>8^xX#^()$|^ZVUR+gF6(_2M=F) z@OFpr@TGw8pRaX%{O4=`c|{0!9=<@~-?Aw@eDT3uO8=%HuTZ|2{-R{_!8<@+;T-?i z17W)9!CRDwd*MKSagzhTBLMPGxu>E(c;_Ky;pTtbbFbfd`0~RaKlo_y;3MQvVgh&@ z`D;Nc$j21^3V=JD%w+*6(|3?l3it4NF6w7oa}O^+_>9t|5N|#B8>NAAT^XRlAHF!C z0H5IHi(CyKaZ-dxQtu$LhD7n)89aQ6LLkwX1`jFc6zNCejnV&jyFvfsIa{u?Ypy|Zig&aT}$yLK%=$lKZVpL(S0uZowGvul^nuKnih+Mg+w z!P$*>&u-j1yK(vK#)kwD{vPAE&Td?D$XkNkeDCb$y|bIQ&TbO&&Uc*4aCR zy!+nSyZ6rCy><33A@9F*_WsSY4}N;~{%FsE_s(wJI=gl4>^9*azIXQFy|WK*oqb5@eEi&id<*Ogxl9zFlnqs#yN==paBk1qe^ z(Um_wx_s}^m5&Jd;L(-0A6>rj=*mwBx%KGE7ySGiAs;=u@@I1HJi78Sg(2v3yv3_4 zuRpqc_0g3pk1l`q=*n9h&y_zsx_pfw@;vzV5^EbX^=gn8)JpT1dPrm%+;M=>ufBN>jPoH~*pm(2M`I6)K;`wh+en0s3 z%U^u=(Q{1r@{RM`w+9r@Q``{{`MUqy#4LT=Z|0i-QfKC%isOv1E$@) z{q3D!49?$wpAu&RK_6S_)2DBIJ~;oN$>HtW=Rg0egTDNWg&zOqCPN?o;^}YS6zHl8 z@!{K#fAT6rAAS1x&vzKQ^VPQ}Zw}7yULhJ2?!ABh)8CWxktIBS;f?cm-muV)?+#juPC;YlgBUreDL`5S8Z#2eD9;D zzkZIL-`pHLxqRmdwdf~5e&z9-9NUvWeRTfW9~ip+NBUY0x$*OF@4jv!s%8gCy*+vB z)hEBYCD7;RuTZq_zhoQvlTTiFa_3hbL@mlfw&cJ*e~Ep3`r(sLuA;SDsHHi-gnj;| zrGNL?2OQhyO$whkF)?JTiaP4~AD&}}+ATRx{`Na|YzhQ@{-$*}ae?sa-nFMUxLUq@ z{#Q?*`~Bd%m+qqbeD~T-+i1VL^%-@f!FM0O_v9yU56H`RACmL>XSO91^zM?aC%AiCk1|rGPIsU0oY}{5+N4d|fE#dTIbUI) zqNO=!wbIGoz|B5n;@Kf&hZxfBWD6-~aDFUH_(xx%SR{ z{HJR-JausX`U*gnUWKbw@#Xvs{57cOweJAFH?MkUW2de1SM7*)>-u@`{16DT?@srN z+lKrKgey~k@h2n|d{IAg|j_Q>Pv6Gnn zzD8%A(LIV0lr2POl)t!MrvTfG4PESRUC8O90>AuFAgG6Ka5vQ{Bc)L2{b0ME>Mgi~ zrWUtS08-Y29(C*%*Q?HkwL=vrk9s0c!7W?V&Y}SfFLk>v+M=-4a{E>m-)K?}%H#2Q zy>Ah%#Dr@Xh2ne++TNWI?%FFVmTQlU-x0~(Z(-gk$$;ChM=H`+hj&lHCKsZ%MRU(7mA1C$P##G3+`YQc&HDO4dCZ7?rXrd5ElgV?QrRYGvxBmylrNnf&e1RZ zk`hM{wSZA&l)Mbe-5#osx#SGJw$Y)5mR@1>=sOgBs(Zs89aTl&ElN6)?MAnEk}`yP z>nJHbRhvYTLZ=pYy?F+xRo%(UoGRbq!ENt*Lv;Q6GdcW7wwJDV-b%U%n|})h_LL|z zrkpj9v`epJNAWQ9a@?rV)Yfi)P1-Lh^mW8z>Ehja6Qd9xAhTLsxWYsx|Y$kHA*CVisMfm zl*p;}391_dmE+=4L4{}E_JOd6>+k)iyp5F6n~vAd9ZW4!k%o=R=cZ~*Z8c^W#x(Jq zD|Jft8DcKH?WR0;cf^bFrYxS@5`EjQiD68g z&zU7`?YdC)$lc9uB9?(d|J(I8e*Eokzr0>A{`zm~`s_b`k+DU}nOP&g`~`l0`SrKy zL1UE)nhJWDPXz0jK<#uzdFu#tc2NiY+^C>|8co$a(9oa+1B0XXM=*V(iH#Ay@`s_L zvZrhUr1Hayy9Y*4P-rJzY|uev6xgl7sCFxC*=md`?U!GtRe~dz{gR9De*5j8*H!mm zVU);!TyC7JnTmx=?AIU5>Q|K2uYdd7->%a}?r;AY?dezji5TEe1aK()-+ui5H+=uw zuM*jBG#D&8>NHCH9q<0WXsSU9O#li{01EN%8+-c?c>9l$81TnG0RH2bU#`)8{NwKu z=s)<)Kk?>2xO6Z z>X|s$q;DA|p`#6Kp1QZDlx_qs2+I+tgEP|bO|D0Akh8ttPQdNDQ~ww@3RZ&HhKWM{ z=qMHawNw0zc-|Q9H9svsJwJCm?+-jjrjPE)$?w4y@m%<6_{lyrzeRlgb>?tqrYveq zUoJC01D>YiC;KxSKVSTO<7qiXmf@9st{j5rZ$10>>_2b_fqkMv=*g*$OxZ?$a=cGY z<(or$bGqLMAysqV4a!h4-!i;smy#FMh7TYjQd|EJ;i&Hn4e5xWC)Q!(McXI!13k(B z+$jz=y<0trP_}vDHWGbptUzS0k10J=cQjIWR$4(15{bGSJ8IYxsGo{hwTj5 zn5cdR{%GJ(qMLUKWY7kqC6~v*!~1suu%&RH07bitbn%)*eJN_A5{Xhj5I2|Sbpjww zh8)!Du#al*xbhN+CQYTOq!<-`53i-GaUs#;YM$bvH<5eeM3mS4vfU1B@WiF9BLwEdVN6YJjCh z5{YF%Nf8wiQp>Ircctu%o7Go0V`P#fP2ANdP80Pr&HY#36w=nP9-SG89ylaTxz~_< zN&H17Qg{@yy{ZWW9=^_UObgvSlCQ?B`UREs+9f$Il;T7yeN6p z{hACjF`R~>ODDs~K{=x&_Yg)x?~xjAFc~4?i5*E`CexUH ztqLYg?n)!Tm`Z~Bc-58kd!tz^$r1N$rg?!j$=7=`+%3^ZTNqLK;r{>LCN& zd`0ohKa3o6H&_{t2^{s6KeZ~o(^PwI?)D@}aU>d@e8j9IeMO`SRKuu#@Bwm#PQwp= zrlCR{HCt_e@Fg!Q!dv|m7*R7ud8!)QJWxxfN!jdj1l;X%XJkZKFhsX(2h0ncR|!b|L=!)Z{M}QFIp?zC!Uv4XxS2M_=xl*YLbK7dh zSJ3iaVT`e7y!%F=5%>3v29z_M7}trUK1t{Zq2PB)DJsyYPkP+Be2DjxAe+`P2*tQ( z7R|*;Srj+qMJcXB6R2v2u7Zw;$;G@nWzur}*lyV|-34Tbon6rZ=R9^`=%~g+peXjHp~gNgSu@AA`0b8LKxhhsMHfKl;1_g*kRg4#Ke=zWz)xjwEDo8Xm4{Y1UqNR&k~BN7uF%vjG~XbDpibdn~w=Y_2TH zjrzWchu=2{8#Yc5kg_LWD;37LSG2aZpgU8#L|~u^MAN(pKl4Ts8|vzD#J8LwE`3c7 z6Ay^`>*YyoLhTYkNF@WHrAyykFTA>>XaaWm<*JB#QA@dDQ89MQEbXoK^XvbDpWpt{ zPjFkD{s-~!`~OK=4nKdHmcnfWg5b1DZVTU8JFj}IAtWU7Y7~K*KY>U}V2A_px*@yx!H|d`EK&thESNl^0lN`uU|-R@S6A5Nd&M zoe^b62u@`bSXWF<>8b7Ei6Xs)+vkBU5bPwiyo!Y7RyCCOAk}L|h3*Qxp=X1;|4#p0 zs?-&{S`a%Ry&df6_f0R-{-|J5He|Bwx!d{fh6f8qZyMF5^AR@$bHdt97L5|==oY>+ zn2>quNX=k?POV~<1m91cLYE}Yx_qbZHA%}eQVmd#g(RQRTIBb6wDUBZ@N)v~LCvcG z#G+)5Rq4gYT-Z7(2U{vI%!`?GBolp`m*XC zYgTAfOsMgJDxP|5YJFiEX}BD?flw$vOeuNnAJLa638T)mT@so5pirvPoUroV2BZ=5 zOihC$p0!Cp8tlXTbW2LroX6up^QgK32FuGR%PsH*7VQ3=>AZNOuikQmI*!&@rmcm$@*HWr=vKZ4d$Lf9#}Iutj-D zwy4)(e+fG)K&XN1=P|Spg&NY6YxQ}J6w;FhR-L-~lfsi;L{RQfPfc=p$8OWoo{so1 zH)(-*Ns~bt*`5wkDc-;6zkAeT=quniE)E-$eXodnQ#(lG_bV6@G6be}^+|Dm>Vr2E z*D%C7-kHtr-HoQ+d+x})w4eECMmzS&n}$VQ^UWOnt^BRi51NsHoxQc8ay=M7)@!iT zcW~`DFAd{)G47_9v?lVy?g-P;-c6!>{oiT1l32v;!jo8Pp*QSe+|UJXSm?f;w<~D6 zP6JGmH*YNK&@)MyG@GYc%}8<`Dxa{OAGc-WQ3o(h2xo!&nI#TSH68ewyKJ+>|sf#ybIf)u8?ElPY@o_WKisi|7G+oF4*13yR%ZHDO^Phu;Pfe14_P_Lf*6S;p& zt-$}1fnPH~{f6et2XrLP_e;0;BuHjB02nq&rB`?7IE1m&mS1Vfay@On9Lq}0^td6D zSblN$%WU0i;Wa`iKcp9b@h0rt;u+|>3@qC%gS>em@SqZ)wghNffD)X}fKdgo`2+OR z1g2sm$XTojXT;~^q#_4Yl2b_3VAl*{r#yihR0eXmIpIm7m3B+G#8+pnP}s+&yq5k9 zMFOs*ASFz!OZDQW1O&wcP6m!j52{9{S)-c#Rw3Nog6>J0dx|<1P->%HOch$jvm1@) z;Rr6eTAU-i?i-Z)s@HE5jcerYME$r?G2STsw}8RscB43MPpb5utG+L~89{UjP)ZP~I?q zeQpN>A$*fz_oggw9A+dg3hAMV@YSV->YMVT1W#SoB#(Zi!al#W&X z0z2j@&PyB#%!(K5*;ys%RRUXu807OP5k(+OM! z)7zu-X_Coc5`}LM>RLX@>$k@?N`Div>iUYTpft!L&l(bz+=p5N1{lzP0%6^!~QDc<)a5 z>Ag}Xd_3Wy#Z7E+d-5Mo>DlV|o)ugb$xx+XsLJN9E4T`Gtl+8gKh^ZAoOBgFx^IE2 zyy+@m=u;VZbT{L$?RJ zUTB`d6+kb|z|GsZj)eGr61`Yv6ozsIW=oOCtjDe^%?3yiB+y?MDi{h&1P<)L`5~`= z5DL}Pyg*Ij7lbL-$&N0fbAyvN!`GhzsL9g^2KMLf2zeF;>Xu>IM@O${vM?#1n3$sp zAC19U^~~(uqMxF?b;G*4Y!nhGP1G%KnxtQved9zF(BQYE6k$T<>>=nl5M{V@ZsrG% zx8x>49eXl_nniY=Z!UnvL6v-F$Jyi@VZv9W2~)K#PzczOSN25yfp|!9BxCg|DPnyS zxZK8@fC8j>hx^3uPM>poaJyu0r_o5+K@b`M+i7y5sBffZk_-|9EIi2OPKLpQ639uV z%1#O5eVLo@1{J_ec`A?I17LqqA*b!boMVr8 z*2y3=PU8DTbFk3eRouA;p@wMcNB*+B=Qmr;=lmAJH#8KWdhv;gMn%}Wq@zNhm1PS5 z^{2I2rpZW2BZVq+&mfX?2v^y$`M~T=7`)7%wn04}3DnE*krdp60DSNvrGoJI(s3G) zS8fd3JYn-5>Ds=p)@(nl)@(nl)@)_9W+TbiLF+cpm_UfokLqd~cK6C2-)-~bhkrkf&Pcb*S`{4&+@QF^1P5BD)62=J3TGFrUAQOI+Drds09(WK+jJ4A^?&$`tF9` zf@Rx5nH1R2)ru26^+r4%A;mfpyOD*lzMFbglu(F$<0mhc?v_@=2-bJ!?ZHBNETr_% zce0wgY0@Df!c$wSP0k8@86lfA^(tSR;ptOSjq=E>S^3dn|1@b4Fm7`a%t})Y8V8LU zv};H$#X|Yi4hlUy5kiLDjW?gzt36U<(UlHt*jH)k1Uux!KD&$TQ?wYD<*JBJSEC~+ z(Y@ev#WAz&f^`!pV{zXhLB8VwbdQtnFE{9A=1&dv0Qf-Jrd*7vT&A(C)$9f z;T1oWPY%;Ymm7@t6!67h-!FXyLW5((V?ZC<)`W6Ek=Rf*-=-0y;|Ho4oB;4Z?c6wQ zOjX_#KYVT^G_9wH=Jo~$QVxcrrD`A{`nvt%vxpTktml;`5urumQ+?9h6M{_!a-QSe zxj~9NP7aIK8OVC*efOzT6XCNNJVDgpN#;F!M}w**W&0~Sx6J?J3=`CDxhFz3X~djgjHl_@~}+~hQv z9FfW4n4EHx12j1cU{dtV8L>Gun?tix1|AtO8F*$OC(mWiE|;*&1-s@1ubJX=Izx^< z3pShYD_bG;>JT^-GjYg8$gCbERXQH z9qb7Q>Yx^TJ^9r?|9QbC7-K4Lef2ET(=%;-^{St=mpM_d7VI|Xj=+oWAFWnN8e?dP z|7o|bSJVrzUX7D&`mXzGmmMTCCPu6R_N9o;FETJ3_}70u2&ebe>pT5l^mhYzh;CN5Za?Bk$~FY_P{ujvsLS$-ylu6T3=x#5LtqO-RDSCXVWLjm z-a*$K>NVx$7SSKjp|@F2SZMP$x>}ZF()1H)u1|t6?eX24>CT>lYBY(2HenDre|wTD ziM9;>m_uefd?U1TO^~Tw#T15_p_)gsc|Wxq;J{<2;jZiUUH1p{kO1#ikJC$i6^SQ_ zn`WQkf&)`DDO2G>lS?SVQpe_&{DYVLV&4w66==x~ZO4t! z7?XBuKRKEP(%5(;+1vPJB}J^s*AuV?$);U9w*D8fvfUorShk$q~(zjzbN-UP)fI2-EkAV&|B5^%_e9 z{JeYW{K6$Q>o8$euculc6uX)qJ)S#1SU@6|clCPx)JsuW5&i}e&fio@EJAyKr@gvk zhU7GNLZ3=hcxam6lTbCwQ^n&n1rw<1 z^C=j@Epi73D?0#c`5Ai&6+*%>CxOQXJgHOta@}a&!6&&nUPSd>30UZSbUSGpW7x!K zQ%pQyCqUj6#V)rJ^N3nzE^>^}QB;OP{@hcBh)T1(S12H#HD^RlSF$OFh9EfyzOD@t zvONl+q?2U%fOAb-)Ns)53rYCZc*`_uOYsQ&zS&-KSx66kzwZZ1uUHi^BiR4SFvQ&q zLWLnCYAYb7c?G%5;1AMTuFuFFT zS^OONY4|Dhi0AFbPtDH)6zbxS-KesXA>M2ADpc)sx*W;~1LFe6V^ z$0vx7KoLLVAVyBsDDaLaxC-x5$>tQE9KPmYG{>Sj=?~5r7$omo;pyecA1^&WIZnfA zH|)u9l!l`*oHN6Tw(KV>qXFcsT26!IBD3sK^1Ckb#OW&loV=C8^X%Dk%$_NM6CC*S zNP@IwO?Ad5esal24mh&k$bL6Y)5a;@I8hsiy7Aj5$Nc1EzS-xSLwF<34nv7Mmcj|f z63?LSsyZaq(*PW!l2RNL>pj3s!-p6E;b-37Bjk__-TkiMYs|AVw_r<+oT29B;17Mn z?Lp!2*}ZpGS~hPnFd54T%ZubA-I;c%rgy#@9CTRJp^0%`NEW;r<2dQ&+V$ex#TmuX z;w<7MpZ+85ShDjH=gkhL;c#x^OyWo=+<(ZCP`Do%9<^n=lbs+={78GA>`2hPgwo6B zy?oxw=e?w*e~KeX>gDr6i6h?)^1&csD#^4GFG@14BoRsyahFuz<@39wbCeH8$=@g` z8>N&+N!hrHlRl8ZMoH%=DVt_-ZU<5*Q@fAn^sMl^}ryi8e^ILGm6X_9(37P2Cn(g+`oRRTgF7##j&BRIKbJ;gbBu!atgRZbqltKBN; zA(y!exy)C{Wp+U>_gJ_uak=x5>k}U3JLtvhr_8k=b5F1%aik6nfQuAn4Nk4fd!-%C zuP@k~`KucAL9-m?pU}uV=t0@HtRItzzM1OH)=xA5chO-VIZ3hDo7SZSH!9CPyJF<7 z`rOv7bX&O%z(GZ9KJZw;+I~IQ(JH1}`rmo{AtG-g(-YkmXSUEHpykva;3CZ4JXKmv zn0W`hPpkJdy==nZQ@dsp#y&fgt92MhDlZPSWSF6)hj} zUI$v6-!wW0JA}&oK=vmBiH!@}no1M7@W~Sl-g8ZB;?&PJoLAZjbu;v;o5 z8Ye#)rslerNzLBzG+?jJ_V>HN2!`iDqQ=8U4;kY9T7t+ICGuSY;~m=mP4nh~H+KmP zd?a$f<|s|PpBQCW5n||gS!U=+$fV~$KQ(TcL=f;$&L)srA`R8h4xnTX9W)-W7O@?0 z0IbL6YylCdQy)e!2#?ib(7?t*nxlb3x0FSk0p~5kff<{0$WibEmhb4fE?QwygQG1U z#X@EICi0t;r4**r%XUNn#~pC`%ff*rJnR5UOa;Zb$Ec^W-H*52eHeKXCx76K17=GJ z{raQEgT{$j#&-I>I~=~R*2`r3Y3NB-8-@#J=F9hcZ4hlxr> z!vI@ur5fAfX!2Su1F@Bjq!>Q6K?Eu}J<=G+#hSSdQz0ww z0VbyKN!?NcuW(L~!*4nC>jr1|#N0q~T})*_4M|GaS+Lyh@Y@ERF^Ra1#+j_&pJAc1 zSyUm1WFMex&kPRXJmvKAK=S3{ATz9-C_ZmOPs=b(dCw4+LThJ@^8WFvSe z2?3Jn)T-HzhtKbbOViWcx>*A8Sk4-}7%E{G4aR@{nSBIdHds5)FzPvjIHWfOv)i2C z1an~}n2Q8_URq-$R<_+b`flszQe+zy1CGjvYXP7uWxDKb3(C3_gY=j=8J0WP&7d8aTqLWbn<2Noc z%Hh$AGQzpfh@=e`9QsSyOb|lAZu#Yi7P>o0RhTfMU%GfX;g^&0;xn?ycv%&KDJqn0X#QslXW>RC5yCC(_0M5H95B$NQWOAzBAj(jvqK1NB%DES{HJ>x2l zWMGs4M@ikdvop=&$On^n(SqsU#gX)AdH0YE%#x&8qMapWvwSy8wAkQdR|;U32xrOp zB9*a7Wh_z-izH@|^ez(bBE`7K=SFgEBzhws7|FGf=#8Y%$md3qZ6p*UX)&MTq%b8( zR>HKBB`b+=lCxEkyGrbXl3{sRqk{BeaAW;R$Z;;?Z`atp0p>ejQa{rq7qj&)T^}k)I(9^CphHeaz-+cg={goYDgDqDBgQ&X zZRkVI#D8I>gNpJe{e89EmTu%`v()>i>4pZE?|-OpEOMx2mT#WQ4lpNid`BXJoJCNO zIp}%gzGp}p{DhV|nuhsd2r@TVZ>;8H3WLSW4x4FCm1A(y=;BG(PshxJ(hzuwpB#^g zIvA+orD292f!^xL4cQ7=7SHnblL9N@_$~MG6ALbiiSA6ivi5mi3f2Rro+QWSJX7@P&9Yy?~# z^x1JOrPdyxsjoum`XMi#5H#~MEuko!MQY*--Pvlf3ep|}jbtIH&ypk6!T}XJ z-So3hGZ>)%W?^u~3SxOcsCswdQrg#Mb^DPMK$yA6R zVl<3TS)>dwPSxYZXzD>+ZYftG@;oIJ6c+ocNq8d3#4jVf*LClxS&N_Rk?LhiJ%4;FCze^@KMx?C7?SN z*T)~X1@Fp>GQ^z=qB}s%t|W#^9LpJ83@S>BVkvgEM{}PpW}~qzis_{L#BFZk-a*bR z=#w1^I^APedTye5JX6QMvtIRGcX(j$BklkwIIS>Ox?>rR0cyEyCr&ySt1;o?ZKg;AIg=>hp1Spk3-dx zAXVvOB(%z#ttAXX(}8M0X&D7qV(|mJjG1HdJy~yQciN}3;DBD;vRv}zaM@==9DeY~ z%^?vL385=h5hlM(gNiIkZv>k}Gte|;cZ%X_E3UmKcNEtr|4)w8(0B)cm^&VteIbPS zkW;z@vGVKvLI0S9-yhh-<5v$QQoEdtyDyy}9d;3h1jEMjQMe0?RS$4uIYxh92LF_T zS=3D2GS3$XE%SvtE2+bgLk$FsQ<9JbMglZ^h(#N6*L4@K&Zm?)Q3^r^3D(CUNJiH# zeTZ`q?7IA!n2~@zYG#{D%vU?&_LKfilpR0b_#)TZya&qFxX7{QJH^B5LU&ePzws4siN4aPe79^i<8EJbVtM4zjiVf_yt_raq@9~zFSCMWDGrh5Qb~%rJN^y) z$ojklvpxbW@v*@*;t>}yi^Xf0K-u76M%?CQxe`dgLTr9RGk^>qinN3b{1EO+A${UG zDz-wDI3wY(@PZc5p=&2xhk`HqB4^kn%Y?V+*MGg72@M{&VZ%+F)R8p5aIy04r{+XP zqe-mZmaa-YiYZPNAwQY#0C?x}$VPqdE=tJ6wq;^|fJZQ>_V0 zhC~ahXPsa^X`QOmce19;=c%CXQ8EqfCz5|+O?c}tclMCo?w&ZDKDY)p>UjfT^6cIm z5AzaJLGR^d`|fx(ZZ8sybS$JgybpSNRH6IzyGtSmif<9`IJ> z@mYoctmv*2~<2EP8C86nAv0tFcw z;+jsHVX_v9u;D;uvtA*jvi*|LY$Wi$!H%zfb#hAOzR|>TK5fktF=@jRgdsf+usk2% zEM#tv)_^()Fa>d@X}+DhXy}0?*H)bTG4T|?Q2Bbu*?oU$>bnRMp*k-u6ncB2VFPXd zo&ZQIX zrQDZDT(8A^IEaJe(in@cYVo@P43gF~jV5sK&h?C|rRwW=4o%2LC-Oi}nQFaow5O(P z@sk@%k7K|f@wF25{SqKf?61y1J`4G?Kup3EKe}F*v-kJSK|_f<+2%r+MO@!JT34HX zZ#CboS)d~fzkR#g4n*kGoXf^<+~Cm?$5a(T`uG;A8<+?SUEPhLj(QF&-rNEw-PjmP ztBW921&Gw<*#u_mOu*(tCOl<{U?;h3r)fYa^MIX1jyw_g`ZLMnBi5`&tQ3sb=gqGR zuF%m$|K(S(sj>SI^Cn}b4;8MF=FRD*laJGlCqUW5vaN7J`hcpNZ*t0oGD57!LvCfj zfW}x}@#z`G78%?iPYB#>b+}xDNZ3=)5``VRr^ZTm!d{}MJa+H~8v`G$sewGTE+~op zUOwJ(L5&^d@J9bUtc{r5jBGJ_9OxhO-*I52HF99xj3E$rSiJ#8x#ZztRP+&)aP6C2 zDw{4HP$m?Hn2uxAqoU3P4Oq@1wz;ZX21jMicl_Wa2F>sJKn80)umR>#oHsi(!jLm} z2R|Xyb&@jco*9xyv6loyOGt6y7dpRSm4~stS%^@Ygm`t4#Z?I2MDkn+fqF;t|W$BNY)nc=u?W=--KE{;26+O%dkBy4*N5_8pE|*7wMd@WGp3 zc?axp^;-m<5vQ7ICL$Ft$k)FT25Sq)C)T}iJoC8b6r^|8Qv7llI0Uu}kk%?k9WOXf z8m?aR9lK2NYIUp@H1fTnu-!?}wB01PfN;65RxeXyGC#fqp)m%rev#W|QKx{-cz zbv~3yQ&j@}kTx*^=UErQr4u|{?qrXzKQl;eyHdml9OQYB6n-if@1lotYKoB9Pgunx z=mq60^cB8^BRSu0(@x~mr4*ndI2y-ZDGXdOgObLIkLVeW%QoigcSlMI@70dxMlA_9 z5%G71ycud~)QzlGZ_DSHM?Tg)@)>S=R{B|lrA@Mt&t#9huq%V<$fvGHK6Opcw0So2 zA?T40HjjL;dE~>)BOhZP-3=-XX7DH+9>Mq4rtqwrRCU+i=n#e*cEttbMt-1Cv2(B@M*F(r#(Ly5h02;w-gm71n z??hN}m!e90orKeHU)>Bkx()lo%t_t$l;%io#-}LmY{WH-xB*QAmHvdf7CTCuyEuzD zUYsD#CeE9kTPMy<9Qh7?296QOew1GDgt`_xQJh^I39KK)k!XAQyqC{=CyvD4e~KfY z58`tWFM|Z8Bu7eeq(*Th+WUi@QQ{lL%P6VFZ~;f69VOMHL_11+)69;R@3bUW%Ln>* zapXHKxz!TwLlQVkT4sr8mc-BU`Miqr5=XMKNFgs$$ctobkwh#K(IOEo644@+x=3=3 zd~PJUMq)Sexsk*hiQPy7jf80=Oe1+W5~h)qnH01nki_pO-&hIVO0ZUlPO`X40k0DC zDqdEJc@>|lM7c^fR*B?yNxzqOUXtS_9YNj&DVoqH$4LM|DmX}@g2W#r;vjhq5^9hJ z6(q(e?IViMD9MkK(kS1h{6>i=N@_Mq%_cc~N@|``?oavrCGqV-e9H%KiQ&zmC|{|M z5FS}Pqjo_piz1Z;kg+V=j=XF;@(#y{JxN%sCg7o7GCcWC#y42d^u!Q{WAOEzC@}zd z>g;Wua5*jmj_vIc7|ZoVKs3|dM>wiWw=Lknl*N;nBG`}DrU(mOW4!VDm2V*(z3X{; z;N2W}V}O^)Gpa+uE$qLdum~I_Fb5l@GN5{_n@^Oz<&YitqzgX_;ca(rJpw_h^ecBG z&&s6aNMTUs!nG4Qk$@=yVn%pmi=p(Ctr!BPB?FoA=iU84ovd^X{$E{<-6MSnu z4d?{ipl3L4J;o8-mJ<$}!s7;Rx#@wQ5mrRU?LlKAo7f*=Fs_IP+mcEkFSd-Ed*ak5 z&6(vC-?*VZHok(<=teSrLgyLJ_#uZ*N9r6TP>&BjV>*6vHBd5l8Wyu{F+p%KUxt&R zv2k}Z?wqSFnvHJ`;_Huk()#ts62AUO;D7%=>)GPhf3q~B9&xPPu-1#16v(oC5n;FOoGlAtxR3tCttAYR~bHI!bu2XntSMzFRYK( z7s*c@EbBI_SVV%MZcc>4bxw61Os8uxahe}i z27=pAR2I|Ts#)81C6);L))H2uQ>m@1+v*1D+q(9h5r00Z2E!7lsqSGV{AiD!Ca)2< zGu~R`5)&?yJ?yG8sv8L#D~mVE5JZHj%j~G`U{Y$CwFwSBQcseIx(!{M)j*YXN%s~C z#(Ss)rYZ77ZDTww|AMwl6RK%po29mzRa6*1Wvz-d5udsZXEkgp6yop`RlU|nY3$wi zHF!`ZNLOd*T^X^QFx?#Z*c5SXV8q;L9y$&8o*!&Kh8Pp*s#|CZE6xRmt8t5;mklAI zmh=clGERb?`E#~?P2iKK>XV|;LYMg$E+XwBWpkS<3!;;nc@^eJw5lxu5XPjSElJ-Q zINqAuJ`On5dD{+ko(an!T$p7&grJbMJ}0%ZrUDCNlSo12q(-SY3tnA{h6IZ=MAED` zU*hmsz$AypsjM9&7}hc}hWi0Mt2%mTLP>ydp2NodB-f#uuRnkCEDA}rZ<>ROg@S2} z&kwA{+Yd2M4NJ9R2%PQIhGTT+y^R_N zCt^Kr2?=`#d?jy@KhlezZ0@F4N6%{en7oDk)rS2SvMe{3!9wWs`EJ*PzWH-$r8lpi z=_Ds%p}R1BA@hJFi9Gff>UZCmNP0)n^Q&`!)VZiVRt!0jRkIh9s7`KH9vfO~kvLJY zPbNI)XfX0(GqO+i?Gq?7y1Ml+mD#6mY3+_!MU3uS{&ts+tDU3cM6m7P#9j21z9Xrs z3>;KH{w(v9P0pk8XDuaDQ6Se;Wo1--zcBE`drM5F-ss|_Re52om;nYpsP;XNq!q=n z3F)zJ(JSufgkfait{S!h+d+{?Xxg=C!SxuM@`D;rGgfL=TW$KI&*EPdzn1~6756k6 zW-S7+5c@iF3F3=coGD$=f7^UZv^w?fBxa+NBfCxV>r#TKfE`^x9DfsMh)y5-f?|!V z-g7x9xcXcjwxsflbmvM-4gK_;a`tr!YIpa*mX52`#JWM@CM})ade1tMEGqOnS+>xB zpvN;+^d%>a0R%^3i}*{k!1uCP(Q2vW0ILTThMNMc->wIE}|8U z%`ozPdXHJ=52RMu%4y(hhXMeV2z>P-xu&{3n$Xy#xisLfe;tT)-ft)M#T>=469JsB zHA=!e?pJ{s7lA5I_n2lt3C?t^u?L3q;Q{ufu25M{$o84aJY$td!g5&YqMnYPv>8zjmwFLJFdkj?5NdPZ{Wj7a2QRpq$h^y8!qYfX5Pyc$Hv5I{d*fkUC=GliGW{YO(-lC{8g%v0NB`DPOpxOF#m_QWOQ zV{RW|l_CyuZH-KXVH#sdr}~nXKz1+1PP2I4vlaoSFWg)r&ed-TSmp%8w*Xv|5qEvD zgG;oM*0n?yc~_0Oo;;8Iyy&+V1#f~`4_xNFp8oTC=LFFyO)vQ989iaz!%rupg+ml#9n6`03sy7{iR{rwXa2$&FQYI1}t&X~4y_+4qbh#~` zMx3^^F*-f7lKZsNoQ$5h+APmb%V586W7q725e1j6e@yS5i}~x1vM}`ZhcRD&)N27> zf0W7d*MFI5jD^tw`c|~Xr>}oEOEh19R?Qg7WuTRR@c39{(u&r^ zV_i`78jbEZ{7BknY@mN^tkLtQ^BW*zis@lRUo);fp39S;JD%{KJfp%$A}m6&9`4ws z(iCKr3LkhA3r>7}Xe!onrdumT=p9=b`c8F`Zlt>8E2_9&60xC8YHy@IF;-V3Ip_yA zvk0yE@MY~IezUiyMZB*)y&*JKQWz+<@j~3w;px%SvP7?0ZY{iDYQ8XNJwv6jsLKgj z+9YE&qZLXWCGewtQ&m%^gi{ODGz~Cyf;RSFg+f)dlzQOvF*@JsjRW0-D5|5d7qIDe zl}j(~sghlAS!B>eRI3TTI5X2pPgs zLEz{KktnLV8tujPqVvvR_nQnXdu?qz8dde!{P z_V_V#u>F**cxpLX1ZRxwaAghHriK$4Q>(JD8i>QPI3a_!xy{WRZE=NR{E4h-Ts@J+ zh|h_b6q^z?t+_Lp4%*=&)x)-gVBHB_Nze{04TkiCmUq4-5U15BIODT#BNY$T|~Y9Bk}xI-(5N$LNF}< z5%KpANISm!z2wJJ@0AZcPN8C*=XkfZYn~|caOp18?LC&TQ|K!WE;McQlJHzO}LrN$&k?gCZV#uY3SlK&QU|1XD)Fmuk?I#<9ttl|aTBl9SO&)kT``isr9qKp5NbrG`6f;&*%(@_z zR}yy*j0E<9&EeIlp!rp-@!9g+v4n^zOTcBUl^>Fj_6Dcfg-^%54npj3k5^5!+vf!h zu?qc|-~gotrTgY1%OY=6@0RVT7If`&n}d}GG{nDLAMGDHh4*BEuI-C zxo2qzSdwc97V8!@A-t3-X~J3z>X3zDiKvWFq0F;odJ&p#-t_XOlT(l7)l<9Ww0G?` z0|;C_-IN#h%WNndf^bkgf3LR!*!=q`EamfLldV}oxt*cVPus%gcVUGI;g>Bx&ATph zvp*=BBEDT+@x|FReq7Uk}y5=H}`!68?q_G4HL^agjE zMrcd8%qEdh>RUA208mivqoU_*(iog(M%Y8EMq&CULUl@~8ac#}_{$ZBk!V^BugX3z z0?KJAy#9fh4rd*6lGx47kv9;qEq9c7#4P2Q)8J;-(|S#WtQ)C8@O8n$D06bT$<)s&25TdERkM)8#4!2@kr)~YG{ctIaw$n1{SQ!Dz>gz2j zbhT<6liuG;^1RQ^1ol_AgZE|~mw27D2bMS=R~}7?en;=XB=T`(V{c-NqL*928XCCX zqvHjSM+Y5Aa?EXC&~6@BDLh2a2ky2PkCp!CqkDGrpeCKpi#%X}R;=wk`WyZD0?a4Y zp4a}W=h~prBVBU&6LEfjJctDzX7L{bPdp!r{s(HicWPb7OA>48alfh4hokwO zUa08NjNBqSL5L`CPCcBLcYZA_^Wj1>B0L;or-|vdY`Lo4=3!iv=hF#+G0bnBD0>uo;{V)uv45^--dx>ByL5O-dAYEv( zxxmnpoIWu%#`%V(Nu;?c&6mVl#oryl`XllB@{aq=use3pl5+f z`dsv=R+b)-|C@PD0y4yparBJR6L%T$$7qfhf18=JX*yX zcvE<$q~Nw^?vEb(ghQ8+KoXf8HcHrB;4SIvRuTBhnlWQIoKm9mY->{j#@_dF>l6s> z)ESgoi-GVZ$j%yp=77=`+l;mMK5-o%xA&gFO=hge_9tkjYbrLJnPKRfz8+2!VWA*% z^(UyUX6Ojq{EmtaNhhSCd<&ULN1+kkwqz#whM_a*Jn1BIH9;c`EVmh)m{Mnxa9tNU zW=S{I_Is@Dj2+l%S|Wo}&i zO?+x)NnNe7ATulP_oTMSFf8X_=^~+gjhu%bAmP!!cPn2(QI!uz43v=j^g(mcdBg(5 zJYj)x#<9l`5*McSHtT1i``IN>R$~}6YOypN&w4-bo$y@?j;$c*WzLjyO$2=-=CQRB zwC?9{fq50og%1qV-dPWUA7vZ>jH!iIk{FzM$URB3L=ujCZbUfWa25-+ zSTJh@KB9e>dtnz^XEXkUEs2^w0gWdL4YSc=%u+H9ID(%SvhXAhEBbYmu97+pUW(3U??yI}^&_$%I#R;;T^Fb`y#9 zp1!M2T{X2Ag?}DQnJM3RWu~6vG3O>3r76~Y1=|xH4rI~ryPb2415LNg37hyZsGXzZ zHqthh*iRVR^y`=@>6hjQ*4Ssg*9V0Ol@`}X&^VjaoemW+QPnj|_*OT}_g1xur4!o) zP?ui?aKn2R=C^$PJH4f@X1MX1HLQ6@aHjP0E<79PxrRMNWr%55_X^M{Uqsh%wx4;4 zn)?%#8y_fbOUd29=JzC7l!n4Ug;MjYk1x$m-Ef!uvn*Q^WwG)+Na^6lF|&6k84P$W zN5Ooo(seweYD5BjSWayb=B%scO2i;3_|j?O0=hexeB zmUFY)iV3bd?AI<=}+(5f8l zSWK)l^3++aoKP);qqAXlFSm3V+lbAVHs$P&J9@DQJv#?2{dBPhVg9^Qguyo*mY$v0 zKTHd8{OJ&B93~Xa5F`BX;BXF0IaP+jgkixkr9FwwL{@Qax*t)$H8v9H)tMIS!NNsX zM_M0G1ctM3^{kUf+et)q8;{C`UpSJ9!q%o&r0aGhbKCo9IXTAt#H?VN?o9Z0^lp~z zwqqD`Z}*asn~>Fzn6XmFTx$kGMVqEYD2Zv`f!K6bb4uw?F@DNM&R zzC-UqNUm94+PsW7-vs*&vU&nyv$!UQ)SIY+EZh`1I1vsuSRG$Ksv!JeT!X3S1<(!Z zF_b_od1si5Ce$4x;s&VGhcQk4wij!M=Z5;;T3af!%#5DZj>ofG3j279eG+nQv5z&= za9FHj0sBmaxB95&AlRU6=_NH%=8r$>f33Yr1N)%tcMg(@?$K~%As2)gi zX}TGzPX-U;Zh%Jh>_$lr;IDsWr1t)aD|D7_dPq>HlsO1Za?(P> z&9Wfnbs6$c+l*=U7{M^er3C39-#$x=Te=s1yoC+-jhsT=mYlZ)^VV#GZMl6cJ^eG> zZ?|Hk8TC3)KG?qTqPjus+4c@dZH<{wlr=qzjUhrB6I=_;1Hx@jAa1fj$*5b@CY!5Y zRNtql`rajAQND-!7BjAkx|2NdkxZ_V(}6Zx?ECZU5#i$)SrTgr@kf&-Bp0*N#N@{y zw!jvZQ#ps?VUZ{nNY+qiS(M#I@TdiMJ|<74K2><6Af8p^FC7fDGLB}gKGD9^yL*T^ z>19M`qbK$JWxP?QsTK2WT?;i~(Ia4JDUdHvD9}4YqDR1xD^Sdk=n*iaGNcqc_Y%Qa zf)G6dKw?t{kS=dUqky6Et*8LP|^}gT4KqEXcz$6O6s2_yk`mJ zS>C?N+gEw}N+}(v1?kk$u}|)PeL1=M&OFBn#5cZs8~rTYw>AFaBOOtn~}>_rx!O-Zp60^+6Nq(Tik-5Ufn8@GH80P z077E7Zgv*TNS2J`#@yHvW}*Sv6YP@rw=^tg|LQ(2y!!PoU!8R`i8MHy9BD&rTz}9b zn{7xhN{x{ufnl7>d|hS4z%_OGcI<^FT2whpC4IP{b`p$A(ZyVKk&8P+f#H{y?caqa8mzaMzdA;Dyj_>$4#j0XANyJ;{Z#c-Bt=P`Ak8=ivN+&} zAxIm6c6LV1&NQ>Lh=Z;ahx8pZd&wb~I!dwlKoA1oZaCM$s|f_ldewqMH3{mwbjpCh zJ_F1Zb0!Z%@ldU?qEAj>ILLF3Ah9)aZ>q-|YZKes(&1GClI)*tZvcup)KA3^)7<|> zl+9CVY;RZ{%|z;F&yrc51}smR4uGfbcFc0dUb^mXKYzG{bou(D2+UvqrIJd&{#|61 zuRkje084X6^ZWWUH7^5+-av*n9sOr(_yi^4OGa=*V!CKf6Qs1u5Sxvn^5=cFp<2Bn z!j8|1QYL}azmjthm7HEE^G~dJyvyC;xE@_aF(hOT+ofajs_!3c?2xLFT$_k!zQ@^6 zxu+V=8>idKM2TjRYGWrGz|Vt>RSEkh070zvMGgm=t^|hpRsP=B7E}#R zm#Opu)$KQd#?;8Xj{2|zn{Zd*Ni|#!g(nB2wLoZk-j-hPct(=?880TayXqz_Fx6{yLTeU!aE;-f z!U#CDT5cU?LW^&$QC!nSDNmd@7B4Yuw?<(`NLak77aEy5v^!lwbH|zm6VxffAonR9 z`xZv5Jf1TTA}>|89W0Yi-&Y|W3YSE6`fmQkb58_61MJeCKi`g90;UaV3pNBMzvUs0F0BQX4Pzb zn+t?U-zYRJ{bcOVsQMCZ!r+_cTGi$eP6A%?iAceo(4ftjTtmy;Qh{S1qoJxcrj1%e z@?4Y%0We5$*yD6^}(=8H>O&eHfkq!7>ZOXt=sF8qd%$Ce2p6&~#vIw&uCm6C96op@e%^ zT~5t-aCgKqu-OZoqbi<E+!Zn35RO$j<%2&M5JX zlQ@x`NkW0-3MXN|v-6O^W(frh3y!2^mUNQ9566fXlQ2n(5ieHWSuKu)Y31E2Nm?aI zt7L4I&wrO90H25RVkd~tAc+s+GfMuVBrr-0QPLUZyD0H(^1)Mz=P9x8;=Cokw}kTM z?>Z|TZOLp>W7d8wU0_l4fX{jnpq!L~3|l!hO=q#9ec3j9C|+K=g{I)mhJMn>tai8( z<&gWc&88+Hpq&)25|O7Hr_&bc6?9DN)(hedNA0Ta2iiAXEg{2r!#k-)R*C=Nz=gc1 zj^ii7NpVxCNu9pUhT*&JzLDLCQ@GztHgwkOd8>scrpL~nG+TwfIo7VP)UAb%x{*!6 zru^IM2SACH%5cJu(Gv@S1~zX@9#mjn;uvx@_Z?d;(gCZqy%~jpS%Z;)ruPAQABW$= zW;&4D_N`61sY#yWa~JhD=dz9bAi+RZ%Z&E2mc&PB3&wpn!8}OGhIq}5Lt~Z^cxW_E z%;|32gx3{!KCF@{mC!Dfb{ydQbdMcqBJ|GQsm#Qr1s`}h>-l72+bU^XUyd=KP`52r z@rP~HN5e+(KwGe`f5KH&+}sMQ9LLkh6WvL51Ejr~_d+-IhQxlP^EG*koKdKe)J^$( z+6tvRv^9Pd_m0FK!R@fd(C{Osl>KYLtvhM&nnR1K`mi3l_tdkRn%!BW{rp)S=sW9( zH^h2jB-wkfWC|giWC9_!vAbl6Vr%@xwy56Q)b#GOqu-<%1|yBG>ioU6H$EFV@th{t zkFP%~jAkoyndk5touQF)x#5>B>=-NoV9CpLAmQM$AqFGk8E@hk3dvpc#dmV?5FtTh zNhV;i8aK0BJmKGo|IRB>Kr*6}dJF^ZrulIl1>yM?T-zmg6c1w*->>I|xG!A-6Izdnul*{)Q1vtM@-v}H)Lrqzvw81WgOp%-)+*3|_7C11hWNQGd zRe03F;2mzy;lnUB3nePRqxG|vWyAHd-sQ183X1gP!YZ9NSPOODiDmzW4>ZD2Q=Gb|ZWdIsQ z!cVuWq!;xi9>~>UZnSZDBA1|7hB%W9x#AD(oS~lWqP2mMbgC>h_eyMqJv(_eq>g95 z0^Qt4F?$E*&v(sNV%o-wmh~A)B5jyNv%?`#>M7afl1KAN|2z~CN8T^lzO}T<{gN+O z$70of@x+WpX^4GoXDs6^JgWh@Cyo;sFfkN$z>h1qu*_SoRaU*HYbN-hsn^tRW zY=2HnycqVa*Qfc z+@1Xo>z_M-03x#}ja4P!?t#D+I2?e(y+rkI>_ADJOskzjy0V+jpxlOh=8LhY?`8=x zy!Nrc^5P6TL?T&0NCt!9#yz6x(`vLMq=C6)3-d8_*+J3H)P=^8g=NkK)^##Ps6l1O zPTiD6_A`U5&6~_@Tr8#*PNH*$8On|=KlGATu#wJZ`I4DKG&u|iU9O5mP6Epghg!09 z;q`gPdztmrrlRub&Ue|>DXZq<)-}z`GrpXem>8d=F^*mE2wx6x)(JHrl{*C9 z8VzZ)K{~TRB$z!ye4Y*PCdRWteA%E}wz2|3F~C)f*MsLck?l+}VJ&eyta=Q^HJO%n zV_MkIw$xQMwa^-}ko<9|Ii6gKPc3Oo#u>)RrT!4(xx|aWZ-X8T;I47=< ztLjPCqD#Ytu#;8tWQ(j+3G^-=roHrMl}zwU8o#`&64u{u&tJmzCYal0#J_+NUwZ8s zU<(Zia&6u19D%0dSHgVs`v%~l@Es+Z5P^+Xsx06mP zpaxh%Kw3hUGYBY%*gIhay7(*WcjEI{0pG?`m)5uM zpR>=6jn`PZvFWWU_PMN4>nyF7p0GF3w6yzGG5$n5RTV3g3GGb~MJsJ9Kx@8xC|H#Y z`%RS$KX=9FM}AvQ2!kdFx&1*VV3jEPWECzghOLxVzj+(BHf(=3G4LzOc`qxKbc znu<45`?{z)HE24$@+O~;8lq`DxWJA zv)HtVZ&y?j>3l4L0Jni#ui=^v+;%Y%3GXUR%(!htZ+Hb0!Vs=-Y?-H97IMUYk{Q;H%6n6JZz{=7*Wz{T%_QVZg3KhAR0@_#QKay0aR_iOxtq(o z3n~9Xo-L%r3rTuWiziuLNK6aK$U<_k%*B%zmJ)>4pX^CwnIx1+knEgz5@#mWa44BL zlyc;fmt1Nim-lihcrMB2Qq)3fzmVE5q~L{QsgM*3NugMYC$E?CUMb0z@e(0BN=QYXIh9_>P1VvX!$Bya;7CcEeUBUw3ZaKq@X1QBO#468zY%F zk~1Uk8OflL_l#tsl}xl!qE;enr3zM(rInO@CAGAYI9F1XwdAFfARCEn!>O}9ZSv1jBLy`E4*7r?>%$93o$9TJF@*oi(BzLUg7J2xWSdO;tdk3Eu>$W(P7+ z@M|`_&_C@Uoa)gd!;b940OUcnOJaMwXg6~nwdVzX?!=^;Yrk=UMz!!=d7<#*=1v|z zQ{0TmLv<}0#YWMpC2xe-HN0HbsnBnioJfTcVyXEVeTQtyJr(MS57|RhY^e>CaIkUh zi6Q@$VYGr3Hh5{>8($%;q2-vuR(8hCJ6IlCFeWV{sX$&c46h#(v5ePjS+!|Nn$GRZN-gDd%J;NQEne1>vh&kG&?Q ziuw$zv>pF~xQ-?*Q!v`S?%Jy0(W784!duI$B)yWk3BHpDRE;y)G8G8#2_QoR!z@rM zAScfdM=4vnkPL1e0Sgs1VO^-v=Tj3J8TPENl?XmFI15)T!1_+5a8G!zhTs0tj-KEC z(T=v?N-ct2WWoj~E0v0m!_dbMqfHn^qY0)*#oq-C1g=^+pQ{%-$SUlG&cs`=hk=p2 zRI@j4*vm`yN(lm99bU#>EwO+-fLE~B2-ZksMqXbDalY1 z1WCtgF>Y6VtaDZL(<;r!%W;mDwuF8IUKxQF1z7X7jmjRyfP?`Y8lw7PmN2_p);IzS zc=U6I60TjDB!kHDJb?KF;y^r^@cAH zG^|6v0vkzTT7HMGra{cjgnP__M?*?m4mB!PE!M?&ov$EQtYg0F&bpdNPtLfRC>NKj zE=hPT*fG;X{uIB1vJ%hMPFMAeWT&O7yA~3M!EO-M`-VnwTHX>fTNJ?DV0v;XSl^#q zIk__2-aonOuEkX+$7nDXQ#dP7*rrgT7a7cl3ATt7HKE8NrkX@j%7TXb>qN17iNmQH zVm0*J(Kv;-%CvxzaIxB=SzG9mH4fRBWhM&2dahE-hcl#jEo<_7233yY z6`AS62-eY_t{NN|sNn`L6Pi#|Kn2=N2#!?`sYL-He;KmW!s#xv9g_$;jbrDdn!Z`= z2*?U0s(oI_D3*!uUtGo)v6N-8?ZYfC!7_`tFx4`5+-jeSaaGv|i%&xoI$9bq2}CH} zAwO#rnhoN_xl$a1>HQvIHST`QgGCcJM-kjb>m^a6psvM415$1;$op18jFcP zAq)_)UeE(T<*RxPsS>*vdt1z<*y%?&RL$q+3*g$hy zf-PqaOo~d71%5mUREt5rGh!-L1ub(yRnl@zvEl~n`A;X9S&m?qDQfYR3dX8xScABn z;8vg_xEy6d$?oQ1+k%~MGj%mN6Om3W^`kV3JajB&mPtKI-6(q;bw0g(rDaS z2#UhOCZ?!8s#*)ooNxHFPAhhj%0oi@o_1c7ju7!)zoXzo%TJNZ2B#u$`Dxk0trEEP8ZJIw zgL4w-tXYgibBzjxAPAWjhyzCx){{k$p$cfIfA|w2!C>{Y=t+olfg=j`Qt{^E*=Lz} zg?OcSjd-ni8}=rNcoXrK;>qiiL-FMGNhO{VPa>OW@r-zD@g(Z0#4?rlrt;oYQm4fy zd-B4xV{ax2%_QVZVo9Z#sT4Dn@}-h&D#^|zpL2PAAt4tMav>#JNM06FAq&aUq83kz zvXICYlEH;!X_<>BFDxaStiM55+pk(p2V3+J`W{Jhf=Uya+XV$a(O+M*K^5I zF7=X2CUU8XLOxX?pQ@00DI|l1q*q9Kh16~#ub1*(DVZoG^-|s|r3|H{UP=Z_iKUd% zmQvbM;w&X+<&k(c1<7C~300CpCFQFmXO#p|QrcQV){>=K+HNhMs+OG9lCxTJR!c0k z+e0oA?5m9Y?g|6i@{u7iJi=$(+bD`>FrDbBti81Cnvid`6nIWz zpuyMTkp!3$X^ChbnspWTi!EI!iC=Y%h5Tj=gKn9vadp@@ML|H7?5Hrv%I+Mp&g3$& zAnPKp1*52J8Z2|J!o3X@YNjV-(a+6%AuFyQ6KNfGdPn_yYm!*itui}Gq7~-<_?;%+ zt;IGwCJNZO#`z|eWFhZi)WB{9QRZ#FL(6s*$SS!Z=2s(;4pd;%&<2-WpAavL-x?mW zKHMXHxkd~%^+N(CQ z5LI~1n*z00btLNkc;ju7rjyRFE;Pnxv{JD${PRpmU=q{Wc+!pQChaS4XWveUQ{rU( zK2n`f=!xntVG+UV*&(R4z#?S_yWGa(+bl9L1_WLi2&-&s^aUpT-(I3E?eX8t%0zhh7b`7sO`ijhWJ?~eUjizi|e*9 z1@VbDMV6F&Ltq1}wDsIjYdz@gUJ`*FlS$KQ3@#fpAZ|yl7Q2i-YE7M+)(Q-znA>2~ z1uKVMZmLcU^e;{TtumW7#Wlg+8o91{PJDA@g)cRa+x3*#*E+aET+jF+w$-Jj;2#T8 za$QV(Ij?4!Dso+{*tF-aN#A~*O4X%R<$w)eQmbizOdBCJ;09|Map4j7LZ0;Z8rE^Z zs|r9oi~vReO3b)Xgz$D@%bjYf^>N!wGT{h>5aCmM%uu8CQo?hz&{56IZ_PWA^&)X% z1NCAq2Wlf??CK@HEkx+BOz$y1B(Z4c0sjq`l*MIMK)F2m{kIKhNt4EOlNMb_$cSmI zmnyBYqn?bFF5kuwm$#3*5DtPGg$RxgQn^UTLUI&Bqi1CP!?HXkx$cu@7@OoOVhx)} z`M8;@{CNBGQ*L^BSs>tlgZ=G$3@gyc5 z5By0pLB#3S7`xz7`=DW=rehMe*rf){Y)T&PeRCMgMC{YTG{Y7Ut?zOFYaf^MqMuHd{aq zUxOxag>zX63bmx<5_choFA%z<#Wp+)8jAIhK*D&+TBZOQd&^DW6n^e)-4SAv6(5Dv zU~+WsGE2zDf>j3Vc!@=7Oq109Srr=!!6k1hINGm6EYdo7(X>_NkdsUQ@}hracvK<3 z7m)=PYKddK!1iWO!I-UBJsA7MA&%4O(zatF=rMGY8)*FzxqvCRo4#3s1E;)7y&B)& zscI4YZJ)6@&4}&y?}>*Eq#lK&xp+lOeuFldZ53$NsVvpO&g7VbSYeR)Zf%Tzo%@ z{hAY6VFsWfk0w5~o)=gZ@u0y^Xu?{iNkN^&sb`kH#3fbyi5ew!uB6loJ5ccEhwLpm zG&dRY$`yN6!XBCpd9}Q5B&6x;6l0gPDk7}-RcdFx1JN3hopu_qCLYK4P;+){)bmvL zgG)m*R?4jH$Z?nc<4_MA1$Ou>$i*`0RK`PG&t+*_1Vxp%)F%yejS;9fRwZlQtY}`A zv5z|S8r_`f6sw+cjp$hufXOH{A@bT zs&j4DbUa8g#TOiyUQ*GHWG9*kstBH%LZl$-Hk}lF+q`ate`#?xDG+q_bJp9cmU^>rDEpmivKexn2?73owMH@UT zYyl8u0?6_x6qE+&(K*fcG-M3Pl$&bLQH4=|5YJU8Vbpi&TTFA^xlN)5`J?>Is(<jKC9 z>>h<33swnDut+gA3B~2E4bl3^>jie&O&VyDbvDBqTtgZvc4(mOq6+tLnxw%_AuYks zqMC$NK;i9GTFsn&Pmg(NH%BQ`58_ye;mQ_$h2C#3zBb7^8Pj*-I_EV}Gh1Qvp`i$P zI&XN5gR8Ubj3-Lv(&>Pf-30p29ZJj1nVPZ^7oc5<50BE&SdA(&X#jGXgwcq)VSv`v z;!`=&NgL}QXi^@X;7t{Kv}A(U2!_g{N#C#rOoFm`YQxio z$V)QDCTiBXN~#N~?YfY5l!E<&$K!MYigsZ&CR6Yx&_C>ng1P>~oQuo9z%-5=U>;x0 zT5Y7|*aw-$hu!;(Mkn6J*z*vwIDGorC*n!+eKpJ*K=ZzRDU*pR$RvkiJC{`mVuKWz z5@403YwKzDv57uGlt(lfFGmeeMa{Bbo;19=6f+kPna!F+20)tg_6r2llO;PzGb=Jc z3V3R4O!H8YT$5!v_%rC2+m*)!b%SruQrv#OwZSj|C3ZGOr}Y|pO|Ct$iNj2Ew(uU5 z(@WZ9{F5@M2{xN;KjmjeU-UA-*;k2!%F>rMCfH*#xy6bu((zmSjTP zg2W%vL&t~{WLfY=ipCZXn#w<~Ebc;45HI-LC?Aa1k|J$Lt`97CS-}dXjd-EL z7^u)l`g=B?^bhw-rQy zJ>F>)+Ma6U3U0$~3qG{_@S(hPR?$8Zs7J@f^}-f+RVl7im^>I`!hz~J7;nx&%k3DX zI(MVA@ynpbFMv=kjic(uEA?q~|8Q!#46b#(q7u_c*hl!f&xOCzqJ>IJx9lkCRJ|jX1etxulaTo*g;48n6>5$DS8D zIqp9$bp!ihPmb-ErC_;#$$t_JR*qMB`j_LR9<%f`1U|;UIKW8)v8rof`i9S+*!x^V zci0*4^0UXp-9O(G_cR&fK!A9ueQ&4jPdtS{_~Rb!Nzpy}<(@}JkS^b!*gT`Ly47R) zx@V@Ulkr*gKyRK^1wRofJ^rajdm>$@6YS{!!1UkF#?+LUgPmeGAV+!+_BJAl%`#R9RjzjC1 zX`anwJx%DDIZsA?_1Ja7Bu%ixR^&DWwtjTtkZA+gZVu_h?G0&vKrb61I!RbGh=56w z_L8YOnZd4=K#@u`oy=2qXq7IWaF0#`gZ&VRuTy~HblwNT@x){e)gBS)FtAHPC^Qs> zGC`WPiaSwy4eLZyul=cXz_~eaK#KJO>m8jF=pSpe9s5T_Y~yI4FgPYOiS?plw(<1{ zp$u=B2(`b$pksAlIw`ys55UF(DLZBV-HOy&{3B3RaGm-T0-?B&ffaolzD(v|3X=tq zY(gC@+9@=Ok$hyUn+h8J7RmEtZ3+&t77IU-X1HkEbYa|fZLlA7Sv8To9?&6D51UgtYT^xG$pSJx?>Kp;yrniQ< zjjS%$&Woc$*SllHy2%<1Mfa8LF2e1O{y2Q~#atk$L|}{e@p5wM8l(OKI@I=*&`jjjV*O zlZInnr&-@)rx|VlSXErkr`7Z{Jkz%10ZM&&p!BPMkX6_U-gy!$2#$z)K;0kpFq9S* zVMQ@`V!$&AH#Aj-oltZ^Phn>%ZN{?3;!g((HnOK^%ndZaN?)NiH{-U=VoG{edA@CC zB~}4b-Fd5H+6$*?FOa5fGHDX3wvjz~cz84+ZW32)xNAX@S;J!~%p6dY3LgmFwCTvH zsP%w>3gW5l;c1FjY|=2^WRuU91I`Wh#RI;8w~51<1B7-!=|XNWJ*+yZf_(N1CsK;j zO-!?CaB&t0)Sos&4t^(XgPDlR>@>Z(%7XgYq$o!_>y( zr)p|2^X>o*EM-KGsoRW;RJ+=9q&C1aSBHeahAng++a$^f)ED~uzC_?FX#O~WhIm*s zN$@eMlwHin{fL`Z^u@5BZ3Jr$ADBsx25! z4Sm3=YPmBSK4b8K(jyuot3^P8>gNdYQ8=a0jIixVAC58qjOL>`EP40OmnMvL*_Nse za+)>M9zg}mj=4{`tbf@*ub&8Fs{3w1*ts?d%hqTuI7({}3lr=*lvP1cWyC zC=MvS{b&c+u_rau)w+7 z&6<8k_~8^29(U0r8ZP+iyq;6*q7Sh+OFe_8VTmOi^paNctWK>3oGUZXN3YQ|nyg3w z4Nj3jVVAPAq>dx5F9~rklZK}Jerj1}h=vw2k)C`<35N+HrPL}1$?eg81EQ=M{G|^j zMc-wavCd|_Y$JnELLc(V%WQ6Fim2&ZLiQrWG3WtJXPL3c!X=3%T(rtv(z+VgQB9yA zMecBhN=z6WT=`&HIjEvMQN!97l~6&8V^gdlX9qj1IW@vI9Mg$N-)y9e4L&JrSPP0Py?mg28v%eY$#&vaH7)g0$KEbgdzisnvtv1vrP^&=DxMD52 zuvbn%3-)y|ZmoH~qogvw5R#n_nv-$L@22={D%7cy!eX!!2r^!BM4nkgUOHR29k?v> zH)eHK9E!9DK{-2p0%cvKUWc-veYHg>uaA1lBEnGT8P?_GIB`va7cj!4siRD-3?sol zhbCp`z)Z$gzk+=Yv<8;vS$!SwB2DJ<#kf>_g<^UjX8?!v&r)`p%7z0axUN>A(qA@g z334}q32vo6@^q$46@a;FtZrtVXZZP=$}>x~+mHk_tE2}{E?KyOQ=65G=Fonm{E$M~ zolAz@9%X)ba>WKIQfb?{znDSb)QV&fIJ4`sT=n*@bl%}N%U1qI9H9$ZF8dFWcQw^x zesalI#>thwHYnyI5rJxrZ4ohDq>CApA;7DtN()&Z7u<`Awszq+Or|tS=BUf0C|Dl~ z*M6BaM%;q9GB!OIY*>}BW=C}{S64L^XE~i!lH>B^*pjI_E9R}KVQDEnFAy1+&dJGW zh3c29mGTcm0eoGZT=B1;T(Lp$?<-oi?$sWqSWR(71s=K&dAga}=BTDqtWkMGUAH6A z4Z%&#Ro@fF3N)eU`+CW{iJH)WZVEsNfgFIbr>l^(!+U5<^7Ac zPO;4fmm~6-EUXD?KqC6D)$mF-Q7Rip6>3OiG_zHRCPI!E^280#p1)BQwO6GEo4B+l zGx8alK&vA#r_>R!3g}Qf=np|y1*6SLqo%}sbGuXl3nBF0jaS>K-IW}HZ6jA&5{(#L zg|=hw$7@>U&-j2rhr4{BP7~3y$tT^@1m?i|8=y?Y;cHJAoH{A0hT89bvB4m6-5wbF z99x`XcWl%c60p)a>fjPCBe`8b)exL!4{ed}f?_|Dfz(mBXV%1=9qrMdqwB-8$P*`f z#e%c!^3+>nXb3=@FnNn>ehK1-n`tcikR1Ht8sCd_d{qm{OMUEvfeu;@XAx=>u^ znBqRDYjN@QNR1nJzUvVJ>!A!z@e{>l+N4Q;IBL=iH-vlT+KSL7Iokj|vv1b$6j%9ET^z!E-^P0E*g!D#{+}qo%>$RuhdYX|eM0s0PBW)+Z*e znx#j*##qp2E@1GEypck$kpQ#Y0@d6CjSa~MbquWRTN6xEeJuUVM#$lT{o-|soyX{; z7#x!g$X7QkNFTv^1q~8B6*|nb2d2r~CDg?gU!vtIJ7g^ zZkN79i49uQ+K1MB;b7Zly0=_Om_oJ5nChDVX>G&NS`0XOk=Hp2y6&Mm{a1=ER|ZL-Q@6)hlfsAf^jT}SlK{3}&o zH-n91@qAKUo_EE{j#8afNR3i;l^V|^j|394){SSG&fQ=f(W79@l!%^~k=%*nCO|Cg zX1YnIHn#+KMwHd*jotg+_>2(j$i$=CfrU?3Q7Fm{+<7Qd|jv5_^s;dQ1-tT(~0w~po)=xjO> zH^3Wvsf-9v_!}+M4YmPUHE}Q+88KNH?izxtz*9e@7zkk5)(RL)ie7#LCmq(h`yz9M zSOKQlF{o$cIMDCln1sf-YHWEt!Va@&U(6&!TM|O?xyrB|6D66|X$G$eO{EdeM`&*J zvUpHbwrmg&o`%KLg8IoKjhH4m%mQQXK$|GaJP8xb@mfDRfUpE97~q9gM)hMUUW`pB zO&je}3Q@-gOF|ros)0BxIt~_w-+L zLt<1-8Y;O4lsr(>%M_=$cF~jCK|2|mb!Lj>zv&6A+A69HAw_X>mirIw2w{%w{(o3A z8>faXsF`%Rv)2e}pqH3Y6{~wTN!aG?5&EFCSrykBhVgV5C=a*)O|+40AfM=VZ6Vw` zinaIx+uflya_-~vR*F5!plV9gNYpI3wdD}GirRjebZvMXM3hO?G-Rwc(&D@XgT>=f zqk>4+PF8z)LxMdMZ`j0Y$m^IyO%eoZlAuN!mYE7aO2bA7d4wj`LOkXLur5-QW|J-~ z)`sH*%>y{ninb0+q9NS_&kFhgw4%cVE_3j)8nEFW*=Povku0V|wJaELyeB;?pvsq}iZFr&S)B)*!sfP&ZXL%B4!G4j)U>Y07lNZHbn=nI%=K z&I&%N?Oih;8LHO>1ia8A=%X#^ z+b>x(6gMm=2hR8J0Hp;a`FuQrTr8nBBdmn=oieQqsOQ; z3*%fw!y8OHuxX@VJcEIU;9>#c8FCw*KN~i%m_rh$F~&R#5X4@jX@or%@$1KqW+4Qd{6YlNbb`>Bx#vE3FU z`u3xA(0-%(hb8Jb8M}YeH!Y|du@iC6P_k;SD59JfQUV9oNPwY@1YEePwA+}b8Mm0z z++-&xNCm^K!cNA&c*3Juk)QY6EK$%$nrt@6S7VhFTBwg9RJaMg!(MMTN=xw2nj0`D zvJ(=giJa|1B%V?gKjJQx4!BQ6{O2gRgyX=7)b`3P2x&51LN|m1G3Z$kqZ@&!ur)-N z0uETMD|Y&b))lNwjotn^PbLuIh?`{x)_F*B?O@1KMJjlK@p)br5M=EZk$7T{C~U<( zXjmPZRvbdb&sDUvA_BMjpe+y&omel9$?WuGu-oOZcXr&Aqj3y^vOBefs^2klL?lg( z5OWuw8-WjN+?ls&gv2ckH`Z!+U_IbAvZD(aN4eJbMEa6uk+SL|c>`8}>LNXI6C0EX z1(9Txjm54o2oNL3fHG*XYqDfaoux>P-I?JBj$%Xj2ZHW|cZ4{!@+slm8q%g}(W5ib zRKa*CNbU)2jSiSSh$pa4ELR8JLxuIQnQEch(~JuQY2V6+g%%7Cc{OiDn(=Jkq&=U6 z^SrDY>vlHo_q2NA9$LCLWV$El$=CaWM!RQ1RAc%Cvuu&Zv^}K4sC^-cyi3(Pi4$!P zX;0DBzOt+Rg;#q^ul5&T?Js`_@2QI2n%G|vd+T9OHSE^H-b&b42m7mFZw>6PfPLlP zm-?Q>_olrs>AflMChV$xm1zrRP(LG};!82oBh|v`C?lA7OV$|*UG_!4gKoU`7>1OG zPL3^D&6a5FA}Q~k0?5ml}vMT)s229 z$9;Zfj+ec6qapnQ?Y=WE0F?t{wr)MwuiFV2%8*9|$;9%_pzW>)SQkC!j*u(S?IPYq z1OW!g`YBwuS#1A`_wN=%`-M#9DYEAT!8%Tc31Xi$ylcv&vcK%i0=Ns6Me#s7E-rNy z&iRZ+JApK&wu8NVkQU)iuMq53XTXm$JsVbO!{v`ASP)GTSJrUN)EQ|%(PhGw@-`5eh zrAennLRoZ#e>|9Eixsx1_}X-E4nz1dI@oAw9;v)uIKd#=BADNFZ3|5mlT%&0Bjw&m z2StAv9DKLsgug}U^eDEm@H?S>#a1}O30J}`8$WY^?v=~8RrWumI;zayqy((^nNtu+ z;0jAQ_I1TR7*W#&U?1lp1d_No)#1q{4_9Jj&kbNL6I}wTe zNmZ=$vmek~Sm6jtSo0U=dsKO{!Tv8Z=lO<+MaEyPR$ld3>jYCEqR zAlr7?wDBPb4by|1QK?`;9kons_fznt&VyhukJT0h~Ck_SgY*^^y zf!xk2YhWte>-^)PUt5DYJ~>|@*Tit4mOVe_5 zdIj!*^)jyTkKsUW0jyZb_9{tgEM%Bq74{P}lT`@-S(L1jMdJL*0#^6!D#@K5l~q!V zXX8X^V-q4Y#NubsBWhKFEi@shULVT}7IUJv37zc_V%)zNlZUSj-jZa}0G|yh19TSS zzEuJ{d2bLO2(um15D%lQ@Zn^Rhu=~c0sxUApHSsRvQ~+b*J@?^guqr#3jv^qr4qn> zU8wMt*P6vb1gQwLADB6W)s+4jm`Pow^e@0%OUkKjBd{8(X$9*L4fo_qKr2?F?*Mt` zD5_M}*nl>fO`u}!!3+_@T-eAfF$qJ=!6d0%&}K>;78q>{;_j}1MP@^|Hkvk>&K4Db z^5hE`Jt8KUPbCKw=p-VNRi{EwW1BuC6SGh+1t_VMhd35!sI~8EQSJfFLbA;W$TI%` zBO76s;O*f7r*5YFi>s3>3%mD6^@kq@)fHrGF<>=NHyEKgvPQM-*7&QrxLO*<|2#1X&&4cqATe z!BN8NnJmk?jhWY*r4AoFwhD+aqX;1io(91+@&lO}@(k<-O3i>FA!d#SRSc2Y3K1Rg zh*sd>B!%w%9`w-_$t=s06)nafmlC4dqGi_jM}V2GSbkwed}s%e9ll@#T^}n-q~a=5 ziJSSv5vrzu4H;MYN=uU?KV5kp zeJdL8;c#n!k+l^qJ{Lq1!KqbUL8=JcHi58?1a4!5 z!I7@9d$neDnrp8?bL}-~u9-RIBiw#ZXw9}sFr{-jz$WK|Yvq=84!5S(ELGa?wOTwl zUk>F7Jv<<$;dUtD*fx$=2t;fn(SmhSOqxwMU4kWFLqVIkt_=}Vs47bXobR8K4`yUd z4TPPALVZ-CO~%POtdpjHuSq76;t!&fSt7|cnonaHW)%+*UYPdp>Lqa-$=b@=t)bLz zV8nF|*~7#OelnUx<-~micG&_LHTG%VCt$E~Iol<2br|f{G);QlCW8&^E_&)d(H4@vP?9IemwCrUw@hbL;oV{u;UdCQ6L~|%!!yd7@@HPp& zX;Q-DTuk`hf3|TTueK~)rVc{)v>=xK49eB<35O}5i-}7*aTZcsK)zV$bUqKSa)Hj* zD#g+Pp)484!fu4XS_TYwLj3KgSiLiXpTYH=8TxDn@MpX-oS%QjD?={j%vb)Kr9PWk z{28zOymCB-h1~zbW4OsPU)axBo*DeVQ%h&Dn~x9u^Xld-CUk%3Gx^c|!Ovn%_lG`< zOMQIkpI6MYc-O~=-i>?4QZcv-Ru{BT^P(#hjD33BUh8zxh_Z%t zn(^?NVQedkNlNju#Z2LnVp@tZRhwUoTbsqhY(DSozyz}_o?BzIg(bZM8r#{(56olM zwf3RseC<96-|8p!2d2?_$(Fx-=q1!^R8#^Cq04etOE`!-YQonv2Geh}mN_p=iYBvoh;%G6Gj?WU@-(uqEeprgZ;;nFa6?GDU@Kssrt)ci_}d@O2;Z$ZJhm)6~q8 zLJTBpIi6jYGTHECgr-!^i^QrLTvzFlh|I5XnNSyY_9jlal*@Vq;=*rUv};V3gwf06 zSz3y@(6v%CO>3eNi#o%>zA^S}0MiHNE7@{H#1ts^buxM&XmR@xEH>`yjM(lOT%C>$ zu?YtT@vcYfno{U((5&mUqGeB7E6QW)Xkrvy4u6?Ywob_hVA#=Osr_|>rU(16tYwj( z(_GAjZ@3;Aq>S>m|GL)+zt*|eBd`WzW2jxXYU61uZk6jb*!yGSBmE?9 z)5^i{(b2(z5-MJN$I<-p( z&I3R)nmp`J28U5yvcyGfFH%c5PN{=)JfbK?E;jmu?RO#!bj)?QuNU$6M8Q?+kO{V= z;FPgrHRwCvfXIed;D{_%nPMqHo*D1Y8bzWbI!*9G9**(%gs75wNe~bB>n2ay3FpKB zI=RRT!Eua` zavDA&wS7Xy)xFt(sGWlFD50aaVt=F3FnAh&-)iR;ENEzOg9yRQkA^&bmjpt+gg|bp z|Li)xa?Zl%krDx>G%DZQzS6Zqb^v9VWt(z+Qx?Y{u!SvDZ}b$-VabJia_6G8P&T0xhx2_90|_?nL=g~PRSn>)jRWwt}A z`WuTDU!eBg?E|JoS4LROU7AGjiCX;3vd<|qRilpjY>UmLaI>gusd(;q8K&%p_h^MS zFwN4nvAsLOTe&I_4kj3cAU7GO*JMitg`0hIX>}{cUwmihQ}E~-YS*^0ELhiW2H(2f z4D@$zFyU`7;ZxAb1}@qkc^JRQ19!NgDVwd?gIC$`c`*aIsxf9TT*jpbA-)E^Ny2$& zg9FTLv)nBC;%JY`W;fxr((s^xma_l|jLL?p0gfzkV3y*C|w>4By#xj>9pT87m7a`-gx8K8@6n}G3>S} zny$k5tV)?SN!R~$(0;taLY=N!g{H@ zrARQ&Wi4D5nFW*)z@3?%T+!A`8&9#vm?y`14>nG%27%6WB0!ttFqmT;mJrI zTF=LDi+~pc{Odc%-#ryzx9)rf@AjQ<*!%80Q9ikIoe+RN;O#p%@S4r=?K__Z@Hdo! z>vwJca8)6+dDUU zOk%r;!omxac-e*e-)~a9UylCm`oCTJx6eo4|MvTLzyHJcfBydU?_W6}=e_T*5$UZF zf!Dr&mC&~cdfU}B2YB`S-wi@~@Xz!|uSAcpe*emV@-9X3_UP`rcdy-h?(Q+UF93P} z?&o*kz4tUApf?D4=HA77&y6hg#@&za{YsE)cR##)r z@x2%BzBeG;dp08c$4i3{|MAj)Tol61dr#B*@7fgZJ#+UKrGHJ37bss$e@3#&`K8b| zTzCt@GRoa|DG~R;f&Abazx=)c$Uo(tYU1wu_b3b3{{6Ol{QkY??)~cSr=z={B8L(a zz#GV44^lxsqxUZYxXH;}5P&j$6FH^#?w#kNe#td=@50?LDNTCg-MfFMG*GUKBUJdk zXGZkG=Xm%GSHq{A6d{t-`-sewD4v_6d(YAvNc7p!J<2&n`l$qC^xxm}=)XT@%eB4y z>h{X>+shvjbZvX(+3n@O5cJ{p^6l;A>)XqhBZPu&ulzb7U3pQ09B(gQ*k1nQ_VPOv z%V>M`gYDJZ+p8D0S3e7(})TH#ozFhpes+8N+4b#b zm$#o?7;V4!X8Xm3?H6xszkGSLJ$`z7{NeWa52c5NzY%6$R4_NWqa$B?X7o5|9SEE|9SD1(f#w^-oNmN`{&;u-M{eH`xpOw|HAG2 z7e6KBHfuw z_b+^T|KhtG&&9XzU${&V1s?ry{QRS5e~lUVhvU~CzWNe*@BeV?7Ob}XaQxv9-(G@u z`sO$6z4aoz2d_Q*@SER_ez^6;=YKeUWAwu}zy0ykrcC#s#7tap0(-AB*-p2NL$?cuF&N2h=J z`r&URh0E`rKKCmNJ$Uh3c#r<{z7XE~;rOcuuf9Gyz4F|T&wtFcYd3zl`P~_u%;#8T#~# z2k+cu=;pUS9KSU>y>*djOt}5g>95})?^8>7@bsIf@4soGhkv=k&@<1SzV`I!!E?WR z_}q;jzIkUv@jiI#*66{DZ~l1xPooE~e0%!BCH8K;Wj%Z)3)!#q;ML#!c;OSKzxsL% zxe%{iKYihy)3+}HdhpF(IO*4}Kl77i!0*6C$Bv`ewv{#FQHw&La`kmKX~rt(SxsEw5{>M?N1-Q_7r=6yf%7x;pRhX z(GP$1!h^RswugWD^z_TO8M^Xk`dSXT`tlFAUbPTavxB7G9=`kH!&j~g^wsGL6zxaP z+D88H^QRx)d?kRWMOny}9N1USa)>WJdHDGyv~~;iG#8ezuimosAHV#VWBbad@Rg5= zAzM|{QBU7~ialz#+IPS2>R+R>v7@&;nD5OkFIjH{CNJAM^C*m`tjLY=srKb zbj>!}AFqE&9clFAXCFR%{=E?e`SBC-Uj5RxWP%<&E6|(2I(_r6I ze>Zyc_U|A3?IV8r_UpD%AN}pmr_a6j;Pa~l{pIuz=SPn&|Mv7Z&y1)7?599gyz@2n z#Ro4wKeF}m= Ww@(5BcD|?i=>G#%kSu;;!2tkAS`0t{ diff --git a/okhttp/src/test/resources/okhttp3/internal/publicsuffix/public_suffix_list.dat b/okhttp/src/test/resources/okhttp3/internal/publicsuffix/public_suffix_list.dat index fcdecb55e42a..03c37d19860b 100644 --- a/okhttp/src/test/resources/okhttp3/internal/publicsuffix/public_suffix_list.dat +++ b/okhttp/src/test/resources/okhttp3/internal/publicsuffix/public_suffix_list.dat @@ -5,6 +5,9 @@ // Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat, // rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported. +// VERSION: 2024-11-26_09-06-27_UTC +// COMMIT: bf32ba1ae6228a185ebf297d636f1c6541149c45 + // Instructions on pulling and using this list can be found at https://publicsuffix.org/list/. // ===BEGIN ICANN DOMAINS=== @@ -18,9 +21,9 @@ net.ac mil.ac org.ac -// ad : https://en.wikipedia.org/wiki/.ad +// ad : https://www.iana.org/domains/root/db/ad.html +// Confirmed by Amadeu Abril i Abril (CORE) 2024-11-17 ad -nom.ad // ae : https://tdra.gov.ae/en/aeda/ae-policies ae @@ -32,22 +35,30 @@ ac.ae gov.ae mil.ae -// aero : see https://www.information.aero/index.php?id=66 +// aero : https://information.aero/registration/policies/dmp aero +// 2LDs +airline.aero +airport.aero +// 2LDs (currently not accepting registration, seemingly never have) +// As of 2024-07, these are marked as reserved for potential 3LD +// registrations (clause 11 "allocated subdomains" in the 2006 TLD +// policy), but the relevant industry partners have not opened them up +// for registration. Current status can be determined from the TLD's +// policy document: 2LDs that are open for registration must list +// their policy in the TLD's policy. Any 2LD without such a policy is +// not open for registrations. accident-investigation.aero accident-prevention.aero aerobatic.aero aeroclub.aero aerodrome.aero agents.aero -aircraft.aero -airline.aero -airport.aero air-surveillance.aero -airtraffic.aero air-traffic-control.aero +aircraft.aero +airtraffic.aero ambulance.aero -amusement.aero association.aero author.aero ballooning.aero @@ -78,6 +89,7 @@ exchange.aero express.aero federation.aero flight.aero +freight.aero fuel.aero gliding.aero government.aero @@ -92,6 +104,7 @@ leasing.aero logistics.aero magazine.aero maintenance.aero +marketplace.aero media.aero microlight.aero modelling.aero @@ -114,6 +127,7 @@ show.aero skydiving.aero software.aero student.aero +taxi.aero trader.aero trading.aero trainer.aero @@ -121,13 +135,13 @@ union.aero workinggroup.aero works.aero -// af : http://www.nic.af/help.jsp +// af : https://www.nic.af/domain-price af -gov.af com.af -org.af -net.af edu.af +gov.af +net.af +org.af // ag : http://www.nic.ag/prices.htm ag @@ -161,17 +175,20 @@ commune.am net.am org.am -// ao : https://en.wikipedia.org/wiki/.ao +// ao : https://www.iana.org/domains/root/db/ao.html // http://www.dns.ao/REGISTR.DOC ao ed.ao +edu.ao +gov.ao gv.ao og.ao +org.ao co.ao pb.ao it.ao -// aq : https://en.wikipedia.org/wiki/.aq +// aq : https://www.iana.org/domains/root/db/aq.html aq // ar : https://nic.ar/es/nic-argentina/normativa @@ -191,24 +208,25 @@ org.ar senasa.ar tur.ar -// arpa : https://en.wikipedia.org/wiki/.arpa +// arpa : https://www.iana.org/domains/root/db/arpa.html // Confirmed by registry 2008-06-18 arpa e164.arpa +home.arpa in-addr.arpa ip6.arpa iris.arpa uri.arpa urn.arpa -// as : https://en.wikipedia.org/wiki/.as +// as : https://www.iana.org/domains/root/db/as.html as gov.as -// asia : https://en.wikipedia.org/wiki/.asia +// asia : https://www.iana.org/domains/root/db/asia.html asia -// at : https://en.wikipedia.org/wiki/.at +// at : https://www.iana.org/domains/root/db/at.html // Confirmed by registry 2008-06-17 at ac.at @@ -217,8 +235,9 @@ gv.at or.at sth.ac.at -// au : https://en.wikipedia.org/wiki/.au +// au : https://www.iana.org/domains/root/db/au.html // http://www.auda.org.au/ +// Confirmed by registry 2024-11-17 au // 2LDs com.au @@ -229,7 +248,6 @@ gov.au asn.au id.au // Historic 2LDs (closed to new registration, but sites still exist) -info.au conf.au oz.au // CGDNs - http://www.cgdn.org.au/ @@ -264,27 +282,28 @@ wa.gov.au // education.tas.edu.au - Removed at the request of the Department of Education Tasmania schools.nsw.edu.au -// aw : https://en.wikipedia.org/wiki/.aw +// aw : https://www.iana.org/domains/root/db/aw.html aw com.aw -// ax : https://en.wikipedia.org/wiki/.ax +// ax : https://www.iana.org/domains/root/db/ax.html ax -// az : https://en.wikipedia.org/wiki/.az +// az : https://www.iana.org/domains/root/db/az.html +// https://whois.az/?page_id=10 az +biz.az com.az -net.az -int.az -gov.az -org.az edu.az +gov.az info.az -pp.az +int.az mil.az name.az +net.az +org.az +pp.az pro.az -biz.az // ba : http://nic.ba/users_data/files/pravilnik_o_registraciji.pdf ba @@ -295,7 +314,7 @@ mil.ba net.ba org.ba -// bb : https://en.wikipedia.org/wiki/.bb +// bb : https://www.iana.org/domains/root/db/bb.html bb biz.bb co.bb @@ -308,19 +327,19 @@ org.bb store.bb tv.bb -// bd : https://en.wikipedia.org/wiki/.bd +// bd : https://www.iana.org/domains/root/db/bd.html *.bd -// be : https://en.wikipedia.org/wiki/.be +// be : https://www.iana.org/domains/root/db/be.html // Confirmed by registry 2008-06-08 be ac.be -// bf : https://en.wikipedia.org/wiki/.bf +// bf : https://www.iana.org/domains/root/db/bf.html bf gov.bf -// bg : https://en.wikipedia.org/wiki/.bg +// bg : https://www.iana.org/domains/root/db/bg.html // https://www.register.bg/user/static/rules/en/index.html bg a.bg @@ -360,7 +379,7 @@ z.bg 8.bg 9.bg -// bh : https://en.wikipedia.org/wiki/.bh +// bh : https://www.iana.org/domains/root/db/bh.html bh com.bh edu.bh @@ -368,7 +387,7 @@ net.bh org.bh gov.bh -// bi : https://en.wikipedia.org/wiki/.bi +// bi : https://www.iana.org/domains/root/db/bi.html // http://whois.nic.bi/ bi co.bi @@ -377,7 +396,7 @@ edu.bi or.bi org.bi -// biz : https://en.wikipedia.org/wiki/.biz +// biz : https://www.iana.org/domains/root/db/biz.html biz // bj : https://nic.bj/bj-suffixes.txt @@ -420,15 +439,16 @@ gov.bn net.bn org.bn -// bo : https://nic.bo/delegacion2015.php#h-1.10 +// bo : https://nic.bo +// Confirmed by registry 2024-11-19 bo com.bo edu.bo gob.bo int.bo -org.bo -net.bo mil.bo +net.bo +org.bo tv.bo web.bo // Social Domains @@ -454,9 +474,9 @@ natural.bo nombre.bo noticias.bo patria.bo +plurinacional.bo politica.bo profesional.bo -plurinacional.bo pueblo.bo revista.bo salud.bo @@ -484,6 +504,7 @@ ato.br b.br barueri.br belem.br +bet.br bhz.br bib.br bio.br @@ -571,6 +592,7 @@ joinville.br jor.br jus.br leg.br +leilao.br lel.br log.br londrina.br @@ -646,7 +668,7 @@ org.bs edu.bs gov.bs -// bt : https://en.wikipedia.org/wiki/.bt +// bt : https://www.iana.org/domains/root/db/bt.html bt com.bt edu.bt @@ -658,14 +680,14 @@ org.bt // Submitted by registry bv -// bw : https://en.wikipedia.org/wiki/.bw +// bw : https://www.iana.org/domains/root/db/bw.html // http://www.gobin.info/domainname/bw.doc // list of other 2nd level tlds ? bw co.bw org.bw -// by : https://en.wikipedia.org/wiki/.by +// by : https://www.iana.org/domains/root/db/by.html // http://tld.by/rules_2006_en.html // list of other 2nd level tlds ? by @@ -675,20 +697,20 @@ mil.by // second-level domain, but it's being used as one (see www.google.com.by and // www.yahoo.com.by, for example), so we list it here for safety's sake. com.by - // http://hoster.by/ of.by -// bz : https://en.wikipedia.org/wiki/.bz +// bz : https://www.iana.org/domains/root/db/bz.html // http://www.belizenic.bz/ bz +co.bz com.bz net.bz org.bz edu.bz gov.bz -// ca : https://en.wikipedia.org/wiki/.ca +// ca : https://www.iana.org/domains/root/db/ca.html ca // ca geographical names ab.ca @@ -709,27 +731,27 @@ yk.ca // see also: http://registry.gc.ca/en/SubdomainFAQ gc.ca -// cat : https://en.wikipedia.org/wiki/.cat +// cat : https://www.iana.org/domains/root/db/cat.html cat -// cc : https://en.wikipedia.org/wiki/.cc +// cc : https://www.iana.org/domains/root/db/cc.html cc -// cd : https://en.wikipedia.org/wiki/.cd +// cd : https://www.iana.org/domains/root/db/cd.html // see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1 cd gov.cd -// cf : https://en.wikipedia.org/wiki/.cf +// cf : https://www.iana.org/domains/root/db/cf.html cf -// cg : https://en.wikipedia.org/wiki/.cg +// cg : https://www.iana.org/domains/root/db/cg.html cg -// ch : https://en.wikipedia.org/wiki/.ch +// ch : https://www.iana.org/domains/root/db/ch.html ch -// ci : https://en.wikipedia.org/wiki/.ci +// ci : https://www.iana.org/domains/root/db/ci.html // http://www.nic.ci/index.php?page=charte ci org.ci @@ -744,11 +766,9 @@ go.ci asso.ci aéroport.ci int.ci -presse.ci -md.ci gouv.ci -// ck : https://en.wikipedia.org/wiki/.ck +// ck : https://www.iana.org/domains/root/db/ck.html *.ck !www.ck @@ -760,14 +780,14 @@ gob.cl gov.cl mil.cl -// cm : https://en.wikipedia.org/wiki/.cm plus bug 981927 +// cm : https://www.iana.org/domains/root/db/cm.html plus bug 981927 cm co.cm com.cm gov.cm net.cm -// cn : https://en.wikipedia.org/wiki/.cn +// cn : https://www.iana.org/domains/root/db/cn.html // Submitted by registry cn ac.cn @@ -816,27 +836,23 @@ hk.cn mo.cn tw.cn -// co : https://en.wikipedia.org/wiki/.co -// Submitted by registry +// co : https://www.iana.org/domains/root/db/co.html +// https://www.cointernet.com.co/registra +// https://www.cointernet.com.co/como-funciona-un-dominio-restringido +// Confirmed by registry 2024-11-18 co -arts.co com.co edu.co -firm.co gov.co -info.co -int.co mil.co net.co nom.co org.co -rec.co -web.co -// com : https://en.wikipedia.org/wiki/.com +// com : https://www.iana.org/domains/root/db/com.html com -// coop : https://en.wikipedia.org/wiki/.coop +// coop : https://www.iana.org/domains/root/db/coop.html coop // cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do @@ -849,33 +865,38 @@ go.cr or.cr sa.cr -// cu : https://en.wikipedia.org/wiki/.cu +// cu : https://www.iana.org/domains/root/db/cu.html cu com.cu edu.cu -org.cu -net.cu -gov.cu +gob.cu inf.cu +nat.cu +net.cu +org.cu -// cv : https://en.wikipedia.org/wiki/.cv -// cv : http://www.dns.cv/tldcv_portal/do?com=DS;5446457100;111;+PAGE(4000018)+K-CAT-CODIGO(RDOM)+RCNT(100); <- registration rules +// cv : https://www.iana.org/domains/root/db/cv.html +// https://ola.cv/domain-extensions-under-cv/ +// Confirmed by registry 2024-11-26 cv com.cv edu.cv +id.cv int.cv +net.cv nome.cv org.cv +publ.cv -// cw : http://www.una.cw/cw_registry/ -// Confirmed by registry 2013-03-26 +// cw : https://www.uoc.cw/cw-registry +// Confirmed by registry 2024-11-19 cw com.cw edu.cw net.cw org.cw -// cx : https://en.wikipedia.org/wiki/.cx +// cx : https://www.iana.org/domains/root/db/cx.html // list of other 2nd level tlds ? cx gov.cx @@ -897,30 +918,33 @@ press.cy pro.cy tm.cy -// cz : https://en.wikipedia.org/wiki/.cz +// cz : https://www.iana.org/domains/root/db/cz.html cz -// de : https://en.wikipedia.org/wiki/.de +// de : https://www.iana.org/domains/root/db/de.html // Confirmed by registry (with technical // reservations) 2008-07-01 de -// dj : https://en.wikipedia.org/wiki/.dj +// dj : https://www.iana.org/domains/root/db/dj.html dj -// dk : https://en.wikipedia.org/wiki/.dk +// dk : https://www.iana.org/domains/root/db/dk.html // Confirmed by registry 2008-06-17 dk -// dm : https://en.wikipedia.org/wiki/.dm +// dm : https://www.iana.org/domains/root/db/dm.html +// https://nic.dm/policies/pdf/DMRulesandGuidelines2024v1.pdf +// Confirmed by registry 2024-11-19 dm +co.dm com.dm -net.dm -org.dm edu.dm gov.dm +net.dm +org.dm -// do : https://en.wikipedia.org/wiki/.do +// do : https://www.iana.org/domains/root/db/do.html do art.do com.do @@ -962,7 +986,7 @@ gov.ec gob.ec mil.ec -// edu : https://en.wikipedia.org/wiki/.edu +// edu : https://www.iana.org/domains/root/db/edu.html edu // ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B @@ -978,7 +1002,7 @@ aip.ee org.ee fie.ee -// eg : https://en.wikipedia.org/wiki/.eg +// eg : https://www.iana.org/domains/root/db/eg.html eg com.eg edu.eg @@ -990,7 +1014,7 @@ net.eg org.eg sci.eg -// er : https://en.wikipedia.org/wiki/.er +// er : https://www.iana.org/domains/root/db/er.html *.er // es : https://www.nic.es/site_ingles/ingles/dominios/index.html @@ -1001,7 +1025,7 @@ org.es gob.es edu.es -// et : https://en.wikipedia.org/wiki/.et +// et : https://www.iana.org/domains/root/db/et.html et com.et gov.et @@ -1012,16 +1036,15 @@ name.et info.et net.et -// eu : https://en.wikipedia.org/wiki/.eu +// eu : https://www.iana.org/domains/root/db/eu.html eu -// fi : https://en.wikipedia.org/wiki/.fi +// fi : https://www.iana.org/domains/root/db/fi.html fi -// aland.fi : https://en.wikipedia.org/wiki/.ax +// aland.fi : https://www.iana.org/domains/root/db/ax.html // This domain is being phased out in favor of .ax. As there are still many // domains under aland.fi, we still keep it on the list until aland.fi is // completely removed. -// TODO: Check for updates (expected to be phased out around Q1/2009) aland.fi // fj : http://domains.fj/ @@ -1038,21 +1061,20 @@ net.fj org.fj pro.fj -// fk : https://en.wikipedia.org/wiki/.fk +// fk : https://www.iana.org/domains/root/db/fk.html *.fk -// fm : https://en.wikipedia.org/wiki/.fm +// fm : https://www.iana.org/domains/root/db/fm.html com.fm edu.fm net.fm org.fm fm -// fo : https://en.wikipedia.org/wiki/.fo +// fo : https://www.iana.org/domains/root/db/fo.html fo -// fr : http://www.afnic.fr/ -// domaines descriptifs : https://www.afnic.fr/medias/documents/Cadre_legal/Afnic_Naming_Policy_12122016_VEN.pdf +// fr : https://www.afnic.fr/ https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf fr asso.fr com.fr @@ -1060,46 +1082,36 @@ gouv.fr nom.fr prd.fr tm.fr -// domaines sectoriels : https://www.afnic.fr/en/products-and-services/the-fr-tld/sector-based-fr-domains-4.html -aeroport.fr -avocat.fr +// Other SLDs now selfmanaged out of AFNIC range. Former "domaines sectoriels", still registration suffixes avoues.fr cci.fr -chambagri.fr -chirurgiens-dentistes.fr -experts-comptables.fr -geometre-expert.fr greta.fr huissier-justice.fr -medecin.fr -notaires.fr -pharmacien.fr -port.fr -veterinaire.fr -// ga : https://en.wikipedia.org/wiki/.ga +// ga : https://www.iana.org/domains/root/db/ga.html ga // gb : This registry is effectively dormant // Submitted by registry gb -// gd : https://en.wikipedia.org/wiki/.gd +// gd : https://www.iana.org/domains/root/db/gd.html edu.gd gov.gd gd -// ge : http://www.nic.net.ge/policy_en.pdf +// ge : https://nic.ge/en/administrator/the-ge-domain-regulations +// Confirmed by registry 2024-11-20 ge com.ge edu.ge gov.ge -org.ge -mil.ge net.ge +org.ge pvt.ge +school.ge -// gf : https://en.wikipedia.org/wiki/.gf +// gf : https://www.iana.org/domains/root/db/gf.html gf // gg : http://www.channelisles.net/register-domains/ @@ -1109,7 +1121,7 @@ co.gg net.gg org.gg -// gh : https://en.wikipedia.org/wiki/.gh +// gh : https://www.iana.org/domains/root/db/gh.html // see also: http://www.nic.gh/reg_now.php // Although domains directly at second level are not possible at the moment, // they have been possible for some time and may come back. @@ -1129,7 +1141,7 @@ mod.gi edu.gi org.gi -// gl : https://en.wikipedia.org/wiki/.gl +// gl : https://www.iana.org/domains/root/db/gl.html // http://nic.gl gl co.gl @@ -1151,7 +1163,7 @@ gov.gn org.gn net.gn -// gov : https://en.wikipedia.org/wiki/.gov +// gov : https://www.iana.org/domains/root/db/gov.html gov // gp : http://www.nic.gp/index.php?lang=en @@ -1163,7 +1175,7 @@ edu.gp org.gp asso.gp -// gq : https://en.wikipedia.org/wiki/.gq +// gq : https://www.iana.org/domains/root/db/gq.html gq // gr : https://grweb.ics.forth.gr/english/1617-B-2005.html @@ -1175,7 +1187,7 @@ net.gr org.gr gov.gr -// gs : https://en.wikipedia.org/wiki/.gs +// gs : https://www.iana.org/domains/root/db/gs.html gs // gt : https://www.gt/sitio/registration_policy.php?lang=en @@ -1201,11 +1213,11 @@ net.gu org.gu web.gu -// gw : https://en.wikipedia.org/wiki/.gw +// gw : https://www.iana.org/domains/root/db/gw.html // gw : https://nic.gw/regras/ gw -// gy : https://en.wikipedia.org/wiki/.gy +// gy : https://www.iana.org/domains/root/db/gy.html // http://registry.gy/ gy co.gy @@ -1240,7 +1252,7 @@ org.hk 組織.hk 組织.hk -// hm : https://en.wikipedia.org/wiki/.hm +// hm : https://www.iana.org/domains/root/db/hm.html hm // hn : http://www.nic.hn/politicas/ps02,,05.html @@ -1329,7 +1341,7 @@ ponpes.id sch.id web.id -// ie : https://en.wikipedia.org/wiki/.ie +// ie : https://www.iana.org/domains/root/db/ie.html ie gov.ie @@ -1369,7 +1381,7 @@ plc.co.im tt.im tv.im -// in : https://en.wikipedia.org/wiki/.in +// in : https://www.iana.org/domains/root/db/in.html // see also: https://registry.in/policies // Please note, that nic.in is not an official eTLD, but used by most // government institutions. @@ -1416,18 +1428,24 @@ uk.in up.in us.in -// info : https://en.wikipedia.org/wiki/.info +// info : https://www.iana.org/domains/root/db/info.html info -// int : https://en.wikipedia.org/wiki/.int +// int : https://www.iana.org/domains/root/db/int.html // Confirmed by registry 2008-06-18 int eu.int // io : http://www.nic.io/rules.htm -// list of other 2nd level tlds ? io +co.io com.io +edu.io +gov.io +mil.io +net.io +nom.io +org.io // iq : http://www.cmc.iq/english/iq/iqregister1.htm iq @@ -1455,16 +1473,10 @@ sch.ir ايران.ir // is : http://www.isnic.is/domain/rules.php -// Confirmed by registry 2008-12-06 +// Confirmed by registry 2024-11-17 is -net.is -com.is -edu.is -gov.is -org.is -int.is - -// it : https://en.wikipedia.org/wiki/.it + +// it : https://www.iana.org/domains/root/db/it.html it gov.it edu.it @@ -1887,21 +1899,28 @@ org.je // jm : http://www.com.jm/register.html *.jm -// jo : http://www.dns.jo/Registration_policy.aspx +// jo : https://www.dns.jo/JoFamily.aspx +// Confirmed by registry 2024-11-17 jo +agri.jo +ai.jo com.jo -org.jo -net.jo edu.jo -sch.jo +eng.jo +fm.jo gov.jo mil.jo -name.jo +net.jo +org.jo +per.jo +phd.jo +sch.jo +tv.jo -// jobs : https://en.wikipedia.org/wiki/.jobs +// jobs : https://www.iana.org/domains/root/db/jobs.html jobs -// jp : https://en.wikipedia.org/wiki/.jp +// jp : https://www.iana.org/domains/root/db/jp.html // http://jprs.co.jp/en/jpdomain.html // Submitted by registry jp @@ -2013,18 +2032,18 @@ yamanashi.jp // jp geographic type names // http://jprs.jp/doc/rule/saisoku-1.html *.kawasaki.jp -*.kitakyushu.jp -*.kobe.jp -*.nagoya.jp -*.sapporo.jp -*.sendai.jp -*.yokohama.jp !city.kawasaki.jp +*.kitakyushu.jp !city.kitakyushu.jp +*.kobe.jp !city.kobe.jp +*.nagoya.jp !city.nagoya.jp +*.sapporo.jp !city.sapporo.jp +*.sendai.jp !city.sendai.jp +*.yokohama.jp !city.yokohama.jp // 4th level registration aisai.aichi.jp @@ -3735,7 +3754,7 @@ gov.ki info.ki com.ki -// km : https://en.wikipedia.org/wiki/.km +// km : https://www.iana.org/domains/root/db/km.html // http://www.domaine.km/documents/charte.doc km org.km @@ -3748,7 +3767,7 @@ mil.km ass.km com.km // These are only mentioned as proposed suggestions at domaine.km, but -// https://en.wikipedia.org/wiki/.km says they're available for registration: +// https://www.iana.org/domains/root/db/km.html says they're available for registration: coop.km asso.km presse.km @@ -3758,7 +3777,7 @@ pharmaciens.km veterinaire.km gouv.km -// kn : https://en.wikipedia.org/wiki/.kn +// kn : https://www.iana.org/domains/root/db/kn.html // http://www.dot.kn/domainRules.html kn net.kn @@ -3775,7 +3794,7 @@ org.kp rep.kp tra.kp -// kr : https://en.wikipedia.org/wiki/.kr +// kr : https://www.iana.org/domains/root/db/kr.html // see also: http://domain.nida.or.kr/eng/registration.jsp kr ac.kr @@ -3828,7 +3847,7 @@ edu.ky net.ky org.ky -// kz : https://en.wikipedia.org/wiki/.kz +// kz : https://www.iana.org/domains/root/db/kz.html // see also: http://www.nic.kz/rules/index.jsp kz org.kz @@ -3838,7 +3857,7 @@ gov.kz mil.kz com.kz -// la : https://en.wikipedia.org/wiki/.la +// la : https://www.iana.org/domains/root/db/la.html // Submitted by registry la int.la @@ -3850,7 +3869,7 @@ per.la com.la org.la -// lb : https://en.wikipedia.org/wiki/.lb +// lb : https://www.iana.org/domains/root/db/lb.html // Submitted by registry lb com.lb @@ -3859,7 +3878,7 @@ gov.lb net.lb org.lb -// lc : https://en.wikipedia.org/wiki/.lc +// lc : https://www.iana.org/domains/root/db/lc.html // see also: http://www.nic.lc/rules.htm lc com.lc @@ -3869,7 +3888,7 @@ org.lc edu.lc gov.lc -// li : https://en.wikipedia.org/wiki/.li +// li : https://www.iana.org/domains/root/db/li.html li // lk : https://www.nic.lk/index.php/domain-registration/lk-domain-naming-structure @@ -3912,7 +3931,7 @@ net.ls org.ls sc.ls -// lt : https://en.wikipedia.org/wiki/.lt +// lt : https://www.iana.org/domains/root/db/lt.html lt // gov.lt : http://www.gov.lt/index_en.php gov.lt @@ -3944,7 +3963,7 @@ med.ly org.ly id.ly -// ma : https://en.wikipedia.org/wiki/.ma +// ma : https://www.iana.org/domains/root/db/ma.html // http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf ma co.ma @@ -3959,10 +3978,10 @@ mc tm.mc asso.mc -// md : https://en.wikipedia.org/wiki/.md +// md : https://www.iana.org/domains/root/db/md.html md -// me : https://en.wikipedia.org/wiki/.me +// me : https://www.iana.org/domains/root/db/me.html me co.me net.me @@ -3973,25 +3992,24 @@ gov.me its.me priv.me -// mg : http://nic.mg/nicmg/?page_id=39 +// mg : https://nic.mg mg -org.mg -nom.mg -gov.mg -prd.mg -tm.mg +co.mg +com.mg edu.mg +gov.mg mil.mg -com.mg -co.mg +nom.mg +org.mg +prd.mg -// mh : https://en.wikipedia.org/wiki/.mh +// mh : https://www.iana.org/domains/root/db/mh.html mh -// mil : https://en.wikipedia.org/wiki/.mil +// mil : https://www.iana.org/domains/root/db/mil.html mil -// mk : https://en.wikipedia.org/wiki/.mk +// mk : https://www.iana.org/domains/root/db/mk.html // see also: http://dns.marnet.net.mk/postapka.php mk com.mk @@ -4003,7 +4021,7 @@ inf.mk name.mk // ml : http://www.gobin.info/domainname/ml-template.doc -// see also: https://en.wikipedia.org/wiki/.ml +// see also: https://www.iana.org/domains/root/db/ml.html ml com.ml edu.ml @@ -4013,10 +4031,10 @@ net.ml org.ml presse.ml -// mm : https://en.wikipedia.org/wiki/.mm +// mm : https://www.iana.org/domains/root/db/mm.html *.mm -// mn : https://en.wikipedia.org/wiki/.mn +// mn : https://www.iana.org/domains/root/db/mn.html mn gov.mn edu.mn @@ -4030,17 +4048,17 @@ org.mo edu.mo gov.mo -// mobi : https://en.wikipedia.org/wiki/.mobi +// mobi : https://www.iana.org/domains/root/db/mobi.html mobi // mp : http://www.dot.mp/ // Confirmed by registry 2008-06-17 mp -// mq : https://en.wikipedia.org/wiki/.mq +// mq : https://www.iana.org/domains/root/db/mq.html mq -// mr : https://en.wikipedia.org/wiki/.mr +// mr : https://www.iana.org/domains/root/db/mr.html mr gov.mr @@ -4060,7 +4078,7 @@ edu.mt net.mt org.mt -// mu : https://en.wikipedia.org/wiki/.mu +// mu : https://www.iana.org/domains/root/db/mu.html mu com.mu net.mu @@ -4070,557 +4088,10 @@ ac.mu co.mu or.mu -// museum : http://about.museum/naming/ -// http://index.museum/ +// museum : https://welcome.museum/wp-content/uploads/2018/05/20180525-Registration-Policy-MUSEUM-EN_VF-2.pdf https://welcome.museum/buy-your-dot-museum-2/ museum -academy.museum -agriculture.museum -air.museum -airguard.museum -alabama.museum -alaska.museum -amber.museum -ambulance.museum -american.museum -americana.museum -americanantiques.museum -americanart.museum -amsterdam.museum -and.museum -annefrank.museum -anthro.museum -anthropology.museum -antiques.museum -aquarium.museum -arboretum.museum -archaeological.museum -archaeology.museum -architecture.museum -art.museum -artanddesign.museum -artcenter.museum -artdeco.museum -arteducation.museum -artgallery.museum -arts.museum -artsandcrafts.museum -asmatart.museum -assassination.museum -assisi.museum -association.museum -astronomy.museum -atlanta.museum -austin.museum -australia.museum -automotive.museum -aviation.museum -axis.museum -badajoz.museum -baghdad.museum -bahn.museum -bale.museum -baltimore.museum -barcelona.museum -baseball.museum -basel.museum -baths.museum -bauern.museum -beauxarts.museum -beeldengeluid.museum -bellevue.museum -bergbau.museum -berkeley.museum -berlin.museum -bern.museum -bible.museum -bilbao.museum -bill.museum -birdart.museum -birthplace.museum -bonn.museum -boston.museum -botanical.museum -botanicalgarden.museum -botanicgarden.museum -botany.museum -brandywinevalley.museum -brasil.museum -bristol.museum -british.museum -britishcolumbia.museum -broadcast.museum -brunel.museum -brussel.museum -brussels.museum -bruxelles.museum -building.museum -burghof.museum -bus.museum -bushey.museum -cadaques.museum -california.museum -cambridge.museum -can.museum -canada.museum -capebreton.museum -carrier.museum -cartoonart.museum -casadelamoneda.museum -castle.museum -castres.museum -celtic.museum -center.museum -chattanooga.museum -cheltenham.museum -chesapeakebay.museum -chicago.museum -children.museum -childrens.museum -childrensgarden.museum -chiropractic.museum -chocolate.museum -christiansburg.museum -cincinnati.museum -cinema.museum -circus.museum -civilisation.museum -civilization.museum -civilwar.museum -clinton.museum -clock.museum -coal.museum -coastaldefence.museum -cody.museum -coldwar.museum -collection.museum -colonialwilliamsburg.museum -coloradoplateau.museum -columbia.museum -columbus.museum -communication.museum -communications.museum -community.museum -computer.museum -computerhistory.museum -comunicações.museum -contemporary.museum -contemporaryart.museum -convent.museum -copenhagen.museum -corporation.museum -correios-e-telecomunicações.museum -corvette.museum -costume.museum -countryestate.museum -county.museum -crafts.museum -cranbrook.museum -creation.museum -cultural.museum -culturalcenter.museum -culture.museum -cyber.museum -cymru.museum -dali.museum -dallas.museum -database.museum -ddr.museum -decorativearts.museum -delaware.museum -delmenhorst.museum -denmark.museum -depot.museum -design.museum -detroit.museum -dinosaur.museum -discovery.museum -dolls.museum -donostia.museum -durham.museum -eastafrica.museum -eastcoast.museum -education.museum -educational.museum -egyptian.museum -eisenbahn.museum -elburg.museum -elvendrell.museum -embroidery.museum -encyclopedic.museum -england.museum -entomology.museum -environment.museum -environmentalconservation.museum -epilepsy.museum -essex.museum -estate.museum -ethnology.museum -exeter.museum -exhibition.museum -family.museum -farm.museum -farmequipment.museum -farmers.museum -farmstead.museum -field.museum -figueres.museum -filatelia.museum -film.museum -fineart.museum -finearts.museum -finland.museum -flanders.museum -florida.museum -force.museum -fortmissoula.museum -fortworth.museum -foundation.museum -francaise.museum -frankfurt.museum -franziskaner.museum -freemasonry.museum -freiburg.museum -fribourg.museum -frog.museum -fundacio.museum -furniture.museum -gallery.museum -garden.museum -gateway.museum -geelvinck.museum -gemological.museum -geology.museum -georgia.museum -giessen.museum -glas.museum -glass.museum -gorge.museum -grandrapids.museum -graz.museum -guernsey.museum -halloffame.museum -hamburg.museum -handson.museum -harvestcelebration.museum -hawaii.museum -health.museum -heimatunduhren.museum -hellas.museum -helsinki.museum -hembygdsforbund.museum -heritage.museum -histoire.museum -historical.museum -historicalsociety.museum -historichouses.museum -historisch.museum -historisches.museum -history.museum -historyofscience.museum -horology.museum -house.museum -humanities.museum -illustration.museum -imageandsound.museum -indian.museum -indiana.museum -indianapolis.museum -indianmarket.museum -intelligence.museum -interactive.museum -iraq.museum -iron.museum -isleofman.museum -jamison.museum -jefferson.museum -jerusalem.museum -jewelry.museum -jewish.museum -jewishart.museum -jfk.museum -journalism.museum -judaica.museum -judygarland.museum -juedisches.museum -juif.museum -karate.museum -karikatur.museum -kids.museum -koebenhavn.museum -koeln.museum -kunst.museum -kunstsammlung.museum -kunstunddesign.museum -labor.museum -labour.museum -lajolla.museum -lancashire.museum -landes.museum -lans.museum -läns.museum -larsson.museum -lewismiller.museum -lincoln.museum -linz.museum -living.museum -livinghistory.museum -localhistory.museum -london.museum -losangeles.museum -louvre.museum -loyalist.museum -lucerne.museum -luxembourg.museum -luzern.museum -mad.museum -madrid.museum -mallorca.museum -manchester.museum -mansion.museum -mansions.museum -manx.museum -marburg.museum -maritime.museum -maritimo.museum -maryland.museum -marylhurst.museum -media.museum -medical.museum -medizinhistorisches.museum -meeres.museum -memorial.museum -mesaverde.museum -michigan.museum -midatlantic.museum -military.museum -mill.museum -miners.museum -mining.museum -minnesota.museum -missile.museum -missoula.museum -modern.museum -moma.museum -money.museum -monmouth.museum -monticello.museum -montreal.museum -moscow.museum -motorcycle.museum -muenchen.museum -muenster.museum -mulhouse.museum -muncie.museum -museet.museum -museumcenter.museum -museumvereniging.museum -music.museum -national.museum -nationalfirearms.museum -nationalheritage.museum -nativeamerican.museum -naturalhistory.museum -naturalhistorymuseum.museum -naturalsciences.museum -nature.museum -naturhistorisches.museum -natuurwetenschappen.museum -naumburg.museum -naval.museum -nebraska.museum -neues.museum -newhampshire.museum -newjersey.museum -newmexico.museum -newport.museum -newspaper.museum -newyork.museum -niepce.museum -norfolk.museum -north.museum -nrw.museum -nyc.museum -nyny.museum -oceanographic.museum -oceanographique.museum -omaha.museum -online.museum -ontario.museum -openair.museum -oregon.museum -oregontrail.museum -otago.museum -oxford.museum -pacific.museum -paderborn.museum -palace.museum -paleo.museum -palmsprings.museum -panama.museum -paris.museum -pasadena.museum -pharmacy.museum -philadelphia.museum -philadelphiaarea.museum -philately.museum -phoenix.museum -photography.museum -pilots.museum -pittsburgh.museum -planetarium.museum -plantation.museum -plants.museum -plaza.museum -portal.museum -portland.museum -portlligat.museum -posts-and-telecommunications.museum -preservation.museum -presidio.museum -press.museum -project.museum -public.museum -pubol.museum -quebec.museum -railroad.museum -railway.museum -research.museum -resistance.museum -riodejaneiro.museum -rochester.museum -rockart.museum -roma.museum -russia.museum -saintlouis.museum -salem.museum -salvadordali.museum -salzburg.museum -sandiego.museum -sanfrancisco.museum -santabarbara.museum -santacruz.museum -santafe.museum -saskatchewan.museum -satx.museum -savannahga.museum -schlesisches.museum -schoenbrunn.museum -schokoladen.museum -school.museum -schweiz.museum -science.museum -scienceandhistory.museum -scienceandindustry.museum -sciencecenter.museum -sciencecenters.museum -science-fiction.museum -sciencehistory.museum -sciences.museum -sciencesnaturelles.museum -scotland.museum -seaport.museum -settlement.museum -settlers.museum -shell.museum -sherbrooke.museum -sibenik.museum -silk.museum -ski.museum -skole.museum -society.museum -sologne.museum -soundandvision.museum -southcarolina.museum -southwest.museum -space.museum -spy.museum -square.museum -stadt.museum -stalbans.museum -starnberg.museum -state.museum -stateofdelaware.museum -station.museum -steam.museum -steiermark.museum -stjohn.museum -stockholm.museum -stpetersburg.museum -stuttgart.museum -suisse.museum -surgeonshall.museum -surrey.museum -svizzera.museum -sweden.museum -sydney.museum -tank.museum -tcm.museum -technology.museum -telekommunikation.museum -television.museum -texas.museum -textile.museum -theater.museum -time.museum -timekeeping.museum -topology.museum -torino.museum -touch.museum -town.museum -transport.museum -tree.museum -trolley.museum -trust.museum -trustee.museum -uhren.museum -ulm.museum -undersea.museum -university.museum -usa.museum -usantiques.museum -usarts.museum -uscountryestate.museum -usculture.museum -usdecorativearts.museum -usgarden.museum -ushistory.museum -ushuaia.museum -uslivinghistory.museum -utah.museum -uvic.museum -valley.museum -vantaa.museum -versailles.museum -viking.museum -village.museum -virginia.museum -virtual.museum -virtuel.museum -vlaanderen.museum -volkenkunde.museum -wales.museum -wallonie.museum -war.museum -washingtondc.museum -watchandclock.museum -watch-and-clock.museum -western.museum -westfalen.museum -whaling.museum -wildlife.museum -williamsburg.museum -windmill.museum -workshop.museum -york.museum -yorkshire.museum -yosemite.museum -youth.museum -zoological.museum -zoology.museum -ירושלים.museum -иком.museum - -// mv : https://en.wikipedia.org/wiki/.mv + +// mv : https://www.iana.org/domains/root/db/mv.html // "mv" included because, contra Wikipedia, google.mv exists. mv aero.mv @@ -4648,7 +4119,6 @@ coop.mw edu.mw gov.mw int.mw -museum.mw net.mw org.mw @@ -4686,24 +4156,12 @@ net.mz org.mz // na : http://www.na-nic.com.na/ -// http://www.info.na/domain/ na -info.na -pro.na -name.na -school.na -or.na -dr.na -us.na -mx.na -ca.na -in.na -cc.na -tv.na -ws.na -mobi.na +alt.na co.na com.na +gov.na +net.na org.na // name : has 2nd-level tlds, but there's no list of them @@ -4714,13 +4172,13 @@ nc asso.nc nom.nc -// ne : https://en.wikipedia.org/wiki/.ne +// ne : https://www.iana.org/domains/root/db/ne.html ne -// net : https://en.wikipedia.org/wiki/.net +// net : https://www.iana.org/domains/root/db/net.html net -// nf : https://en.wikipedia.org/wiki/.nf +// nf : https://www.iana.org/domains/root/db/nf.html nf com.nf net.nf @@ -4763,7 +4221,7 @@ nom.ni org.ni web.ni -// nl : https://en.wikipedia.org/wiki/.nl +// nl : https://www.iana.org/domains/root/db/nl.html // https://www.sidn.nl/ // ccTLD for the Netherlands nl @@ -5549,10 +5007,10 @@ org.nr net.nr com.nr -// nu : https://en.wikipedia.org/wiki/.nu +// nu : https://www.iana.org/domains/root/db/nu.html nu -// nz : https://en.wikipedia.org/wiki/.nz +// nz : https://www.iana.org/domains/root/db/nz.html // Submitted by registry nz ac.nz @@ -5572,7 +5030,7 @@ org.nz parliament.nz school.nz -// om : https://en.wikipedia.org/wiki/.om +// om : https://www.iana.org/domains/root/db/om.html om co.om com.om @@ -5587,7 +5045,7 @@ pro.om // onion : https://tools.ietf.org/html/rfc7686 onion -// org : https://en.wikipedia.org/wiki/.org +// org : https://www.iana.org/domains/root/db/org.html org // pa : http://www.nic.pa/ @@ -5622,7 +5080,7 @@ com.pf org.pf edu.pf -// pg : https://en.wikipedia.org/wiki/.pg +// pg : https://www.iana.org/domains/root/db/pg.html *.pg // ph : http://www.domains.ph/FAQ2.asp @@ -5637,32 +5095,37 @@ ngo.ph mil.ph i.ph -// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK +// pk : https://pknic.net.pk +// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK + grandfathered old gon.pk +// Contact Email: staff@pknic.net.pk PKNIC .PK Registry + pk +ac.pk +biz.pk com.pk -net.pk edu.pk -org.pk fam.pk -biz.pk -web.pk -gov.pk +gkp.pk gob.pk +gog.pk gok.pk gon.pk gop.pk gos.pk -info.pk +gov.pk +net.pk +org.pk +web.pk -// pl http://www.dns.pl/english/index.html -// Submitted by registry +// pl : https://www.dns.pl/en/ +// Confirmed by registry 2024-11-18 pl com.pl net.pl org.pl -// pl functional domains (http://www.dns.pl/english/index.html) -aid.pl +// pl functional domains : https://www.dns.pl/en/list_of_functional_domain_names agro.pl +aid.pl atm.pl auto.pl biz.pl @@ -5671,8 +5134,8 @@ gmina.pl gsm.pl info.pl mail.pl -miasta.pl media.pl +miasta.pl mil.pl nieruchomosci.pl nom.pl @@ -5691,56 +5154,65 @@ tm.pl tourism.pl travel.pl turystyka.pl -// Government domains +// Government domains : https://www.dns.pl/informacje_o_rejestracji_domen_gov_pl +// In accordance with the .gov.pl Domain Name Regulations : https://www.dns.pl/regulamin_gov_pl gov.pl ap.gov.pl +griw.gov.pl ic.gov.pl is.gov.pl -us.gov.pl kmpsp.gov.pl +konsulat.gov.pl kppsp.gov.pl -kwpsp.gov.pl -psp.gov.pl -wskr.gov.pl kwp.gov.pl +kwpsp.gov.pl +mup.gov.pl mw.gov.pl -ug.gov.pl -um.gov.pl -umig.gov.pl -ugim.gov.pl -upow.gov.pl -uw.gov.pl -starostwo.gov.pl +oia.gov.pl +oirm.gov.pl +oke.gov.pl +oow.gov.pl +oschr.gov.pl +oum.gov.pl pa.gov.pl +pinb.gov.pl +piw.gov.pl po.gov.pl +pr.gov.pl +psp.gov.pl psse.gov.pl pup.gov.pl rzgw.gov.pl sa.gov.pl +sdn.gov.pl +sko.gov.pl so.gov.pl sr.gov.pl -wsa.gov.pl -sko.gov.pl +starostwo.gov.pl +ug.gov.pl +ugim.gov.pl +um.gov.pl +umig.gov.pl +upow.gov.pl +uppo.gov.pl +us.gov.pl +uw.gov.pl uzs.gov.pl +wif.gov.pl wiih.gov.pl winb.gov.pl -pinb.gov.pl wios.gov.pl witd.gov.pl -wzmiuw.gov.pl -piw.gov.pl wiw.gov.pl -griw.gov.pl -wif.gov.pl -oum.gov.pl -sdn.gov.pl -zp.gov.pl -uppo.gov.pl -mup.gov.pl +wkz.gov.pl +wsa.gov.pl +wskr.gov.pl +wsse.gov.pl wuoz.gov.pl -konsulat.gov.pl -oirm.gov.pl -// pl regional domains (http://www.dns.pl/english/index.html) +wzmiuw.gov.pl +zp.gov.pl +zpisdn.gov.pl +// pl regional domains : https://www.dns.pl/en/list_of_regional_domain_names augustow.pl babia-gora.pl bedzin.pl @@ -5767,11 +5239,11 @@ jaworzno.pl jelenia-gora.pl jgora.pl kalisz.pl -kazimierz-dolny.pl karpacz.pl kartuzy.pl kaszuby.pl katowice.pl +kazimierz-dolny.pl kepno.pl ketrzyn.pl klodzko.pl @@ -5814,8 +5286,8 @@ pisz.pl podhale.pl podlasie.pl polkowice.pl -pomorze.pl pomorskie.pl +pomorze.pl prochowice.pl pruszkow.pl przeworsk.pl @@ -5826,11 +5298,11 @@ rybnik.pl rzeszow.pl sanok.pl sejny.pl +skoczow.pl slask.pl slupsk.pl sosnowiec.pl stalowa-wola.pl -skoczow.pl starachowice.pl stargard.pl suwalki.pl @@ -5861,7 +5333,7 @@ zarow.pl zgora.pl zgorzelec.pl -// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +// pm : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf pm // pn : http://www.government.pn/PnRegistry/policies.htm @@ -5872,7 +5344,7 @@ org.pn edu.pn net.pn -// post : https://en.wikipedia.org/wiki/.post +// post : https://www.iana.org/domains/root/db/post.html post // pr : http://www.nic.pr/index.asp?f=1 @@ -5887,7 +5359,7 @@ pro.pr biz.pr info.pr name.pr -// these aren't mentioned on nic.pr, but on https://en.wikipedia.org/wiki/.pr +// these aren't mentioned on nic.pr, but on https://www.iana.org/domains/root/db/pr.html est.pr prof.pr ac.pr @@ -5906,7 +5378,7 @@ law.pro med.pro recht.pro -// ps : https://en.wikipedia.org/wiki/.ps +// ps : https://www.iana.org/domains/root/db/ps.html // http://www.nic.ps/registration/policy.html#reg ps edu.ps @@ -5928,10 +5400,9 @@ publ.pt com.pt nome.pt -// pw : https://en.wikipedia.org/wiki/.pw +// pw : https://www.iana.org/domains/root/db/pw.html pw co.pw -ne.pw or.pw ed.pw go.pw @@ -5959,11 +5430,12 @@ net.qa org.qa sch.qa -// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs +// re : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf +// Confirmed by registry 2024-11-18 re +// Closed for registration on 2013-03-15 but domains are still maintained asso.re com.re -nom.re // ro : http://www.rotld.ro/ ro @@ -6042,7 +5514,7 @@ tv.sd gov.sd info.sd -// se : https://en.wikipedia.org/wiki/.se +// se : https://www.iana.org/domains/root/db/se.html // Submitted by registry se a.se @@ -6085,14 +5557,14 @@ x.se y.se z.se -// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines +// sg : https://www.sgnic.sg/domain-registration/sg-categories-rules +// Confirmed by registry 2024-11-19 sg com.sg net.sg org.sg gov.sg edu.sg -per.sg // sh : http://nic.sh/rules.htm sh @@ -6102,15 +5574,14 @@ gov.sh org.sh mil.sh -// si : https://en.wikipedia.org/wiki/.si +// si : https://www.iana.org/domains/root/db/si.html si // sj : No registrations at this time. // Submitted by registry sj -// sk : https://en.wikipedia.org/wiki/.sk -// list of 2nd level domains ? +// sk : https://www.iana.org/domains/root/db/sk.html sk // sl : http://www.nic.sl @@ -6122,10 +5593,10 @@ edu.sl gov.sl org.sl -// sm : https://en.wikipedia.org/wiki/.sm +// sm : https://www.iana.org/domains/root/db/sm.html sm -// sn : https://en.wikipedia.org/wiki/.sn +// sn : https://www.iana.org/domains/root/db/sn.html sn art.sn com.sn @@ -6144,13 +5615,14 @@ me.so net.so org.so -// sr : https://en.wikipedia.org/wiki/.sr +// sr : https://www.iana.org/domains/root/db/sr.html sr // ss : https://registry.nic.ss/ // Submitted by registry ss biz.ss +co.ss com.ss edu.ss gov.ss @@ -6173,7 +5645,7 @@ principe.st saotome.st store.st -// su : https://en.wikipedia.org/wiki/.su +// su : https://www.iana.org/domains/root/db/su.html su // sv : http://www.svnet.org.sv/niveldos.pdf @@ -6184,12 +5656,12 @@ gob.sv org.sv red.sv -// sx : https://en.wikipedia.org/wiki/.sx +// sx : https://www.iana.org/domains/root/db/sx.html // Submitted by registry sx gov.sx -// sy : https://en.wikipedia.org/wiki/.sy +// sy : https://www.iana.org/domains/root/db/sy.html // see also: http://www.gobin.info/domainname/sy.doc sy edu.sy @@ -6199,31 +5671,31 @@ mil.sy com.sy org.sy -// sz : https://en.wikipedia.org/wiki/.sz +// sz : https://www.iana.org/domains/root/db/sz.html // http://www.sispa.org.sz/ sz co.sz ac.sz org.sz -// tc : https://en.wikipedia.org/wiki/.tc +// tc : https://www.iana.org/domains/root/db/tc.html tc -// td : https://en.wikipedia.org/wiki/.td +// td : https://www.iana.org/domains/root/db/td.html td -// tel: https://en.wikipedia.org/wiki/.tel +// tel: https://www.iana.org/domains/root/db/tel.html // http://www.telnic.org/ tel -// tf : https://en.wikipedia.org/wiki/.tf +// tf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf tf -// tg : https://en.wikipedia.org/wiki/.tg +// tg : https://www.iana.org/domains/root/db/tg.html // http://www.nic.tg/ tg -// th : https://en.wikipedia.org/wiki/.th +// th : https://www.iana.org/domains/root/db/th.html // Submitted by registry th ac.th @@ -6252,23 +5724,24 @@ org.tj test.tj web.tj -// tk : https://en.wikipedia.org/wiki/.tk +// tk : https://www.iana.org/domains/root/db/tk.html tk -// tl : https://en.wikipedia.org/wiki/.tl +// tl : https://www.iana.org/domains/root/db/tl.html tl gov.tl -// tm : http://www.nic.tm/local.html +// tm : https://www.nic.tm/local.html +// Confirmed by registry - 2024-11-19 tm -com.tm co.tm -org.tm -net.tm -nom.tm +com.tm +edu.tm gov.tm mil.tm -edu.tm +net.tm +nom.tm +org.tm // tn : http://www.registre.tn/fr/ // https://whois.ati.tn/ @@ -6287,7 +5760,7 @@ org.tn perso.tn tourism.tn -// to : https://en.wikipedia.org/wiki/.to +// to : https://www.iana.org/domains/root/db/to.html // Submitted by registry to com.to @@ -6327,32 +5800,27 @@ nc.tr // Used by government agencies of Northern Cyprus gov.nc.tr -// tt : http://www.nic.tt/ +// tt : https://www.nic.tt/ +// Confirmed by registry - 2024-11-19 tt +biz.tt co.tt com.tt -org.tt -net.tt -biz.tt +edu.tt +gov.tt info.tt -pro.tt -int.tt -coop.tt -jobs.tt -mobi.tt -travel.tt -museum.tt -aero.tt +mil.tt name.tt -gov.tt -edu.tt +net.tt +org.tt +pro.tt -// tv : https://en.wikipedia.org/wiki/.tv +// tv : https://www.iana.org/domains/root/db/tv.html // Not listing any 2LDs as reserved since none seem to exist in practice, // Wikipedia notwithstanding. tv -// tw : https://en.wikipedia.org/wiki/.tw +// tw : https://www.iana.org/domains/root/db/tw.html tw edu.tw gov.tw @@ -6424,6 +5892,7 @@ kiev.ua kirovograd.ua km.ua kr.ua +kropyvnytskyi.ua krym.ua ks.ua kv.ua @@ -6431,6 +5900,7 @@ kyiv.ua lg.ua lt.ua lugansk.ua +luhansk.ua lutsk.ua lv.ua lviv.ua @@ -6454,11 +5924,13 @@ te.ua ternopil.ua uz.ua uzhgorod.ua +uzhhorod.ua vinnica.ua vinnytsia.ua vn.ua volyn.ua yalta.ua +zakarpattia.ua zaporizhzhe.ua zaporizhzhia.ua zhitomir.ua @@ -6477,7 +5949,7 @@ ne.ug com.ug org.ug -// uk : https://en.wikipedia.org/wiki/.uk +// uk : https://www.iana.org/domains/root/db/uk.html // Submitted by registry uk ac.uk @@ -6492,7 +5964,7 @@ plc.uk police.uk *.sch.uk -// us : https://en.wikipedia.org/wiki/.us +// us : https://www.iana.org/domains/root/db/us.html us dni.us fed.us @@ -6570,7 +6042,6 @@ k12.ca.us k12.co.us k12.ct.us k12.dc.us -k12.de.us k12.fl.us k12.ga.us k12.gu.us @@ -6761,10 +6232,10 @@ com.uz net.uz org.uz -// va : https://en.wikipedia.org/wiki/.va +// va : https://www.iana.org/domains/root/db/va.html va -// vc : https://en.wikipedia.org/wiki/.vc +// vc : https://www.iana.org/domains/root/db/vc.html // Submitted by registry vc com.vc @@ -6798,7 +6269,7 @@ store.ve tec.ve web.ve -// vg : https://en.wikipedia.org/wiki/.vg +// vg : https://www.iana.org/domains/root/db/vg.html vg // vi : http://www.nic.vi/newdomainform.htm @@ -6812,22 +6283,91 @@ k12.vi net.vi org.vi -// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp +// vn : https://www.vnnic.vn/en/domain/cctld-vn +// https://vnnic.vn/sites/default/files/tailieu/vn.cctld.domains.txt vn +ac.vn +ai.vn +biz.vn com.vn -net.vn -org.vn edu.vn gov.vn -int.vn -ac.vn -biz.vn +health.vn +id.vn info.vn +int.vn +io.vn name.vn +net.vn +org.vn pro.vn -health.vn -// vu : https://en.wikipedia.org/wiki/.vu +// vn geographical names +angiang.vn +bacgiang.vn +backan.vn +baclieu.vn +bacninh.vn +baria-vungtau.vn +bentre.vn +binhdinh.vn +binhduong.vn +binhphuoc.vn +binhthuan.vn +camau.vn +cantho.vn +caobang.vn +daklak.vn +daknong.vn +danang.vn +dienbien.vn +dongnai.vn +dongthap.vn +gialai.vn +hagiang.vn +haiduong.vn +haiphong.vn +hanam.vn +hanoi.vn +hatinh.vn +haugiang.vn +hoabinh.vn +hungyen.vn +khanhhoa.vn +kiengiang.vn +kontum.vn +laichau.vn +lamdong.vn +langson.vn +laocai.vn +longan.vn +namdinh.vn +nghean.vn +ninhbinh.vn +ninhthuan.vn +phutho.vn +phuyen.vn +quangbinh.vn +quangnam.vn +quangngai.vn +quangninh.vn +quangtri.vn +soctrang.vn +sonla.vn +tayninh.vn +thaibinh.vn +thainguyen.vn +thanhhoa.vn +thanhphohochiminh.vn +thuathienhue.vn +tiengiang.vn +travinh.vn +tuyenquang.vn +vinhlong.vn +vinhphuc.vn +yenbai.vn + +// vu : https://www.iana.org/domains/root/db/vu.html // http://www.vunic.vu/ vu com.vu @@ -6835,10 +6375,10 @@ edu.vu net.vu org.vu -// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +// wf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf wf -// ws : https://en.wikipedia.org/wiki/.ws +// ws : https://www.iana.org/domains/root/db/ws.html // http://samoanic.ws/index.dhtml ws com.ws @@ -6847,7 +6387,7 @@ org.ws gov.ws edu.ws -// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf +// yt : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf yt // IDN ccTLDs @@ -7186,3479 +6726,4515 @@ gov.zw mil.zw org.zw - // newGTLDs -// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2023-02-15T15:49:53Z +// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2024-10-31T15:17:42Z // This list is auto-generated, don't edit it manually. -// aaa : 2015-02-26 American Automobile Association, Inc. +// aaa : American Automobile Association, Inc. +// https://www.iana.org/domains/root/db/aaa.html aaa -// aarp : 2015-05-21 AARP +// aarp : AARP +// https://www.iana.org/domains/root/db/aarp.html aarp -// abarth : 2015-07-30 Fiat Chrysler Automobiles N.V. -abarth - -// abb : 2014-10-24 ABB Ltd +// abb : ABB Ltd +// https://www.iana.org/domains/root/db/abb.html abb -// abbott : 2014-07-24 Abbott Laboratories, Inc. +// abbott : Abbott Laboratories, Inc. +// https://www.iana.org/domains/root/db/abbott.html abbott -// abbvie : 2015-07-30 AbbVie Inc. +// abbvie : AbbVie Inc. +// https://www.iana.org/domains/root/db/abbvie.html abbvie -// abc : 2015-07-30 Disney Enterprises, Inc. +// abc : Disney Enterprises, Inc. +// https://www.iana.org/domains/root/db/abc.html abc -// able : 2015-06-25 Able Inc. +// able : Able Inc. +// https://www.iana.org/domains/root/db/able.html able -// abogado : 2014-04-24 Registry Services, LLC +// abogado : Registry Services, LLC +// https://www.iana.org/domains/root/db/abogado.html abogado -// abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre +// abudhabi : Abu Dhabi Systems and Information Centre +// https://www.iana.org/domains/root/db/abudhabi.html abudhabi -// academy : 2013-11-07 Binky Moon, LLC +// academy : Binky Moon, LLC +// https://www.iana.org/domains/root/db/academy.html academy -// accenture : 2014-08-15 Accenture plc +// accenture : Accenture plc +// https://www.iana.org/domains/root/db/accenture.html accenture -// accountant : 2014-11-20 dot Accountant Limited +// accountant : dot Accountant Limited +// https://www.iana.org/domains/root/db/accountant.html accountant -// accountants : 2014-03-20 Binky Moon, LLC +// accountants : Binky Moon, LLC +// https://www.iana.org/domains/root/db/accountants.html accountants -// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG +// aco : ACO Severin Ahlmann GmbH & Co. KG +// https://www.iana.org/domains/root/db/aco.html aco -// actor : 2013-12-12 Dog Beach, LLC +// actor : Dog Beach, LLC +// https://www.iana.org/domains/root/db/actor.html actor -// ads : 2014-12-04 Charleston Road Registry Inc. +// ads : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/ads.html ads -// adult : 2014-10-16 ICM Registry AD LLC +// adult : ICM Registry AD LLC +// https://www.iana.org/domains/root/db/adult.html adult -// aeg : 2015-03-19 Aktiebolaget Electrolux +// aeg : Aktiebolaget Electrolux +// https://www.iana.org/domains/root/db/aeg.html aeg -// aetna : 2015-05-21 Aetna Life Insurance Company +// aetna : Aetna Life Insurance Company +// https://www.iana.org/domains/root/db/aetna.html aetna -// afl : 2014-10-02 Australian Football League +// afl : Australian Football League +// https://www.iana.org/domains/root/db/afl.html afl -// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa +// africa : ZA Central Registry NPC trading as Registry.Africa +// https://www.iana.org/domains/root/db/africa.html africa -// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +// agakhan : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/agakhan.html agakhan -// agency : 2013-11-14 Binky Moon, LLC +// agency : Binky Moon, LLC +// https://www.iana.org/domains/root/db/agency.html agency -// aig : 2014-12-18 American International Group, Inc. +// aig : American International Group, Inc. +// https://www.iana.org/domains/root/db/aig.html aig -// airbus : 2015-07-30 Airbus S.A.S. +// airbus : Airbus S.A.S. +// https://www.iana.org/domains/root/db/airbus.html airbus -// airforce : 2014-03-06 Dog Beach, LLC +// airforce : Dog Beach, LLC +// https://www.iana.org/domains/root/db/airforce.html airforce -// airtel : 2014-10-24 Bharti Airtel Limited +// airtel : Bharti Airtel Limited +// https://www.iana.org/domains/root/db/airtel.html airtel -// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation) +// akdn : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/akdn.html akdn -// alfaromeo : 2015-07-31 Fiat Chrysler Automobiles N.V. -alfaromeo - -// alibaba : 2015-01-15 Alibaba Group Holding Limited +// alibaba : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/alibaba.html alibaba -// alipay : 2015-01-15 Alibaba Group Holding Limited +// alipay : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/alipay.html alipay -// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +// allfinanz : Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +// https://www.iana.org/domains/root/db/allfinanz.html allfinanz -// allstate : 2015-07-31 Allstate Fire and Casualty Insurance Company +// allstate : Allstate Fire and Casualty Insurance Company +// https://www.iana.org/domains/root/db/allstate.html allstate -// ally : 2015-06-18 Ally Financial Inc. +// ally : Ally Financial Inc. +// https://www.iana.org/domains/root/db/ally.html ally -// alsace : 2014-07-02 Region Grand Est +// alsace : Region Grand Est +// https://www.iana.org/domains/root/db/alsace.html alsace -// alstom : 2015-07-30 ALSTOM +// alstom : ALSTOM +// https://www.iana.org/domains/root/db/alstom.html alstom -// amazon : 2019-12-19 Amazon Registry Services, Inc. +// amazon : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/amazon.html amazon -// americanexpress : 2015-07-31 American Express Travel Related Services Company, Inc. +// americanexpress : American Express Travel Related Services Company, Inc. +// https://www.iana.org/domains/root/db/americanexpress.html americanexpress -// americanfamily : 2015-07-23 AmFam, Inc. +// americanfamily : AmFam, Inc. +// https://www.iana.org/domains/root/db/americanfamily.html americanfamily -// amex : 2015-07-31 American Express Travel Related Services Company, Inc. +// amex : American Express Travel Related Services Company, Inc. +// https://www.iana.org/domains/root/db/amex.html amex -// amfam : 2015-07-23 AmFam, Inc. +// amfam : AmFam, Inc. +// https://www.iana.org/domains/root/db/amfam.html amfam -// amica : 2015-05-28 Amica Mutual Insurance Company +// amica : Amica Mutual Insurance Company +// https://www.iana.org/domains/root/db/amica.html amica -// amsterdam : 2014-07-24 Gemeente Amsterdam +// amsterdam : Gemeente Amsterdam +// https://www.iana.org/domains/root/db/amsterdam.html amsterdam -// analytics : 2014-12-18 Campus IP LLC +// analytics : Campus IP LLC +// https://www.iana.org/domains/root/db/analytics.html analytics -// android : 2014-08-07 Charleston Road Registry Inc. +// android : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/android.html android -// anquan : 2015-01-08 Beijing Qihu Keji Co., Ltd. +// anquan : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/anquan.html anquan -// anz : 2015-07-31 Australia and New Zealand Banking Group Limited +// anz : Australia and New Zealand Banking Group Limited +// https://www.iana.org/domains/root/db/anz.html anz -// aol : 2015-09-17 Oath Inc. +// aol : Yahoo Inc. +// https://www.iana.org/domains/root/db/aol.html aol -// apartments : 2014-12-11 Binky Moon, LLC +// apartments : Binky Moon, LLC +// https://www.iana.org/domains/root/db/apartments.html apartments -// app : 2015-05-14 Charleston Road Registry Inc. +// app : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/app.html app -// apple : 2015-05-14 Apple Inc. +// apple : Apple Inc. +// https://www.iana.org/domains/root/db/apple.html apple -// aquarelle : 2014-07-24 Aquarelle.com +// aquarelle : Aquarelle.com +// https://www.iana.org/domains/root/db/aquarelle.html aquarelle -// arab : 2015-11-12 League of Arab States +// arab : League of Arab States +// https://www.iana.org/domains/root/db/arab.html arab -// aramco : 2014-11-20 Aramco Services Company +// aramco : Aramco Services Company +// https://www.iana.org/domains/root/db/aramco.html aramco -// archi : 2014-02-06 Identity Digital Limited +// archi : Identity Digital Limited +// https://www.iana.org/domains/root/db/archi.html archi -// army : 2014-03-06 Dog Beach, LLC +// army : Dog Beach, LLC +// https://www.iana.org/domains/root/db/army.html army -// art : 2016-03-24 UK Creative Ideas Limited +// art : UK Creative Ideas Limited +// https://www.iana.org/domains/root/db/art.html art -// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E. +// arte : Association Relative à la Télévision Européenne G.E.I.E. +// https://www.iana.org/domains/root/db/arte.html arte -// asda : 2015-07-31 Wal-Mart Stores, Inc. +// asda : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/asda.html asda -// associates : 2014-03-06 Binky Moon, LLC +// associates : Binky Moon, LLC +// https://www.iana.org/domains/root/db/associates.html associates -// athleta : 2015-07-30 The Gap, Inc. +// athleta : The Gap, Inc. +// https://www.iana.org/domains/root/db/athleta.html athleta -// attorney : 2014-03-20 Dog Beach, LLC +// attorney : Dog Beach, LLC +// https://www.iana.org/domains/root/db/attorney.html attorney -// auction : 2014-03-20 Dog Beach, LLC +// auction : Dog Beach, LLC +// https://www.iana.org/domains/root/db/auction.html auction -// audi : 2015-05-21 AUDI Aktiengesellschaft +// audi : AUDI Aktiengesellschaft +// https://www.iana.org/domains/root/db/audi.html audi -// audible : 2015-06-25 Amazon Registry Services, Inc. +// audible : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/audible.html audible -// audio : 2014-03-20 XYZ.COM LLC +// audio : XYZ.COM LLC +// https://www.iana.org/domains/root/db/audio.html audio -// auspost : 2015-08-13 Australian Postal Corporation +// auspost : Australian Postal Corporation +// https://www.iana.org/domains/root/db/auspost.html auspost -// author : 2014-12-18 Amazon Registry Services, Inc. +// author : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/author.html author -// auto : 2014-11-13 XYZ.COM LLC +// auto : XYZ.COM LLC +// https://www.iana.org/domains/root/db/auto.html auto -// autos : 2014-01-09 XYZ.COM LLC +// autos : XYZ.COM LLC +// https://www.iana.org/domains/root/db/autos.html autos -// avianca : 2015-01-08 Avianca Inc. -avianca - -// aws : 2015-06-25 AWS Registry LLC +// aws : AWS Registry LLC +// https://www.iana.org/domains/root/db/aws.html aws -// axa : 2013-12-19 AXA Group Operations SAS +// axa : AXA Group Operations SAS +// https://www.iana.org/domains/root/db/axa.html axa -// azure : 2014-12-18 Microsoft Corporation +// azure : Microsoft Corporation +// https://www.iana.org/domains/root/db/azure.html azure -// baby : 2015-04-09 XYZ.COM LLC +// baby : XYZ.COM LLC +// https://www.iana.org/domains/root/db/baby.html baby -// baidu : 2015-01-08 Baidu, Inc. +// baidu : Baidu, Inc. +// https://www.iana.org/domains/root/db/baidu.html baidu -// banamex : 2015-07-30 Citigroup Inc. +// banamex : Citigroup Inc. +// https://www.iana.org/domains/root/db/banamex.html banamex -// bananarepublic : 2015-07-31 The Gap, Inc. -bananarepublic - -// band : 2014-06-12 Dog Beach, LLC +// band : Dog Beach, LLC +// https://www.iana.org/domains/root/db/band.html band -// bank : 2014-09-25 fTLD Registry Services LLC +// bank : fTLD Registry Services LLC +// https://www.iana.org/domains/root/db/bank.html bank -// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// bar : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// https://www.iana.org/domains/root/db/bar.html bar -// barcelona : 2014-07-24 Municipi de Barcelona +// barcelona : Municipi de Barcelona +// https://www.iana.org/domains/root/db/barcelona.html barcelona -// barclaycard : 2014-11-20 Barclays Bank PLC +// barclaycard : Barclays Bank PLC +// https://www.iana.org/domains/root/db/barclaycard.html barclaycard -// barclays : 2014-11-20 Barclays Bank PLC +// barclays : Barclays Bank PLC +// https://www.iana.org/domains/root/db/barclays.html barclays -// barefoot : 2015-06-11 Gallo Vineyards, Inc. +// barefoot : Gallo Vineyards, Inc. +// https://www.iana.org/domains/root/db/barefoot.html barefoot -// bargains : 2013-11-14 Binky Moon, LLC +// bargains : Binky Moon, LLC +// https://www.iana.org/domains/root/db/bargains.html bargains -// baseball : 2015-10-29 MLB Advanced Media DH, LLC +// baseball : MLB Advanced Media DH, LLC +// https://www.iana.org/domains/root/db/baseball.html baseball -// basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA) +// basketball : Fédération Internationale de Basketball (FIBA) +// https://www.iana.org/domains/root/db/basketball.html basketball -// bauhaus : 2014-04-17 Werkhaus GmbH +// bauhaus : Werkhaus GmbH +// https://www.iana.org/domains/root/db/bauhaus.html bauhaus -// bayern : 2014-01-23 Bayern Connect GmbH +// bayern : Bayern Connect GmbH +// https://www.iana.org/domains/root/db/bayern.html bayern -// bbc : 2014-12-18 British Broadcasting Corporation +// bbc : British Broadcasting Corporation +// https://www.iana.org/domains/root/db/bbc.html bbc -// bbt : 2015-07-23 BB&T Corporation +// bbt : BB&T Corporation +// https://www.iana.org/domains/root/db/bbt.html bbt -// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +// bbva : BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +// https://www.iana.org/domains/root/db/bbva.html bbva -// bcg : 2015-04-02 The Boston Consulting Group, Inc. +// bcg : The Boston Consulting Group, Inc. +// https://www.iana.org/domains/root/db/bcg.html bcg -// bcn : 2014-07-24 Municipi de Barcelona +// bcn : Municipi de Barcelona +// https://www.iana.org/domains/root/db/bcn.html bcn -// beats : 2015-05-14 Beats Electronics, LLC +// beats : Beats Electronics, LLC +// https://www.iana.org/domains/root/db/beats.html beats -// beauty : 2015-12-03 XYZ.COM LLC +// beauty : XYZ.COM LLC +// https://www.iana.org/domains/root/db/beauty.html beauty -// beer : 2014-01-09 Registry Services, LLC +// beer : Registry Services, LLC +// https://www.iana.org/domains/root/db/beer.html beer -// bentley : 2014-12-18 Bentley Motors Limited +// bentley : Bentley Motors Limited +// https://www.iana.org/domains/root/db/bentley.html bentley -// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG +// berlin : dotBERLIN GmbH & Co. KG +// https://www.iana.org/domains/root/db/berlin.html berlin -// best : 2013-12-19 BestTLD Pty Ltd +// best : BestTLD Pty Ltd +// https://www.iana.org/domains/root/db/best.html best -// bestbuy : 2015-07-31 BBY Solutions, Inc. +// bestbuy : BBY Solutions, Inc. +// https://www.iana.org/domains/root/db/bestbuy.html bestbuy -// bet : 2015-05-07 Identity Digital Limited +// bet : Identity Digital Limited +// https://www.iana.org/domains/root/db/bet.html bet -// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited +// bharti : Bharti Enterprises (Holding) Private Limited +// https://www.iana.org/domains/root/db/bharti.html bharti -// bible : 2014-06-19 American Bible Society +// bible : American Bible Society +// https://www.iana.org/domains/root/db/bible.html bible -// bid : 2013-12-19 dot Bid Limited +// bid : dot Bid Limited +// https://www.iana.org/domains/root/db/bid.html bid -// bike : 2013-08-27 Binky Moon, LLC +// bike : Binky Moon, LLC +// https://www.iana.org/domains/root/db/bike.html bike -// bing : 2014-12-18 Microsoft Corporation +// bing : Microsoft Corporation +// https://www.iana.org/domains/root/db/bing.html bing -// bingo : 2014-12-04 Binky Moon, LLC +// bingo : Binky Moon, LLC +// https://www.iana.org/domains/root/db/bingo.html bingo -// bio : 2014-03-06 Identity Digital Limited +// bio : Identity Digital Limited +// https://www.iana.org/domains/root/db/bio.html bio -// black : 2014-01-16 Identity Digital Limited +// black : Identity Digital Limited +// https://www.iana.org/domains/root/db/black.html black -// blackfriday : 2014-01-16 Registry Services, LLC +// blackfriday : Registry Services, LLC +// https://www.iana.org/domains/root/db/blackfriday.html blackfriday -// blockbuster : 2015-07-30 Dish DBS Corporation +// blockbuster : Dish DBS Corporation +// https://www.iana.org/domains/root/db/blockbuster.html blockbuster -// blog : 2015-05-14 Knock Knock WHOIS There, LLC +// blog : Knock Knock WHOIS There, LLC +// https://www.iana.org/domains/root/db/blog.html blog -// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC +// bloomberg : Bloomberg IP Holdings LLC +// https://www.iana.org/domains/root/db/bloomberg.html bloomberg -// blue : 2013-11-07 Identity Digital Limited +// blue : Identity Digital Limited +// https://www.iana.org/domains/root/db/blue.html blue -// bms : 2014-10-30 Bristol-Myers Squibb Company +// bms : Bristol-Myers Squibb Company +// https://www.iana.org/domains/root/db/bms.html bms -// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +// bmw : Bayerische Motoren Werke Aktiengesellschaft +// https://www.iana.org/domains/root/db/bmw.html bmw -// bnpparibas : 2014-05-29 BNP Paribas +// bnpparibas : BNP Paribas +// https://www.iana.org/domains/root/db/bnpparibas.html bnpparibas -// boats : 2014-12-04 XYZ.COM LLC +// boats : XYZ.COM LLC +// https://www.iana.org/domains/root/db/boats.html boats -// boehringer : 2015-07-09 Boehringer Ingelheim International GmbH +// boehringer : Boehringer Ingelheim International GmbH +// https://www.iana.org/domains/root/db/boehringer.html boehringer -// bofa : 2015-07-31 Bank of America Corporation +// bofa : Bank of America Corporation +// https://www.iana.org/domains/root/db/bofa.html bofa -// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// bom : Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// https://www.iana.org/domains/root/db/bom.html bom -// bond : 2014-06-05 ShortDot SA +// bond : ShortDot SA +// https://www.iana.org/domains/root/db/bond.html bond -// boo : 2014-01-30 Charleston Road Registry Inc. +// boo : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/boo.html boo -// book : 2015-08-27 Amazon Registry Services, Inc. +// book : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/book.html book -// booking : 2015-07-16 Booking.com B.V. +// booking : Booking.com B.V. +// https://www.iana.org/domains/root/db/booking.html booking -// bosch : 2015-06-18 Robert Bosch GMBH +// bosch : Robert Bosch GMBH +// https://www.iana.org/domains/root/db/bosch.html bosch -// bostik : 2015-05-28 Bostik SA +// bostik : Bostik SA +// https://www.iana.org/domains/root/db/bostik.html bostik -// boston : 2015-12-10 Registry Services, LLC +// boston : Registry Services, LLC +// https://www.iana.org/domains/root/db/boston.html boston -// bot : 2014-12-18 Amazon Registry Services, Inc. +// bot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/bot.html bot -// boutique : 2013-11-14 Binky Moon, LLC +// boutique : Binky Moon, LLC +// https://www.iana.org/domains/root/db/boutique.html boutique -// box : 2015-11-12 Intercap Registry Inc. +// box : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/box.html box -// bradesco : 2014-12-18 Banco Bradesco S.A. +// bradesco : Banco Bradesco S.A. +// https://www.iana.org/domains/root/db/bradesco.html bradesco -// bridgestone : 2014-12-18 Bridgestone Corporation +// bridgestone : Bridgestone Corporation +// https://www.iana.org/domains/root/db/bridgestone.html bridgestone -// broadway : 2014-12-22 Celebrate Broadway, Inc. +// broadway : Celebrate Broadway, Inc. +// https://www.iana.org/domains/root/db/broadway.html broadway -// broker : 2014-12-11 Dog Beach, LLC +// broker : Dog Beach, LLC +// https://www.iana.org/domains/root/db/broker.html broker -// brother : 2015-01-29 Brother Industries, Ltd. +// brother : Brother Industries, Ltd. +// https://www.iana.org/domains/root/db/brother.html brother -// brussels : 2014-02-06 DNS.be vzw +// brussels : DNS.be vzw +// https://www.iana.org/domains/root/db/brussels.html brussels -// build : 2013-11-07 Plan Bee LLC +// build : Plan Bee LLC +// https://www.iana.org/domains/root/db/build.html build -// builders : 2013-11-07 Binky Moon, LLC +// builders : Binky Moon, LLC +// https://www.iana.org/domains/root/db/builders.html builders -// business : 2013-11-07 Binky Moon, LLC +// business : Binky Moon, LLC +// https://www.iana.org/domains/root/db/business.html business -// buy : 2014-12-18 Amazon Registry Services, Inc. +// buy : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/buy.html buy -// buzz : 2013-10-02 DOTSTRATEGY CO. +// buzz : DOTSTRATEGY CO. +// https://www.iana.org/domains/root/db/buzz.html buzz -// bzh : 2014-02-27 Association www.bzh +// bzh : Association www.bzh +// https://www.iana.org/domains/root/db/bzh.html bzh -// cab : 2013-10-24 Binky Moon, LLC +// cab : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cab.html cab -// cafe : 2015-02-11 Binky Moon, LLC +// cafe : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cafe.html cafe -// cal : 2014-07-24 Charleston Road Registry Inc. +// cal : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/cal.html cal -// call : 2014-12-18 Amazon Registry Services, Inc. +// call : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/call.html call -// calvinklein : 2015-07-30 PVH gTLD Holdings LLC +// calvinklein : PVH gTLD Holdings LLC +// https://www.iana.org/domains/root/db/calvinklein.html calvinklein -// cam : 2016-04-21 Cam Connecting SARL +// cam : Cam Connecting SARL +// https://www.iana.org/domains/root/db/cam.html cam -// camera : 2013-08-27 Binky Moon, LLC +// camera : Binky Moon, LLC +// https://www.iana.org/domains/root/db/camera.html camera -// camp : 2013-11-07 Binky Moon, LLC +// camp : Binky Moon, LLC +// https://www.iana.org/domains/root/db/camp.html camp -// canon : 2014-09-12 Canon Inc. +// canon : Canon Inc. +// https://www.iana.org/domains/root/db/canon.html canon -// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +// capetown : ZA Central Registry NPC trading as ZA Central Registry +// https://www.iana.org/domains/root/db/capetown.html capetown -// capital : 2014-03-06 Binky Moon, LLC +// capital : Binky Moon, LLC +// https://www.iana.org/domains/root/db/capital.html capital -// capitalone : 2015-08-06 Capital One Financial Corporation +// capitalone : Capital One Financial Corporation +// https://www.iana.org/domains/root/db/capitalone.html capitalone -// car : 2015-01-22 XYZ.COM LLC +// car : XYZ.COM LLC +// https://www.iana.org/domains/root/db/car.html car -// caravan : 2013-12-12 Caravan International, Inc. +// caravan : Caravan International, Inc. +// https://www.iana.org/domains/root/db/caravan.html caravan -// cards : 2013-12-05 Binky Moon, LLC +// cards : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cards.html cards -// care : 2014-03-06 Binky Moon, LLC +// care : Binky Moon, LLC +// https://www.iana.org/domains/root/db/care.html care -// career : 2013-10-09 dotCareer LLC +// career : dotCareer LLC +// https://www.iana.org/domains/root/db/career.html career -// careers : 2013-10-02 Binky Moon, LLC +// careers : Binky Moon, LLC +// https://www.iana.org/domains/root/db/careers.html careers -// cars : 2014-11-13 XYZ.COM LLC +// cars : XYZ.COM LLC +// https://www.iana.org/domains/root/db/cars.html cars -// casa : 2013-11-21 Registry Services, LLC +// casa : Registry Services, LLC +// https://www.iana.org/domains/root/db/casa.html casa -// case : 2015-09-03 Digity, LLC +// case : Digity, LLC +// https://www.iana.org/domains/root/db/case.html case -// cash : 2014-03-06 Binky Moon, LLC +// cash : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cash.html cash -// casino : 2014-12-18 Binky Moon, LLC +// casino : Binky Moon, LLC +// https://www.iana.org/domains/root/db/casino.html casino -// catering : 2013-12-05 Binky Moon, LLC +// catering : Binky Moon, LLC +// https://www.iana.org/domains/root/db/catering.html catering -// catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// catholic : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/catholic.html catholic -// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +// cba : COMMONWEALTH BANK OF AUSTRALIA +// https://www.iana.org/domains/root/db/cba.html cba -// cbn : 2014-08-22 The Christian Broadcasting Network, Inc. +// cbn : The Christian Broadcasting Network, Inc. +// https://www.iana.org/domains/root/db/cbn.html cbn -// cbre : 2015-07-02 CBRE, Inc. +// cbre : CBRE, Inc. +// https://www.iana.org/domains/root/db/cbre.html cbre -// cbs : 2015-08-06 CBS Domains Inc. -cbs - -// center : 2013-11-07 Binky Moon, LLC +// center : Binky Moon, LLC +// https://www.iana.org/domains/root/db/center.html center -// ceo : 2013-11-07 CEOTLD Pty Ltd +// ceo : XYZ.COM LLC +// https://www.iana.org/domains/root/db/ceo.html ceo -// cern : 2014-06-05 European Organization for Nuclear Research ("CERN") +// cern : European Organization for Nuclear Research ("CERN") +// https://www.iana.org/domains/root/db/cern.html cern -// cfa : 2014-08-28 CFA Institute +// cfa : CFA Institute +// https://www.iana.org/domains/root/db/cfa.html cfa -// cfd : 2014-12-11 ShortDot SA +// cfd : ShortDot SA +// https://www.iana.org/domains/root/db/cfd.html cfd -// chanel : 2015-04-09 Chanel International B.V. +// chanel : Chanel International B.V. +// https://www.iana.org/domains/root/db/chanel.html chanel -// channel : 2014-05-08 Charleston Road Registry Inc. +// channel : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/channel.html channel -// charity : 2018-04-11 Public Interest Registry +// charity : Public Interest Registry +// https://www.iana.org/domains/root/db/charity.html charity -// chase : 2015-04-30 JPMorgan Chase Bank, National Association +// chase : JPMorgan Chase Bank, National Association +// https://www.iana.org/domains/root/db/chase.html chase -// chat : 2014-12-04 Binky Moon, LLC +// chat : Binky Moon, LLC +// https://www.iana.org/domains/root/db/chat.html chat -// cheap : 2013-11-14 Binky Moon, LLC +// cheap : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cheap.html cheap -// chintai : 2015-06-11 CHINTAI Corporation +// chintai : CHINTAI Corporation +// https://www.iana.org/domains/root/db/chintai.html chintai -// christmas : 2013-11-21 XYZ.COM LLC +// christmas : XYZ.COM LLC +// https://www.iana.org/domains/root/db/christmas.html christmas -// chrome : 2014-07-24 Charleston Road Registry Inc. +// chrome : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/chrome.html chrome -// church : 2014-02-06 Binky Moon, LLC +// church : Binky Moon, LLC +// https://www.iana.org/domains/root/db/church.html church -// cipriani : 2015-02-19 Hotel Cipriani Srl +// cipriani : Hotel Cipriani Srl +// https://www.iana.org/domains/root/db/cipriani.html cipriani -// circle : 2014-12-18 Amazon Registry Services, Inc. +// circle : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/circle.html circle -// cisco : 2014-12-22 Cisco Technology, Inc. +// cisco : Cisco Technology, Inc. +// https://www.iana.org/domains/root/db/cisco.html cisco -// citadel : 2015-07-23 Citadel Domain LLC +// citadel : Citadel Domain LLC +// https://www.iana.org/domains/root/db/citadel.html citadel -// citi : 2015-07-30 Citigroup Inc. +// citi : Citigroup Inc. +// https://www.iana.org/domains/root/db/citi.html citi -// citic : 2014-01-09 CITIC Group Corporation +// citic : CITIC Group Corporation +// https://www.iana.org/domains/root/db/citic.html citic -// city : 2014-05-29 Binky Moon, LLC +// city : Binky Moon, LLC +// https://www.iana.org/domains/root/db/city.html city -// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc. -cityeats - -// claims : 2014-03-20 Binky Moon, LLC +// claims : Binky Moon, LLC +// https://www.iana.org/domains/root/db/claims.html claims -// cleaning : 2013-12-05 Binky Moon, LLC +// cleaning : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cleaning.html cleaning -// click : 2014-06-05 Internet Naming Company LLC +// click : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/click.html click -// clinic : 2014-03-20 Binky Moon, LLC +// clinic : Binky Moon, LLC +// https://www.iana.org/domains/root/db/clinic.html clinic -// clinique : 2015-10-01 The Estée Lauder Companies Inc. +// clinique : The Estée Lauder Companies Inc. +// https://www.iana.org/domains/root/db/clinique.html clinique -// clothing : 2013-08-27 Binky Moon, LLC +// clothing : Binky Moon, LLC +// https://www.iana.org/domains/root/db/clothing.html clothing -// cloud : 2015-04-16 Aruba PEC S.p.A. +// cloud : Aruba PEC S.p.A. +// https://www.iana.org/domains/root/db/cloud.html cloud -// club : 2013-11-08 Registry Services, LLC +// club : Registry Services, LLC +// https://www.iana.org/domains/root/db/club.html club -// clubmed : 2015-06-25 Club Méditerranée S.A. +// clubmed : Club Méditerranée S.A. +// https://www.iana.org/domains/root/db/clubmed.html clubmed -// coach : 2014-10-09 Binky Moon, LLC +// coach : Binky Moon, LLC +// https://www.iana.org/domains/root/db/coach.html coach -// codes : 2013-10-31 Binky Moon, LLC +// codes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/codes.html codes -// coffee : 2013-10-17 Binky Moon, LLC +// coffee : Binky Moon, LLC +// https://www.iana.org/domains/root/db/coffee.html coffee -// college : 2014-01-16 XYZ.COM LLC +// college : XYZ.COM LLC +// https://www.iana.org/domains/root/db/college.html college -// cologne : 2014-02-05 dotKoeln GmbH +// cologne : dotKoeln GmbH +// https://www.iana.org/domains/root/db/cologne.html cologne -// comcast : 2015-07-23 Comcast IP Holdings I, LLC -comcast - -// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +// commbank : COMMONWEALTH BANK OF AUSTRALIA +// https://www.iana.org/domains/root/db/commbank.html commbank -// community : 2013-12-05 Binky Moon, LLC +// community : Binky Moon, LLC +// https://www.iana.org/domains/root/db/community.html community -// company : 2013-11-07 Binky Moon, LLC +// company : Binky Moon, LLC +// https://www.iana.org/domains/root/db/company.html company -// compare : 2015-10-08 Registry Services, LLC +// compare : Registry Services, LLC +// https://www.iana.org/domains/root/db/compare.html compare -// computer : 2013-10-24 Binky Moon, LLC +// computer : Binky Moon, LLC +// https://www.iana.org/domains/root/db/computer.html computer -// comsec : 2015-01-08 VeriSign, Inc. +// comsec : VeriSign, Inc. +// https://www.iana.org/domains/root/db/comsec.html comsec -// condos : 2013-12-05 Binky Moon, LLC +// condos : Binky Moon, LLC +// https://www.iana.org/domains/root/db/condos.html condos -// construction : 2013-09-16 Binky Moon, LLC +// construction : Binky Moon, LLC +// https://www.iana.org/domains/root/db/construction.html construction -// consulting : 2013-12-05 Dog Beach, LLC +// consulting : Dog Beach, LLC +// https://www.iana.org/domains/root/db/consulting.html consulting -// contact : 2015-01-08 Dog Beach, LLC +// contact : Dog Beach, LLC +// https://www.iana.org/domains/root/db/contact.html contact -// contractors : 2013-09-10 Binky Moon, LLC +// contractors : Binky Moon, LLC +// https://www.iana.org/domains/root/db/contractors.html contractors -// cooking : 2013-11-21 Registry Services, LLC +// cooking : Registry Services, LLC +// https://www.iana.org/domains/root/db/cooking.html cooking -// cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. -cookingchannel - -// cool : 2013-11-14 Binky Moon, LLC +// cool : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cool.html cool -// corsica : 2014-09-25 Collectivité de Corse +// corsica : Collectivité de Corse +// https://www.iana.org/domains/root/db/corsica.html corsica -// country : 2013-12-19 Internet Naming Company LLC +// country : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/country.html country -// coupon : 2015-02-26 Amazon Registry Services, Inc. +// coupon : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/coupon.html coupon -// coupons : 2015-03-26 Binky Moon, LLC +// coupons : Binky Moon, LLC +// https://www.iana.org/domains/root/db/coupons.html coupons -// courses : 2014-12-04 Registry Services, LLC +// courses : Registry Services, LLC +// https://www.iana.org/domains/root/db/courses.html courses -// cpa : 2019-06-10 American Institute of Certified Public Accountants +// cpa : American Institute of Certified Public Accountants +// https://www.iana.org/domains/root/db/cpa.html cpa -// credit : 2014-03-20 Binky Moon, LLC +// credit : Binky Moon, LLC +// https://www.iana.org/domains/root/db/credit.html credit -// creditcard : 2014-03-20 Binky Moon, LLC +// creditcard : Binky Moon, LLC +// https://www.iana.org/domains/root/db/creditcard.html creditcard -// creditunion : 2015-01-22 DotCooperation LLC +// creditunion : DotCooperation LLC +// https://www.iana.org/domains/root/db/creditunion.html creditunion -// cricket : 2014-10-09 dot Cricket Limited +// cricket : dot Cricket Limited +// https://www.iana.org/domains/root/db/cricket.html cricket -// crown : 2014-10-24 Crown Equipment Corporation +// crown : Crown Equipment Corporation +// https://www.iana.org/domains/root/db/crown.html crown -// crs : 2014-04-03 Federated Co-operatives Limited +// crs : Federated Co-operatives Limited +// https://www.iana.org/domains/root/db/crs.html crs -// cruise : 2015-12-10 Viking River Cruises (Bermuda) Ltd. +// cruise : Viking River Cruises (Bermuda) Ltd. +// https://www.iana.org/domains/root/db/cruise.html cruise -// cruises : 2013-12-05 Binky Moon, LLC +// cruises : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cruises.html cruises -// cuisinella : 2014-04-03 SCHMIDT GROUPE S.A.S. +// cuisinella : SCHMIDT GROUPE S.A.S. +// https://www.iana.org/domains/root/db/cuisinella.html cuisinella -// cymru : 2014-05-08 Nominet UK +// cymru : Nominet UK +// https://www.iana.org/domains/root/db/cymru.html cymru -// cyou : 2015-01-22 ShortDot SA +// cyou : ShortDot SA +// https://www.iana.org/domains/root/db/cyou.html cyou -// dabur : 2014-02-06 Dabur India Limited -dabur - -// dad : 2014-01-23 Charleston Road Registry Inc. +// dad : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/dad.html dad -// dance : 2013-10-24 Dog Beach, LLC +// dance : Dog Beach, LLC +// https://www.iana.org/domains/root/db/dance.html dance -// data : 2016-06-02 Dish DBS Corporation +// data : Dish DBS Corporation +// https://www.iana.org/domains/root/db/data.html data -// date : 2014-11-20 dot Date Limited +// date : dot Date Limited +// https://www.iana.org/domains/root/db/date.html date -// dating : 2013-12-05 Binky Moon, LLC +// dating : Binky Moon, LLC +// https://www.iana.org/domains/root/db/dating.html dating -// datsun : 2014-03-27 NISSAN MOTOR CO., LTD. +// datsun : NISSAN MOTOR CO., LTD. +// https://www.iana.org/domains/root/db/datsun.html datsun -// day : 2014-01-30 Charleston Road Registry Inc. +// day : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/day.html day -// dclk : 2014-11-20 Charleston Road Registry Inc. +// dclk : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/dclk.html dclk -// dds : 2015-05-07 Registry Services, LLC +// dds : Registry Services, LLC +// https://www.iana.org/domains/root/db/dds.html dds -// deal : 2015-06-25 Amazon Registry Services, Inc. +// deal : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/deal.html deal -// dealer : 2014-12-22 Intercap Registry Inc. +// dealer : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/dealer.html dealer -// deals : 2014-05-22 Binky Moon, LLC +// deals : Binky Moon, LLC +// https://www.iana.org/domains/root/db/deals.html deals -// degree : 2014-03-06 Dog Beach, LLC +// degree : Dog Beach, LLC +// https://www.iana.org/domains/root/db/degree.html degree -// delivery : 2014-09-11 Binky Moon, LLC +// delivery : Binky Moon, LLC +// https://www.iana.org/domains/root/db/delivery.html delivery -// dell : 2014-10-24 Dell Inc. +// dell : Dell Inc. +// https://www.iana.org/domains/root/db/dell.html dell -// deloitte : 2015-07-31 Deloitte Touche Tohmatsu +// deloitte : Deloitte Touche Tohmatsu +// https://www.iana.org/domains/root/db/deloitte.html deloitte -// delta : 2015-02-19 Delta Air Lines, Inc. +// delta : Delta Air Lines, Inc. +// https://www.iana.org/domains/root/db/delta.html delta -// democrat : 2013-10-24 Dog Beach, LLC +// democrat : Dog Beach, LLC +// https://www.iana.org/domains/root/db/democrat.html democrat -// dental : 2014-03-20 Binky Moon, LLC +// dental : Binky Moon, LLC +// https://www.iana.org/domains/root/db/dental.html dental -// dentist : 2014-03-20 Dog Beach, LLC +// dentist : Dog Beach, LLC +// https://www.iana.org/domains/root/db/dentist.html dentist -// desi : 2013-11-14 Desi Networks LLC +// desi +// https://www.iana.org/domains/root/db/desi.html desi -// design : 2014-11-07 Registry Services, LLC +// design : Registry Services, LLC +// https://www.iana.org/domains/root/db/design.html design -// dev : 2014-10-16 Charleston Road Registry Inc. +// dev : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/dev.html dev -// dhl : 2015-07-23 Deutsche Post AG +// dhl : Deutsche Post AG +// https://www.iana.org/domains/root/db/dhl.html dhl -// diamonds : 2013-09-22 Binky Moon, LLC +// diamonds : Binky Moon, LLC +// https://www.iana.org/domains/root/db/diamonds.html diamonds -// diet : 2014-06-26 XYZ.COM LLC +// diet : XYZ.COM LLC +// https://www.iana.org/domains/root/db/diet.html diet -// digital : 2014-03-06 Binky Moon, LLC +// digital : Binky Moon, LLC +// https://www.iana.org/domains/root/db/digital.html digital -// direct : 2014-04-10 Binky Moon, LLC +// direct : Binky Moon, LLC +// https://www.iana.org/domains/root/db/direct.html direct -// directory : 2013-09-20 Binky Moon, LLC +// directory : Binky Moon, LLC +// https://www.iana.org/domains/root/db/directory.html directory -// discount : 2014-03-06 Binky Moon, LLC +// discount : Binky Moon, LLC +// https://www.iana.org/domains/root/db/discount.html discount -// discover : 2015-07-23 Discover Financial Services +// discover : Discover Financial Services +// https://www.iana.org/domains/root/db/discover.html discover -// dish : 2015-07-30 Dish DBS Corporation +// dish : Dish DBS Corporation +// https://www.iana.org/domains/root/db/dish.html dish -// diy : 2015-11-05 Lifestyle Domain Holdings, Inc. +// diy : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/diy.html diy -// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd. +// dnp : Dai Nippon Printing Co., Ltd. +// https://www.iana.org/domains/root/db/dnp.html dnp -// docs : 2014-10-16 Charleston Road Registry Inc. +// docs : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/docs.html docs -// doctor : 2016-06-02 Binky Moon, LLC +// doctor : Binky Moon, LLC +// https://www.iana.org/domains/root/db/doctor.html doctor -// dog : 2014-12-04 Binky Moon, LLC +// dog : Binky Moon, LLC +// https://www.iana.org/domains/root/db/dog.html dog -// domains : 2013-10-17 Binky Moon, LLC +// domains : Binky Moon, LLC +// https://www.iana.org/domains/root/db/domains.html domains -// dot : 2015-05-21 Dish DBS Corporation +// dot : Dish DBS Corporation +// https://www.iana.org/domains/root/db/dot.html dot -// download : 2014-11-20 dot Support Limited +// download : dot Support Limited +// https://www.iana.org/domains/root/db/download.html download -// drive : 2015-03-05 Charleston Road Registry Inc. +// drive : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/drive.html drive -// dtv : 2015-06-04 Dish DBS Corporation +// dtv : Dish DBS Corporation +// https://www.iana.org/domains/root/db/dtv.html dtv -// dubai : 2015-01-01 Dubai Smart Government Department +// dubai : Dubai Smart Government Department +// https://www.iana.org/domains/root/db/dubai.html dubai -// dunlop : 2015-07-02 The Goodyear Tire & Rubber Company +// dunlop : The Goodyear Tire & Rubber Company +// https://www.iana.org/domains/root/db/dunlop.html dunlop -// dupont : 2015-06-25 DuPont Specialty Products USA, LLC +// dupont : DuPont Specialty Products USA, LLC +// https://www.iana.org/domains/root/db/dupont.html dupont -// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +// durban : ZA Central Registry NPC trading as ZA Central Registry +// https://www.iana.org/domains/root/db/durban.html durban -// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +// dvag : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/dvag.html dvag -// dvr : 2016-05-26 DISH Technologies L.L.C. +// dvr : DISH Technologies L.L.C. +// https://www.iana.org/domains/root/db/dvr.html dvr -// earth : 2014-12-04 Interlink Systems Innovation Institute K.K. +// earth : Interlink Systems Innovation Institute K.K. +// https://www.iana.org/domains/root/db/earth.html earth -// eat : 2014-01-23 Charleston Road Registry Inc. +// eat : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/eat.html eat -// eco : 2016-07-08 Big Room Inc. +// eco : Big Room Inc. +// https://www.iana.org/domains/root/db/eco.html eco -// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V. +// edeka : EDEKA Verband kaufmännischer Genossenschaften e.V. +// https://www.iana.org/domains/root/db/edeka.html edeka -// education : 2013-11-07 Binky Moon, LLC +// education : Binky Moon, LLC +// https://www.iana.org/domains/root/db/education.html education -// email : 2013-10-31 Binky Moon, LLC +// email : Binky Moon, LLC +// https://www.iana.org/domains/root/db/email.html email -// emerck : 2014-04-03 Merck KGaA +// emerck : Merck KGaA +// https://www.iana.org/domains/root/db/emerck.html emerck -// energy : 2014-09-11 Binky Moon, LLC +// energy : Binky Moon, LLC +// https://www.iana.org/domains/root/db/energy.html energy -// engineer : 2014-03-06 Dog Beach, LLC +// engineer : Dog Beach, LLC +// https://www.iana.org/domains/root/db/engineer.html engineer -// engineering : 2014-03-06 Binky Moon, LLC +// engineering : Binky Moon, LLC +// https://www.iana.org/domains/root/db/engineering.html engineering -// enterprises : 2013-09-20 Binky Moon, LLC +// enterprises : Binky Moon, LLC +// https://www.iana.org/domains/root/db/enterprises.html enterprises -// epson : 2014-12-04 Seiko Epson Corporation +// epson : Seiko Epson Corporation +// https://www.iana.org/domains/root/db/epson.html epson -// equipment : 2013-08-27 Binky Moon, LLC +// equipment : Binky Moon, LLC +// https://www.iana.org/domains/root/db/equipment.html equipment -// ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson +// ericsson : Telefonaktiebolaget L M Ericsson +// https://www.iana.org/domains/root/db/ericsson.html ericsson -// erni : 2014-04-03 ERNI Group Holding AG +// erni : ERNI Group Holding AG +// https://www.iana.org/domains/root/db/erni.html erni -// esq : 2014-05-08 Charleston Road Registry Inc. +// esq : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/esq.html esq -// estate : 2013-08-27 Binky Moon, LLC +// estate : Binky Moon, LLC +// https://www.iana.org/domains/root/db/estate.html estate -// etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) -etisalat - -// eurovision : 2014-04-24 European Broadcasting Union (EBU) +// eurovision : European Broadcasting Union (EBU) +// https://www.iana.org/domains/root/db/eurovision.html eurovision -// eus : 2013-12-12 Puntueus Fundazioa +// eus : Puntueus Fundazioa +// https://www.iana.org/domains/root/db/eus.html eus -// events : 2013-12-05 Binky Moon, LLC +// events : Binky Moon, LLC +// https://www.iana.org/domains/root/db/events.html events -// exchange : 2014-03-06 Binky Moon, LLC +// exchange : Binky Moon, LLC +// https://www.iana.org/domains/root/db/exchange.html exchange -// expert : 2013-11-21 Binky Moon, LLC +// expert : Binky Moon, LLC +// https://www.iana.org/domains/root/db/expert.html expert -// exposed : 2013-12-05 Binky Moon, LLC +// exposed : Binky Moon, LLC +// https://www.iana.org/domains/root/db/exposed.html exposed -// express : 2015-02-11 Binky Moon, LLC +// express : Binky Moon, LLC +// https://www.iana.org/domains/root/db/express.html express -// extraspace : 2015-05-14 Extra Space Storage LLC +// extraspace : Extra Space Storage LLC +// https://www.iana.org/domains/root/db/extraspace.html extraspace -// fage : 2014-12-18 Fage International S.A. +// fage : Fage International S.A. +// https://www.iana.org/domains/root/db/fage.html fage -// fail : 2014-03-06 Binky Moon, LLC +// fail : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fail.html fail -// fairwinds : 2014-11-13 FairWinds Partners, LLC +// fairwinds : FairWinds Partners, LLC +// https://www.iana.org/domains/root/db/fairwinds.html fairwinds -// faith : 2014-11-20 dot Faith Limited +// faith : dot Faith Limited +// https://www.iana.org/domains/root/db/faith.html faith -// family : 2015-04-02 Dog Beach, LLC +// family : Dog Beach, LLC +// https://www.iana.org/domains/root/db/family.html family -// fan : 2014-03-06 Dog Beach, LLC +// fan : Dog Beach, LLC +// https://www.iana.org/domains/root/db/fan.html fan -// fans : 2014-11-07 ZDNS International Limited +// fans : ZDNS International Limited +// https://www.iana.org/domains/root/db/fans.html fans -// farm : 2013-11-07 Binky Moon, LLC +// farm : Binky Moon, LLC +// https://www.iana.org/domains/root/db/farm.html farm -// farmers : 2015-07-09 Farmers Insurance Exchange +// farmers : Farmers Insurance Exchange +// https://www.iana.org/domains/root/db/farmers.html farmers -// fashion : 2014-07-03 Registry Services, LLC +// fashion : Registry Services, LLC +// https://www.iana.org/domains/root/db/fashion.html fashion -// fast : 2014-12-18 Amazon Registry Services, Inc. +// fast : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/fast.html fast -// fedex : 2015-08-06 Federal Express Corporation +// fedex : Federal Express Corporation +// https://www.iana.org/domains/root/db/fedex.html fedex -// feedback : 2013-12-19 Top Level Spectrum, Inc. +// feedback : Top Level Spectrum, Inc. +// https://www.iana.org/domains/root/db/feedback.html feedback -// ferrari : 2015-07-31 Fiat Chrysler Automobiles N.V. +// ferrari : Fiat Chrysler Automobiles N.V. +// https://www.iana.org/domains/root/db/ferrari.html ferrari -// ferrero : 2014-12-18 Ferrero Trading Lux S.A. +// ferrero : Ferrero Trading Lux S.A. +// https://www.iana.org/domains/root/db/ferrero.html ferrero -// fiat : 2015-07-31 Fiat Chrysler Automobiles N.V. -fiat - -// fidelity : 2015-07-30 Fidelity Brokerage Services LLC +// fidelity : Fidelity Brokerage Services LLC +// https://www.iana.org/domains/root/db/fidelity.html fidelity -// fido : 2015-08-06 Rogers Communications Canada Inc. +// fido : Rogers Communications Canada Inc. +// https://www.iana.org/domains/root/db/fido.html fido -// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd +// film : Motion Picture Domain Registry Pty Ltd +// https://www.iana.org/domains/root/db/film.html film -// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// final : Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// https://www.iana.org/domains/root/db/final.html final -// finance : 2014-03-20 Binky Moon, LLC +// finance : Binky Moon, LLC +// https://www.iana.org/domains/root/db/finance.html finance -// financial : 2014-03-06 Binky Moon, LLC +// financial : Binky Moon, LLC +// https://www.iana.org/domains/root/db/financial.html financial -// fire : 2015-06-25 Amazon Registry Services, Inc. +// fire : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/fire.html fire -// firestone : 2014-12-18 Bridgestone Licensing Services, Inc +// firestone : Bridgestone Licensing Services, Inc +// https://www.iana.org/domains/root/db/firestone.html firestone -// firmdale : 2014-03-27 Firmdale Holdings Limited +// firmdale : Firmdale Holdings Limited +// https://www.iana.org/domains/root/db/firmdale.html firmdale -// fish : 2013-12-12 Binky Moon, LLC +// fish : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fish.html fish -// fishing : 2013-11-21 Registry Services, LLC +// fishing : Registry Services, LLC +// https://www.iana.org/domains/root/db/fishing.html fishing -// fit : 2014-11-07 Registry Services, LLC +// fit : Registry Services, LLC +// https://www.iana.org/domains/root/db/fit.html fit -// fitness : 2014-03-06 Binky Moon, LLC +// fitness : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fitness.html fitness -// flickr : 2015-04-02 Flickr, Inc. +// flickr : Flickr, Inc. +// https://www.iana.org/domains/root/db/flickr.html flickr -// flights : 2013-12-05 Binky Moon, LLC +// flights : Binky Moon, LLC +// https://www.iana.org/domains/root/db/flights.html flights -// flir : 2015-07-23 FLIR Systems, Inc. +// flir : FLIR Systems, Inc. +// https://www.iana.org/domains/root/db/flir.html flir -// florist : 2013-11-07 Binky Moon, LLC +// florist : Binky Moon, LLC +// https://www.iana.org/domains/root/db/florist.html florist -// flowers : 2014-10-09 XYZ.COM LLC +// flowers : XYZ.COM LLC +// https://www.iana.org/domains/root/db/flowers.html flowers -// fly : 2014-05-08 Charleston Road Registry Inc. +// fly : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/fly.html fly -// foo : 2014-01-23 Charleston Road Registry Inc. +// foo : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/foo.html foo -// food : 2016-04-21 Lifestyle Domain Holdings, Inc. +// food : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/food.html food -// foodnetwork : 2015-07-02 Lifestyle Domain Holdings, Inc. -foodnetwork - -// football : 2014-12-18 Binky Moon, LLC +// football : Binky Moon, LLC +// https://www.iana.org/domains/root/db/football.html football -// ford : 2014-11-13 Ford Motor Company +// ford : Ford Motor Company +// https://www.iana.org/domains/root/db/ford.html ford -// forex : 2014-12-11 Dog Beach, LLC +// forex : Dog Beach, LLC +// https://www.iana.org/domains/root/db/forex.html forex -// forsale : 2014-05-22 Dog Beach, LLC +// forsale : Dog Beach, LLC +// https://www.iana.org/domains/root/db/forsale.html forsale -// forum : 2015-04-02 Fegistry, LLC +// forum : Waterford Limited +// https://www.iana.org/domains/root/db/forum.html forum -// foundation : 2013-12-05 Public Interest Registry +// foundation : Public Interest Registry +// https://www.iana.org/domains/root/db/foundation.html foundation -// fox : 2015-09-11 FOX Registry, LLC +// fox : FOX Registry, LLC +// https://www.iana.org/domains/root/db/fox.html fox -// free : 2015-12-10 Amazon Registry Services, Inc. +// free : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/free.html free -// fresenius : 2015-07-30 Fresenius Immobilien-Verwaltungs-GmbH +// fresenius : Fresenius Immobilien-Verwaltungs-GmbH +// https://www.iana.org/domains/root/db/fresenius.html fresenius -// frl : 2014-05-15 FRLregistry B.V. +// frl : FRLregistry B.V. +// https://www.iana.org/domains/root/db/frl.html frl -// frogans : 2013-12-19 OP3FT +// frogans : OP3FT +// https://www.iana.org/domains/root/db/frogans.html frogans -// frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc. -frontdoor - -// frontier : 2015-02-05 Frontier Communications Corporation +// frontier : Frontier Communications Corporation +// https://www.iana.org/domains/root/db/frontier.html frontier -// ftr : 2015-07-16 Frontier Communications Corporation +// ftr : Frontier Communications Corporation +// https://www.iana.org/domains/root/db/ftr.html ftr -// fujitsu : 2015-07-30 Fujitsu Limited +// fujitsu : Fujitsu Limited +// https://www.iana.org/domains/root/db/fujitsu.html fujitsu -// fun : 2016-01-14 Radix FZC +// fun : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/fun.html fun -// fund : 2014-03-20 Binky Moon, LLC +// fund : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fund.html fund -// furniture : 2014-03-20 Binky Moon, LLC +// furniture : Binky Moon, LLC +// https://www.iana.org/domains/root/db/furniture.html furniture -// futbol : 2013-09-20 Dog Beach, LLC +// futbol : Dog Beach, LLC +// https://www.iana.org/domains/root/db/futbol.html futbol -// fyi : 2015-04-02 Binky Moon, LLC +// fyi : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fyi.html fyi -// gal : 2013-11-07 Asociación puntoGAL +// gal : Asociación puntoGAL +// https://www.iana.org/domains/root/db/gal.html gal -// gallery : 2013-09-13 Binky Moon, LLC +// gallery : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gallery.html gallery -// gallo : 2015-06-11 Gallo Vineyards, Inc. +// gallo : Gallo Vineyards, Inc. +// https://www.iana.org/domains/root/db/gallo.html gallo -// gallup : 2015-02-19 Gallup, Inc. +// gallup : Gallup, Inc. +// https://www.iana.org/domains/root/db/gallup.html gallup -// game : 2015-05-28 XYZ.COM LLC +// game : XYZ.COM LLC +// https://www.iana.org/domains/root/db/game.html game -// games : 2015-05-28 Dog Beach, LLC +// games : Dog Beach, LLC +// https://www.iana.org/domains/root/db/games.html games -// gap : 2015-07-31 The Gap, Inc. +// gap : The Gap, Inc. +// https://www.iana.org/domains/root/db/gap.html gap -// garden : 2014-06-26 Registry Services, LLC +// garden : Registry Services, LLC +// https://www.iana.org/domains/root/db/garden.html garden -// gay : 2019-05-23 Top Level Design, LLC +// gay : Registry Services, LLC +// https://www.iana.org/domains/root/db/gay.html gay -// gbiz : 2014-07-17 Charleston Road Registry Inc. +// gbiz : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/gbiz.html gbiz -// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems" +// gdn : Joint Stock Company "Navigation-information systems" +// https://www.iana.org/domains/root/db/gdn.html gdn -// gea : 2014-12-04 GEA Group Aktiengesellschaft +// gea : GEA Group Aktiengesellschaft +// https://www.iana.org/domains/root/db/gea.html gea -// gent : 2014-01-23 Easyhost BV +// gent : Easyhost BV +// https://www.iana.org/domains/root/db/gent.html gent -// genting : 2015-03-12 Resorts World Inc Pte. Ltd. +// genting : Resorts World Inc Pte. Ltd. +// https://www.iana.org/domains/root/db/genting.html genting -// george : 2015-07-31 Wal-Mart Stores, Inc. +// george : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/george.html george -// ggee : 2014-01-09 GMO Internet, Inc. +// ggee : GMO Internet, Inc. +// https://www.iana.org/domains/root/db/ggee.html ggee -// gift : 2013-10-17 DotGift, LLC +// gift : DotGift, LLC +// https://www.iana.org/domains/root/db/gift.html gift -// gifts : 2014-07-03 Binky Moon, LLC +// gifts : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gifts.html gifts -// gives : 2014-03-06 Public Interest Registry +// gives : Public Interest Registry +// https://www.iana.org/domains/root/db/gives.html gives -// giving : 2014-11-13 Public Interest Registry +// giving : Public Interest Registry +// https://www.iana.org/domains/root/db/giving.html giving -// glass : 2013-11-07 Binky Moon, LLC +// glass : Binky Moon, LLC +// https://www.iana.org/domains/root/db/glass.html glass -// gle : 2014-07-24 Charleston Road Registry Inc. +// gle : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/gle.html gle -// global : 2014-04-17 Dot Global Domain Registry Limited +// global : Identity Digital Limited +// https://www.iana.org/domains/root/db/global.html global -// globo : 2013-12-19 Globo Comunicação e Participações S.A +// globo : Globo Comunicação e Participações S.A +// https://www.iana.org/domains/root/db/globo.html globo -// gmail : 2014-05-01 Charleston Road Registry Inc. +// gmail : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/gmail.html gmail -// gmbh : 2016-01-29 Binky Moon, LLC +// gmbh : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gmbh.html gmbh -// gmo : 2014-01-09 GMO Internet, Inc. +// gmo : GMO Internet, Inc. +// https://www.iana.org/domains/root/db/gmo.html gmo -// gmx : 2014-04-24 1&1 Mail & Media GmbH +// gmx : 1&1 Mail & Media GmbH +// https://www.iana.org/domains/root/db/gmx.html gmx -// godaddy : 2015-07-23 Go Daddy East, LLC +// godaddy : Go Daddy East, LLC +// https://www.iana.org/domains/root/db/godaddy.html godaddy -// gold : 2015-01-22 Binky Moon, LLC +// gold : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gold.html gold -// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +// goldpoint : YODOBASHI CAMERA CO.,LTD. +// https://www.iana.org/domains/root/db/goldpoint.html goldpoint -// golf : 2014-12-18 Binky Moon, LLC +// golf : Binky Moon, LLC +// https://www.iana.org/domains/root/db/golf.html golf -// goo : 2014-12-18 NTT Resonant Inc. +// goo : NTT DOCOMO, INC. +// https://www.iana.org/domains/root/db/goo.html goo -// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company +// goodyear : The Goodyear Tire & Rubber Company +// https://www.iana.org/domains/root/db/goodyear.html goodyear -// goog : 2014-11-20 Charleston Road Registry Inc. +// goog : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/goog.html goog -// google : 2014-07-24 Charleston Road Registry Inc. +// google : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/google.html google -// gop : 2014-01-16 Republican State Leadership Committee, Inc. +// gop : Republican State Leadership Committee, Inc. +// https://www.iana.org/domains/root/db/gop.html gop -// got : 2014-12-18 Amazon Registry Services, Inc. +// got : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/got.html got -// grainger : 2015-05-07 Grainger Registry Services, LLC +// grainger : Grainger Registry Services, LLC +// https://www.iana.org/domains/root/db/grainger.html grainger -// graphics : 2013-09-13 Binky Moon, LLC +// graphics : Binky Moon, LLC +// https://www.iana.org/domains/root/db/graphics.html graphics -// gratis : 2014-03-20 Binky Moon, LLC +// gratis : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gratis.html gratis -// green : 2014-05-08 Identity Digital Limited +// green : Identity Digital Limited +// https://www.iana.org/domains/root/db/green.html green -// gripe : 2014-03-06 Binky Moon, LLC +// gripe : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gripe.html gripe -// grocery : 2016-06-16 Wal-Mart Stores, Inc. +// grocery : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/grocery.html grocery -// group : 2014-08-15 Binky Moon, LLC +// group : Binky Moon, LLC +// https://www.iana.org/domains/root/db/group.html group -// guardian : 2015-07-30 The Guardian Life Insurance Company of America -guardian - -// gucci : 2014-11-13 Guccio Gucci S.p.a. +// gucci : Guccio Gucci S.p.a. +// https://www.iana.org/domains/root/db/gucci.html gucci -// guge : 2014-08-28 Charleston Road Registry Inc. +// guge : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/guge.html guge -// guide : 2013-09-13 Binky Moon, LLC +// guide : Binky Moon, LLC +// https://www.iana.org/domains/root/db/guide.html guide -// guitars : 2013-11-14 XYZ.COM LLC +// guitars : XYZ.COM LLC +// https://www.iana.org/domains/root/db/guitars.html guitars -// guru : 2013-08-27 Binky Moon, LLC +// guru : Binky Moon, LLC +// https://www.iana.org/domains/root/db/guru.html guru -// hair : 2015-12-03 XYZ.COM LLC +// hair : XYZ.COM LLC +// https://www.iana.org/domains/root/db/hair.html hair -// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH +// hamburg : Hamburg Top-Level-Domain GmbH +// https://www.iana.org/domains/root/db/hamburg.html hamburg -// hangout : 2014-11-13 Charleston Road Registry Inc. +// hangout : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/hangout.html hangout -// haus : 2013-12-05 Dog Beach, LLC +// haus : Dog Beach, LLC +// https://www.iana.org/domains/root/db/haus.html haus -// hbo : 2015-07-30 HBO Registry Services, Inc. +// hbo : HBO Registry Services, Inc. +// https://www.iana.org/domains/root/db/hbo.html hbo -// hdfc : 2015-07-30 HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED +// hdfc : HDFC BANK LIMITED +// https://www.iana.org/domains/root/db/hdfc.html hdfc -// hdfcbank : 2015-02-12 HDFC Bank Limited +// hdfcbank : HDFC BANK LIMITED +// https://www.iana.org/domains/root/db/hdfcbank.html hdfcbank -// health : 2015-02-11 DotHealth, LLC +// health : Registry Services, LLC +// https://www.iana.org/domains/root/db/health.html health -// healthcare : 2014-06-12 Binky Moon, LLC +// healthcare : Binky Moon, LLC +// https://www.iana.org/domains/root/db/healthcare.html healthcare -// help : 2014-06-26 Innovation service Limited +// help : Innovation service Limited +// https://www.iana.org/domains/root/db/help.html help -// helsinki : 2015-02-05 City of Helsinki +// helsinki : City of Helsinki +// https://www.iana.org/domains/root/db/helsinki.html helsinki -// here : 2014-02-06 Charleston Road Registry Inc. +// here : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/here.html here -// hermes : 2014-07-10 HERMES INTERNATIONAL +// hermes : HERMES INTERNATIONAL +// https://www.iana.org/domains/root/db/hermes.html hermes -// hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc. -hgtv - -// hiphop : 2014-03-06 Dot Hip Hop, LLC +// hiphop : Dot Hip Hop, LLC +// https://www.iana.org/domains/root/db/hiphop.html hiphop -// hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc. +// hisamitsu : Hisamitsu Pharmaceutical Co.,Inc. +// https://www.iana.org/domains/root/db/hisamitsu.html hisamitsu -// hitachi : 2014-10-31 Hitachi, Ltd. +// hitachi : Hitachi, Ltd. +// https://www.iana.org/domains/root/db/hitachi.html hitachi -// hiv : 2014-03-13 Internet Naming Company LLC +// hiv : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/hiv.html hiv -// hkt : 2015-05-14 PCCW-HKT DataCom Services Limited +// hkt : PCCW-HKT DataCom Services Limited +// https://www.iana.org/domains/root/db/hkt.html hkt -// hockey : 2015-03-19 Binky Moon, LLC +// hockey : Binky Moon, LLC +// https://www.iana.org/domains/root/db/hockey.html hockey -// holdings : 2013-08-27 Binky Moon, LLC +// holdings : Binky Moon, LLC +// https://www.iana.org/domains/root/db/holdings.html holdings -// holiday : 2013-11-07 Binky Moon, LLC +// holiday : Binky Moon, LLC +// https://www.iana.org/domains/root/db/holiday.html holiday -// homedepot : 2015-04-02 Home Depot Product Authority, LLC +// homedepot : Home Depot Product Authority, LLC +// https://www.iana.org/domains/root/db/homedepot.html homedepot -// homegoods : 2015-07-16 The TJX Companies, Inc. +// homegoods : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/homegoods.html homegoods -// homes : 2014-01-09 XYZ.COM LLC +// homes : XYZ.COM LLC +// https://www.iana.org/domains/root/db/homes.html homes -// homesense : 2015-07-16 The TJX Companies, Inc. +// homesense : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/homesense.html homesense -// honda : 2014-12-18 Honda Motor Co., Ltd. +// honda : Honda Motor Co., Ltd. +// https://www.iana.org/domains/root/db/honda.html honda -// horse : 2013-11-21 Registry Services, LLC +// horse : Registry Services, LLC +// https://www.iana.org/domains/root/db/horse.html horse -// hospital : 2016-10-20 Binky Moon, LLC +// hospital : Binky Moon, LLC +// https://www.iana.org/domains/root/db/hospital.html hospital -// host : 2014-04-17 Radix FZC +// host : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/host.html host -// hosting : 2014-05-29 XYZ.COM LLC +// hosting : XYZ.COM LLC +// https://www.iana.org/domains/root/db/hosting.html hosting -// hot : 2015-08-27 Amazon Registry Services, Inc. +// hot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/hot.html hot -// hoteles : 2015-03-05 Travel Reservations SRL -hoteles - -// hotels : 2016-04-07 Booking.com B.V. +// hotels : Booking.com B.V. +// https://www.iana.org/domains/root/db/hotels.html hotels -// hotmail : 2014-12-18 Microsoft Corporation +// hotmail : Microsoft Corporation +// https://www.iana.org/domains/root/db/hotmail.html hotmail -// house : 2013-11-07 Binky Moon, LLC +// house : Binky Moon, LLC +// https://www.iana.org/domains/root/db/house.html house -// how : 2014-01-23 Charleston Road Registry Inc. +// how : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/how.html how -// hsbc : 2014-10-24 HSBC Global Services (UK) Limited +// hsbc : HSBC Global Services (UK) Limited +// https://www.iana.org/domains/root/db/hsbc.html hsbc -// hughes : 2015-07-30 Hughes Satellite Systems Corporation +// hughes : Hughes Satellite Systems Corporation +// https://www.iana.org/domains/root/db/hughes.html hughes -// hyatt : 2015-07-30 Hyatt GTLD, L.L.C. +// hyatt : Hyatt GTLD, L.L.C. +// https://www.iana.org/domains/root/db/hyatt.html hyatt -// hyundai : 2015-07-09 Hyundai Motor Company +// hyundai : Hyundai Motor Company +// https://www.iana.org/domains/root/db/hyundai.html hyundai -// ibm : 2014-07-31 International Business Machines Corporation +// ibm : International Business Machines Corporation +// https://www.iana.org/domains/root/db/ibm.html ibm -// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited +// icbc : Industrial and Commercial Bank of China Limited +// https://www.iana.org/domains/root/db/icbc.html icbc -// ice : 2014-10-30 IntercontinentalExchange, Inc. +// ice : IntercontinentalExchange, Inc. +// https://www.iana.org/domains/root/db/ice.html ice -// icu : 2015-01-08 ShortDot SA +// icu : ShortDot SA +// https://www.iana.org/domains/root/db/icu.html icu -// ieee : 2015-07-23 IEEE Global LLC +// ieee : IEEE Global LLC +// https://www.iana.org/domains/root/db/ieee.html ieee -// ifm : 2014-01-30 ifm electronic gmbh +// ifm : ifm electronic gmbh +// https://www.iana.org/domains/root/db/ifm.html ifm -// ikano : 2015-07-09 Ikano S.A. +// ikano : Ikano S.A. +// https://www.iana.org/domains/root/db/ikano.html ikano -// imamat : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +// imamat : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/imamat.html imamat -// imdb : 2015-06-25 Amazon Registry Services, Inc. +// imdb : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/imdb.html imdb -// immo : 2014-07-10 Binky Moon, LLC +// immo : Binky Moon, LLC +// https://www.iana.org/domains/root/db/immo.html immo -// immobilien : 2013-11-07 Dog Beach, LLC +// immobilien : Dog Beach, LLC +// https://www.iana.org/domains/root/db/immobilien.html immobilien -// inc : 2018-03-10 Intercap Registry Inc. +// inc : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/inc.html inc -// industries : 2013-12-05 Binky Moon, LLC +// industries : Binky Moon, LLC +// https://www.iana.org/domains/root/db/industries.html industries -// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD. +// infiniti : NISSAN MOTOR CO., LTD. +// https://www.iana.org/domains/root/db/infiniti.html infiniti -// ing : 2014-01-23 Charleston Road Registry Inc. +// ing : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/ing.html ing -// ink : 2013-12-05 Top Level Design, LLC +// ink : Registry Services, LLC +// https://www.iana.org/domains/root/db/ink.html ink -// institute : 2013-11-07 Binky Moon, LLC +// institute : Binky Moon, LLC +// https://www.iana.org/domains/root/db/institute.html institute -// insurance : 2015-02-19 fTLD Registry Services LLC +// insurance : fTLD Registry Services LLC +// https://www.iana.org/domains/root/db/insurance.html insurance -// insure : 2014-03-20 Binky Moon, LLC +// insure : Binky Moon, LLC +// https://www.iana.org/domains/root/db/insure.html insure -// international : 2013-11-07 Binky Moon, LLC +// international : Binky Moon, LLC +// https://www.iana.org/domains/root/db/international.html international -// intuit : 2015-07-30 Intuit Administrative Services, Inc. +// intuit : Intuit Administrative Services, Inc. +// https://www.iana.org/domains/root/db/intuit.html intuit -// investments : 2014-03-20 Binky Moon, LLC +// investments : Binky Moon, LLC +// https://www.iana.org/domains/root/db/investments.html investments -// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A. +// ipiranga : Ipiranga Produtos de Petroleo S.A. +// https://www.iana.org/domains/root/db/ipiranga.html ipiranga -// irish : 2014-08-07 Binky Moon, LLC +// irish : Binky Moon, LLC +// https://www.iana.org/domains/root/db/irish.html irish -// ismaili : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation) +// ismaili : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/ismaili.html ismaili -// ist : 2014-08-28 Istanbul Metropolitan Municipality +// ist : Istanbul Metropolitan Municipality +// https://www.iana.org/domains/root/db/ist.html ist -// istanbul : 2014-08-28 Istanbul Metropolitan Municipality +// istanbul : Istanbul Metropolitan Municipality +// https://www.iana.org/domains/root/db/istanbul.html istanbul -// itau : 2014-10-02 Itau Unibanco Holding S.A. +// itau : Itau Unibanco Holding S.A. +// https://www.iana.org/domains/root/db/itau.html itau -// itv : 2015-07-09 ITV Services Limited +// itv : ITV Services Limited +// https://www.iana.org/domains/root/db/itv.html itv -// jaguar : 2014-11-13 Jaguar Land Rover Ltd +// jaguar : Jaguar Land Rover Ltd +// https://www.iana.org/domains/root/db/jaguar.html jaguar -// java : 2014-06-19 Oracle Corporation +// java : Oracle Corporation +// https://www.iana.org/domains/root/db/java.html java -// jcb : 2014-11-20 JCB Co., Ltd. +// jcb : JCB Co., Ltd. +// https://www.iana.org/domains/root/db/jcb.html jcb -// jeep : 2015-07-30 FCA US LLC. +// jeep : FCA US LLC. +// https://www.iana.org/domains/root/db/jeep.html jeep -// jetzt : 2014-01-09 Binky Moon, LLC +// jetzt : Binky Moon, LLC +// https://www.iana.org/domains/root/db/jetzt.html jetzt -// jewelry : 2015-03-05 Binky Moon, LLC +// jewelry : Binky Moon, LLC +// https://www.iana.org/domains/root/db/jewelry.html jewelry -// jio : 2015-04-02 Reliance Industries Limited +// jio : Reliance Industries Limited +// https://www.iana.org/domains/root/db/jio.html jio -// jll : 2015-04-02 Jones Lang LaSalle Incorporated +// jll : Jones Lang LaSalle Incorporated +// https://www.iana.org/domains/root/db/jll.html jll -// jmp : 2015-03-26 Matrix IP LLC +// jmp : Matrix IP LLC +// https://www.iana.org/domains/root/db/jmp.html jmp -// jnj : 2015-06-18 Johnson & Johnson Services, Inc. +// jnj : Johnson & Johnson Services, Inc. +// https://www.iana.org/domains/root/db/jnj.html jnj -// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry +// joburg : ZA Central Registry NPC trading as ZA Central Registry +// https://www.iana.org/domains/root/db/joburg.html joburg -// jot : 2014-12-18 Amazon Registry Services, Inc. +// jot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/jot.html jot -// joy : 2014-12-18 Amazon Registry Services, Inc. +// joy : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/joy.html joy -// jpmorgan : 2015-04-30 JPMorgan Chase Bank, National Association +// jpmorgan : JPMorgan Chase Bank, National Association +// https://www.iana.org/domains/root/db/jpmorgan.html jpmorgan -// jprs : 2014-09-18 Japan Registry Services Co., Ltd. +// jprs : Japan Registry Services Co., Ltd. +// https://www.iana.org/domains/root/db/jprs.html jprs -// juegos : 2014-03-20 Internet Naming Company LLC +// juegos : Dog Beach, LLC +// https://www.iana.org/domains/root/db/juegos.html juegos -// juniper : 2015-07-30 JUNIPER NETWORKS, INC. +// juniper : JUNIPER NETWORKS, INC. +// https://www.iana.org/domains/root/db/juniper.html juniper -// kaufen : 2013-11-07 Dog Beach, LLC +// kaufen : Dog Beach, LLC +// https://www.iana.org/domains/root/db/kaufen.html kaufen -// kddi : 2014-09-12 KDDI CORPORATION +// kddi : KDDI CORPORATION +// https://www.iana.org/domains/root/db/kddi.html kddi -// kerryhotels : 2015-04-30 Kerry Trading Co. Limited +// kerryhotels : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kerryhotels.html kerryhotels -// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited +// kerrylogistics : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kerrylogistics.html kerrylogistics -// kerryproperties : 2015-04-09 Kerry Trading Co. Limited +// kerryproperties : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kerryproperties.html kerryproperties -// kfh : 2014-12-04 Kuwait Finance House +// kfh : Kuwait Finance House +// https://www.iana.org/domains/root/db/kfh.html kfh -// kia : 2015-07-09 KIA MOTORS CORPORATION +// kia : KIA MOTORS CORPORATION +// https://www.iana.org/domains/root/db/kia.html kia -// kids : 2021-08-13 DotKids Foundation Limited +// kids : DotKids Foundation Limited +// https://www.iana.org/domains/root/db/kids.html kids -// kim : 2013-09-23 Identity Digital Limited +// kim : Identity Digital Limited +// https://www.iana.org/domains/root/db/kim.html kim -// kinder : 2014-11-07 Ferrero Trading Lux S.A. -kinder - -// kindle : 2015-06-25 Amazon Registry Services, Inc. +// kindle : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/kindle.html kindle -// kitchen : 2013-09-20 Binky Moon, LLC +// kitchen : Binky Moon, LLC +// https://www.iana.org/domains/root/db/kitchen.html kitchen -// kiwi : 2013-09-20 DOT KIWI LIMITED +// kiwi : DOT KIWI LIMITED +// https://www.iana.org/domains/root/db/kiwi.html kiwi -// koeln : 2014-01-09 dotKoeln GmbH +// koeln : dotKoeln GmbH +// https://www.iana.org/domains/root/db/koeln.html koeln -// komatsu : 2015-01-08 Komatsu Ltd. +// komatsu : Komatsu Ltd. +// https://www.iana.org/domains/root/db/komatsu.html komatsu -// kosher : 2015-08-20 Kosher Marketing Assets LLC +// kosher : Kosher Marketing Assets LLC +// https://www.iana.org/domains/root/db/kosher.html kosher -// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft) +// kpmg : KPMG International Cooperative (KPMG International Genossenschaft) +// https://www.iana.org/domains/root/db/kpmg.html kpmg -// kpn : 2015-01-08 Koninklijke KPN N.V. +// kpn : Koninklijke KPN N.V. +// https://www.iana.org/domains/root/db/kpn.html kpn -// krd : 2013-12-05 KRG Department of Information Technology +// krd : KRG Department of Information Technology +// https://www.iana.org/domains/root/db/krd.html krd -// kred : 2013-12-19 KredTLD Pty Ltd +// kred : KredTLD Pty Ltd +// https://www.iana.org/domains/root/db/kred.html kred -// kuokgroup : 2015-04-09 Kerry Trading Co. Limited +// kuokgroup : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kuokgroup.html kuokgroup -// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen +// kyoto : Academic Institution: Kyoto Jyoho Gakuen +// https://www.iana.org/domains/root/db/kyoto.html kyoto -// lacaixa : 2014-01-09 Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa” +// lacaixa : Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa” +// https://www.iana.org/domains/root/db/lacaixa.html lacaixa -// lamborghini : 2015-06-04 Automobili Lamborghini S.p.A. +// lamborghini : Automobili Lamborghini S.p.A. +// https://www.iana.org/domains/root/db/lamborghini.html lamborghini -// lamer : 2015-10-01 The Estée Lauder Companies Inc. +// lamer : The Estée Lauder Companies Inc. +// https://www.iana.org/domains/root/db/lamer.html lamer -// lancaster : 2015-02-12 LANCASTER +// lancaster : LANCASTER +// https://www.iana.org/domains/root/db/lancaster.html lancaster -// lancia : 2015-07-31 Fiat Chrysler Automobiles N.V. -lancia - -// land : 2013-09-10 Binky Moon, LLC +// land : Binky Moon, LLC +// https://www.iana.org/domains/root/db/land.html land -// landrover : 2014-11-13 Jaguar Land Rover Ltd +// landrover : Jaguar Land Rover Ltd +// https://www.iana.org/domains/root/db/landrover.html landrover -// lanxess : 2015-07-30 LANXESS Corporation +// lanxess : LANXESS Corporation +// https://www.iana.org/domains/root/db/lanxess.html lanxess -// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated +// lasalle : Jones Lang LaSalle Incorporated +// https://www.iana.org/domains/root/db/lasalle.html lasalle -// lat : 2014-10-16 XYZ.COM LLC +// lat : XYZ.COM LLC +// https://www.iana.org/domains/root/db/lat.html lat -// latino : 2015-07-30 Dish DBS Corporation +// latino : Dish DBS Corporation +// https://www.iana.org/domains/root/db/latino.html latino -// latrobe : 2014-06-16 La Trobe University +// latrobe : La Trobe University +// https://www.iana.org/domains/root/db/latrobe.html latrobe -// law : 2015-01-22 Registry Services, LLC +// law : Registry Services, LLC +// https://www.iana.org/domains/root/db/law.html law -// lawyer : 2014-03-20 Dog Beach, LLC +// lawyer : Dog Beach, LLC +// https://www.iana.org/domains/root/db/lawyer.html lawyer -// lds : 2014-03-20 IRI Domain Management, LLC +// lds : IRI Domain Management, LLC +// https://www.iana.org/domains/root/db/lds.html lds -// lease : 2014-03-06 Binky Moon, LLC +// lease : Binky Moon, LLC +// https://www.iana.org/domains/root/db/lease.html lease -// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +// leclerc : A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +// https://www.iana.org/domains/root/db/leclerc.html leclerc -// lefrak : 2015-07-16 LeFrak Organization, Inc. +// lefrak : LeFrak Organization, Inc. +// https://www.iana.org/domains/root/db/lefrak.html lefrak -// legal : 2014-10-16 Binky Moon, LLC +// legal : Binky Moon, LLC +// https://www.iana.org/domains/root/db/legal.html legal -// lego : 2015-07-16 LEGO Juris A/S +// lego : LEGO Juris A/S +// https://www.iana.org/domains/root/db/lego.html lego -// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION +// lexus : TOYOTA MOTOR CORPORATION +// https://www.iana.org/domains/root/db/lexus.html lexus -// lgbt : 2014-05-08 Identity Digital Limited +// lgbt : Identity Digital Limited +// https://www.iana.org/domains/root/db/lgbt.html lgbt -// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +// lidl : Schwarz Domains und Services GmbH & Co. KG +// https://www.iana.org/domains/root/db/lidl.html lidl -// life : 2014-02-06 Binky Moon, LLC +// life : Binky Moon, LLC +// https://www.iana.org/domains/root/db/life.html life -// lifeinsurance : 2015-01-15 American Council of Life Insurers +// lifeinsurance : American Council of Life Insurers +// https://www.iana.org/domains/root/db/lifeinsurance.html lifeinsurance -// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc. +// lifestyle : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/lifestyle.html lifestyle -// lighting : 2013-08-27 Binky Moon, LLC +// lighting : Binky Moon, LLC +// https://www.iana.org/domains/root/db/lighting.html lighting -// like : 2014-12-18 Amazon Registry Services, Inc. +// like : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/like.html like -// lilly : 2015-07-31 Eli Lilly and Company +// lilly : Eli Lilly and Company +// https://www.iana.org/domains/root/db/lilly.html lilly -// limited : 2014-03-06 Binky Moon, LLC +// limited : Binky Moon, LLC +// https://www.iana.org/domains/root/db/limited.html limited -// limo : 2013-10-17 Binky Moon, LLC +// limo : Binky Moon, LLC +// https://www.iana.org/domains/root/db/limo.html limo -// lincoln : 2014-11-13 Ford Motor Company +// lincoln : Ford Motor Company +// https://www.iana.org/domains/root/db/lincoln.html lincoln -// linde : 2014-12-04 Linde Aktiengesellschaft -linde - -// link : 2013-11-14 Nova Registry Ltd +// link : Nova Registry Ltd +// https://www.iana.org/domains/root/db/link.html link -// lipsy : 2015-06-25 Lipsy Ltd +// lipsy : Lipsy Ltd +// https://www.iana.org/domains/root/db/lipsy.html lipsy -// live : 2014-12-04 Dog Beach, LLC +// live : Dog Beach, LLC +// https://www.iana.org/domains/root/db/live.html live -// living : 2015-07-30 Lifestyle Domain Holdings, Inc. +// living : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/living.html living -// llc : 2017-12-14 Identity Digital Limited +// llc : Identity Digital Limited +// https://www.iana.org/domains/root/db/llc.html llc -// llp : 2019-08-26 Intercap Registry Inc. +// llp : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/llp.html llp -// loan : 2014-11-20 dot Loan Limited +// loan : dot Loan Limited +// https://www.iana.org/domains/root/db/loan.html loan -// loans : 2014-03-20 Binky Moon, LLC +// loans : Binky Moon, LLC +// https://www.iana.org/domains/root/db/loans.html loans -// locker : 2015-06-04 Dish DBS Corporation +// locker : Orange Domains LLC +// https://www.iana.org/domains/root/db/locker.html locker -// locus : 2015-06-25 Locus Analytics LLC +// locus : Locus Analytics LLC +// https://www.iana.org/domains/root/db/locus.html locus -// lol : 2015-01-30 XYZ.COM LLC +// lol : XYZ.COM LLC +// https://www.iana.org/domains/root/db/lol.html lol -// london : 2013-11-14 Dot London Domains Limited +// london : Dot London Domains Limited +// https://www.iana.org/domains/root/db/london.html london -// lotte : 2014-11-07 Lotte Holdings Co., Ltd. +// lotte : Lotte Holdings Co., Ltd. +// https://www.iana.org/domains/root/db/lotte.html lotte -// lotto : 2014-04-10 Identity Digital Limited +// lotto : Identity Digital Limited +// https://www.iana.org/domains/root/db/lotto.html lotto -// love : 2014-12-22 Merchant Law Group LLP +// love : Waterford Limited +// https://www.iana.org/domains/root/db/love.html love -// lpl : 2015-07-30 LPL Holdings, Inc. +// lpl : LPL Holdings, Inc. +// https://www.iana.org/domains/root/db/lpl.html lpl -// lplfinancial : 2015-07-30 LPL Holdings, Inc. +// lplfinancial : LPL Holdings, Inc. +// https://www.iana.org/domains/root/db/lplfinancial.html lplfinancial -// ltd : 2014-09-25 Binky Moon, LLC +// ltd : Binky Moon, LLC +// https://www.iana.org/domains/root/db/ltd.html ltd -// ltda : 2014-04-17 InterNetX, Corp +// ltda : InterNetX, Corp +// https://www.iana.org/domains/root/db/ltda.html ltda -// lundbeck : 2015-08-06 H. Lundbeck A/S +// lundbeck : H. Lundbeck A/S +// https://www.iana.org/domains/root/db/lundbeck.html lundbeck -// luxe : 2014-01-09 Registry Services, LLC +// luxe : Registry Services, LLC +// https://www.iana.org/domains/root/db/luxe.html luxe -// luxury : 2013-10-17 Luxury Partners, LLC +// luxury : Luxury Partners, LLC +// https://www.iana.org/domains/root/db/luxury.html luxury -// macys : 2015-07-31 Macys, Inc. -macys - -// madrid : 2014-05-01 Comunidad de Madrid +// madrid : Comunidad de Madrid +// https://www.iana.org/domains/root/db/madrid.html madrid -// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF) +// maif : Mutuelle Assurance Instituteur France (MAIF) +// https://www.iana.org/domains/root/db/maif.html maif -// maison : 2013-12-05 Binky Moon, LLC +// maison : Binky Moon, LLC +// https://www.iana.org/domains/root/db/maison.html maison -// makeup : 2015-01-15 XYZ.COM LLC +// makeup : XYZ.COM LLC +// https://www.iana.org/domains/root/db/makeup.html makeup -// man : 2014-12-04 MAN SE +// man : MAN Truck & Bus SE +// https://www.iana.org/domains/root/db/man.html man -// management : 2013-11-07 Binky Moon, LLC +// management : Binky Moon, LLC +// https://www.iana.org/domains/root/db/management.html management -// mango : 2013-10-24 PUNTO FA S.L. +// mango : PUNTO FA S.L. +// https://www.iana.org/domains/root/db/mango.html mango -// map : 2016-06-09 Charleston Road Registry Inc. +// map : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/map.html map -// market : 2014-03-06 Dog Beach, LLC +// market : Dog Beach, LLC +// https://www.iana.org/domains/root/db/market.html market -// marketing : 2013-11-07 Binky Moon, LLC +// marketing : Binky Moon, LLC +// https://www.iana.org/domains/root/db/marketing.html marketing -// markets : 2014-12-11 Dog Beach, LLC +// markets : Dog Beach, LLC +// https://www.iana.org/domains/root/db/markets.html markets -// marriott : 2014-10-09 Marriott Worldwide Corporation +// marriott : Marriott Worldwide Corporation +// https://www.iana.org/domains/root/db/marriott.html marriott -// marshalls : 2015-07-16 The TJX Companies, Inc. +// marshalls : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/marshalls.html marshalls -// maserati : 2015-07-31 Fiat Chrysler Automobiles N.V. -maserati - -// mattel : 2015-08-06 Mattel Sites, Inc. +// mattel : Mattel Sites, Inc. +// https://www.iana.org/domains/root/db/mattel.html mattel -// mba : 2015-04-02 Binky Moon, LLC +// mba : Binky Moon, LLC +// https://www.iana.org/domains/root/db/mba.html mba -// mckinsey : 2015-07-31 McKinsey Holdings, Inc. +// mckinsey : McKinsey Holdings, Inc. +// https://www.iana.org/domains/root/db/mckinsey.html mckinsey -// med : 2015-08-06 Medistry LLC +// med : Medistry LLC +// https://www.iana.org/domains/root/db/med.html med -// media : 2014-03-06 Binky Moon, LLC +// media : Binky Moon, LLC +// https://www.iana.org/domains/root/db/media.html media -// meet : 2014-01-16 Charleston Road Registry Inc. +// meet : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/meet.html meet -// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +// melbourne : The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +// https://www.iana.org/domains/root/db/melbourne.html melbourne -// meme : 2014-01-30 Charleston Road Registry Inc. +// meme : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/meme.html meme -// memorial : 2014-10-16 Dog Beach, LLC +// memorial : Dog Beach, LLC +// https://www.iana.org/domains/root/db/memorial.html memorial -// men : 2015-02-26 Exclusive Registry Limited +// men : Exclusive Registry Limited +// https://www.iana.org/domains/root/db/men.html men -// menu : 2013-09-11 Dot Menu Registry, LLC +// menu : Dot Menu Registry, LLC +// https://www.iana.org/domains/root/db/menu.html menu -// merckmsd : 2016-07-14 MSD Registry Holdings, Inc. +// merck : Merck Registry Holdings, Inc. +// https://www.iana.org/domains/root/db/merck.html +merck + +// merckmsd : MSD Registry Holdings, Inc. +// https://www.iana.org/domains/root/db/merckmsd.html merckmsd -// miami : 2013-12-19 Registry Services, LLC +// miami : Registry Services, LLC +// https://www.iana.org/domains/root/db/miami.html miami -// microsoft : 2014-12-18 Microsoft Corporation +// microsoft : Microsoft Corporation +// https://www.iana.org/domains/root/db/microsoft.html microsoft -// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft +// mini : Bayerische Motoren Werke Aktiengesellschaft +// https://www.iana.org/domains/root/db/mini.html mini -// mint : 2015-07-30 Intuit Administrative Services, Inc. +// mint : Intuit Administrative Services, Inc. +// https://www.iana.org/domains/root/db/mint.html mint -// mit : 2015-07-02 Massachusetts Institute of Technology +// mit : Massachusetts Institute of Technology +// https://www.iana.org/domains/root/db/mit.html mit -// mitsubishi : 2015-07-23 Mitsubishi Corporation +// mitsubishi : Mitsubishi Corporation +// https://www.iana.org/domains/root/db/mitsubishi.html mitsubishi -// mlb : 2015-05-21 MLB Advanced Media DH, LLC +// mlb : MLB Advanced Media DH, LLC +// https://www.iana.org/domains/root/db/mlb.html mlb -// mls : 2015-04-23 The Canadian Real Estate Association +// mls : The Canadian Real Estate Association +// https://www.iana.org/domains/root/db/mls.html mls -// mma : 2014-11-07 MMA IARD +// mma : MMA IARD +// https://www.iana.org/domains/root/db/mma.html mma -// mobile : 2016-06-02 Dish DBS Corporation +// mobile : Dish DBS Corporation +// https://www.iana.org/domains/root/db/mobile.html mobile -// moda : 2013-11-07 Dog Beach, LLC +// moda : Dog Beach, LLC +// https://www.iana.org/domains/root/db/moda.html moda -// moe : 2013-11-13 Interlink Systems Innovation Institute K.K. +// moe : Interlink Systems Innovation Institute K.K. +// https://www.iana.org/domains/root/db/moe.html moe -// moi : 2014-12-18 Amazon Registry Services, Inc. +// moi : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/moi.html moi -// mom : 2015-04-16 XYZ.COM LLC +// mom : XYZ.COM LLC +// https://www.iana.org/domains/root/db/mom.html mom -// monash : 2013-09-30 Monash University +// monash : Monash University +// https://www.iana.org/domains/root/db/monash.html monash -// money : 2014-10-16 Binky Moon, LLC +// money : Binky Moon, LLC +// https://www.iana.org/domains/root/db/money.html money -// monster : 2015-09-11 XYZ.COM LLC +// monster : XYZ.COM LLC +// https://www.iana.org/domains/root/db/monster.html monster -// mormon : 2013-12-05 IRI Domain Management, LLC +// mormon : IRI Domain Management, LLC +// https://www.iana.org/domains/root/db/mormon.html mormon -// mortgage : 2014-03-20 Dog Beach, LLC +// mortgage : Dog Beach, LLC +// https://www.iana.org/domains/root/db/mortgage.html mortgage -// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// moscow : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// https://www.iana.org/domains/root/db/moscow.html moscow -// moto : 2015-06-04 Motorola Trademark Holdings, LLC +// moto : Motorola Trademark Holdings, LLC +// https://www.iana.org/domains/root/db/moto.html moto -// motorcycles : 2014-01-09 XYZ.COM LLC +// motorcycles : XYZ.COM LLC +// https://www.iana.org/domains/root/db/motorcycles.html motorcycles -// mov : 2014-01-30 Charleston Road Registry Inc. +// mov : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/mov.html mov -// movie : 2015-02-05 Binky Moon, LLC +// movie : Binky Moon, LLC +// https://www.iana.org/domains/root/db/movie.html movie -// msd : 2015-07-23 MSD Registry Holdings, Inc. +// msd : MSD Registry Holdings, Inc. +// https://www.iana.org/domains/root/db/msd.html msd -// mtn : 2014-12-04 MTN Dubai Limited +// mtn : MTN Dubai Limited +// https://www.iana.org/domains/root/db/mtn.html mtn -// mtr : 2015-03-12 MTR Corporation Limited +// mtr : MTR Corporation Limited +// https://www.iana.org/domains/root/db/mtr.html mtr -// music : 2021-05-04 DotMusic Limited +// music : DotMusic Limited +// https://www.iana.org/domains/root/db/music.html music -// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC -mutual - -// nab : 2015-08-20 National Australia Bank Limited +// nab : National Australia Bank Limited +// https://www.iana.org/domains/root/db/nab.html nab -// nagoya : 2013-10-24 GMO Registry, Inc. +// nagoya : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/nagoya.html nagoya -// natura : 2015-03-12 NATURA COSMÉTICOS S.A. -natura - -// navy : 2014-03-06 Dog Beach, LLC +// navy : Dog Beach, LLC +// https://www.iana.org/domains/root/db/navy.html navy -// nba : 2015-07-31 NBA REGISTRY, LLC +// nba : NBA REGISTRY, LLC +// https://www.iana.org/domains/root/db/nba.html nba -// nec : 2015-01-08 NEC Corporation +// nec : NEC Corporation +// https://www.iana.org/domains/root/db/nec.html nec -// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA +// netbank : COMMONWEALTH BANK OF AUSTRALIA +// https://www.iana.org/domains/root/db/netbank.html netbank -// netflix : 2015-06-18 Netflix, Inc. +// netflix : Netflix, Inc. +// https://www.iana.org/domains/root/db/netflix.html netflix -// network : 2013-11-14 Binky Moon, LLC +// network : Binky Moon, LLC +// https://www.iana.org/domains/root/db/network.html network -// neustar : 2013-12-05 NeuStar, Inc. +// neustar : NeuStar, Inc. +// https://www.iana.org/domains/root/db/neustar.html neustar -// new : 2014-01-30 Charleston Road Registry Inc. +// new : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/new.html new -// news : 2014-12-18 Dog Beach, LLC +// news : Dog Beach, LLC +// https://www.iana.org/domains/root/db/news.html news -// next : 2015-06-18 Next plc +// next : Next plc +// https://www.iana.org/domains/root/db/next.html next -// nextdirect : 2015-06-18 Next plc +// nextdirect : Next plc +// https://www.iana.org/domains/root/db/nextdirect.html nextdirect -// nexus : 2014-07-24 Charleston Road Registry Inc. +// nexus : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/nexus.html nexus -// nfl : 2015-07-23 NFL Reg Ops LLC +// nfl : NFL Reg Ops LLC +// https://www.iana.org/domains/root/db/nfl.html nfl -// ngo : 2014-03-06 Public Interest Registry +// ngo : Public Interest Registry +// https://www.iana.org/domains/root/db/ngo.html ngo -// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK) +// nhk : Japan Broadcasting Corporation (NHK) +// https://www.iana.org/domains/root/db/nhk.html nhk -// nico : 2014-12-04 DWANGO Co., Ltd. +// nico : DWANGO Co., Ltd. +// https://www.iana.org/domains/root/db/nico.html nico -// nike : 2015-07-23 NIKE, Inc. +// nike : NIKE, Inc. +// https://www.iana.org/domains/root/db/nike.html nike -// nikon : 2015-05-21 NIKON CORPORATION +// nikon : NIKON CORPORATION +// https://www.iana.org/domains/root/db/nikon.html nikon -// ninja : 2013-11-07 Dog Beach, LLC +// ninja : Dog Beach, LLC +// https://www.iana.org/domains/root/db/ninja.html ninja -// nissan : 2014-03-27 NISSAN MOTOR CO., LTD. +// nissan : NISSAN MOTOR CO., LTD. +// https://www.iana.org/domains/root/db/nissan.html nissan -// nissay : 2015-10-29 Nippon Life Insurance Company +// nissay : Nippon Life Insurance Company +// https://www.iana.org/domains/root/db/nissay.html nissay -// nokia : 2015-01-08 Nokia Corporation +// nokia : Nokia Corporation +// https://www.iana.org/domains/root/db/nokia.html nokia -// northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC -northwesternmutual - -// norton : 2014-12-04 NortonLifeLock Inc. +// norton : Gen Digital Inc. +// https://www.iana.org/domains/root/db/norton.html norton -// now : 2015-06-25 Amazon Registry Services, Inc. +// now : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/now.html now -// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// nowruz : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/nowruz.html nowruz -// nowtv : 2015-05-14 Starbucks (HK) Limited +// nowtv : Starbucks (HK) Limited +// https://www.iana.org/domains/root/db/nowtv.html nowtv -// nra : 2014-05-22 NRA Holdings Company, INC. +// nra : NRA Holdings Company, INC. +// https://www.iana.org/domains/root/db/nra.html nra -// nrw : 2013-11-21 Minds + Machines GmbH +// nrw : Minds + Machines GmbH +// https://www.iana.org/domains/root/db/nrw.html nrw -// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION +// ntt : NIPPON TELEGRAPH AND TELEPHONE CORPORATION +// https://www.iana.org/domains/root/db/ntt.html ntt -// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications +// nyc : The City of New York by and through the New York City Department of Information Technology & Telecommunications +// https://www.iana.org/domains/root/db/nyc.html nyc -// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA +// obi : OBI Group Holding SE & Co. KGaA +// https://www.iana.org/domains/root/db/obi.html obi -// observer : 2015-04-30 Dog Beach, LLC +// observer : Fegistry, LLC +// https://www.iana.org/domains/root/db/observer.html observer -// office : 2015-03-12 Microsoft Corporation +// office : Microsoft Corporation +// https://www.iana.org/domains/root/db/office.html office -// okinawa : 2013-12-05 BRregistry, Inc. +// okinawa : BRregistry, Inc. +// https://www.iana.org/domains/root/db/okinawa.html okinawa -// olayan : 2015-05-14 Crescent Holding GmbH +// olayan : Competrol (Luxembourg) Sarl +// https://www.iana.org/domains/root/db/olayan.html olayan -// olayangroup : 2015-05-14 Crescent Holding GmbH +// olayangroup : Competrol (Luxembourg) Sarl +// https://www.iana.org/domains/root/db/olayangroup.html olayangroup -// oldnavy : 2015-07-31 The Gap, Inc. -oldnavy - -// ollo : 2015-06-04 Dish DBS Corporation +// ollo : Dish DBS Corporation +// https://www.iana.org/domains/root/db/ollo.html ollo -// omega : 2015-01-08 The Swatch Group Ltd +// omega : The Swatch Group Ltd +// https://www.iana.org/domains/root/db/omega.html omega -// one : 2014-11-07 One.com A/S +// one : One.com A/S +// https://www.iana.org/domains/root/db/one.html one -// ong : 2014-03-06 Public Interest Registry +// ong : Public Interest Registry +// https://www.iana.org/domains/root/db/ong.html ong -// onl : 2013-09-16 iRegistry GmbH +// onl : iRegistry GmbH +// https://www.iana.org/domains/root/db/onl.html onl -// online : 2015-01-15 Radix FZC +// online : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/online.html online -// ooo : 2014-01-09 INFIBEAM AVENUES LIMITED +// ooo : INFIBEAM AVENUES LIMITED +// https://www.iana.org/domains/root/db/ooo.html ooo -// open : 2015-07-31 American Express Travel Related Services Company, Inc. +// open : American Express Travel Related Services Company, Inc. +// https://www.iana.org/domains/root/db/open.html open -// oracle : 2014-06-19 Oracle Corporation +// oracle : Oracle Corporation +// https://www.iana.org/domains/root/db/oracle.html oracle -// orange : 2015-03-12 Orange Brand Services Limited +// orange : Orange Brand Services Limited +// https://www.iana.org/domains/root/db/orange.html orange -// organic : 2014-03-27 Identity Digital Limited +// organic : Identity Digital Limited +// https://www.iana.org/domains/root/db/organic.html organic -// origins : 2015-10-01 The Estée Lauder Companies Inc. +// origins : The Estée Lauder Companies Inc. +// https://www.iana.org/domains/root/db/origins.html origins -// osaka : 2014-09-04 Osaka Registry Co., Ltd. +// osaka : Osaka Registry Co., Ltd. +// https://www.iana.org/domains/root/db/osaka.html osaka -// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd. +// otsuka : Otsuka Holdings Co., Ltd. +// https://www.iana.org/domains/root/db/otsuka.html otsuka -// ott : 2015-06-04 Dish DBS Corporation +// ott : Dish DBS Corporation +// https://www.iana.org/domains/root/db/ott.html ott -// ovh : 2014-01-16 MédiaBC +// ovh : MédiaBC +// https://www.iana.org/domains/root/db/ovh.html ovh -// page : 2014-12-04 Charleston Road Registry Inc. +// page : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/page.html page -// panasonic : 2015-07-30 Panasonic Corporation +// panasonic : Panasonic Holdings Corporation +// https://www.iana.org/domains/root/db/panasonic.html panasonic -// paris : 2014-01-30 City of Paris +// paris : City of Paris +// https://www.iana.org/domains/root/db/paris.html paris -// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// pars : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/pars.html pars -// partners : 2013-12-05 Binky Moon, LLC +// partners : Binky Moon, LLC +// https://www.iana.org/domains/root/db/partners.html partners -// parts : 2013-12-05 Binky Moon, LLC +// parts : Binky Moon, LLC +// https://www.iana.org/domains/root/db/parts.html parts -// party : 2014-09-11 Blue Sky Registry Limited +// party : Blue Sky Registry Limited +// https://www.iana.org/domains/root/db/party.html party -// passagens : 2015-03-05 Travel Reservations SRL -passagens - -// pay : 2015-08-27 Amazon Registry Services, Inc. +// pay : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/pay.html pay -// pccw : 2015-05-14 PCCW Enterprises Limited +// pccw : PCCW Enterprises Limited +// https://www.iana.org/domains/root/db/pccw.html pccw -// pet : 2015-05-07 Identity Digital Limited +// pet : Identity Digital Limited +// https://www.iana.org/domains/root/db/pet.html pet -// pfizer : 2015-09-11 Pfizer Inc. +// pfizer : Pfizer Inc. +// https://www.iana.org/domains/root/db/pfizer.html pfizer -// pharmacy : 2014-06-19 National Association of Boards of Pharmacy +// pharmacy : National Association of Boards of Pharmacy +// https://www.iana.org/domains/root/db/pharmacy.html pharmacy -// phd : 2016-07-28 Charleston Road Registry Inc. +// phd : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/phd.html phd -// philips : 2014-11-07 Koninklijke Philips N.V. +// philips : Koninklijke Philips N.V. +// https://www.iana.org/domains/root/db/philips.html philips -// phone : 2016-06-02 Dish DBS Corporation +// phone : Dish DBS Corporation +// https://www.iana.org/domains/root/db/phone.html phone -// photo : 2013-11-14 Registry Services, LLC +// photo : Registry Services, LLC +// https://www.iana.org/domains/root/db/photo.html photo -// photography : 2013-09-20 Binky Moon, LLC +// photography : Binky Moon, LLC +// https://www.iana.org/domains/root/db/photography.html photography -// photos : 2013-10-17 Binky Moon, LLC +// photos : Binky Moon, LLC +// https://www.iana.org/domains/root/db/photos.html photos -// physio : 2014-05-01 PhysBiz Pty Ltd +// physio : PhysBiz Pty Ltd +// https://www.iana.org/domains/root/db/physio.html physio -// pics : 2013-11-14 XYZ.COM LLC +// pics : XYZ.COM LLC +// https://www.iana.org/domains/root/db/pics.html pics -// pictet : 2014-06-26 Pictet Europe S.A. +// pictet : Pictet Europe S.A. +// https://www.iana.org/domains/root/db/pictet.html pictet -// pictures : 2014-03-06 Binky Moon, LLC +// pictures : Binky Moon, LLC +// https://www.iana.org/domains/root/db/pictures.html pictures -// pid : 2015-01-08 Top Level Spectrum, Inc. +// pid : Top Level Spectrum, Inc. +// https://www.iana.org/domains/root/db/pid.html pid -// pin : 2014-12-18 Amazon Registry Services, Inc. +// pin : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/pin.html pin -// ping : 2015-06-11 Ping Registry Provider, Inc. +// ping : Ping Registry Provider, Inc. +// https://www.iana.org/domains/root/db/ping.html ping -// pink : 2013-10-01 Identity Digital Limited +// pink : Identity Digital Limited +// https://www.iana.org/domains/root/db/pink.html pink -// pioneer : 2015-07-16 Pioneer Corporation +// pioneer : Pioneer Corporation +// https://www.iana.org/domains/root/db/pioneer.html pioneer -// pizza : 2014-06-26 Binky Moon, LLC +// pizza : Binky Moon, LLC +// https://www.iana.org/domains/root/db/pizza.html pizza -// place : 2014-04-24 Binky Moon, LLC +// place : Binky Moon, LLC +// https://www.iana.org/domains/root/db/place.html place -// play : 2015-03-05 Charleston Road Registry Inc. +// play : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/play.html play -// playstation : 2015-07-02 Sony Interactive Entertainment Inc. +// playstation : Sony Interactive Entertainment Inc. +// https://www.iana.org/domains/root/db/playstation.html playstation -// plumbing : 2013-09-10 Binky Moon, LLC +// plumbing : Binky Moon, LLC +// https://www.iana.org/domains/root/db/plumbing.html plumbing -// plus : 2015-02-05 Binky Moon, LLC +// plus : Binky Moon, LLC +// https://www.iana.org/domains/root/db/plus.html plus -// pnc : 2015-07-02 PNC Domain Co., LLC +// pnc : PNC Domain Co., LLC +// https://www.iana.org/domains/root/db/pnc.html pnc -// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +// pohl : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/pohl.html pohl -// poker : 2014-07-03 Identity Digital Limited +// poker : Identity Digital Limited +// https://www.iana.org/domains/root/db/poker.html poker -// politie : 2015-08-20 Politie Nederland +// politie : Politie Nederland +// https://www.iana.org/domains/root/db/politie.html politie -// porn : 2014-10-16 ICM Registry PN LLC +// porn : ICM Registry PN LLC +// https://www.iana.org/domains/root/db/porn.html porn -// pramerica : 2015-07-30 Prudential Financial, Inc. +// pramerica : Prudential Financial, Inc. +// https://www.iana.org/domains/root/db/pramerica.html pramerica -// praxi : 2013-12-05 Praxi S.p.A. +// praxi : Praxi S.p.A. +// https://www.iana.org/domains/root/db/praxi.html praxi -// press : 2014-04-03 Radix FZC +// press : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/press.html press -// prime : 2015-06-25 Amazon Registry Services, Inc. +// prime : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/prime.html prime -// prod : 2014-01-23 Charleston Road Registry Inc. +// prod : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/prod.html prod -// productions : 2013-12-05 Binky Moon, LLC +// productions : Binky Moon, LLC +// https://www.iana.org/domains/root/db/productions.html productions -// prof : 2014-07-24 Charleston Road Registry Inc. +// prof : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/prof.html prof -// progressive : 2015-07-23 Progressive Casualty Insurance Company +// progressive : Progressive Casualty Insurance Company +// https://www.iana.org/domains/root/db/progressive.html progressive -// promo : 2014-12-18 Identity Digital Limited +// promo : Identity Digital Limited +// https://www.iana.org/domains/root/db/promo.html promo -// properties : 2013-12-05 Binky Moon, LLC +// properties : Binky Moon, LLC +// https://www.iana.org/domains/root/db/properties.html properties -// property : 2014-05-22 Internet Naming Company LLC +// property : Digital Property Infrastructure Limited +// https://www.iana.org/domains/root/db/property.html property -// protection : 2015-04-23 XYZ.COM LLC +// protection : XYZ.COM LLC +// https://www.iana.org/domains/root/db/protection.html protection -// pru : 2015-07-30 Prudential Financial, Inc. +// pru : Prudential Financial, Inc. +// https://www.iana.org/domains/root/db/pru.html pru -// prudential : 2015-07-30 Prudential Financial, Inc. +// prudential : Prudential Financial, Inc. +// https://www.iana.org/domains/root/db/prudential.html prudential -// pub : 2013-12-12 Dog Beach, LLC +// pub : Dog Beach, LLC +// https://www.iana.org/domains/root/db/pub.html pub -// pwc : 2015-10-29 PricewaterhouseCoopers LLP +// pwc : PricewaterhouseCoopers LLP +// https://www.iana.org/domains/root/db/pwc.html pwc -// qpon : 2013-11-14 dotQPON LLC +// qpon : dotQPON LLC +// https://www.iana.org/domains/root/db/qpon.html qpon -// quebec : 2013-12-19 PointQuébec Inc +// quebec : PointQuébec Inc +// https://www.iana.org/domains/root/db/quebec.html quebec -// quest : 2015-03-26 XYZ.COM LLC +// quest : XYZ.COM LLC +// https://www.iana.org/domains/root/db/quest.html quest -// racing : 2014-12-04 Premier Registry Limited +// racing : Premier Registry Limited +// https://www.iana.org/domains/root/db/racing.html racing -// radio : 2016-07-21 European Broadcasting Union (EBU) +// radio : European Broadcasting Union (EBU) +// https://www.iana.org/domains/root/db/radio.html radio -// read : 2014-12-18 Amazon Registry Services, Inc. +// read : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/read.html read -// realestate : 2015-09-11 dotRealEstate LLC +// realestate : dotRealEstate LLC +// https://www.iana.org/domains/root/db/realestate.html realestate -// realtor : 2014-05-29 Real Estate Domains LLC +// realtor : Real Estate Domains LLC +// https://www.iana.org/domains/root/db/realtor.html realtor -// realty : 2015-03-19 Dog Beach, LLC +// realty : Waterford Limited +// https://www.iana.org/domains/root/db/realty.html realty -// recipes : 2013-10-17 Binky Moon, LLC +// recipes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/recipes.html recipes -// red : 2013-11-07 Identity Digital Limited +// red : Identity Digital Limited +// https://www.iana.org/domains/root/db/red.html red -// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd. +// redstone : Redstone Haute Couture Co., Ltd. +// https://www.iana.org/domains/root/db/redstone.html redstone -// redumbrella : 2015-03-26 Travelers TLD, LLC +// redumbrella : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/redumbrella.html redumbrella -// rehab : 2014-03-06 Dog Beach, LLC +// rehab : Dog Beach, LLC +// https://www.iana.org/domains/root/db/rehab.html rehab -// reise : 2014-03-13 Binky Moon, LLC +// reise : Binky Moon, LLC +// https://www.iana.org/domains/root/db/reise.html reise -// reisen : 2014-03-06 Binky Moon, LLC +// reisen : Binky Moon, LLC +// https://www.iana.org/domains/root/db/reisen.html reisen -// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc. +// reit : National Association of Real Estate Investment Trusts, Inc. +// https://www.iana.org/domains/root/db/reit.html reit -// reliance : 2015-04-02 Reliance Industries Limited +// reliance : Reliance Industries Limited +// https://www.iana.org/domains/root/db/reliance.html reliance -// ren : 2013-12-12 ZDNS International Limited +// ren : ZDNS International Limited +// https://www.iana.org/domains/root/db/ren.html ren -// rent : 2014-12-04 XYZ.COM LLC +// rent : XYZ.COM LLC +// https://www.iana.org/domains/root/db/rent.html rent -// rentals : 2013-12-05 Binky Moon, LLC +// rentals : Binky Moon, LLC +// https://www.iana.org/domains/root/db/rentals.html rentals -// repair : 2013-11-07 Binky Moon, LLC +// repair : Binky Moon, LLC +// https://www.iana.org/domains/root/db/repair.html repair -// report : 2013-12-05 Binky Moon, LLC +// report : Binky Moon, LLC +// https://www.iana.org/domains/root/db/report.html report -// republican : 2014-03-20 Dog Beach, LLC +// republican : Dog Beach, LLC +// https://www.iana.org/domains/root/db/republican.html republican -// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// rest : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// https://www.iana.org/domains/root/db/rest.html rest -// restaurant : 2014-07-03 Binky Moon, LLC +// restaurant : Binky Moon, LLC +// https://www.iana.org/domains/root/db/restaurant.html restaurant -// review : 2014-11-20 dot Review Limited +// review : dot Review Limited +// https://www.iana.org/domains/root/db/review.html review -// reviews : 2013-09-13 Dog Beach, LLC +// reviews : Dog Beach, LLC +// https://www.iana.org/domains/root/db/reviews.html reviews -// rexroth : 2015-06-18 Robert Bosch GMBH +// rexroth : Robert Bosch GMBH +// https://www.iana.org/domains/root/db/rexroth.html rexroth -// rich : 2013-11-21 iRegistry GmbH +// rich : iRegistry GmbH +// https://www.iana.org/domains/root/db/rich.html rich -// richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited +// richardli : Pacific Century Asset Management (HK) Limited +// https://www.iana.org/domains/root/db/richardli.html richardli -// ricoh : 2014-11-20 Ricoh Company, Ltd. +// ricoh : Ricoh Company, Ltd. +// https://www.iana.org/domains/root/db/ricoh.html ricoh -// ril : 2015-04-02 Reliance Industries Limited +// ril : Reliance Industries Limited +// https://www.iana.org/domains/root/db/ril.html ril -// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO +// rio : Empresa Municipal de Informática SA - IPLANRIO +// https://www.iana.org/domains/root/db/rio.html rio -// rip : 2014-07-10 Dog Beach, LLC +// rip : Dog Beach, LLC +// https://www.iana.org/domains/root/db/rip.html rip -// rocher : 2014-12-18 Ferrero Trading Lux S.A. -rocher - -// rocks : 2013-11-14 Dog Beach, LLC +// rocks : Dog Beach, LLC +// https://www.iana.org/domains/root/db/rocks.html rocks -// rodeo : 2013-12-19 Registry Services, LLC +// rodeo : Registry Services, LLC +// https://www.iana.org/domains/root/db/rodeo.html rodeo -// rogers : 2015-08-06 Rogers Communications Canada Inc. +// rogers : Rogers Communications Canada Inc. +// https://www.iana.org/domains/root/db/rogers.html rogers -// room : 2014-12-18 Amazon Registry Services, Inc. +// room : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/room.html room -// rsvp : 2014-05-08 Charleston Road Registry Inc. +// rsvp : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/rsvp.html rsvp -// rugby : 2016-12-15 World Rugby Strategic Developments Limited +// rugby : World Rugby Strategic Developments Limited +// https://www.iana.org/domains/root/db/rugby.html rugby -// ruhr : 2013-10-02 dotSaarland GmbH +// ruhr : dotSaarland GmbH +// https://www.iana.org/domains/root/db/ruhr.html ruhr -// run : 2015-03-19 Binky Moon, LLC +// run : Binky Moon, LLC +// https://www.iana.org/domains/root/db/run.html run -// rwe : 2015-04-02 RWE AG +// rwe : RWE AG +// https://www.iana.org/domains/root/db/rwe.html rwe -// ryukyu : 2014-01-09 BRregistry, Inc. +// ryukyu : BRregistry, Inc. +// https://www.iana.org/domains/root/db/ryukyu.html ryukyu -// saarland : 2013-12-12 dotSaarland GmbH +// saarland : dotSaarland GmbH +// https://www.iana.org/domains/root/db/saarland.html saarland -// safe : 2014-12-18 Amazon Registry Services, Inc. +// safe : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/safe.html safe -// safety : 2015-01-08 Safety Registry Services, LLC. +// safety : Safety Registry Services, LLC. +// https://www.iana.org/domains/root/db/safety.html safety -// sakura : 2014-12-18 SAKURA Internet Inc. +// sakura : SAKURA Internet Inc. +// https://www.iana.org/domains/root/db/sakura.html sakura -// sale : 2014-10-16 Dog Beach, LLC +// sale : Dog Beach, LLC +// https://www.iana.org/domains/root/db/sale.html sale -// salon : 2014-12-11 Binky Moon, LLC +// salon : Binky Moon, LLC +// https://www.iana.org/domains/root/db/salon.html salon -// samsclub : 2015-07-31 Wal-Mart Stores, Inc. +// samsclub : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/samsclub.html samsclub -// samsung : 2014-04-03 SAMSUNG SDS CO., LTD +// samsung : SAMSUNG SDS CO., LTD +// https://www.iana.org/domains/root/db/samsung.html samsung -// sandvik : 2014-11-13 Sandvik AB +// sandvik : Sandvik AB +// https://www.iana.org/domains/root/db/sandvik.html sandvik -// sandvikcoromant : 2014-11-07 Sandvik AB +// sandvikcoromant : Sandvik AB +// https://www.iana.org/domains/root/db/sandvikcoromant.html sandvikcoromant -// sanofi : 2014-10-09 Sanofi +// sanofi : Sanofi +// https://www.iana.org/domains/root/db/sanofi.html sanofi -// sap : 2014-03-27 SAP AG +// sap : SAP AG +// https://www.iana.org/domains/root/db/sap.html sap -// sarl : 2014-07-03 Binky Moon, LLC +// sarl : Binky Moon, LLC +// https://www.iana.org/domains/root/db/sarl.html sarl -// sas : 2015-04-02 Research IP LLC +// sas : Research IP LLC +// https://www.iana.org/domains/root/db/sas.html sas -// save : 2015-06-25 Amazon Registry Services, Inc. +// save : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/save.html save -// saxo : 2014-10-31 Saxo Bank A/S +// saxo : Saxo Bank A/S +// https://www.iana.org/domains/root/db/saxo.html saxo -// sbi : 2015-03-12 STATE BANK OF INDIA +// sbi : STATE BANK OF INDIA +// https://www.iana.org/domains/root/db/sbi.html sbi -// sbs : 2014-11-07 ShortDot SA +// sbs : ShortDot SA +// https://www.iana.org/domains/root/db/sbs.html sbs -// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ) -sca - -// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB") +// scb : The Siam Commercial Bank Public Company Limited ("SCB") +// https://www.iana.org/domains/root/db/scb.html scb -// schaeffler : 2015-08-06 Schaeffler Technologies AG & Co. KG +// schaeffler : Schaeffler Technologies AG & Co. KG +// https://www.iana.org/domains/root/db/schaeffler.html schaeffler -// schmidt : 2014-04-03 SCHMIDT GROUPE S.A.S. +// schmidt : SCHMIDT GROUPE S.A.S. +// https://www.iana.org/domains/root/db/schmidt.html schmidt -// scholarships : 2014-04-24 Scholarships.com, LLC +// scholarships : Scholarships.com, LLC +// https://www.iana.org/domains/root/db/scholarships.html scholarships -// school : 2014-12-18 Binky Moon, LLC +// school : Binky Moon, LLC +// https://www.iana.org/domains/root/db/school.html school -// schule : 2014-03-06 Binky Moon, LLC +// schule : Binky Moon, LLC +// https://www.iana.org/domains/root/db/schule.html schule -// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG +// schwarz : Schwarz Domains und Services GmbH & Co. KG +// https://www.iana.org/domains/root/db/schwarz.html schwarz -// science : 2014-09-11 dot Science Limited +// science : dot Science Limited +// https://www.iana.org/domains/root/db/science.html science -// scot : 2014-01-23 Dot Scot Registry Limited +// scot : Dot Scot Registry Limited +// https://www.iana.org/domains/root/db/scot.html scot -// search : 2016-06-09 Charleston Road Registry Inc. +// search : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/search.html search -// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal) +// seat : SEAT, S.A. (Sociedad Unipersonal) +// https://www.iana.org/domains/root/db/seat.html seat -// secure : 2015-08-27 Amazon Registry Services, Inc. +// secure : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/secure.html secure -// security : 2015-05-14 XYZ.COM LLC +// security : XYZ.COM LLC +// https://www.iana.org/domains/root/db/security.html security -// seek : 2014-12-04 Seek Limited +// seek : Seek Limited +// https://www.iana.org/domains/root/db/seek.html seek -// select : 2015-10-08 Registry Services, LLC +// select : Registry Services, LLC +// https://www.iana.org/domains/root/db/select.html select -// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A. +// sener : Sener Ingeniería y Sistemas, S.A. +// https://www.iana.org/domains/root/db/sener.html sener -// services : 2014-02-27 Binky Moon, LLC +// services : Binky Moon, LLC +// https://www.iana.org/domains/root/db/services.html services -// seven : 2015-08-06 Seven West Media Ltd +// seven : Seven West Media Ltd +// https://www.iana.org/domains/root/db/seven.html seven -// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG +// sew : SEW-EURODRIVE GmbH & Co KG +// https://www.iana.org/domains/root/db/sew.html sew -// sex : 2014-11-13 ICM Registry SX LLC +// sex : ICM Registry SX LLC +// https://www.iana.org/domains/root/db/sex.html sex -// sexy : 2013-09-11 Internet Naming Company LLC +// sexy : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/sexy.html sexy -// sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR +// sfr : Societe Francaise du Radiotelephone - SFR +// https://www.iana.org/domains/root/db/sfr.html sfr -// shangrila : 2015-09-03 Shangri‐La International Hotel Management Limited +// shangrila : Shangri‐La International Hotel Management Limited +// https://www.iana.org/domains/root/db/shangrila.html shangrila -// sharp : 2014-05-01 Sharp Corporation +// sharp : Sharp Corporation +// https://www.iana.org/domains/root/db/sharp.html sharp -// shaw : 2015-04-23 Shaw Cablesystems G.P. -shaw - -// shell : 2015-07-30 Shell Information Technology International Inc +// shell : Shell Information Technology International Inc +// https://www.iana.org/domains/root/db/shell.html shell -// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// shia : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/shia.html shia -// shiksha : 2013-11-14 Identity Digital Limited +// shiksha : Identity Digital Limited +// https://www.iana.org/domains/root/db/shiksha.html shiksha -// shoes : 2013-10-02 Binky Moon, LLC +// shoes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/shoes.html shoes -// shop : 2016-04-08 GMO Registry, Inc. +// shop : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/shop.html shop -// shopping : 2016-03-31 Binky Moon, LLC +// shopping : Binky Moon, LLC +// https://www.iana.org/domains/root/db/shopping.html shopping -// shouji : 2015-01-08 Beijing Qihu Keji Co., Ltd. +// shouji : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/shouji.html shouji -// show : 2015-03-05 Binky Moon, LLC +// show : Binky Moon, LLC +// https://www.iana.org/domains/root/db/show.html show -// showtime : 2015-08-06 CBS Domains Inc. -showtime - -// silk : 2015-06-25 Amazon Registry Services, Inc. +// silk : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/silk.html silk -// sina : 2015-03-12 Sina Corporation +// sina : Sina Corporation +// https://www.iana.org/domains/root/db/sina.html sina -// singles : 2013-08-27 Binky Moon, LLC +// singles : Binky Moon, LLC +// https://www.iana.org/domains/root/db/singles.html singles -// site : 2015-01-15 Radix FZC +// site : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/site.html site -// ski : 2015-04-09 Identity Digital Limited +// ski : Identity Digital Limited +// https://www.iana.org/domains/root/db/ski.html ski -// skin : 2015-01-15 XYZ.COM LLC +// skin : XYZ.COM LLC +// https://www.iana.org/domains/root/db/skin.html skin -// sky : 2014-06-19 Sky International AG +// sky : Sky UK Limited +// https://www.iana.org/domains/root/db/sky.html sky -// skype : 2014-12-18 Microsoft Corporation +// skype : Microsoft Corporation +// https://www.iana.org/domains/root/db/skype.html skype -// sling : 2015-07-30 DISH Technologies L.L.C. +// sling : DISH Technologies L.L.C. +// https://www.iana.org/domains/root/db/sling.html sling -// smart : 2015-07-09 Smart Communications, Inc. (SMART) +// smart : Smart Communications, Inc. (SMART) +// https://www.iana.org/domains/root/db/smart.html smart -// smile : 2014-12-18 Amazon Registry Services, Inc. +// smile : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/smile.html smile -// sncf : 2015-02-19 Société Nationale SNCF +// sncf : Société Nationale SNCF +// https://www.iana.org/domains/root/db/sncf.html sncf -// soccer : 2015-03-26 Binky Moon, LLC +// soccer : Binky Moon, LLC +// https://www.iana.org/domains/root/db/soccer.html soccer -// social : 2013-11-07 Dog Beach, LLC +// social : Dog Beach, LLC +// https://www.iana.org/domains/root/db/social.html social -// softbank : 2015-07-02 SoftBank Group Corp. +// softbank : SoftBank Group Corp. +// https://www.iana.org/domains/root/db/softbank.html softbank -// software : 2014-03-20 Dog Beach, LLC +// software : Dog Beach, LLC +// https://www.iana.org/domains/root/db/software.html software -// sohu : 2013-12-19 Sohu.com Limited +// sohu : Sohu.com Limited +// https://www.iana.org/domains/root/db/sohu.html sohu -// solar : 2013-11-07 Binky Moon, LLC +// solar : Binky Moon, LLC +// https://www.iana.org/domains/root/db/solar.html solar -// solutions : 2013-11-07 Binky Moon, LLC +// solutions : Binky Moon, LLC +// https://www.iana.org/domains/root/db/solutions.html solutions -// song : 2015-02-26 Amazon Registry Services, Inc. +// song : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/song.html song -// sony : 2015-01-08 Sony Corporation +// sony : Sony Corporation +// https://www.iana.org/domains/root/db/sony.html sony -// soy : 2014-01-23 Charleston Road Registry Inc. +// soy : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/soy.html soy -// spa : 2019-09-19 Asia Spa and Wellness Promotion Council Limited +// spa : Asia Spa and Wellness Promotion Council Limited +// https://www.iana.org/domains/root/db/spa.html spa -// space : 2014-04-03 Radix FZC +// space : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/space.html space -// sport : 2017-11-16 Global Association of International Sports Federations (GAISF) +// sport : SportAccord +// https://www.iana.org/domains/root/db/sport.html sport -// spot : 2015-02-26 Amazon Registry Services, Inc. +// spot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/spot.html spot -// srl : 2015-05-07 InterNetX, Corp +// srl : InterNetX, Corp +// https://www.iana.org/domains/root/db/srl.html srl -// stada : 2014-11-13 STADA Arzneimittel AG +// stada : STADA Arzneimittel AG +// https://www.iana.org/domains/root/db/stada.html stada -// staples : 2015-07-30 Staples, Inc. +// staples : Staples, Inc. +// https://www.iana.org/domains/root/db/staples.html staples -// star : 2015-01-08 Star India Private Limited +// star : Star India Private Limited +// https://www.iana.org/domains/root/db/star.html star -// statebank : 2015-03-12 STATE BANK OF INDIA +// statebank : STATE BANK OF INDIA +// https://www.iana.org/domains/root/db/statebank.html statebank -// statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company +// statefarm : State Farm Mutual Automobile Insurance Company +// https://www.iana.org/domains/root/db/statefarm.html statefarm -// stc : 2014-10-09 Saudi Telecom Company +// stc : Saudi Telecom Company +// https://www.iana.org/domains/root/db/stc.html stc -// stcgroup : 2014-10-09 Saudi Telecom Company +// stcgroup : Saudi Telecom Company +// https://www.iana.org/domains/root/db/stcgroup.html stcgroup -// stockholm : 2014-12-18 Stockholms kommun +// stockholm : Stockholms kommun +// https://www.iana.org/domains/root/db/stockholm.html stockholm -// storage : 2014-12-22 XYZ.COM LLC +// storage : XYZ.COM LLC +// https://www.iana.org/domains/root/db/storage.html storage -// store : 2015-04-09 Radix FZC +// store : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/store.html store -// stream : 2016-01-08 dot Stream Limited +// stream : dot Stream Limited +// https://www.iana.org/domains/root/db/stream.html stream -// studio : 2015-02-11 Dog Beach, LLC +// studio : Dog Beach, LLC +// https://www.iana.org/domains/root/db/studio.html studio -// study : 2014-12-11 Registry Services, LLC +// study : Registry Services, LLC +// https://www.iana.org/domains/root/db/study.html study -// style : 2014-12-04 Binky Moon, LLC +// style : Binky Moon, LLC +// https://www.iana.org/domains/root/db/style.html style -// sucks : 2014-12-22 Vox Populi Registry Ltd. +// sucks : Vox Populi Registry Ltd. +// https://www.iana.org/domains/root/db/sucks.html sucks -// supplies : 2013-12-19 Binky Moon, LLC +// supplies : Binky Moon, LLC +// https://www.iana.org/domains/root/db/supplies.html supplies -// supply : 2013-12-19 Binky Moon, LLC +// supply : Binky Moon, LLC +// https://www.iana.org/domains/root/db/supply.html supply -// support : 2013-10-24 Binky Moon, LLC +// support : Binky Moon, LLC +// https://www.iana.org/domains/root/db/support.html support -// surf : 2014-01-09 Registry Services, LLC +// surf : Registry Services, LLC +// https://www.iana.org/domains/root/db/surf.html surf -// surgery : 2014-03-20 Binky Moon, LLC +// surgery : Binky Moon, LLC +// https://www.iana.org/domains/root/db/surgery.html surgery -// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION +// suzuki : SUZUKI MOTOR CORPORATION +// https://www.iana.org/domains/root/db/suzuki.html suzuki -// swatch : 2015-01-08 The Swatch Group Ltd +// swatch : The Swatch Group Ltd +// https://www.iana.org/domains/root/db/swatch.html swatch -// swiss : 2014-10-16 Swiss Confederation +// swiss : Swiss Confederation +// https://www.iana.org/domains/root/db/swiss.html swiss -// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet +// sydney : State of New South Wales, Department of Premier and Cabinet +// https://www.iana.org/domains/root/db/sydney.html sydney -// systems : 2013-11-07 Binky Moon, LLC +// systems : Binky Moon, LLC +// https://www.iana.org/domains/root/db/systems.html systems -// tab : 2014-12-04 Tabcorp Holdings Limited +// tab : Tabcorp Holdings Limited +// https://www.iana.org/domains/root/db/tab.html tab -// taipei : 2014-07-10 Taipei City Government +// taipei : Taipei City Government +// https://www.iana.org/domains/root/db/taipei.html taipei -// talk : 2015-04-09 Amazon Registry Services, Inc. +// talk : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/talk.html talk -// taobao : 2015-01-15 Alibaba Group Holding Limited +// taobao : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/taobao.html taobao -// target : 2015-07-31 Target Domain Holdings, LLC +// target : Target Domain Holdings, LLC +// https://www.iana.org/domains/root/db/target.html target -// tatamotors : 2015-03-12 Tata Motors Ltd +// tatamotors : Tata Motors Ltd +// https://www.iana.org/domains/root/db/tatamotors.html tatamotors -// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +// tatar : Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +// https://www.iana.org/domains/root/db/tatar.html tatar -// tattoo : 2013-08-30 Top Level Design, LLC +// tattoo : Registry Services, LLC +// https://www.iana.org/domains/root/db/tattoo.html tattoo -// tax : 2014-03-20 Binky Moon, LLC +// tax : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tax.html tax -// taxi : 2015-03-19 Binky Moon, LLC +// taxi : Binky Moon, LLC +// https://www.iana.org/domains/root/db/taxi.html taxi -// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// tci : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/tci.html tci -// tdk : 2015-06-11 TDK Corporation +// tdk : TDK Corporation +// https://www.iana.org/domains/root/db/tdk.html tdk -// team : 2015-03-05 Binky Moon, LLC +// team : Binky Moon, LLC +// https://www.iana.org/domains/root/db/team.html team -// tech : 2015-01-30 Radix FZC +// tech : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/tech.html tech -// technology : 2013-09-13 Binky Moon, LLC +// technology : Binky Moon, LLC +// https://www.iana.org/domains/root/db/technology.html technology -// temasek : 2014-08-07 Temasek Holdings (Private) Limited +// temasek : Temasek Holdings (Private) Limited +// https://www.iana.org/domains/root/db/temasek.html temasek -// tennis : 2014-12-04 Binky Moon, LLC +// tennis : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tennis.html tennis -// teva : 2015-07-02 Teva Pharmaceutical Industries Limited +// teva : Teva Pharmaceutical Industries Limited +// https://www.iana.org/domains/root/db/teva.html teva -// thd : 2015-04-02 Home Depot Product Authority, LLC +// thd : Home Depot Product Authority, LLC +// https://www.iana.org/domains/root/db/thd.html thd -// theater : 2015-03-19 Binky Moon, LLC +// theater : Binky Moon, LLC +// https://www.iana.org/domains/root/db/theater.html theater -// theatre : 2015-05-07 XYZ.COM LLC +// theatre : XYZ.COM LLC +// https://www.iana.org/domains/root/db/theatre.html theatre -// tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America +// tiaa : Teachers Insurance and Annuity Association of America +// https://www.iana.org/domains/root/db/tiaa.html tiaa -// tickets : 2015-02-05 XYZ.COM LLC +// tickets : XYZ.COM LLC +// https://www.iana.org/domains/root/db/tickets.html tickets -// tienda : 2013-11-14 Binky Moon, LLC +// tienda : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tienda.html tienda -// tiffany : 2015-01-30 Tiffany and Company -tiffany - -// tips : 2013-09-20 Binky Moon, LLC +// tips : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tips.html tips -// tires : 2014-11-07 Binky Moon, LLC +// tires : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tires.html tires -// tirol : 2014-04-24 punkt Tirol GmbH +// tirol : punkt Tirol GmbH +// https://www.iana.org/domains/root/db/tirol.html tirol -// tjmaxx : 2015-07-16 The TJX Companies, Inc. +// tjmaxx : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/tjmaxx.html tjmaxx -// tjx : 2015-07-16 The TJX Companies, Inc. +// tjx : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/tjx.html tjx -// tkmaxx : 2015-07-16 The TJX Companies, Inc. +// tkmaxx : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/tkmaxx.html tkmaxx -// tmall : 2015-01-15 Alibaba Group Holding Limited +// tmall : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/tmall.html tmall -// today : 2013-09-20 Binky Moon, LLC +// today : Binky Moon, LLC +// https://www.iana.org/domains/root/db/today.html today -// tokyo : 2013-11-13 GMO Registry, Inc. +// tokyo : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/tokyo.html tokyo -// tools : 2013-11-21 Binky Moon, LLC +// tools : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tools.html tools -// top : 2014-03-20 .TOP Registry +// top : .TOP Registry +// https://www.iana.org/domains/root/db/top.html top -// toray : 2014-12-18 Toray Industries, Inc. +// toray : Toray Industries, Inc. +// https://www.iana.org/domains/root/db/toray.html toray -// toshiba : 2014-04-10 TOSHIBA Corporation +// toshiba : TOSHIBA Corporation +// https://www.iana.org/domains/root/db/toshiba.html toshiba -// total : 2015-08-06 TotalEnergies SE +// total : TotalEnergies SE +// https://www.iana.org/domains/root/db/total.html total -// tours : 2015-01-22 Binky Moon, LLC +// tours : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tours.html tours -// town : 2014-03-06 Binky Moon, LLC +// town : Binky Moon, LLC +// https://www.iana.org/domains/root/db/town.html town -// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION +// toyota : TOYOTA MOTOR CORPORATION +// https://www.iana.org/domains/root/db/toyota.html toyota -// toys : 2014-03-06 Binky Moon, LLC +// toys : Binky Moon, LLC +// https://www.iana.org/domains/root/db/toys.html toys -// trade : 2014-01-23 Elite Registry Limited +// trade : Elite Registry Limited +// https://www.iana.org/domains/root/db/trade.html trade -// trading : 2014-12-11 Dog Beach, LLC +// trading : Dog Beach, LLC +// https://www.iana.org/domains/root/db/trading.html trading -// training : 2013-11-07 Binky Moon, LLC +// training : Binky Moon, LLC +// https://www.iana.org/domains/root/db/training.html training -// travel : 2015-10-09 Dog Beach, LLC +// travel : Dog Beach, LLC +// https://www.iana.org/domains/root/db/travel.html travel -// travelchannel : 2015-07-02 Lifestyle Domain Holdings, Inc. -travelchannel - -// travelers : 2015-03-26 Travelers TLD, LLC +// travelers : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/travelers.html travelers -// travelersinsurance : 2015-03-26 Travelers TLD, LLC +// travelersinsurance : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/travelersinsurance.html travelersinsurance -// trust : 2014-10-16 Internet Naming Company LLC +// trust : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/trust.html trust -// trv : 2015-03-26 Travelers TLD, LLC +// trv : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/trv.html trv -// tube : 2015-06-11 Latin American Telecom LLC +// tube : Latin American Telecom LLC +// https://www.iana.org/domains/root/db/tube.html tube -// tui : 2014-07-03 TUI AG +// tui : TUI AG +// https://www.iana.org/domains/root/db/tui.html tui -// tunes : 2015-02-26 Amazon Registry Services, Inc. +// tunes : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/tunes.html tunes -// tushu : 2014-12-18 Amazon Registry Services, Inc. +// tushu : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/tushu.html tushu -// tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED +// tvs : T V SUNDRAM IYENGAR & SONS LIMITED +// https://www.iana.org/domains/root/db/tvs.html tvs -// ubank : 2015-08-20 National Australia Bank Limited +// ubank : National Australia Bank Limited +// https://www.iana.org/domains/root/db/ubank.html ubank -// ubs : 2014-12-11 UBS AG +// ubs : UBS AG +// https://www.iana.org/domains/root/db/ubs.html ubs -// unicom : 2015-10-15 China United Network Communications Corporation Limited +// unicom : China United Network Communications Corporation Limited +// https://www.iana.org/domains/root/db/unicom.html unicom -// university : 2014-03-06 Binky Moon, LLC +// university : Binky Moon, LLC +// https://www.iana.org/domains/root/db/university.html university -// uno : 2013-09-11 Radix FZC +// uno : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/uno.html uno -// uol : 2014-05-01 UBN INTERNET LTDA. +// uol : UBN INTERNET LTDA. +// https://www.iana.org/domains/root/db/uol.html uol -// ups : 2015-06-25 UPS Market Driver, Inc. +// ups : UPS Market Driver, Inc. +// https://www.iana.org/domains/root/db/ups.html ups -// vacations : 2013-12-05 Binky Moon, LLC +// vacations : Binky Moon, LLC +// https://www.iana.org/domains/root/db/vacations.html vacations -// vana : 2014-12-11 Lifestyle Domain Holdings, Inc. +// vana : D3 Registry LLC +// https://www.iana.org/domains/root/db/vana.html vana -// vanguard : 2015-09-03 The Vanguard Group, Inc. +// vanguard : The Vanguard Group, Inc. +// https://www.iana.org/domains/root/db/vanguard.html vanguard -// vegas : 2014-01-16 Dot Vegas, Inc. +// vegas : Dot Vegas, Inc. +// https://www.iana.org/domains/root/db/vegas.html vegas -// ventures : 2013-08-27 Binky Moon, LLC +// ventures : Binky Moon, LLC +// https://www.iana.org/domains/root/db/ventures.html ventures -// verisign : 2015-08-13 VeriSign, Inc. +// verisign : VeriSign, Inc. +// https://www.iana.org/domains/root/db/verisign.html verisign -// versicherung : 2014-03-20 tldbox GmbH +// versicherung : tldbox GmbH +// https://www.iana.org/domains/root/db/versicherung.html versicherung -// vet : 2014-03-06 Dog Beach, LLC +// vet : Dog Beach, LLC +// https://www.iana.org/domains/root/db/vet.html vet -// viajes : 2013-10-17 Binky Moon, LLC +// viajes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/viajes.html viajes -// video : 2014-10-16 Dog Beach, LLC +// video : Dog Beach, LLC +// https://www.iana.org/domains/root/db/video.html video -// vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe +// vig : VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe +// https://www.iana.org/domains/root/db/vig.html vig -// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd. +// viking : Viking River Cruises (Bermuda) Ltd. +// https://www.iana.org/domains/root/db/viking.html viking -// villas : 2013-12-05 Binky Moon, LLC +// villas : Binky Moon, LLC +// https://www.iana.org/domains/root/db/villas.html villas -// vin : 2015-06-18 Binky Moon, LLC +// vin : Binky Moon, LLC +// https://www.iana.org/domains/root/db/vin.html vin -// vip : 2015-01-22 Registry Services, LLC +// vip : Registry Services, LLC +// https://www.iana.org/domains/root/db/vip.html vip -// virgin : 2014-09-25 Virgin Enterprises Limited +// virgin : Virgin Enterprises Limited +// https://www.iana.org/domains/root/db/virgin.html virgin -// visa : 2015-07-30 Visa Worldwide Pte. Limited +// visa : Visa Worldwide Pte. Limited +// https://www.iana.org/domains/root/db/visa.html visa -// vision : 2013-12-05 Binky Moon, LLC +// vision : Binky Moon, LLC +// https://www.iana.org/domains/root/db/vision.html vision -// viva : 2014-11-07 Saudi Telecom Company +// viva : Saudi Telecom Company +// https://www.iana.org/domains/root/db/viva.html viva -// vivo : 2015-07-31 Telefonica Brasil S.A. +// vivo : Telefonica Brasil S.A. +// https://www.iana.org/domains/root/db/vivo.html vivo -// vlaanderen : 2014-02-06 DNS.be vzw +// vlaanderen : DNS.be vzw +// https://www.iana.org/domains/root/db/vlaanderen.html vlaanderen -// vodka : 2013-12-19 Registry Services, LLC +// vodka : Registry Services, LLC +// https://www.iana.org/domains/root/db/vodka.html vodka -// volkswagen : 2015-05-14 Volkswagen Group of America Inc. -volkswagen - -// volvo : 2015-11-12 Volvo Holding Sverige Aktiebolag +// volvo : Volvo Holding Sverige Aktiebolag +// https://www.iana.org/domains/root/db/volvo.html volvo -// vote : 2013-11-21 Monolith Registry LLC +// vote : Monolith Registry LLC +// https://www.iana.org/domains/root/db/vote.html vote -// voting : 2013-11-13 Valuetainment Corp. +// voting : Valuetainment Corp. +// https://www.iana.org/domains/root/db/voting.html voting -// voto : 2013-11-21 Monolith Registry LLC +// voto : Monolith Registry LLC +// https://www.iana.org/domains/root/db/voto.html voto -// voyage : 2013-08-27 Binky Moon, LLC +// voyage : Binky Moon, LLC +// https://www.iana.org/domains/root/db/voyage.html voyage -// vuelos : 2015-03-05 Travel Reservations SRL -vuelos - -// wales : 2014-05-08 Nominet UK +// wales : Nominet UK +// https://www.iana.org/domains/root/db/wales.html wales -// walmart : 2015-07-31 Wal-Mart Stores, Inc. +// walmart : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/walmart.html walmart -// walter : 2014-11-13 Sandvik AB +// walter : Sandvik AB +// https://www.iana.org/domains/root/db/walter.html walter -// wang : 2013-10-24 Zodiac Wang Limited +// wang : Zodiac Wang Limited +// https://www.iana.org/domains/root/db/wang.html wang -// wanggou : 2014-12-18 Amazon Registry Services, Inc. +// wanggou : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/wanggou.html wanggou -// watch : 2013-11-14 Binky Moon, LLC +// watch : Binky Moon, LLC +// https://www.iana.org/domains/root/db/watch.html watch -// watches : 2014-12-22 Identity Digital Limited +// watches : Identity Digital Limited +// https://www.iana.org/domains/root/db/watches.html watches -// weather : 2015-01-08 International Business Machines Corporation +// weather : International Business Machines Corporation +// https://www.iana.org/domains/root/db/weather.html weather -// weatherchannel : 2015-03-12 International Business Machines Corporation +// weatherchannel : International Business Machines Corporation +// https://www.iana.org/domains/root/db/weatherchannel.html weatherchannel -// webcam : 2014-01-23 dot Webcam Limited +// webcam : dot Webcam Limited +// https://www.iana.org/domains/root/db/webcam.html webcam -// weber : 2015-06-04 Saint-Gobain Weber SA +// weber : Saint-Gobain Weber SA +// https://www.iana.org/domains/root/db/weber.html weber -// website : 2014-04-03 Radix FZC +// website : Radix Technologies Inc. +// https://www.iana.org/domains/root/db/website.html website -// wedding : 2014-04-24 Registry Services, LLC +// wed +// https://www.iana.org/domains/root/db/wed.html +wed + +// wedding : Registry Services, LLC +// https://www.iana.org/domains/root/db/wedding.html wedding -// weibo : 2015-03-05 Sina Corporation +// weibo : Sina Corporation +// https://www.iana.org/domains/root/db/weibo.html weibo -// weir : 2015-01-29 Weir Group IP Limited +// weir : Weir Group IP Limited +// https://www.iana.org/domains/root/db/weir.html weir -// whoswho : 2014-02-20 Who's Who Registry +// whoswho : Who's Who Registry +// https://www.iana.org/domains/root/db/whoswho.html whoswho -// wien : 2013-10-28 punkt.wien GmbH +// wien : punkt.wien GmbH +// https://www.iana.org/domains/root/db/wien.html wien -// wiki : 2013-11-07 Top Level Design, LLC +// wiki : Registry Services, LLC +// https://www.iana.org/domains/root/db/wiki.html wiki -// williamhill : 2014-03-13 William Hill Organization Limited +// williamhill : William Hill Organization Limited +// https://www.iana.org/domains/root/db/williamhill.html williamhill -// win : 2014-11-20 First Registry Limited +// win : First Registry Limited +// https://www.iana.org/domains/root/db/win.html win -// windows : 2014-12-18 Microsoft Corporation +// windows : Microsoft Corporation +// https://www.iana.org/domains/root/db/windows.html windows -// wine : 2015-06-18 Binky Moon, LLC +// wine : Binky Moon, LLC +// https://www.iana.org/domains/root/db/wine.html wine -// winners : 2015-07-16 The TJX Companies, Inc. +// winners : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/winners.html winners -// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC +// wme : William Morris Endeavor Entertainment, LLC +// https://www.iana.org/domains/root/db/wme.html wme -// wolterskluwer : 2015-08-06 Wolters Kluwer N.V. +// wolterskluwer : Wolters Kluwer N.V. +// https://www.iana.org/domains/root/db/wolterskluwer.html wolterskluwer -// woodside : 2015-07-09 Woodside Petroleum Limited +// woodside : Woodside Petroleum Limited +// https://www.iana.org/domains/root/db/woodside.html woodside -// work : 2013-12-19 Registry Services, LLC +// work : Registry Services, LLC +// https://www.iana.org/domains/root/db/work.html work -// works : 2013-11-14 Binky Moon, LLC +// works : Binky Moon, LLC +// https://www.iana.org/domains/root/db/works.html works -// world : 2014-06-12 Binky Moon, LLC +// world : Binky Moon, LLC +// https://www.iana.org/domains/root/db/world.html world -// wow : 2015-10-08 Amazon Registry Services, Inc. +// wow : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/wow.html wow -// wtc : 2013-12-19 World Trade Centers Association, Inc. +// wtc : World Trade Centers Association, Inc. +// https://www.iana.org/domains/root/db/wtc.html wtc -// wtf : 2014-03-06 Binky Moon, LLC +// wtf : Binky Moon, LLC +// https://www.iana.org/domains/root/db/wtf.html wtf -// xbox : 2014-12-18 Microsoft Corporation +// xbox : Microsoft Corporation +// https://www.iana.org/domains/root/db/xbox.html xbox -// xerox : 2014-10-24 Xerox DNHC LLC +// xerox : Xerox DNHC LLC +// https://www.iana.org/domains/root/db/xerox.html xerox -// xfinity : 2015-07-09 Comcast IP Holdings I, LLC -xfinity - -// xihuan : 2015-01-08 Beijing Qihu Keji Co., Ltd. +// xihuan : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/xihuan.html xihuan -// xin : 2014-12-11 Elegant Leader Limited +// xin : Elegant Leader Limited +// https://www.iana.org/domains/root/db/xin.html xin -// xn--11b4c3d : 2015-01-15 VeriSign Sarl +// xn--11b4c3d : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--11b4c3d.html कॉम -// xn--1ck2e1b : 2015-02-26 Amazon Registry Services, Inc. +// xn--1ck2e1b : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--1ck2e1b.html セール -// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd. +// xn--1qqw23a : Guangzhou YU Wei Information Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--1qqw23a.html 佛山 -// xn--30rr7y : 2014-06-12 Excellent First Limited +// xn--30rr7y : Excellent First Limited +// https://www.iana.org/domains/root/db/xn--30rr7y.html 慈善 -// xn--3bst00m : 2013-09-13 Eagle Horizon Limited +// xn--3bst00m : Eagle Horizon Limited +// https://www.iana.org/domains/root/db/xn--3bst00m.html 集团 -// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED OY +// xn--3ds443g : TLD REGISTRY LIMITED OY +// https://www.iana.org/domains/root/db/xn--3ds443g.html 在线 -// xn--3pxu8k : 2015-01-15 VeriSign Sarl +// xn--3pxu8k : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--3pxu8k.html 点看 -// xn--42c2d9a : 2015-01-15 VeriSign Sarl +// xn--42c2d9a : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--42c2d9a.html คอม -// xn--45q11c : 2013-11-21 Zodiac Gemini Ltd +// xn--45q11c : Zodiac Gemini Ltd +// https://www.iana.org/domains/root/db/xn--45q11c.html 八卦 -// xn--4gbrim : 2013-10-04 Helium TLDs Ltd +// xn--4gbrim : Helium TLDs Ltd +// https://www.iana.org/domains/root/db/xn--4gbrim.html موقع -// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center +// xn--55qw42g : China Organizational Name Administration Center +// https://www.iana.org/domains/root/db/xn--55qw42g.html 公益 -// xn--55qx5d : 2013-11-14 China Internet Network Information Center (CNNIC) +// xn--55qx5d : China Internet Network Information Center (CNNIC) +// https://www.iana.org/domains/root/db/xn--55qx5d.html 公司 -// xn--5su34j936bgsg : 2015-09-03 Shangri‐La International Hotel Management Limited +// xn--5su34j936bgsg : Shangri‐La International Hotel Management Limited +// https://www.iana.org/domains/root/db/xn--5su34j936bgsg.html 香格里拉 -// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited +// xn--5tzm5g : Global Website TLD Asia Limited +// https://www.iana.org/domains/root/db/xn--5tzm5g.html 网站 -// xn--6frz82g : 2013-09-23 Identity Digital Limited +// xn--6frz82g : Identity Digital Limited +// https://www.iana.org/domains/root/db/xn--6frz82g.html 移动 -// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited +// xn--6qq986b3xl : Tycoon Treasure Limited +// https://www.iana.org/domains/root/db/xn--6qq986b3xl.html 我爱你 -// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// xn--80adxhks : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// https://www.iana.org/domains/root/db/xn--80adxhks.html москва -// xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// xn--80aqecdr1a : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/xn--80aqecdr1a.html католик -// xn--80asehdb : 2013-07-14 CORE Association +// xn--80asehdb : CORE Association +// https://www.iana.org/domains/root/db/xn--80asehdb.html онлайн -// xn--80aswg : 2013-07-14 CORE Association +// xn--80aswg : CORE Association +// https://www.iana.org/domains/root/db/xn--80aswg.html сайт -// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited +// xn--8y0a063a : China United Network Communications Corporation Limited +// https://www.iana.org/domains/root/db/xn--8y0a063a.html 联通 -// xn--9dbq2a : 2015-01-15 VeriSign Sarl +// xn--9dbq2a : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--9dbq2a.html קום -// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED +// xn--9et52u : RISE VICTORY LIMITED +// https://www.iana.org/domains/root/db/xn--9et52u.html 时尚 -// xn--9krt00a : 2015-03-12 Sina Corporation +// xn--9krt00a : Sina Corporation +// https://www.iana.org/domains/root/db/xn--9krt00a.html 微博 -// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited +// xn--b4w605ferd : Temasek Holdings (Private) Limited +// https://www.iana.org/domains/root/db/xn--b4w605ferd.html 淡马锡 -// xn--bck1b9a5dre4c : 2015-02-26 Amazon Registry Services, Inc. +// xn--bck1b9a5dre4c : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--bck1b9a5dre4c.html ファッション -// xn--c1avg : 2013-11-14 Public Interest Registry +// xn--c1avg : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--c1avg.html орг -// xn--c2br7g : 2015-01-15 VeriSign Sarl +// xn--c2br7g : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--c2br7g.html नेट -// xn--cck2b3b : 2015-02-26 Amazon Registry Services, Inc. +// xn--cck2b3b : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--cck2b3b.html ストア -// xn--cckwcxetd : 2019-12-19 Amazon Registry Services, Inc. +// xn--cckwcxetd : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--cckwcxetd.html アマゾン -// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD +// xn--cg4bki : SAMSUNG SDS CO., LTD +// https://www.iana.org/domains/root/db/xn--cg4bki.html 삼성 -// xn--czr694b : 2014-01-16 Internet DotTrademark Organisation Limited +// xn--czr694b : Internet DotTrademark Organisation Limited +// https://www.iana.org/domains/root/db/xn--czr694b.html 商标 -// xn--czrs0t : 2013-12-19 Binky Moon, LLC +// xn--czrs0t : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--czrs0t.html 商店 -// xn--czru2d : 2013-11-21 Zodiac Aquarius Limited +// xn--czru2d : Zodiac Aquarius Limited +// https://www.iana.org/domains/root/db/xn--czru2d.html 商城 -// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet” +// xn--d1acj3b : The Foundation for Network Initiatives “The Smart Internet” +// https://www.iana.org/domains/root/db/xn--d1acj3b.html дети -// xn--eckvdtc9d : 2014-12-18 Amazon Registry Services, Inc. +// xn--eckvdtc9d : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--eckvdtc9d.html ポイント -// xn--efvy88h : 2014-08-22 Guangzhou YU Wei Information Technology Co., Ltd. +// xn--efvy88h : Guangzhou YU Wei Information Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--efvy88h.html 新闻 -// xn--fct429k : 2015-04-09 Amazon Registry Services, Inc. +// xn--fct429k : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--fct429k.html 家電 -// xn--fhbei : 2015-01-15 VeriSign Sarl +// xn--fhbei : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--fhbei.html كوم -// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED OY +// xn--fiq228c5hs : TLD REGISTRY LIMITED OY +// https://www.iana.org/domains/root/db/xn--fiq228c5hs.html 中文网 -// xn--fiq64b : 2013-10-14 CITIC Group Corporation +// xn--fiq64b : CITIC Group Corporation +// https://www.iana.org/domains/root/db/xn--fiq64b.html 中信 -// xn--fjq720a : 2014-05-22 Binky Moon, LLC +// xn--fjq720a : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--fjq720a.html 娱乐 -// xn--flw351e : 2014-07-31 Charleston Road Registry Inc. +// xn--flw351e : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/xn--flw351e.html 谷歌 -// xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited +// xn--fzys8d69uvgm : PCCW Enterprises Limited +// https://www.iana.org/domains/root/db/xn--fzys8d69uvgm.html 電訊盈科 -// xn--g2xx48c : 2015-01-30 Nawang Heli(Xiamen) Network Service Co., LTD. +// xn--g2xx48c : Nawang Heli(Xiamen) Network Service Co., LTD. +// https://www.iana.org/domains/root/db/xn--g2xx48c.html 购物 -// xn--gckr3f0f : 2015-02-26 Amazon Registry Services, Inc. +// xn--gckr3f0f : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--gckr3f0f.html クラウド -// xn--gk3at1e : 2015-10-08 Amazon Registry Services, Inc. +// xn--gk3at1e : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--gk3at1e.html 通販 -// xn--hxt814e : 2014-05-15 Zodiac Taurus Limited +// xn--hxt814e : Zodiac Taurus Limited +// https://www.iana.org/domains/root/db/xn--hxt814e.html 网店 -// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry +// xn--i1b6b1a6a2e : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--i1b6b1a6a2e.html संगठन -// xn--imr513n : 2014-12-11 Internet DotTrademark Organisation Limited +// xn--imr513n : Internet DotTrademark Organisation Limited +// https://www.iana.org/domains/root/db/xn--imr513n.html 餐厅 -// xn--io0a7i : 2013-11-14 China Internet Network Information Center (CNNIC) +// xn--io0a7i : China Internet Network Information Center (CNNIC) +// https://www.iana.org/domains/root/db/xn--io0a7i.html 网络 -// xn--j1aef : 2015-01-15 VeriSign Sarl +// xn--j1aef : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--j1aef.html ком -// xn--jlq480n2rg : 2019-12-19 Amazon Registry Services, Inc. +// xn--jlq480n2rg : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--jlq480n2rg.html 亚马逊 -// xn--jvr189m : 2015-02-26 Amazon Registry Services, Inc. +// xn--jvr189m : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--jvr189m.html 食品 -// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V. +// xn--kcrx77d1x4a : Koninklijke Philips N.V. +// https://www.iana.org/domains/root/db/xn--kcrx77d1x4a.html 飞利浦 -// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd +// xn--kput3i : Beijing RITT-Net Technology Development Co., Ltd +// https://www.iana.org/domains/root/db/xn--kput3i.html 手机 -// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company +// xn--mgba3a3ejt : Aramco Services Company +// https://www.iana.org/domains/root/db/xn--mgba3a3ejt.html ارامكو -// xn--mgba7c0bbn0a : 2015-05-14 Crescent Holding GmbH +// xn--mgba7c0bbn0a : Competrol (Luxembourg) Sarl +// https://www.iana.org/domains/root/db/xn--mgba7c0bbn0a.html العليان -// xn--mgbaakc7dvf : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat) -اتصالات - -// xn--mgbab2bd : 2013-10-31 CORE Association +// xn--mgbab2bd : CORE Association +// https://www.iana.org/domains/root/db/xn--mgbab2bd.html بازار -// xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre +// xn--mgbca7dzdo : Abu Dhabi Systems and Information Centre +// https://www.iana.org/domains/root/db/xn--mgbca7dzdo.html ابوظبي -// xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// xn--mgbi4ecexp : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/xn--mgbi4ecexp.html كاثوليك -// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// xn--mgbt3dhd : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// https://www.iana.org/domains/root/db/xn--mgbt3dhd.html همراه -// xn--mk1bu44c : 2015-01-15 VeriSign Sarl +// xn--mk1bu44c : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--mk1bu44c.html 닷컴 -// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd. +// xn--mxtq1m : Net-Chinese Co., Ltd. +// https://www.iana.org/domains/root/db/xn--mxtq1m.html 政府 -// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd. +// xn--ngbc5azd : International Domain Registry Pty. Ltd. +// https://www.iana.org/domains/root/db/xn--ngbc5azd.html شبكة -// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House +// xn--ngbe9e0a : Kuwait Finance House +// https://www.iana.org/domains/root/db/xn--ngbe9e0a.html بيتك -// xn--ngbrx : 2015-11-12 League of Arab States +// xn--ngbrx : League of Arab States +// https://www.iana.org/domains/root/db/xn--ngbrx.html عرب -// xn--nqv7f : 2013-11-14 Public Interest Registry +// xn--nqv7f : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--nqv7f.html 机构 -// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry +// xn--nqv7fs00ema : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--nqv7fs00ema.html 组织机构 -// xn--nyqy26a : 2014-11-07 Stable Tone Limited +// xn--nyqy26a : Stable Tone Limited +// https://www.iana.org/domains/root/db/xn--nyqy26a.html 健康 -// xn--otu796d : 2017-08-06 Jiang Yu Liang Cai Technology Company Limited +// xn--otu796d : Jiang Yu Liang Cai Technology Company Limited +// https://www.iana.org/domains/root/db/xn--otu796d.html 招聘 -// xn--p1acf : 2013-12-12 Rusnames Limited +// xn--p1acf : Rusnames Limited +// https://www.iana.org/domains/root/db/xn--p1acf.html рус -// xn--pssy2u : 2015-01-15 VeriSign Sarl +// xn--pssy2u : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--pssy2u.html 大拿 -// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc. +// xn--q9jyb4c : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/xn--q9jyb4c.html みんな -// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc. +// xn--qcka1pmc : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/xn--qcka1pmc.html グーグル -// xn--rhqv96g : 2013-09-11 Stable Tone Limited +// xn--rhqv96g : Stable Tone Limited +// https://www.iana.org/domains/root/db/xn--rhqv96g.html 世界 -// xn--rovu88b : 2015-02-26 Amazon Registry Services, Inc. +// xn--rovu88b : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--rovu88b.html 書籍 -// xn--ses554g : 2014-01-16 KNET Co., Ltd. +// xn--ses554g : KNET Co., Ltd. +// https://www.iana.org/domains/root/db/xn--ses554g.html 网址 -// xn--t60b56a : 2015-01-15 VeriSign Sarl +// xn--t60b56a : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--t60b56a.html 닷넷 -// xn--tckwe : 2015-01-15 VeriSign Sarl +// xn--tckwe : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--tckwe.html コム -// xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// xn--tiq49xqyj : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/xn--tiq49xqyj.html 天主教 -// xn--unup4y : 2013-07-14 Binky Moon, LLC +// xn--unup4y : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--unup4y.html 游戏 -// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +// xn--vermgensberater-ctb : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/xn--vermgensberater-ctb.html vermögensberater -// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG +// xn--vermgensberatung-pwb : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/xn--vermgensberatung-pwb.html vermögensberatung -// xn--vhquv : 2013-08-27 Binky Moon, LLC +// xn--vhquv : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--vhquv.html 企业 -// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd. +// xn--vuq861b : Beijing Tele-info Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--vuq861b.html 信息 -// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited +// xn--w4r85el8fhu5dnra : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/xn--w4r85el8fhu5dnra.html 嘉里大酒店 -// xn--w4rs40l : 2015-07-30 Kerry Trading Co. Limited +// xn--w4rs40l : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/xn--w4rs40l.html 嘉里 -// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd. +// xn--xhq521b : Guangzhou YU Wei Information Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--xhq521b.html 广东 -// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center +// xn--zfr164b : China Organizational Name Administration Center +// https://www.iana.org/domains/root/db/xn--zfr164b.html 政务 -// xyz : 2013-12-05 XYZ.COM LLC +// xyz : XYZ.COM LLC +// https://www.iana.org/domains/root/db/xyz.html xyz -// yachts : 2014-01-09 XYZ.COM LLC +// yachts : XYZ.COM LLC +// https://www.iana.org/domains/root/db/yachts.html yachts -// yahoo : 2015-04-02 Oath Inc. +// yahoo : Yahoo Inc. +// https://www.iana.org/domains/root/db/yahoo.html yahoo -// yamaxun : 2014-12-18 Amazon Registry Services, Inc. +// yamaxun : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/yamaxun.html yamaxun -// yandex : 2014-04-10 Yandex Europe B.V. +// yandex : Yandex Europe B.V. +// https://www.iana.org/domains/root/db/yandex.html yandex -// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD. +// yodobashi : YODOBASHI CAMERA CO.,LTD. +// https://www.iana.org/domains/root/db/yodobashi.html yodobashi -// yoga : 2014-05-29 Registry Services, LLC +// yoga : Registry Services, LLC +// https://www.iana.org/domains/root/db/yoga.html yoga -// yokohama : 2013-12-12 GMO Registry, Inc. +// yokohama : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/yokohama.html yokohama -// you : 2015-04-09 Amazon Registry Services, Inc. +// you : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/you.html you -// youtube : 2014-05-01 Charleston Road Registry Inc. +// youtube : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/youtube.html youtube -// yun : 2015-01-08 Beijing Qihu Keji Co., Ltd. +// yun : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/yun.html yun -// zappos : 2015-06-25 Amazon Registry Services, Inc. +// zappos : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/zappos.html zappos -// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.) +// zara : Industria de Diseño Textil, S.A. (INDITEX, S.A.) +// https://www.iana.org/domains/root/db/zara.html zara -// zero : 2014-12-18 Amazon Registry Services, Inc. +// zero : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/zero.html zero -// zip : 2014-05-08 Charleston Road Registry Inc. +// zip : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/zip.html zip -// zone : 2013-11-14 Binky Moon, LLC +// zone : Binky Moon, LLC +// https://www.iana.org/domains/root/db/zone.html zone -// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich) +// zuerich : Kanton Zürich (Canton of Zurich) +// https://www.iana.org/domains/root/db/zuerich.html zuerich - // ===END ICANN DOMAINS=== + // ===BEGIN PRIVATE DOMAINS=== + // (Note: these are in alphabetical order by company name) +// .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf +co.krd +edu.krd + +// .pl domains (grandfathered) +art.pl +gliwice.pl +krakow.pl +poznan.pl +wroc.pl +zakopane.pl + +// .US +// Submitted by Ed Moore +lib.de.us + +// 12CHARS: https://12chars.com +// Submitted by Kenny Niehage +12chars.dev +12chars.it +12chars.pro + // 1GB LLC : https://www.1gb.ua/ // Submitted by 1GB LLC cc.ua inf.ua ltd.ua -// 611coin : https://611project.org/ +// 611 blockchain domain name system : https://611project.net/ 611.to -// Aaron Marais' Gitlab pages: https://lab.aaronleem.co.za -// Submitted by Aaron Marais -graphox.us +// A2 Hosting +// Submitted by Tyler Hall +a2hosted.com +cpserver.com -// accesso Technology Group, plc. : https://accesso.com/ -// Submitted by accesso Team -*.devcdnaccesso.com +// AAA workspace : https://aaa.vodka +// Submitted by Kirill Rezraf +aaa.vodka // Acorn Labs : https://acorn.io // Submitted by Craig Jellick @@ -10668,12 +11244,18 @@ graphox.us // Submitted by Ofer Kalaora activetrail.biz +// Adaptable.io : https://adaptable.io +// Submitted by Mark Terrel +adaptable.app + // Adobe : https://www.adobe.com/ // Submitted by Ian Boston and Lars Trieloff adobeaemcloud.com *.dev.adobeaemcloud.com +aem.live hlx.live adobeaemcloud.net +aem.page hlx.page hlx3.page @@ -10682,8 +11264,12 @@ hlx3.page adobeio-static.net adobeioruntime.net -// Agnat sp. z o.o. : https://domena.pl -// Submitted by Przemyslaw Plewa +// Africa.com Web Solutions Ltd : https://registry.africa.com +// Submitted by Gavin Brown +africa.com + +// Agnat sp. z o.o. : https://domena.pl +// Submitted by Przemyslaw Plewa beep.pl // Airkit : https://www.airkit.com/ @@ -10743,60 +11329,454 @@ myamaze.net // Submitted by AWS Security // Subsections of Amazon/subsidiaries will appear until "concludes" tag +// Amazon API Gateway +// Submitted by AWS Security +// Reference: 6a4f5a95-8c7d-4077-a7af-9cf1abec0a53 +execute-api.cn-north-1.amazonaws.com.cn +execute-api.cn-northwest-1.amazonaws.com.cn +execute-api.af-south-1.amazonaws.com +execute-api.ap-east-1.amazonaws.com +execute-api.ap-northeast-1.amazonaws.com +execute-api.ap-northeast-2.amazonaws.com +execute-api.ap-northeast-3.amazonaws.com +execute-api.ap-south-1.amazonaws.com +execute-api.ap-south-2.amazonaws.com +execute-api.ap-southeast-1.amazonaws.com +execute-api.ap-southeast-2.amazonaws.com +execute-api.ap-southeast-3.amazonaws.com +execute-api.ap-southeast-4.amazonaws.com +execute-api.ap-southeast-5.amazonaws.com +execute-api.ca-central-1.amazonaws.com +execute-api.ca-west-1.amazonaws.com +execute-api.eu-central-1.amazonaws.com +execute-api.eu-central-2.amazonaws.com +execute-api.eu-north-1.amazonaws.com +execute-api.eu-south-1.amazonaws.com +execute-api.eu-south-2.amazonaws.com +execute-api.eu-west-1.amazonaws.com +execute-api.eu-west-2.amazonaws.com +execute-api.eu-west-3.amazonaws.com +execute-api.il-central-1.amazonaws.com +execute-api.me-central-1.amazonaws.com +execute-api.me-south-1.amazonaws.com +execute-api.sa-east-1.amazonaws.com +execute-api.us-east-1.amazonaws.com +execute-api.us-east-2.amazonaws.com +execute-api.us-gov-east-1.amazonaws.com +execute-api.us-gov-west-1.amazonaws.com +execute-api.us-west-1.amazonaws.com +execute-api.us-west-2.amazonaws.com + // Amazon CloudFront // Submitted by Donavan Miller // Reference: 54144616-fd49-4435-8535-19c6a601bdb3 cloudfront.net +// Amazon Cognito +// Submitted by AWS Security +// Reference: cb38c251-c93d-4cda-81ec-e72c4f0fdb72 +auth.af-south-1.amazoncognito.com +auth.ap-east-1.amazoncognito.com +auth.ap-northeast-1.amazoncognito.com +auth.ap-northeast-2.amazoncognito.com +auth.ap-northeast-3.amazoncognito.com +auth.ap-south-1.amazoncognito.com +auth.ap-south-2.amazoncognito.com +auth.ap-southeast-1.amazoncognito.com +auth.ap-southeast-2.amazoncognito.com +auth.ap-southeast-3.amazoncognito.com +auth.ap-southeast-4.amazoncognito.com +auth.ca-central-1.amazoncognito.com +auth.ca-west-1.amazoncognito.com +auth.eu-central-1.amazoncognito.com +auth.eu-central-2.amazoncognito.com +auth.eu-north-1.amazoncognito.com +auth.eu-south-1.amazoncognito.com +auth.eu-south-2.amazoncognito.com +auth.eu-west-1.amazoncognito.com +auth.eu-west-2.amazoncognito.com +auth.eu-west-3.amazoncognito.com +auth.il-central-1.amazoncognito.com +auth.me-central-1.amazoncognito.com +auth.me-south-1.amazoncognito.com +auth.sa-east-1.amazoncognito.com +auth.us-east-1.amazoncognito.com +auth-fips.us-east-1.amazoncognito.com +auth.us-east-2.amazoncognito.com +auth-fips.us-east-2.amazoncognito.com +auth-fips.us-gov-west-1.amazoncognito.com +auth.us-west-1.amazoncognito.com +auth-fips.us-west-1.amazoncognito.com +auth.us-west-2.amazoncognito.com +auth-fips.us-west-2.amazoncognito.com + // Amazon EC2 // Submitted by Luke Wells // Reference: 4c38fa71-58ac-4768-99e5-689c1767e537 +*.compute.amazonaws.com.cn *.compute.amazonaws.com *.compute-1.amazonaws.com -*.compute.amazonaws.com.cn us-east-1.amazonaws.com +// Amazon EMR +// Submitted by AWS Security +// Reference: 82f43f9f-bbb8-400e-8349-854f5a62f20d +emrappui-prod.cn-north-1.amazonaws.com.cn +emrnotebooks-prod.cn-north-1.amazonaws.com.cn +emrstudio-prod.cn-north-1.amazonaws.com.cn +emrappui-prod.cn-northwest-1.amazonaws.com.cn +emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn +emrstudio-prod.cn-northwest-1.amazonaws.com.cn +emrappui-prod.af-south-1.amazonaws.com +emrnotebooks-prod.af-south-1.amazonaws.com +emrstudio-prod.af-south-1.amazonaws.com +emrappui-prod.ap-east-1.amazonaws.com +emrnotebooks-prod.ap-east-1.amazonaws.com +emrstudio-prod.ap-east-1.amazonaws.com +emrappui-prod.ap-northeast-1.amazonaws.com +emrnotebooks-prod.ap-northeast-1.amazonaws.com +emrstudio-prod.ap-northeast-1.amazonaws.com +emrappui-prod.ap-northeast-2.amazonaws.com +emrnotebooks-prod.ap-northeast-2.amazonaws.com +emrstudio-prod.ap-northeast-2.amazonaws.com +emrappui-prod.ap-northeast-3.amazonaws.com +emrnotebooks-prod.ap-northeast-3.amazonaws.com +emrstudio-prod.ap-northeast-3.amazonaws.com +emrappui-prod.ap-south-1.amazonaws.com +emrnotebooks-prod.ap-south-1.amazonaws.com +emrstudio-prod.ap-south-1.amazonaws.com +emrappui-prod.ap-south-2.amazonaws.com +emrnotebooks-prod.ap-south-2.amazonaws.com +emrstudio-prod.ap-south-2.amazonaws.com +emrappui-prod.ap-southeast-1.amazonaws.com +emrnotebooks-prod.ap-southeast-1.amazonaws.com +emrstudio-prod.ap-southeast-1.amazonaws.com +emrappui-prod.ap-southeast-2.amazonaws.com +emrnotebooks-prod.ap-southeast-2.amazonaws.com +emrstudio-prod.ap-southeast-2.amazonaws.com +emrappui-prod.ap-southeast-3.amazonaws.com +emrnotebooks-prod.ap-southeast-3.amazonaws.com +emrstudio-prod.ap-southeast-3.amazonaws.com +emrappui-prod.ap-southeast-4.amazonaws.com +emrnotebooks-prod.ap-southeast-4.amazonaws.com +emrstudio-prod.ap-southeast-4.amazonaws.com +emrappui-prod.ca-central-1.amazonaws.com +emrnotebooks-prod.ca-central-1.amazonaws.com +emrstudio-prod.ca-central-1.amazonaws.com +emrappui-prod.ca-west-1.amazonaws.com +emrnotebooks-prod.ca-west-1.amazonaws.com +emrstudio-prod.ca-west-1.amazonaws.com +emrappui-prod.eu-central-1.amazonaws.com +emrnotebooks-prod.eu-central-1.amazonaws.com +emrstudio-prod.eu-central-1.amazonaws.com +emrappui-prod.eu-central-2.amazonaws.com +emrnotebooks-prod.eu-central-2.amazonaws.com +emrstudio-prod.eu-central-2.amazonaws.com +emrappui-prod.eu-north-1.amazonaws.com +emrnotebooks-prod.eu-north-1.amazonaws.com +emrstudio-prod.eu-north-1.amazonaws.com +emrappui-prod.eu-south-1.amazonaws.com +emrnotebooks-prod.eu-south-1.amazonaws.com +emrstudio-prod.eu-south-1.amazonaws.com +emrappui-prod.eu-south-2.amazonaws.com +emrnotebooks-prod.eu-south-2.amazonaws.com +emrstudio-prod.eu-south-2.amazonaws.com +emrappui-prod.eu-west-1.amazonaws.com +emrnotebooks-prod.eu-west-1.amazonaws.com +emrstudio-prod.eu-west-1.amazonaws.com +emrappui-prod.eu-west-2.amazonaws.com +emrnotebooks-prod.eu-west-2.amazonaws.com +emrstudio-prod.eu-west-2.amazonaws.com +emrappui-prod.eu-west-3.amazonaws.com +emrnotebooks-prod.eu-west-3.amazonaws.com +emrstudio-prod.eu-west-3.amazonaws.com +emrappui-prod.il-central-1.amazonaws.com +emrnotebooks-prod.il-central-1.amazonaws.com +emrstudio-prod.il-central-1.amazonaws.com +emrappui-prod.me-central-1.amazonaws.com +emrnotebooks-prod.me-central-1.amazonaws.com +emrstudio-prod.me-central-1.amazonaws.com +emrappui-prod.me-south-1.amazonaws.com +emrnotebooks-prod.me-south-1.amazonaws.com +emrstudio-prod.me-south-1.amazonaws.com +emrappui-prod.sa-east-1.amazonaws.com +emrnotebooks-prod.sa-east-1.amazonaws.com +emrstudio-prod.sa-east-1.amazonaws.com +emrappui-prod.us-east-1.amazonaws.com +emrnotebooks-prod.us-east-1.amazonaws.com +emrstudio-prod.us-east-1.amazonaws.com +emrappui-prod.us-east-2.amazonaws.com +emrnotebooks-prod.us-east-2.amazonaws.com +emrstudio-prod.us-east-2.amazonaws.com +emrappui-prod.us-gov-east-1.amazonaws.com +emrnotebooks-prod.us-gov-east-1.amazonaws.com +emrstudio-prod.us-gov-east-1.amazonaws.com +emrappui-prod.us-gov-west-1.amazonaws.com +emrnotebooks-prod.us-gov-west-1.amazonaws.com +emrstudio-prod.us-gov-west-1.amazonaws.com +emrappui-prod.us-west-1.amazonaws.com +emrnotebooks-prod.us-west-1.amazonaws.com +emrstudio-prod.us-west-1.amazonaws.com +emrappui-prod.us-west-2.amazonaws.com +emrnotebooks-prod.us-west-2.amazonaws.com +emrstudio-prod.us-west-2.amazonaws.com + +// Amazon Managed Workflows for Apache Airflow +// Submitted by AWS Security +// Reference: f5ea5d0a-ec6a-4f23-ac1c-553fbff13f5c +*.cn-north-1.airflow.amazonaws.com.cn +*.cn-northwest-1.airflow.amazonaws.com.cn +*.af-south-1.airflow.amazonaws.com +*.ap-east-1.airflow.amazonaws.com +*.ap-northeast-1.airflow.amazonaws.com +*.ap-northeast-2.airflow.amazonaws.com +*.ap-northeast-3.airflow.amazonaws.com +*.ap-south-1.airflow.amazonaws.com +*.ap-south-2.airflow.amazonaws.com +*.ap-southeast-1.airflow.amazonaws.com +*.ap-southeast-2.airflow.amazonaws.com +*.ap-southeast-3.airflow.amazonaws.com +*.ap-southeast-4.airflow.amazonaws.com +*.ca-central-1.airflow.amazonaws.com +*.ca-west-1.airflow.amazonaws.com +*.eu-central-1.airflow.amazonaws.com +*.eu-central-2.airflow.amazonaws.com +*.eu-north-1.airflow.amazonaws.com +*.eu-south-1.airflow.amazonaws.com +*.eu-south-2.airflow.amazonaws.com +*.eu-west-1.airflow.amazonaws.com +*.eu-west-2.airflow.amazonaws.com +*.eu-west-3.airflow.amazonaws.com +*.il-central-1.airflow.amazonaws.com +*.me-central-1.airflow.amazonaws.com +*.me-south-1.airflow.amazonaws.com +*.sa-east-1.airflow.amazonaws.com +*.us-east-1.airflow.amazonaws.com +*.us-east-2.airflow.amazonaws.com +*.us-west-1.airflow.amazonaws.com +*.us-west-2.airflow.amazonaws.com + // Amazon S3 -// Submitted by Luke Wells -// Reference: d068bd97-f0a9-4838-a6d8-954b622ef4ae +// Submitted by AWS Security +// Reference: ada5c9df-55e1-4195-a1ce-732d6c81e357 +s3.dualstack.cn-north-1.amazonaws.com.cn +s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn +s3-website.dualstack.cn-north-1.amazonaws.com.cn s3.cn-north-1.amazonaws.com.cn +s3-accesspoint.cn-north-1.amazonaws.com.cn +s3-deprecated.cn-north-1.amazonaws.com.cn +s3-object-lambda.cn-north-1.amazonaws.com.cn +s3-website.cn-north-1.amazonaws.com.cn +s3.dualstack.cn-northwest-1.amazonaws.com.cn +s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn +s3.cn-northwest-1.amazonaws.com.cn +s3-accesspoint.cn-northwest-1.amazonaws.com.cn +s3-object-lambda.cn-northwest-1.amazonaws.com.cn +s3-website.cn-northwest-1.amazonaws.com.cn +s3.dualstack.af-south-1.amazonaws.com +s3-accesspoint.dualstack.af-south-1.amazonaws.com +s3-website.dualstack.af-south-1.amazonaws.com +s3.af-south-1.amazonaws.com +s3-accesspoint.af-south-1.amazonaws.com +s3-object-lambda.af-south-1.amazonaws.com +s3-website.af-south-1.amazonaws.com +s3.dualstack.ap-east-1.amazonaws.com +s3-accesspoint.dualstack.ap-east-1.amazonaws.com +s3.ap-east-1.amazonaws.com +s3-accesspoint.ap-east-1.amazonaws.com +s3-object-lambda.ap-east-1.amazonaws.com +s3-website.ap-east-1.amazonaws.com s3.dualstack.ap-northeast-1.amazonaws.com +s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com +s3-website.dualstack.ap-northeast-1.amazonaws.com +s3.ap-northeast-1.amazonaws.com +s3-accesspoint.ap-northeast-1.amazonaws.com +s3-object-lambda.ap-northeast-1.amazonaws.com +s3-website.ap-northeast-1.amazonaws.com s3.dualstack.ap-northeast-2.amazonaws.com +s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com +s3-website.dualstack.ap-northeast-2.amazonaws.com s3.ap-northeast-2.amazonaws.com +s3-accesspoint.ap-northeast-2.amazonaws.com +s3-object-lambda.ap-northeast-2.amazonaws.com s3-website.ap-northeast-2.amazonaws.com +s3.dualstack.ap-northeast-3.amazonaws.com +s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com +s3-website.dualstack.ap-northeast-3.amazonaws.com +s3.ap-northeast-3.amazonaws.com +s3-accesspoint.ap-northeast-3.amazonaws.com +s3-object-lambda.ap-northeast-3.amazonaws.com +s3-website.ap-northeast-3.amazonaws.com s3.dualstack.ap-south-1.amazonaws.com +s3-accesspoint.dualstack.ap-south-1.amazonaws.com +s3-website.dualstack.ap-south-1.amazonaws.com s3.ap-south-1.amazonaws.com +s3-accesspoint.ap-south-1.amazonaws.com +s3-object-lambda.ap-south-1.amazonaws.com s3-website.ap-south-1.amazonaws.com +s3.dualstack.ap-south-2.amazonaws.com +s3-accesspoint.dualstack.ap-south-2.amazonaws.com +s3-website.dualstack.ap-south-2.amazonaws.com +s3.ap-south-2.amazonaws.com +s3-accesspoint.ap-south-2.amazonaws.com +s3-object-lambda.ap-south-2.amazonaws.com +s3-website.ap-south-2.amazonaws.com s3.dualstack.ap-southeast-1.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com +s3-website.dualstack.ap-southeast-1.amazonaws.com +s3.ap-southeast-1.amazonaws.com +s3-accesspoint.ap-southeast-1.amazonaws.com +s3-object-lambda.ap-southeast-1.amazonaws.com +s3-website.ap-southeast-1.amazonaws.com s3.dualstack.ap-southeast-2.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com +s3-website.dualstack.ap-southeast-2.amazonaws.com +s3.ap-southeast-2.amazonaws.com +s3-accesspoint.ap-southeast-2.amazonaws.com +s3-object-lambda.ap-southeast-2.amazonaws.com +s3-website.ap-southeast-2.amazonaws.com +s3.dualstack.ap-southeast-3.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com +s3-website.dualstack.ap-southeast-3.amazonaws.com +s3.ap-southeast-3.amazonaws.com +s3-accesspoint.ap-southeast-3.amazonaws.com +s3-object-lambda.ap-southeast-3.amazonaws.com +s3-website.ap-southeast-3.amazonaws.com +s3.dualstack.ap-southeast-4.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com +s3-website.dualstack.ap-southeast-4.amazonaws.com +s3.ap-southeast-4.amazonaws.com +s3-accesspoint.ap-southeast-4.amazonaws.com +s3-object-lambda.ap-southeast-4.amazonaws.com +s3-website.ap-southeast-4.amazonaws.com +s3.dualstack.ap-southeast-5.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-5.amazonaws.com +s3-website.dualstack.ap-southeast-5.amazonaws.com +s3.ap-southeast-5.amazonaws.com +s3-accesspoint.ap-southeast-5.amazonaws.com +s3-deprecated.ap-southeast-5.amazonaws.com +s3-object-lambda.ap-southeast-5.amazonaws.com +s3-website.ap-southeast-5.amazonaws.com s3.dualstack.ca-central-1.amazonaws.com +s3-accesspoint.dualstack.ca-central-1.amazonaws.com +s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com +s3-fips.dualstack.ca-central-1.amazonaws.com +s3-website.dualstack.ca-central-1.amazonaws.com s3.ca-central-1.amazonaws.com +s3-accesspoint.ca-central-1.amazonaws.com +s3-accesspoint-fips.ca-central-1.amazonaws.com +s3-fips.ca-central-1.amazonaws.com +s3-object-lambda.ca-central-1.amazonaws.com s3-website.ca-central-1.amazonaws.com +s3.dualstack.ca-west-1.amazonaws.com +s3-accesspoint.dualstack.ca-west-1.amazonaws.com +s3-accesspoint-fips.dualstack.ca-west-1.amazonaws.com +s3-fips.dualstack.ca-west-1.amazonaws.com +s3-website.dualstack.ca-west-1.amazonaws.com +s3.ca-west-1.amazonaws.com +s3-accesspoint.ca-west-1.amazonaws.com +s3-accesspoint-fips.ca-west-1.amazonaws.com +s3-fips.ca-west-1.amazonaws.com +s3-object-lambda.ca-west-1.amazonaws.com +s3-website.ca-west-1.amazonaws.com s3.dualstack.eu-central-1.amazonaws.com +s3-accesspoint.dualstack.eu-central-1.amazonaws.com +s3-website.dualstack.eu-central-1.amazonaws.com s3.eu-central-1.amazonaws.com +s3-accesspoint.eu-central-1.amazonaws.com +s3-object-lambda.eu-central-1.amazonaws.com s3-website.eu-central-1.amazonaws.com +s3.dualstack.eu-central-2.amazonaws.com +s3-accesspoint.dualstack.eu-central-2.amazonaws.com +s3-website.dualstack.eu-central-2.amazonaws.com +s3.eu-central-2.amazonaws.com +s3-accesspoint.eu-central-2.amazonaws.com +s3-object-lambda.eu-central-2.amazonaws.com +s3-website.eu-central-2.amazonaws.com +s3.dualstack.eu-north-1.amazonaws.com +s3-accesspoint.dualstack.eu-north-1.amazonaws.com +s3.eu-north-1.amazonaws.com +s3-accesspoint.eu-north-1.amazonaws.com +s3-object-lambda.eu-north-1.amazonaws.com +s3-website.eu-north-1.amazonaws.com +s3.dualstack.eu-south-1.amazonaws.com +s3-accesspoint.dualstack.eu-south-1.amazonaws.com +s3-website.dualstack.eu-south-1.amazonaws.com +s3.eu-south-1.amazonaws.com +s3-accesspoint.eu-south-1.amazonaws.com +s3-object-lambda.eu-south-1.amazonaws.com +s3-website.eu-south-1.amazonaws.com +s3.dualstack.eu-south-2.amazonaws.com +s3-accesspoint.dualstack.eu-south-2.amazonaws.com +s3-website.dualstack.eu-south-2.amazonaws.com +s3.eu-south-2.amazonaws.com +s3-accesspoint.eu-south-2.amazonaws.com +s3-object-lambda.eu-south-2.amazonaws.com +s3-website.eu-south-2.amazonaws.com s3.dualstack.eu-west-1.amazonaws.com +s3-accesspoint.dualstack.eu-west-1.amazonaws.com +s3-website.dualstack.eu-west-1.amazonaws.com +s3.eu-west-1.amazonaws.com +s3-accesspoint.eu-west-1.amazonaws.com +s3-deprecated.eu-west-1.amazonaws.com +s3-object-lambda.eu-west-1.amazonaws.com +s3-website.eu-west-1.amazonaws.com s3.dualstack.eu-west-2.amazonaws.com +s3-accesspoint.dualstack.eu-west-2.amazonaws.com s3.eu-west-2.amazonaws.com +s3-accesspoint.eu-west-2.amazonaws.com +s3-object-lambda.eu-west-2.amazonaws.com s3-website.eu-west-2.amazonaws.com s3.dualstack.eu-west-3.amazonaws.com +s3-accesspoint.dualstack.eu-west-3.amazonaws.com +s3-website.dualstack.eu-west-3.amazonaws.com s3.eu-west-3.amazonaws.com +s3-accesspoint.eu-west-3.amazonaws.com +s3-object-lambda.eu-west-3.amazonaws.com s3-website.eu-west-3.amazonaws.com +s3.dualstack.il-central-1.amazonaws.com +s3-accesspoint.dualstack.il-central-1.amazonaws.com +s3-website.dualstack.il-central-1.amazonaws.com +s3.il-central-1.amazonaws.com +s3-accesspoint.il-central-1.amazonaws.com +s3-object-lambda.il-central-1.amazonaws.com +s3-website.il-central-1.amazonaws.com +s3.dualstack.me-central-1.amazonaws.com +s3-accesspoint.dualstack.me-central-1.amazonaws.com +s3-website.dualstack.me-central-1.amazonaws.com +s3.me-central-1.amazonaws.com +s3-accesspoint.me-central-1.amazonaws.com +s3-object-lambda.me-central-1.amazonaws.com +s3-website.me-central-1.amazonaws.com +s3.dualstack.me-south-1.amazonaws.com +s3-accesspoint.dualstack.me-south-1.amazonaws.com +s3.me-south-1.amazonaws.com +s3-accesspoint.me-south-1.amazonaws.com +s3-object-lambda.me-south-1.amazonaws.com +s3-website.me-south-1.amazonaws.com s3.amazonaws.com +s3-1.amazonaws.com +s3-ap-east-1.amazonaws.com s3-ap-northeast-1.amazonaws.com s3-ap-northeast-2.amazonaws.com +s3-ap-northeast-3.amazonaws.com s3-ap-south-1.amazonaws.com s3-ap-southeast-1.amazonaws.com s3-ap-southeast-2.amazonaws.com s3-ca-central-1.amazonaws.com s3-eu-central-1.amazonaws.com +s3-eu-north-1.amazonaws.com s3-eu-west-1.amazonaws.com s3-eu-west-2.amazonaws.com s3-eu-west-3.amazonaws.com s3-external-1.amazonaws.com +s3-fips-us-gov-east-1.amazonaws.com s3-fips-us-gov-west-1.amazonaws.com +mrap.accesspoint.s3-global.amazonaws.com +s3-me-south-1.amazonaws.com s3-sa-east-1.amazonaws.com s3-us-east-2.amazonaws.com +s3-us-gov-east-1.amazonaws.com s3-us-gov-west-1.amazonaws.com s3-us-west-1.amazonaws.com s3-us-west-2.amazonaws.com @@ -10806,80 +11786,311 @@ s3-website-ap-southeast-2.amazonaws.com s3-website-eu-west-1.amazonaws.com s3-website-sa-east-1.amazonaws.com s3-website-us-east-1.amazonaws.com +s3-website-us-gov-west-1.amazonaws.com s3-website-us-west-1.amazonaws.com s3-website-us-west-2.amazonaws.com s3.dualstack.sa-east-1.amazonaws.com +s3-accesspoint.dualstack.sa-east-1.amazonaws.com +s3-website.dualstack.sa-east-1.amazonaws.com +s3.sa-east-1.amazonaws.com +s3-accesspoint.sa-east-1.amazonaws.com +s3-object-lambda.sa-east-1.amazonaws.com +s3-website.sa-east-1.amazonaws.com s3.dualstack.us-east-1.amazonaws.com +s3-accesspoint.dualstack.us-east-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com +s3-fips.dualstack.us-east-1.amazonaws.com +s3-website.dualstack.us-east-1.amazonaws.com +s3.us-east-1.amazonaws.com +s3-accesspoint.us-east-1.amazonaws.com +s3-accesspoint-fips.us-east-1.amazonaws.com +s3-deprecated.us-east-1.amazonaws.com +s3-fips.us-east-1.amazonaws.com +s3-object-lambda.us-east-1.amazonaws.com +s3-website.us-east-1.amazonaws.com s3.dualstack.us-east-2.amazonaws.com +s3-accesspoint.dualstack.us-east-2.amazonaws.com +s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com +s3-fips.dualstack.us-east-2.amazonaws.com +s3-website.dualstack.us-east-2.amazonaws.com s3.us-east-2.amazonaws.com +s3-accesspoint.us-east-2.amazonaws.com +s3-accesspoint-fips.us-east-2.amazonaws.com +s3-deprecated.us-east-2.amazonaws.com +s3-fips.us-east-2.amazonaws.com +s3-object-lambda.us-east-2.amazonaws.com s3-website.us-east-2.amazonaws.com +s3.dualstack.us-gov-east-1.amazonaws.com +s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com +s3-fips.dualstack.us-gov-east-1.amazonaws.com +s3.us-gov-east-1.amazonaws.com +s3-accesspoint.us-gov-east-1.amazonaws.com +s3-accesspoint-fips.us-gov-east-1.amazonaws.com +s3-fips.us-gov-east-1.amazonaws.com +s3-object-lambda.us-gov-east-1.amazonaws.com +s3-website.us-gov-east-1.amazonaws.com +s3.dualstack.us-gov-west-1.amazonaws.com +s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com +s3-fips.dualstack.us-gov-west-1.amazonaws.com +s3.us-gov-west-1.amazonaws.com +s3-accesspoint.us-gov-west-1.amazonaws.com +s3-accesspoint-fips.us-gov-west-1.amazonaws.com +s3-fips.us-gov-west-1.amazonaws.com +s3-object-lambda.us-gov-west-1.amazonaws.com +s3-website.us-gov-west-1.amazonaws.com +s3.dualstack.us-west-1.amazonaws.com +s3-accesspoint.dualstack.us-west-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com +s3-fips.dualstack.us-west-1.amazonaws.com +s3-website.dualstack.us-west-1.amazonaws.com +s3.us-west-1.amazonaws.com +s3-accesspoint.us-west-1.amazonaws.com +s3-accesspoint-fips.us-west-1.amazonaws.com +s3-fips.us-west-1.amazonaws.com +s3-object-lambda.us-west-1.amazonaws.com +s3-website.us-west-1.amazonaws.com +s3.dualstack.us-west-2.amazonaws.com +s3-accesspoint.dualstack.us-west-2.amazonaws.com +s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com +s3-fips.dualstack.us-west-2.amazonaws.com +s3-website.dualstack.us-west-2.amazonaws.com +s3.us-west-2.amazonaws.com +s3-accesspoint.us-west-2.amazonaws.com +s3-accesspoint-fips.us-west-2.amazonaws.com +s3-deprecated.us-west-2.amazonaws.com +s3-fips.us-west-2.amazonaws.com +s3-object-lambda.us-west-2.amazonaws.com +s3-website.us-west-2.amazonaws.com + +// Amazon SageMaker Ground Truth +// Submitted by AWS Security +// Reference: 98dbfde4-7802-48c3-8751-b60f204e0d9c +labeling.ap-northeast-1.sagemaker.aws +labeling.ap-northeast-2.sagemaker.aws +labeling.ap-south-1.sagemaker.aws +labeling.ap-southeast-1.sagemaker.aws +labeling.ap-southeast-2.sagemaker.aws +labeling.ca-central-1.sagemaker.aws +labeling.eu-central-1.sagemaker.aws +labeling.eu-west-1.sagemaker.aws +labeling.eu-west-2.sagemaker.aws +labeling.us-east-1.sagemaker.aws +labeling.us-east-2.sagemaker.aws +labeling.us-west-2.sagemaker.aws + +// Amazon SageMaker Notebook Instances +// Submitted by AWS Security +// Reference: b5ea56df-669e-43cc-9537-14aa172f5dfc +notebook.af-south-1.sagemaker.aws +notebook.ap-east-1.sagemaker.aws +notebook.ap-northeast-1.sagemaker.aws +notebook.ap-northeast-2.sagemaker.aws +notebook.ap-northeast-3.sagemaker.aws +notebook.ap-south-1.sagemaker.aws +notebook.ap-south-2.sagemaker.aws +notebook.ap-southeast-1.sagemaker.aws +notebook.ap-southeast-2.sagemaker.aws +notebook.ap-southeast-3.sagemaker.aws +notebook.ap-southeast-4.sagemaker.aws +notebook.ca-central-1.sagemaker.aws +notebook-fips.ca-central-1.sagemaker.aws +notebook.ca-west-1.sagemaker.aws +notebook-fips.ca-west-1.sagemaker.aws +notebook.eu-central-1.sagemaker.aws +notebook.eu-central-2.sagemaker.aws +notebook.eu-north-1.sagemaker.aws +notebook.eu-south-1.sagemaker.aws +notebook.eu-south-2.sagemaker.aws +notebook.eu-west-1.sagemaker.aws +notebook.eu-west-2.sagemaker.aws +notebook.eu-west-3.sagemaker.aws +notebook.il-central-1.sagemaker.aws +notebook.me-central-1.sagemaker.aws +notebook.me-south-1.sagemaker.aws +notebook.sa-east-1.sagemaker.aws +notebook.us-east-1.sagemaker.aws +notebook-fips.us-east-1.sagemaker.aws +notebook.us-east-2.sagemaker.aws +notebook-fips.us-east-2.sagemaker.aws +notebook.us-gov-east-1.sagemaker.aws +notebook-fips.us-gov-east-1.sagemaker.aws +notebook.us-gov-west-1.sagemaker.aws +notebook-fips.us-gov-west-1.sagemaker.aws +notebook.us-west-1.sagemaker.aws +notebook-fips.us-west-1.sagemaker.aws +notebook.us-west-2.sagemaker.aws +notebook-fips.us-west-2.sagemaker.aws +notebook.cn-north-1.sagemaker.com.cn +notebook.cn-northwest-1.sagemaker.com.cn + +// Amazon SageMaker Studio +// Submitted by AWS Security +// Reference: 69c723d9-6e1a-4bff-a203-48eecd203183 +studio.af-south-1.sagemaker.aws +studio.ap-east-1.sagemaker.aws +studio.ap-northeast-1.sagemaker.aws +studio.ap-northeast-2.sagemaker.aws +studio.ap-northeast-3.sagemaker.aws +studio.ap-south-1.sagemaker.aws +studio.ap-southeast-1.sagemaker.aws +studio.ap-southeast-2.sagemaker.aws +studio.ap-southeast-3.sagemaker.aws +studio.ca-central-1.sagemaker.aws +studio.eu-central-1.sagemaker.aws +studio.eu-north-1.sagemaker.aws +studio.eu-south-1.sagemaker.aws +studio.eu-south-2.sagemaker.aws +studio.eu-west-1.sagemaker.aws +studio.eu-west-2.sagemaker.aws +studio.eu-west-3.sagemaker.aws +studio.il-central-1.sagemaker.aws +studio.me-central-1.sagemaker.aws +studio.me-south-1.sagemaker.aws +studio.sa-east-1.sagemaker.aws +studio.us-east-1.sagemaker.aws +studio.us-east-2.sagemaker.aws +studio.us-gov-east-1.sagemaker.aws +studio-fips.us-gov-east-1.sagemaker.aws +studio.us-gov-west-1.sagemaker.aws +studio-fips.us-gov-west-1.sagemaker.aws +studio.us-west-1.sagemaker.aws +studio.us-west-2.sagemaker.aws +studio.cn-north-1.sagemaker.com.cn +studio.cn-northwest-1.sagemaker.com.cn + +// Amazon SageMaker with MLflow +// Submited by: AWS Security +// Reference: c19f92b3-a82a-452d-8189-831b572eea7e +*.experiments.sagemaker.aws + +// Analytics on AWS +// Submitted by AWS Security +// Reference: 955f9f40-a495-4e73-ae85-67b77ac9cadd +analytics-gateway.ap-northeast-1.amazonaws.com +analytics-gateway.ap-northeast-2.amazonaws.com +analytics-gateway.ap-south-1.amazonaws.com +analytics-gateway.ap-southeast-1.amazonaws.com +analytics-gateway.ap-southeast-2.amazonaws.com +analytics-gateway.eu-central-1.amazonaws.com +analytics-gateway.eu-west-1.amazonaws.com +analytics-gateway.us-east-1.amazonaws.com +analytics-gateway.us-east-2.amazonaws.com +analytics-gateway.us-west-2.amazonaws.com + +// AWS Amplify +// Submitted by AWS Security +// Reference: c35bed18-6f4f-424f-9298-5756f2f7d72b +amplifyapp.com + +// AWS App Runner +// Submitted by AWS Security +// Reference: 6828c008-ba5d-442f-ade5-48da4e7c2316 +*.awsapprunner.com // AWS Cloud9 // Submitted by: AWS Security -// Reference: 2b6dfa9a-3a7f-4367-b2e7-0321e77c0d59 +// Reference: 30717f72-4007-4f0f-8ed4-864c6f2efec9 +webview-assets.aws-cloud9.af-south-1.amazonaws.com vfs.cloud9.af-south-1.amazonaws.com webview-assets.cloud9.af-south-1.amazonaws.com +webview-assets.aws-cloud9.ap-east-1.amazonaws.com vfs.cloud9.ap-east-1.amazonaws.com webview-assets.cloud9.ap-east-1.amazonaws.com +webview-assets.aws-cloud9.ap-northeast-1.amazonaws.com vfs.cloud9.ap-northeast-1.amazonaws.com webview-assets.cloud9.ap-northeast-1.amazonaws.com +webview-assets.aws-cloud9.ap-northeast-2.amazonaws.com vfs.cloud9.ap-northeast-2.amazonaws.com webview-assets.cloud9.ap-northeast-2.amazonaws.com +webview-assets.aws-cloud9.ap-northeast-3.amazonaws.com vfs.cloud9.ap-northeast-3.amazonaws.com webview-assets.cloud9.ap-northeast-3.amazonaws.com +webview-assets.aws-cloud9.ap-south-1.amazonaws.com vfs.cloud9.ap-south-1.amazonaws.com webview-assets.cloud9.ap-south-1.amazonaws.com +webview-assets.aws-cloud9.ap-southeast-1.amazonaws.com vfs.cloud9.ap-southeast-1.amazonaws.com webview-assets.cloud9.ap-southeast-1.amazonaws.com +webview-assets.aws-cloud9.ap-southeast-2.amazonaws.com vfs.cloud9.ap-southeast-2.amazonaws.com webview-assets.cloud9.ap-southeast-2.amazonaws.com +webview-assets.aws-cloud9.ca-central-1.amazonaws.com vfs.cloud9.ca-central-1.amazonaws.com webview-assets.cloud9.ca-central-1.amazonaws.com +webview-assets.aws-cloud9.eu-central-1.amazonaws.com vfs.cloud9.eu-central-1.amazonaws.com webview-assets.cloud9.eu-central-1.amazonaws.com +webview-assets.aws-cloud9.eu-north-1.amazonaws.com vfs.cloud9.eu-north-1.amazonaws.com webview-assets.cloud9.eu-north-1.amazonaws.com +webview-assets.aws-cloud9.eu-south-1.amazonaws.com vfs.cloud9.eu-south-1.amazonaws.com webview-assets.cloud9.eu-south-1.amazonaws.com +webview-assets.aws-cloud9.eu-west-1.amazonaws.com vfs.cloud9.eu-west-1.amazonaws.com webview-assets.cloud9.eu-west-1.amazonaws.com +webview-assets.aws-cloud9.eu-west-2.amazonaws.com vfs.cloud9.eu-west-2.amazonaws.com webview-assets.cloud9.eu-west-2.amazonaws.com +webview-assets.aws-cloud9.eu-west-3.amazonaws.com vfs.cloud9.eu-west-3.amazonaws.com webview-assets.cloud9.eu-west-3.amazonaws.com +webview-assets.aws-cloud9.il-central-1.amazonaws.com +vfs.cloud9.il-central-1.amazonaws.com +webview-assets.aws-cloud9.me-south-1.amazonaws.com vfs.cloud9.me-south-1.amazonaws.com webview-assets.cloud9.me-south-1.amazonaws.com +webview-assets.aws-cloud9.sa-east-1.amazonaws.com vfs.cloud9.sa-east-1.amazonaws.com webview-assets.cloud9.sa-east-1.amazonaws.com +webview-assets.aws-cloud9.us-east-1.amazonaws.com vfs.cloud9.us-east-1.amazonaws.com webview-assets.cloud9.us-east-1.amazonaws.com +webview-assets.aws-cloud9.us-east-2.amazonaws.com vfs.cloud9.us-east-2.amazonaws.com webview-assets.cloud9.us-east-2.amazonaws.com +webview-assets.aws-cloud9.us-west-1.amazonaws.com vfs.cloud9.us-west-1.amazonaws.com webview-assets.cloud9.us-west-1.amazonaws.com +webview-assets.aws-cloud9.us-west-2.amazonaws.com vfs.cloud9.us-west-2.amazonaws.com webview-assets.cloud9.us-west-2.amazonaws.com +// AWS Directory Service +// Submitted by AWS Security +// Reference: a13203e8-42dc-4045-a0d2-2ee67bed1068 +awsapps.com + // AWS Elastic Beanstalk -// Submitted by Luke Wells -// Reference: aa202394-43a0-4857-b245-8db04549137e +// Submitted by AWS Security +// Reference: bb5a965c-dec3-4967-aa22-e306ad064797 cn-north-1.eb.amazonaws.com.cn cn-northwest-1.eb.amazonaws.com.cn elasticbeanstalk.com +af-south-1.elasticbeanstalk.com +ap-east-1.elasticbeanstalk.com ap-northeast-1.elasticbeanstalk.com ap-northeast-2.elasticbeanstalk.com ap-northeast-3.elasticbeanstalk.com ap-south-1.elasticbeanstalk.com ap-southeast-1.elasticbeanstalk.com ap-southeast-2.elasticbeanstalk.com +ap-southeast-3.elasticbeanstalk.com ca-central-1.elasticbeanstalk.com eu-central-1.elasticbeanstalk.com +eu-north-1.elasticbeanstalk.com +eu-south-1.elasticbeanstalk.com eu-west-1.elasticbeanstalk.com eu-west-2.elasticbeanstalk.com eu-west-3.elasticbeanstalk.com +il-central-1.elasticbeanstalk.com +me-south-1.elasticbeanstalk.com sa-east-1.elasticbeanstalk.com us-east-1.elasticbeanstalk.com us-east-2.elasticbeanstalk.com +us-gov-east-1.elasticbeanstalk.com us-gov-west-1.elasticbeanstalk.com us-west-1.elasticbeanstalk.com us-west-2.elasticbeanstalk.com @@ -10895,6 +12106,11 @@ us-west-2.elasticbeanstalk.com // Reference: d916759d-a08b-4241-b536-4db887383a6a awsglobalaccelerator.com +// AWS re:Post Private +// Submitted by AWS Security +// Reference: 83385945-225f-416e-9aa0-ad0632bfdcee +*.private.repost.aws + // eero // Submitted by Yue Kang // Reference: 264afe70-f62c-4c02-8ab9-b5281ed24461 @@ -10903,15 +12119,14 @@ eero-stage.online // concludes Amazon -// Amune : https://amune.org/ -// Submitted by Team Amune -t3l3p0rt.net -tele.amune.org - // Apigee : https://apigee.com/ // Submitted by Apigee Security Team apigee.io +// Apis Networks : https://apisnetworks.com +// Submitted by Matt Saladna +panel.dev + // Apphud : https://apphud.com // Submitted by Alexander Selivanov siiites.com @@ -10929,6 +12144,14 @@ appudo.net // Submitted by Thomas Orozco on-aptible.com +// Aquapal : https://aquapal.net/ +// Submitted by Aki Ueno +f5.si + +// ArvanCloud EdgeCompute +// Submitted by ArvanCloud CDN +arvanedge.ir + // ASEINet : https://www.aseinet.com/ // Submitted by Asei SEKIGUCHI user.aseinet.ne.jp @@ -10958,12 +12181,9 @@ cdn.prod.atlassian-dev.net // Submitted by Lukas Reschke translated.page -// Autocode : https://autocode.com -// Submitted by Jacob Lee -autocode.dev - // AVM : https://avm.de // Submitted by Andreas Weise +myfritz.link myfritz.net // AVStack Pte. Ltd. : https://avstack.io @@ -10975,7 +12195,7 @@ onavstack.net *.awdev.ca *.advisor.ws -// AZ.pl sp. z.o.o: https://az.pl +// AZ.pl sp. z.o.o : https://az.pl // Submitted by Krzysztof Wolski ecommerce-shop.pl @@ -10983,25 +12203,10 @@ ecommerce-shop.pl // Submitted by Olivier Benz b-data.io -// backplane : https://www.backplane.io -// Submitted by Anthony Voutas -backplaneapp.io - // Balena : https://www.balena.io // Submitted by Petros Angelatos balena-devices.com -// University of Banja Luka : https://unibl.org -// Domains for Republic of Srpska administrative entity. -// Submitted by Marko Ivanovic -rs.ba - -// Banzai Cloud -// Submitted by Janos Matyas -*.banzai.cloud -app.banzaicloud.io -*.backyards.banzaicloud.io - // BASE, Inc. : https://binc.jp // Submitted by Yuya NAGASAWA base.ec @@ -11023,9 +12228,9 @@ beagleboard.io // Submitted by Lev Nekrasov *.beget.app -// BetaInABox -// Submitted by Adrian -betainabox.com +// Besties : https://besties.house +// Submitted by Hazel Cora +pages.gay // BinaryLane : http://www.binarylane.com // Submitted by Nathan O'Sullivan @@ -11068,14 +12273,24 @@ square7.de bplaced.net square7.net +// Brave : https://brave.com +// Submitted by Andrea Brancaleoni +*.s.brave.io + // Brendly : https://brendly.rs -// Submitted by Dusan Radovanovic +// Submitted by Dusan Radovanovic +shop.brendly.hr shop.brendly.rs // BrowserSafetyMark // Submitted by Dave Tharp browsersafetymark.io +// BRS Media : https://brsmedia.com/ +// Submitted by Gavin Brown +radio.am +radio.fm + // Bytemark Hosting : https://www.bytemark.co.uk // Submitted by Paul Cammish uk0.bigv.io @@ -11086,14 +12301,12 @@ vm.bytemark.co.uk // Submitted by Antonio Lain cafjs.com -// callidomus : https://www.callidomus.com/ -// Submitted by Marcus Popp -mycd.eu - // Canva Pty Ltd : https://canva.com/ // Submitted by Joel Aquilina canva-apps.cn +*.my.canvasite.cn canva-apps.com +*.my.canva.site // Carrd : https://carrd.co // Submitted by AJ @@ -11103,75 +12316,42 @@ carrd.co crd.co ju.mp +// CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk +// Submitted by Jamie Tanna +api.gov.uk + +// CDN77.com : http://www.cdn77.com +// Submitted by Jan Krpes +cdn77-storage.com +rsc.contentproxy9.cz +r.cdn77.net +cdn77-ssl.net +c.cdn77.org +rsc.cdn77.org +ssl.origin.cdn77-secure.org + // CentralNic : http://www.centralnic.com/names/domains // Submitted by registry -ae.org +za.bz br.com cn.com -com.de -com.se de.com eu.com -gb.net -hu.net -jp.net jpn.com mex.com ru.com sa.com -se.net uk.com -uk.net us.com -za.bz za.com - -// No longer operated by CentralNic, these entries should be adopted and/or removed by current operators -// Submitted by Gavin Brown -ar.com -hu.com -kr.com -no.com -qc.com -uy.com - -// Africa.com Web Solutions Ltd : https://registry.africa.com -// Submitted by Gavin Brown -africa.com - -// iDOT Services Limited : http://www.domain.gr.com -// Submitted by Gavin Brown -gr.com - -// Radix FZC : http://domains.in.net -// Submitted by Gavin Brown -in.net -web.in - -// US REGISTRY LLC : http://us.org -// Submitted by Gavin Brown -us.org - -// co.com Registry, LLC : https://registry.co.com -// Submitted by Gavin Brown -co.com - -// Roar Domains LLC : https://roar.basketball/ -// Submitted by Gavin Brown -aus.basketball -nz.basketball - -// BRS Media : https://brsmedia.com/ -// Submitted by Gavin Brown -radio.am -radio.fm - -// c.la : http://www.c.la/ -c.la - -// certmgr.org : https://certmgr.org -// Submitted by B. Blechschmidt -certmgr.org +com.de +gb.net +hu.net +jp.net +se.net +uk.net +ae.org +com.se // Cityhost LLC : https://cityhost.ua // Submitted by Maksym Rivtin @@ -11182,10 +12362,6 @@ cx.ua discourse.group discourse.team -// Clever Cloud : https://www.clever-cloud.com/ -// Submitted by Quentin Adam -cleverapps.io - // Clerk : https://www.clerk.dev // Submitted by Colin Sidoti clerk.app @@ -11195,10 +12371,44 @@ clerkstage.app *.stg.dev *.stgstage.dev +// Clever Cloud : https://www.clever-cloud.com/ +// Submitted by Quentin Adam +cleverapps.cc +*.services.clever-cloud.com +cleverapps.io +cleverapps.tech + // ClickRising : https://clickrising.com/ // Submitted by Umut Gumeli clickrising.net +// Cloud DNS Ltd : http://www.cloudns.net +// Submitted by Aleksander Hristov & Boyan Peychev +cloudns.asia +cloudns.be +cloud-ip.biz +cloudns.biz +cloudns.cc +cloudns.ch +cloudns.cl +cloudns.club +dnsabr.com +ip-ddns.com +cloudns.cx +cloudns.eu +cloudns.in +cloudns.info +ddns-ip.net +dns-cloud.net +dns-dynamic.net +cloudns.nz +cloudns.org +ip-dynamic.org +cloudns.ph +cloudns.pro +cloudns.pw +cloudns.us + // Cloud66 : https://www.cloud66.com/ // Submitted by Khash Sajadi c66.me @@ -11213,11 +12423,6 @@ cloudaccess.host freesite.host cloudaccess.net -// cloudControl : https://www.cloudcontrol.com/ -// Submitted by Tobias Wilken -cloudcontrolled.com -cloudcontrolapp.com - // Cloudera, Inc. : https://www.cloudera.com/ // Submitted by Kedarnath Waikar *.cloudera.site @@ -11230,52 +12435,46 @@ trycloudflare.com pages.dev r2.dev workers.dev +cloudflare.net +cdn.cloudflare.net +cdn.cloudflareanycast.net +cdn.cloudflarecn.net +cdn.cloudflareglobal.net + +// cloudscale.ch AG : https://www.cloudscale.ch/ +// Submitted by Gaudenz Steinlin +cust.cloudscale.ch +objects.lpg.cloudscale.ch +objects.rma.cloudscale.ch // Clovyr : https://clovyr.io // Submitted by Patrick Nielsen wnext.app -// co.ca : http://registry.co.ca/ -co.ca +// CNPY : https://cnpy.gdn +// Submitted by Angelo Gladding +cnpy.gdn // Co & Co : https://co-co.nl/ // Submitted by Govert Versluis *.otap.co -// i-registry s.r.o. : http://www.i-registry.cz/ -// Submitted by Martin Semrad -co.cz - -// CDN77.com : http://www.cdn77.com -// Submitted by Jan Krpes -c.cdn77.org -cdn77-ssl.net -r.cdn77.net -rsc.cdn77.org -ssl.origin.cdn77-secure.org - -// Cloud DNS Ltd : http://www.cloudns.net -// Submitted by Aleksander Hristov -cloudns.asia -cloudns.biz -cloudns.club -cloudns.cc -cloudns.eu -cloudns.in -cloudns.info -cloudns.org -cloudns.pro -cloudns.pw -cloudns.us +// co.ca : http://registry.co.ca/ +co.ca -// CNPY : https://cnpy.gdn -// Submitted by Angelo Gladding -cnpy.gdn +// co.com Registry, LLC : https://registry.co.com +// Submitted by Gavin Brown +co.com // Codeberg e. V. : https://codeberg.org // Submitted by Moritz Marquardt codeberg.page +// CodeSandbox B.V. : https://codesandbox.io +// Submitted by Ives van Hoorne +csb.app +preview.csb.app + // CoDNS B.V. co.nl co.no @@ -11285,6 +12484,14 @@ co.no webhosting.be hosting-cluster.nl +// Contentful GmbH : https://www.contentful.com +// Submitted by Contentful Developer Experience Team +ctfcloud.net + +// Convex : https://convex.dev/ +// Submitted by James Cowling +convex.site + // Coordination Center for TLD RU and XN--P1AI : https://cctld.ru/en/domains/domens_ru/reserved/ // Submitted by George Georgievsky ac.ru @@ -11297,8 +12504,8 @@ test.ru // COSIMO GmbH : http://www.cosimo.de // Submitted by Rene Marticke dyn.cosidns.de -dynamisches-dns.de dnsupdater.de +dynamisches-dns.de internet-dns.de l-o-g-i-n.de dynamic-dns.info @@ -11306,29 +12513,29 @@ feste-ip.net knx-server.net static-access.net +// Craft Docs Ltd : https://www.craft.do/ +// Submitted by Zsombor Fuszenecker +craft.me + // Craynic, s.r.o. : http://www.craynic.com/ // Submitted by Ales Krajnik realm.cz +// Crisp IM SAS : https://crisp.chat/ +// Submitted by Baptiste Jamin +on.crisp.email + // Cryptonomic : https://cryptonomic.net/ // Submitted by Andrew Cady *.cryptonomic.net -// Cupcake : https://cupcake.io/ -// Submitted by Jonathan Rudenberg -cupcake.is - // Curv UG : https://curv-labs.de/ // Submitted by Marvin Wiesner curv.dev -// Customer OCI - Oracle Dyn https://cloud.oracle.com/home https://dyn.com/dns/ -// Submitted by Gregory Drake -// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label -*.customer-oci.com -*.oci.customer-oci.com -*.ocp.customer-oci.com -*.ocs.customer-oci.com +// cyber_Folks S.A. : https://cyberfolks.pl +// Submitted by Bartlomiej Kida +cfolks.pl // cyon GmbH : https://www.cyon.ch/ // Submitted by Dominic Luechinger @@ -11337,23 +12544,9 @@ cyon.site // Danger Science Group: https://dangerscience.com/ // Submitted by Skylar MacDonald +platform0.app fnwk.site folionetwork.site -platform0.app - -// Daplie, Inc : https://daplie.com -// Submitted by AJ ONeal -daplie.me -localhost.daplie.me - -// Datto, Inc. : https://www.datto.com/ -// Submitted by Philipp Heckel -dattolocal.com -dattorelay.com -dattoweb.com -mydatto.com -dattolocal.net -mydatto.net // Dansk.net : http://www.dansk.net/ // Submitted by Anani Voule @@ -11367,14 +12560,10 @@ store.dk // Submitted by Abel Boldu / DAppNode Team dyndns.dappnode.io -// dapps.earth : https://dapps.earth/ -// Submitted by Daniil Burdakov -*.dapps.earth -*.bzz.dapps.earth - // Dark, Inc. : https://darklang.com // Submitted by Paul Biggar builtwithdark.com +darklang.io // DataDetect, LLC. : https://datadetect.com // Submitted by Andrew Banchich @@ -11385,14 +12574,36 @@ instance.datadetect.com // Submitted by Richard Li edgestack.me -// DDNS5 : https://ddns5.com -// Submitted by Cameron Elliott -ddns5.com +// Datto, Inc. : https://www.datto.com/ +// Submitted by Philipp Heckel +dattolocal.com +dattorelay.com +dattoweb.com +mydatto.com +dattolocal.net +mydatto.net + +// ddnss.de : https://www.ddnss.de/ +// Submitted by Robert Niedziela +ddnss.de +dyn.ddnss.de +dyndns.ddnss.de +dyn-ip24.de +dyndns1.de +home-webserver.de +dyn.home-webserver.de +myhome-server.de +ddnss.org // Debian : https://www.debian.org/ // Submitted by Peter Palfrader / Debian Sysadmin Team debian.net +// Definima : http://www.definima.com/ +// Submitted by Maxence Bitterli +definima.io +definima.net + // Deno Land Inc : https://deno.com/ // Submitted by Luca Casonato deno.dev @@ -11407,10 +12618,28 @@ dedyn.io deta.app deta.dev +// dhosting.pl Sp. z o.o.: https://dhosting.pl/ +// Submitted by Michal Kokoszkiewicz +dfirma.pl +dkonto.pl +you2.pl + +// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/ +// Submitted by Braxton Huggins +ondigitalocean.app + +// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/ +// Submitted by Robin H. Johnson +*.digitaloceanspaces.com + +// DigitalPlat : https://www.digitalplat.org/ +// Submitted by Edward Hsing +us.kg + // Diher Solutions : https://diher.solutions // Submitted by Didi Hermawan -*.rss.my.id -*.diher.solutions +rss.my.id +diher.solutions // Discord Inc : https://discord.com // Submitted by Sahn Lam @@ -11442,6 +12671,10 @@ shoparena.pl // Submitted by Andrew Farmer dreamhosters.com +// Dreamyoungs, Inc. : https://durumis.com +// Submitted by Infra Team +durumis.com + // Drobo : http://www.drobo.com/ // Submitted by Ricardo Padilha mydrobo.com @@ -11455,91 +12688,54 @@ drud.us // Submitted by Richard Harper duckdns.org -// Bip : https://bip.sh -// Submitted by Joel Kennedy -bip.sh - -// bitbridge.net : Submitted by Craig Welch, abeliidev@gmail.com -bitbridge.net - // dy.fi : http://dy.fi/ // Submitted by Heikki Hannikainen dy.fi tunk.org // DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ -dyndns-at-home.com -dyndns-at-work.com -dyndns-blog.com -dyndns-free.com -dyndns-home.com -dyndns-ip.com -dyndns-mail.com -dyndns-office.com -dyndns-pics.com -dyndns-remote.com -dyndns-server.com -dyndns-web.com -dyndns-wiki.com -dyndns-work.com dyndns.biz -dyndns.info -dyndns.org -dyndns.tv -at-band-camp.net -ath.cx -barrel-of-knowledge.info -barrell-of-knowledge.info -better-than.tv +for-better.biz +for-more.biz +for-some.biz +for-the.biz +selfip.biz +webhop.biz +ftpaccess.cc +game-server.cc +myphotos.cc +scrapping.cc blogdns.com -blogdns.net -blogdns.org -blogsite.org -boldlygoingnowhere.org -broke-it.net -buyshouses.net cechire.com dnsalias.com -dnsalias.net -dnsalias.org dnsdojo.com -dnsdojo.net -dnsdojo.org -does-it.net doesntexist.com -doesntexist.org dontexist.com -dontexist.net -dontexist.org doomdns.com -doomdns.org -dvrdns.org dyn-o-saur.com dynalias.com -dynalias.net -dynalias.org -dynathome.net -dyndns.ws -endofinternet.net -endofinternet.org -endoftheinternet.org +dyndns-at-home.com +dyndns-at-work.com +dyndns-blog.com +dyndns-free.com +dyndns-home.com +dyndns-ip.com +dyndns-mail.com +dyndns-office.com +dyndns-pics.com +dyndns-remote.com +dyndns-server.com +dyndns-web.com +dyndns-wiki.com +dyndns-work.com est-a-la-maison.com est-a-la-masion.com est-le-patron.com est-mon-blogueur.com -for-better.biz -for-more.biz -for-our.info -for-some.biz -for-the.biz -forgot.her.name -forgot.his.name from-ak.com from-al.com from-ar.com -from-az.net from-ca.com -from-co.net from-ct.com from-dc.com from-de.com @@ -11552,10 +12748,8 @@ from-il.com from-in.com from-ks.com from-ky.com -from-la.net from-ma.com from-md.com -from-me.org from-mi.com from-mn.com from-mo.com @@ -11568,7 +12762,6 @@ from-nh.com from-nj.com from-nm.com from-nv.com -from-ny.net from-oh.com from-ok.com from-or.com @@ -11586,45 +12779,18 @@ from-wa.com from-wi.com from-wv.com from-wy.com -ftpaccess.cc -fuettertdasnetz.de -game-host.org -game-server.cc getmyip.com -gets-it.net -go.dyndns.org gotdns.com -gotdns.org -groks-the.info -groks-this.info -ham-radio-op.net -here-for-more.info hobby-site.com -hobby-site.org -home.dyndns.org -homedns.org -homeftp.net -homeftp.org -homeip.net homelinux.com -homelinux.net -homelinux.org homeunix.com -homeunix.net -homeunix.org iamallama.com -in-the-band.net is-a-anarchist.com is-a-blogger.com is-a-bookkeeper.com -is-a-bruinsfan.org is-a-bulls-fan.com -is-a-candidate.org is-a-caterer.com -is-a-celticsfan.org is-a-chef.com -is-a-chef.net -is-a-chef.org is-a-conservative.com is-a-cpa.com is-a-cubicle-slave.com @@ -11633,31 +12799,25 @@ is-a-designer.com is-a-doctor.com is-a-financialadvisor.com is-a-geek.com -is-a-geek.net -is-a-geek.org is-a-green.com is-a-guru.com is-a-hard-worker.com is-a-hunter.com -is-a-knight.org is-a-landscaper.com is-a-lawyer.com is-a-liberal.com is-a-libertarian.com -is-a-linux-user.org is-a-llama.com is-a-musician.com is-a-nascarfan.com is-a-nurse.com is-a-painter.com -is-a-patsfan.org is-a-personaltrainer.com is-a-photographer.com is-a-player.com is-a-republican.com is-a-rockstar.com is-a-socialist.com -is-a-soxfan.org is-a-student.com is-a-teacher.com is-a-techie.com @@ -11669,113 +12829,150 @@ is-an-anarchist.com is-an-artist.com is-an-engineer.com is-an-entertainer.com -is-by.us is-certified.com -is-found.org is-gone.com is-into-anime.com is-into-cars.com is-into-cartoons.com is-into-games.com is-leet.com -is-lost.org is-not-certified.com -is-saved.org is-slick.com is-uberleet.com -is-very-bad.org -is-very-evil.org -is-very-good.org -is-very-nice.org -is-very-sweet.org is-with-theband.com isa-geek.com -isa-geek.net -isa-geek.org isa-hockeynut.com issmarterthanyou.com +likes-pie.com +likescandy.com +neat-url.com +saves-the-whales.com +selfip.com +sells-for-less.com +sells-for-u.com +servebbs.com +simple-url.com +space-to-rent.com +teaches-yoga.com +writesthisblog.com +ath.cx +fuettertdasnetz.de isteingeek.de istmein.de -kicks-ass.net -kicks-ass.org -knowsitall.info -land-4-sale.us lebtimnetz.de leitungsen.de -likes-pie.com -likescandy.com +traeumtgerade.de +barrel-of-knowledge.info +barrell-of-knowledge.info +dyndns.info +for-our.info +groks-the.info +groks-this.info +here-for-more.info +knowsitall.info +selfip.info +webhop.info +forgot.her.name +forgot.his.name +at-band-camp.net +blogdns.net +broke-it.net +buyshouses.net +dnsalias.net +dnsdojo.net +does-it.net +dontexist.net +dynalias.net +dynathome.net +endofinternet.net +from-az.net +from-co.net +from-la.net +from-ny.net +gets-it.net +ham-radio-op.net +homeftp.net +homeip.net +homelinux.net +homeunix.net +in-the-band.net +is-a-chef.net +is-a-geek.net +isa-geek.net +kicks-ass.net +office-on-the.net +podzone.net +scrapper-site.net +selfip.net +sells-it.net +servebbs.net +serveftp.net +thruhere.net +webhop.net merseine.nu mine.nu +shacknet.nu +blogdns.org +blogsite.org +boldlygoingnowhere.org +dnsalias.org +dnsdojo.org +doesntexist.org +dontexist.org +doomdns.org +dvrdns.org +dynalias.org +dyndns.org +go.dyndns.org +home.dyndns.org +endofinternet.org +endoftheinternet.org +from-me.org +game-host.org +gotdns.org +hobby-site.org +homedns.org +homeftp.org +homelinux.org +homeunix.org +is-a-bruinsfan.org +is-a-candidate.org +is-a-celticsfan.org +is-a-chef.org +is-a-geek.org +is-a-knight.org +is-a-linux-user.org +is-a-patsfan.org +is-a-soxfan.org +is-found.org +is-lost.org +is-saved.org +is-very-bad.org +is-very-evil.org +is-very-good.org +is-very-nice.org +is-very-sweet.org +isa-geek.org +kicks-ass.org misconfused.org -mypets.ws -myphotos.cc -neat-url.com -office-on-the.net -on-the-web.tv -podzone.net podzone.org readmyblog.org -saves-the-whales.com -scrapper-site.net -scrapping.cc -selfip.biz -selfip.com -selfip.info -selfip.net selfip.org -sells-for-less.com -sells-for-u.com -sells-it.net sellsyourhome.org -servebbs.com -servebbs.net servebbs.org -serveftp.net serveftp.org servegame.org -shacknet.nu -simple-url.com -space-to-rent.com stuff-4-sale.org -stuff-4-sale.us -teaches-yoga.com -thruhere.net -traeumtgerade.de -webhop.biz -webhop.info -webhop.net webhop.org +better-than.tv +dyndns.tv +on-the-web.tv worse-than.tv -writesthisblog.com - -// ddnss.de : https://www.ddnss.de/ -// Submitted by Robert Niedziela -ddnss.de -dyn.ddnss.de -dyndns.ddnss.de -dyndns1.de -dyn-ip24.de -home-webserver.de -dyn.home-webserver.de -myhome-server.de -ddnss.org - -// Definima : http://www.definima.com/ -// Submitted by Maxence Bitterli -definima.net -definima.io - -// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/ -// Submitted by Braxton Huggins -ondigitalocean.app - -// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/ -// Submitted by Robin H. Johnson -*.digitaloceanspaces.com - -// dnstrace.pro : https://dnstrace.pro/ -// Submitted by Chris Partridge -bci.dnstrace.pro +is-by.us +land-4-sale.us +stuff-4-sale.us +dyndns.ws +mypets.ws // Dynu.com : https://www.dynu.com/ // Submitted by Sue Ye @@ -11795,7 +12992,6 @@ freeddns.org mywire.org webredirect.org myddns.rocks -blogsite.xyz // dynv6 : https://dynv6.com // Submitted by Dominik Menke @@ -11810,6 +13006,26 @@ e4.cz easypanel.app easypanel.host +// EasyWP : https://www.easywp.com +// Submitted by +*.ewp.live + +// eDirect Corp. : https://hosting.url.com.tw/ +// Submitted by C.S. chang +twmail.cc +twmail.net +twmail.org +mymailer.com.tw +url.tw + +// Electromagnetic Field : https://www.emfcamp.org +// Submitted by +at.emf.camp + +// Elefunc, Inc. : https://elefunc.com +// Submitted by Cetin Sert +rt.ht + // Elementor : Elementor Ltd. // Submitted by Anton Barkan elementor.cloud @@ -11820,7 +13036,7 @@ elementor.cool en-root.fr // Enalean SAS: https://www.enalean.com -// Submitted by Thomas Cottier +// Submitted by Enalean Security Team mytuleap.com tuleap-partners.com @@ -11829,11 +13045,6 @@ tuleap-partners.com encr.app encoreapi.com -// ECG Robotics, Inc: https://ecgrobotics.org -// Submitted by -onred.one -staging.onred.one - // encoway GmbH : https://www.encoway.de // Submitted by Marcel Daus eu.encoway.cloud @@ -11874,7 +13085,6 @@ kr.eu.org lt.eu.org lu.eu.org lv.eu.org -mc.eu.org me.eu.org mk.eu.org mt.eu.org @@ -11884,10 +13094,8 @@ ng.eu.org nl.eu.org no.eu.org nz.eu.org -paris.eu.org pl.eu.org pt.eu.org -q-a.eu.org ro.eu.org ru.eu.org se.eu.org @@ -11912,22 +13120,20 @@ us-2.evennode.com us-3.evennode.com us-4.evennode.com -// eDirect Corp. : https://hosting.url.com.tw/ -// Submitted by C.S. chang -twmail.cc -twmail.net -twmail.org -mymailer.com.tw -url.tw +// Evervault : https://evervault.com +// Submitted by Hannah Neary +relay.evervault.app +relay.evervault.dev + +// Expo : https://expo.dev/ +// Submitted by James Ide +expo.app +staging.expo.app // Fabrica Technologies, Inc. : https://www.fabrica.dev/ // Submitted by Eric Jiang onfabrica.com -// Facebook, Inc. -// Submitted by Peter Ruibal -apps.fbsbx.com - // FAITID : https://faitid.org/ // Submitted by Maxim Alzoba // https://www.flexireg.net/stat_info @@ -12014,8 +13220,6 @@ u.channelsdvr.net edgecompute.app fastly-edge.com fastly-terrarium.com -fastlylb.net -map.fastlylb.net freetls.fastly.net map.fastly.net a.prod.fastly.net @@ -12023,6 +13227,8 @@ global.prod.fastly.net a.ssl.fastly.net b.ssl.fastly.net global.ssl.fastly.net +fastlylb.net +map.fastlylb.net // Fastmail : https://www.fastmail.com/ // Submitted by Marc Bradshaw @@ -12036,6 +13242,12 @@ myfast.host fastvps.site myfast.space +// FearWorks Media Ltd. : https://fearworksmedia.co.uk +// submitted by Keith Fairley +conn.uk +copro.uk +hosp.uk + // Fedora : https://fedoraproject.org/ // submitted by Patrick Uiterwijk fedorainfracloud.org @@ -12044,12 +13256,6 @@ cloud.fedoraproject.org app.os.fedoraproject.org app.os.stg.fedoraproject.org -// FearWorks Media Ltd. : https://fearworksmedia.co.uk -// submitted by Keith Fairley -conn.uk -copro.uk -hosp.uk - // Fermax : https://fermax.com/ // submitted by Koen Van Isterdael mydobiss.com @@ -12061,47 +13267,33 @@ fh-muenster.io // Filegear Inc. : https://www.filegear.com // Submitted by Jason Zhu filegear.me -filegear-au.me -filegear-de.me -filegear-gb.me -filegear-ie.me -filegear-jp.me -filegear-sg.me // Firebase, Inc. // Submitted by Chris Raynor firebaseapp.com -// Firewebkit : https://www.firewebkit.com -// Submitted by Majid Qureshi -fireweb.app - -// FLAP : https://www.flap.cloud -// Submitted by Louis Chemineau -flap.id - // FlashDrive : https://flashdrive.io // Submitted by Eric Chan -onflashdrive.app fldrv.com +// FlutterFlow : https://flutterflow.io +// Submitted by Anton Emelyanov +flutterflow.app + // fly.io: https://fly.io // Submitted by Kurt Mackey fly.dev -edgeapp.net shw.io +edgeapp.net -// Flynn : https://flynn.io -// Submitted by Jonathan Rudenberg -flynnhosting.net - -// Forgerock : https://www.forgerock.com +// Forgerock : https://www.forgerock.com // Submitted by Roderick Parr forgeblocks.com id.forgerock.io // Framer : https://www.framer.com -// Submitted by Koen Rouwhorst +// Submitted by Koen Rouwhorst +framer.ai framer.app framercanvas.com framer.media @@ -12109,15 +13301,7 @@ framer.photos framer.website framer.wiki -// Frusky MEDIA&PR : https://www.frusky.de -// Submitted by Victor Pupynin -*.frusky.de - -// RavPage : https://www.ravpage.co.il -// Submitted by Roni Horowitz -ravpage.co.il - -// Frederik Braun https://frederik-braun.com +// Frederik Braun : https://frederik-braun.com // Submitted by Frederik Braun 0e.vc @@ -12138,11 +13322,33 @@ freedesktop.org // Submitted by Cadence freemyip.com +// Frusky MEDIA&PR : https://www.frusky.de +// Submitted by Victor Pupynin +*.frusky.de + // FunkFeuer - Verein zur Förderung freier Netze : https://www.funkfeuer.at // Submitted by Daniel A. Maierhofer wien.funkfeuer.at -// Futureweb OG : http://www.futureweb.at +// Future Versatile Group. : https://www.fvg-on.net/ +// T.Kabu +daemon.asia +dix.asia +mydns.bz +0am.jp +0g0.jp +0j0.jp +0t0.jp +mydns.jp +pgw.jp +wjg.jp +keyword-on.net +live-on.net +server-on.net +mydns.tw +mydns.vc + +// Futureweb GmbH : https://www.futureweb.at // Submitted by Andreas Schnederle-Wagner *.futurecms.at *.ex.futurecms.at @@ -12153,8 +13359,14 @@ futuremailing.at *.kunden.ortsinfo.at *.statics.cloud +// GCom Internet : https://www.gcom.net.au +// Submitted by Leo Julius +aliases121.com + // GDS : https://www.gov.uk/service-manual/technology/managing-domain-names // Submitted by Stephen Ford +campaign.gov.uk +service.gov.uk independent-commission.uk independent-inquest.uk independent-inquiry.uk @@ -12162,12 +13374,6 @@ independent-panel.uk independent-review.uk public-inquiry.uk royal-commission.uk -campaign.gov.uk -service.gov.uk - -// CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk -// Submitted by Jamie Tanna -api.gov.uk // Gehirn Inc. : https://www.gehirn.co.jp/ // Submitted by Kohei YOSHIDA @@ -12181,9 +13387,10 @@ gentlentapis.com lab.ms cdn-edges.net -// Ghost Foundation : https://ghost.org -// Submitted by Matt Hanley -ghost.io +// GetLocalCert : https://getlocalcert.net +// Submitted by William Harrison +localcert.net +localhostcert.net // GignoSystemJapan: http://gsj.bz // Submitted by GignoSystemJapan @@ -12327,105 +13534,86 @@ whitesnow.jp zombie.jp heteml.net -// GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/ -// Submitted by Tom Whitwell -cloudapps.digital -london.cloudapps.digital - -// GOV.UK Pay : https://www.payments.service.gov.uk/ -// Submitted by Richard Baker -pymnt.uk - -// UKHomeOffice : https://www.gov.uk/government/organisations/home-office -// Submitted by Jon Shanks -homeoffice.gov.uk - -// GlobeHosting, Inc. -// Submitted by Zoltan Egresi -ro.im +// GoDaddy Registry : https://registry.godaddy +// Submitted by Rohan Durrant +graphic.design // GoIP DNS Services : http://www.goip.de // Submitted by Christian Poulter goip.de // Google, Inc. -// Submitted by Eduardo Vela -run.app -a.run.app -web.app -*.0emm.com -appspot.com -*.r.appspot.com -codespot.com -googleapis.com -googlecode.com -pagespeedmobilizer.com -publishproxy.com -withgoogle.com -withyoutube.com -*.gateway.dev -cloud.goog -translate.goog -*.usercontent.goog -cloudfunctions.net +// Submitted by Shannon McCabe blogspot.ae blogspot.al blogspot.am +*.hosted.app +*.run.app +web.app +blogspot.com.ar +blogspot.co.at +blogspot.com.au blogspot.ba blogspot.be blogspot.bg blogspot.bj +blogspot.com.br +blogspot.com.by blogspot.ca blogspot.cf blogspot.ch blogspot.cl -blogspot.co.at -blogspot.co.id -blogspot.co.il -blogspot.co.ke -blogspot.co.nz -blogspot.co.uk -blogspot.co.za -blogspot.com -blogspot.com.ar -blogspot.com.au -blogspot.com.br -blogspot.com.by blogspot.com.co -blogspot.com.cy -blogspot.com.ee -blogspot.com.eg -blogspot.com.es -blogspot.com.mt -blogspot.com.ng -blogspot.com.tr -blogspot.com.uy +*.0emm.com +appspot.com +*.r.appspot.com +blogspot.com +codespot.com +googleapis.com +googlecode.com +pagespeedmobilizer.com +withgoogle.com +withyoutube.com blogspot.cv +blogspot.com.cy blogspot.cz blogspot.de +*.gateway.dev blogspot.dk +blogspot.com.ee +blogspot.com.eg +blogspot.com.es blogspot.fi blogspot.fr +cloud.goog +translate.goog +*.usercontent.goog blogspot.gr blogspot.hk blogspot.hr blogspot.hu +blogspot.co.id blogspot.ie +blogspot.co.il blogspot.in blogspot.is blogspot.it blogspot.jp +blogspot.co.ke blogspot.kr blogspot.li blogspot.lt blogspot.lu blogspot.md blogspot.mk -blogspot.mr +blogspot.com.mt blogspot.mx blogspot.my +cloudfunctions.net +blogspot.com.ng blogspot.nl blogspot.no +blogspot.co.nz blogspot.pe blogspot.pt blogspot.qa @@ -12439,21 +13627,38 @@ blogspot.si blogspot.sk blogspot.sn blogspot.td +blogspot.com.tr blogspot.tw blogspot.ug +blogspot.co.uk +blogspot.com.uy blogspot.vn +blogspot.co.za // Goupile : https://goupile.fr // Submitted by Niels Martignene goupile.fr +// GOV.UK Pay : https://www.payments.service.gov.uk/ +// Submitted by Richard Baker +pymnt.uk + +// GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/ +// Submitted by Tom Whitwell +cloudapps.digital +london.cloudapps.digital + // Government of the Netherlands: https://www.government.nl // Submitted by gov.nl -// Group 53, LLC : https://www.group53.com -// Submitted by Tyler Todd -awsmppl.com +// Grafana Labs: https://grafana.com/ +// Submitted by Platform Engineering +grafana-dev.net + +// GrayJay Web Solutions Inc. : https://grayjaysports.ca +// Submitted by Matt Yamkowy +grayjayleagues.com // GünstigBestellen : https://günstigbestellen.de // Submitted by Furkan Akkoc @@ -12468,10 +13673,13 @@ caa.li ua.rs conf.se -// Handshake : https://handshake.org -// Submitted by Mike Damm -hs.zone -hs.run +// Häkkinen.fi +// Submitted by Eero Häkkinen +häkkinen.fi + +// Harrison Network : https://hrsn.net +// Submitted by William Harrison +hrsn.dev // Hashbang : https://hashbang.sh hashbang.sh @@ -12481,9 +13689,28 @@ hashbang.sh hasura.app hasura-app.io +// Hatena Co., Ltd. : https://hatena.co.jp +// Submitted by Masato Nakamura +hatenablog.com +hatenadiary.com +hateblo.jp +hatenablog.jp +hatenadiary.jp +hatenadiary.org + // Heilbronn University of Applied Sciences - Faculty Informatics (GitLab Pages): https://www.hs-heilbronn.de -// Submitted by Richard Zowalla +// Submitted by Richard Zowalla pages.it.hs-heilbronn.de +pages-research.it.hs-heilbronn.de + +// HeiyuSpace: https://lazycat.cloud +// Submitted by Xia Bin +heiyu.space + +// Helio Networks : https://heliohost.org +// Submitted by Ben Frede +helioho.st +heliohost.us // Hepforge : https://www.hepforge.org // Submitted by David Grellscheid @@ -12494,11 +13721,15 @@ hepforge.org herokuapp.com herokussl.com +// Heyflow : https://www.heyflow.com +// Submitted by Mirko Nitschke +heyflow.page +heyflow.site + // Hibernating Rhinos // Submitted by Oren Eini ravendb.cloud ravendb.community -ravendb.me development.run ravendb.run @@ -12506,6 +13737,12 @@ ravendb.run // Submitted by Krzysztof Wolski homesklep.pl +// Homebase : https://homebase.id/ +// Submitted by Jason Babo +*.kin.one +*.id.pub +*.kin.pub + // Hong Kong Productivity Council: https://www.hkpc.org/ // Submitted by SECaaS Team secaas.hk @@ -12514,46 +13751,66 @@ secaas.hk // Submitted by Danilo De Franco hoplix.shop - // HOSTBIP REGISTRY : https://www.hostbip.com/ // Submitted by Atanunu Igbunuroghene orx.biz biz.gl +biz.ng +co.biz.ng +dl.biz.ng +go.biz.ng +lg.biz.ng +on.biz.ng col.ng firm.ng gen.ng ltd.ng ngo.ng -edu.scot -sch.so +plc.ng + +// HostFly : https://www.ie.ua +// Submitted by Bohdan Dub +ie.ua -// HostyHosting (hostyhosting.com) +// HostyHosting : https://hostyhosting.com hostyhosting.io -// Häkkinen.fi -// Submitted by Eero Häkkinen -häkkinen.fi +// Hugging Face: https://huggingface.co +// Submitted by Eliott Coyac +hf.space +static.hf.space + +// Hypernode B.V. : https://www.hypernode.com/ +// Submitted by Cipriano Groenendal +hypernode.io + +// I-O DATA DEVICE, INC. : http://www.iodata.com/ +// Submitted by Yuji Minagawa +iobb.net + +// i-registry s.r.o. : http://www.i-registry.cz/ +// Submitted by Martin Semrad +co.cz // Ici la Lune : http://www.icilalune.com/ // Submitted by Simon Morvan *.moonscale.io moonscale.net +// iDOT Services Limited : http://www.domain.gr.com +// Submitted by Gavin Brown +gr.com + // iki.fi // Submitted by Hannu Aronsson iki.fi -// iliad italia: https://www.iliad.it +// iliad italia : https://www.iliad.it // Submitted by Marios Makassikis ibxos.it iliadboxos.it -// Impertrix Solutions : -// Submitted by Zhixiang Zhao -impertrixcdn.com -impertrix.com - -// Incsub, LLC: https://incsub.com/ +// Incsub, LLC : https://incsub.com/ // Submitted by Aaron Edwards smushcdn.com wphostedmail.com @@ -12568,10 +13825,10 @@ in-berlin.de in-brb.de in-butter.de in-dsl.de -in-dsl.net -in-dsl.org in-vpn.de +in-dsl.net in-vpn.net +in-dsl.org in-vpn.org // info.at : http://www.info.at/ @@ -12579,7 +13836,7 @@ biz.at info.at // info.cx : http://info.cx -// Submitted by Jacob Slater +// Submitted by June Slater info.cx // Interlegis : http://www.interlegis.leg.br @@ -12616,18 +13873,43 @@ to.leg.br // Submitted by Wolfgang Schwarz pixolino.com -// Internet-Pro, LLP: https://netangels.ru/ +// Internet-Pro, LLP : https://netangels.ru/ // Submitted by Vasiliy Sheredeko na4u.ru +// IONOS SE : https://www.ionos.com/, +// IONOS Group SE: https://www.ionos-group.com/ +// submitted by Henrik Willert +apps-1and1.com +live-website.com +apps-1and1.net +websitebuilder.online +app-ionos.space + // iopsys software solutions AB : https://iopsys.eu/ // Submitted by Roman Azarenko iopsys.se +// IPFS Project : https://ipfs.tech/ +// Submitted by Interplanetary Shipyard +*.dweb.link + // IPiFony Systems, Inc. : https://www.ipifony.com/ // Submitted by Matthew Hardeman ipifony.net +// ir.md : https://nic.ir.md +// Submitted by Ali Soizi +ir.md + +// is-a-good.dev : https://is-a-good.dev +// Submitted by William Harrison +is-a-good.dev + +// is-a.dev : https://is-a.dev +// Submitted by William Harrison +is-a.dev + // IServ GmbH : https://iserv.de // Submitted by Mario Hoberg iservschule.de @@ -12637,16 +13919,10 @@ schulserver.de test-iserv.de iserv.dev -// I-O DATA DEVICE, INC. : http://www.iodata.com/ -// Submitted by Yuji Minagawa -iobb.net - // Jelastic, Inc. : https://jelastic.com/ // Submitted by Ihor Kolodyuk mel.cloudlets.com.au cloud.interhostsolutions.be -users.scale.virtualcloud.com.br -mycloud.by alp1.ae.flow.ch appengine.flow.ch es-1.axarnet.cloud @@ -12668,20 +13944,15 @@ us.reclaim.cloud ch.trendhosting.cloud de.trendhosting.cloud jele.club -amscompute.com -clicketcloud.com dopaas.com -hidora.com paas.hosted-by-previder.com rag-cloud.hosteur.com rag-cloud-ch.hosteur.com jcloud.ik-server.com jcloud-ver-jpc.ik-server.com demo.jelastic.com -kilatiron.com paas.massivegrid.com jed.wafaicloud.com -lon.wafaicloud.com ryd.wafaicloud.com j.scaleforce.com.cy jelastic.dogado.eu @@ -12693,18 +13964,14 @@ mircloud.host paas.beebyte.io sekd1.beebyteapp.io jele.io -cloud-fr1.unispace.io jc.neen.it -cloud.jelastic.open.tim.it jcloud.kz -upaas.kazteleport.kz cloudjiffy.net fra1-de.cloudjiffy.net west1-us.cloudjiffy.net jls-sto1.elastx.net jls-sto2.elastx.net jls-sto3.elastx.net -faststacks.net fr-1.paas.massivegrid.net lon-1.paas.massivegrid.net lon-2.paas.massivegrid.net @@ -12714,11 +13981,9 @@ sg-1.paas.massivegrid.net jelastic.saveincloud.net nordeste-idc.saveincloud.net j.scaleforce.net -jelastic.tsukaeru.net sdscloud.pl unicloud.pl mircloud.ru -jelastic.regruhosting.ru enscaled.sg jele.site jelastic.team @@ -12739,10 +14004,15 @@ myjino.ru // Submitted by Daniel Fariña jotelulu.cloud +// JouwWeb B.V. : https://www.jouwweb.nl +// Submitted by Camilo Sperberg +webadorsite.com +jouwweb.site + // Joyent : https://www.joyent.com/ // Submitted by Brian Bennett -*.triton.zone *.cns.joyent.com +*.triton.zone // JS.ORG : http://dns.js.org // Submitted by Stefan Keim @@ -12753,14 +14023,15 @@ js.org kaas.gg khplay.nl -// Kakao : https://www.kakaocorp.com/ -// Submitted by JaeYoong Lee -ktistory.com - // Kapsi : https://kapsi.fi // Submitted by Tomi Juntunen kapsi.fi +// Katholieke Universiteit Leuven: https://www.kuleuven.be +// Submitted by Abuse KU Leuven +ezproxy.kuleuven.be +kuleuven.cloud + // Keyweb AG : https://www.keyweb.de // Submitted by Martin Dannehl keymachine.de @@ -12778,23 +14049,14 @@ knightpoint.systems // Submitted by Iván Oliva koobin.events -// KUROKU LTD : https://kuroku.ltd/ -// Submitted by DisposaBoy -oya.to - -// Katholieke Universiteit Leuven: https://www.kuleuven.be -// Submitted by Abuse KU Leuven -kuleuven.cloud -ezproxy.kuleuven.be - -// .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf -co.krd -edu.krd - // Krellian Ltd. : https://krellian.com // Submitted by Ben Francis -krellian.net webthings.io +krellian.net + +// KUROKU LTD : https://kuroku.ltd/ +// Submitted by DisposaBoy +oya.to // LCube - Professional hosting e.K. : https://www.lcube-webhosting.de // Submitted by Lars Laehn @@ -12812,6 +14074,14 @@ lpusercontent.com // Submitted by Lelux Admin lelux.site +// libp2p project : https://libp2p.io +// Submitted by Interplanetary Shipyard +libp2p.direct + +// Libre IT Ltd : https://libre.nz +// Submitted by Tomas Maggio +runcontainers.dev + // Lifetime Hosting : https://Lifetime.Hosting/ // Submitted by Mike Fillator co.business @@ -12822,14 +14092,10 @@ co.network co.place co.technology -// Lightmaker Property Manager, Inc. : https://app.lmpm.com/ -// Submitted by Greg Holland -app.lmpm.com - // linkyard ldt: https://www.linkyard.ch/ // Submitted by Mario Siegenthaler -linkyard.cloud linkyard-cloud.ch +linkyard.cloud // Linode : https://linode.com // Submitted by @@ -12842,13 +14108,23 @@ ip.linodeusercontent.com // Submitted by Victor Velchev we.bs +// Listen53 : https://www.l53.net +// Submitted by Gerry Keh +filegear-sg.me +ggff.net + // Localcert : https://localcert.dev // Submitted by Lann Martin *.user.localcert.dev -// localzone.xyz -// Submitted by Kenny Niehage -localzone.xyz +// Lodz University of Technology LODMAN regional domains https://www.man.lodz.pl/dns +// Submitted by Piotr Wilk +lodz.pl +pabianice.pl +plock.pl +sieradz.pl +skierniewice.pl +zgierz.pl // Log'in Line : https://www.loginline.com/ // Submitted by Rémi Mach @@ -12858,14 +14134,14 @@ loginline.io loginline.services loginline.site -// Lokalized : https://lokalized.nl -// Submitted by Noah Taheij -servers.run - // Lõhmus Family, The // Submitted by Heiki Lõhmus lohmus.me +// Lokalized : https://lokalized.nl +// Submitted by Noah Taheij +servers.run + // LubMAN UMCS Sp. z o.o : https://lubman.pl/ // Submitted by Ireneusz Maliszewski krasnik.pl @@ -12884,18 +14160,19 @@ lugs.org.uk // Lukanet Ltd : https://lukanet.com // Submitted by Anton Avramov barsy.bg -barsy.co.uk -barsyonline.co.uk +barsy.club barsycenter.com barsyonline.com -barsy.club barsy.de +barsy.dev barsy.eu +barsy.gr barsy.in barsy.info barsy.io barsy.me barsy.menu +barsyonline.menu barsy.mobi barsy.net barsy.online @@ -12903,42 +14180,50 @@ barsy.org barsy.pro barsy.pub barsy.ro +barsy.rs barsy.shop +barsyonline.shop barsy.site +barsy.store barsy.support barsy.uk +barsy.co.uk +barsyonline.co.uk // Magento Commerce // Submitted by Damien Tournoud *.magentosite.cloud -// May First - People Link : https://mayfirst.org/ -// Submitted by Jamie McClelland -mayfirst.info -mayfirst.org - // Mail.Ru Group : https://hb.cldmail.ru // Submitted by Ilya Zaretskiy hb.cldmail.ru -// Mail Transfer Platform : https://www.neupeer.com -// Submitted by Li Hui -cn.vu +// MathWorks : https://www.mathworks.com/ +// Submitted by Emily Reed +matlab.cloud +modelscape.com +mwcloudnonprod.com +polyspace.com + +// May First - People Link : https://mayfirst.org/ +// Submitted by Jamie McClelland +mayfirst.info +mayfirst.org // Maze Play: https://www.mazeplay.com // Submitted by Adam Humpherys mazeplay.com -// mcpe.me : https://mcpe.me -// Submitted by Noa Heyl -mcpe.me - // McHost : https://mchost.ru // Submitted by Evgeniy Subbotin mcdir.me mcdir.ru -mcpre.ru vps.mcdir.ru +mcpre.ru + +// mcpe.me : https://mcpe.me +// Submitted by Noa Heyl +mcpe.me // Mediatech : https://mediatech.by // Submitted by Evgeniy Kozhuhovskiy @@ -12949,6 +14234,10 @@ mediatech.dev // Submitted by Michael Olson hra.health +// MedusaJS, Inc : https://medusajs.com/ +// Submitted by Stevche Radevski +medusajs.app + // Memset hosting : https://www.memset.com // Submitted by Tom Whitwell miniserver.com @@ -12958,13 +14247,15 @@ memset.net // Submitted by Ruben Schmidmeister messerli.app +// Meta Platforms, Inc. : https://meta.com/ +// Submitted by Jacob Cordero +atmeta.com +apps.fbsbx.com + // MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ -// Submitted by Zdeněk Šustr +// Submitted by Zdeněk Šustr and Radim Janča *.cloud.metacentrum.cz custom.metacentrum.cz - -// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ -// Submitted by Radim Janča flt.cloud.muni.cz usr.cloud.muni.cz @@ -12978,35 +14269,55 @@ co.pl // Microsoft Corporation : http://microsoft.com // Submitted by Public Suffix List Admin +// Managed by Corporate Domains +// Microsoft Azure : https://home.azure *.azurecontainer.io -azurewebsites.net +azure-api.net azure-mobile.net -cloudapp.net +azureedge.net +azurefd.net azurestaticapps.net 1.azurestaticapps.net 2.azurestaticapps.net 3.azurestaticapps.net +4.azurestaticapps.net +5.azurestaticapps.net +6.azurestaticapps.net +7.azurestaticapps.net centralus.azurestaticapps.net eastasia.azurestaticapps.net eastus2.azurestaticapps.net westeurope.azurestaticapps.net westus2.azurestaticapps.net +azurewebsites.net +cloudapp.net +trafficmanager.net +blob.core.windows.net +servicebus.windows.net + +// MikroTik: https://mikrotik.com +// Submitted by MikroTik SysAdmin Team +routingthecloud.com +sn.mynetname.net +routingthecloud.net +routingthecloud.org // minion.systems : http://minion.systems // Submitted by Robert Böttinger csx.cc -// Mintere : https://mintere.com/ -// Submitted by Ben Aubin -mintere.site +// Mittwald CM Service GmbH & Co. KG : https://mittwald.de +// Submitted by Marco Rieger +mydbserver.com +webspaceconfig.de +mittwald.info +mittwaldserver.info +typo3server.info +project.space -// MobileEducation, LLC : https://joinforte.com -// Submitted by Grayson Martin -forte.id - -// Mozilla Corporation : https://mozilla.com -// Submitted by Ben Francis -mozilla-iot.org +// MODX Systems LLC : https://modx.com +// Submitted by Elizabeth Southwell +modx.dev // Mozilla Foundation : https://mozilla.org/ // Submitted by glob @@ -13021,8 +14332,8 @@ pp.ru // Mythic Beasts : https://www.mythic-beasts.com // Submitted by Paul Cammish hostedpi.com -customer.mythic-beasts.com caracal.mythic-beasts.com +customer.mythic-beasts.com fentiger.mythic-beasts.com lynx.mythic-beasts.com ocelot.mythic-beasts.com @@ -13042,6 +14353,10 @@ ui.nabu.casa // Submitted by Jan Jaeschke cloud.nospamproxy.com +// Netfy Domains : https://netfy.domains +// Submitted by Suranga Ranasinghe +netfy.app + // Netlify : https://www.netlify.com // Submitted by Jessica Parsons netlify.app @@ -13050,17 +14365,134 @@ netlify.app // Submitted by Trung Tran 4u.com +// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ +// Submitted by Jeff Wheelhouse +nfshost.com + +// NFT.Storage : https://nft.storage/ +// Submitted by Vasco Santos or +ipfs.nftstorage.link + +// NGO.US Registry : https://nic.ngo.us +// Submitted by Alstra Solutions Ltd. Networking Team +ngo.us + // ngrok : https://ngrok.com/ // Submitted by Alan Shreve +ngrok.app +ngrok-free.app +ngrok.dev +ngrok-free.dev ngrok.io +ap.ngrok.io +au.ngrok.io +eu.ngrok.io +in.ngrok.io +jp.ngrok.io +sa.ngrok.io +us.ngrok.io +ngrok.pizza +ngrok.pro + +// Nicolaus Copernicus University in Torun - MSK TORMAN (https://www.man.torun.pl) +torun.pl // Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/ -// Submitted by Nicholas Ford +// Submitted by Nicholas Ford nh-serv.co.uk +nimsite.uk -// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ -// Submitted by Jeff Wheelhouse -nfshost.com +// No-IP.com : https://noip.com/ +// Submitted by Deven Reza +mmafan.biz +myftp.biz +no-ip.biz +no-ip.ca +fantasyleague.cc +gotdns.ch +3utilities.com +blogsyte.com +ciscofreak.com +damnserver.com +ddnsking.com +ditchyourip.com +dnsiskinky.com +dynns.com +geekgalaxy.com +health-carereform.com +homesecuritymac.com +homesecuritypc.com +myactivedirectory.com +mysecuritycamera.com +myvnc.com +net-freaks.com +onthewifi.com +point2this.com +quicksytes.com +securitytactics.com +servebeer.com +servecounterstrike.com +serveexchange.com +serveftp.com +servegame.com +servehalflife.com +servehttp.com +servehumour.com +serveirc.com +servemp3.com +servep2p.com +servepics.com +servequake.com +servesarcasm.com +stufftoread.com +unusualperson.com +workisboring.com +dvrcam.info +ilovecollege.info +no-ip.info +brasilia.me +ddns.me +dnsfor.me +hopto.me +loginto.me +noip.me +webhop.me +bounceme.net +ddns.net +eating-organic.net +mydissent.net +myeffect.net +mymediapc.net +mypsx.net +mysecuritycamera.net +nhlfan.net +no-ip.net +pgafan.net +privatizehealthinsurance.net +redirectme.net +serveblog.net +serveminecraft.net +sytes.net +cable-modem.org +collegefan.org +couchpotatofries.org +hopto.org +mlbfan.org +myftp.org +mysecuritycamera.org +nflfan.org +no-ip.org +read-books.org +ufcfan.org +zapto.org +no-ip.co.uk +golffan.us +noip.us +pointto.us + +// NodeArt : https://nodeart.io +// Submitted by Konstantin Nosov +stage.nodeart.io // Noop : https://noop.app // Submitted by Nathaniel Schweinberg @@ -13079,18 +14511,18 @@ noop.app // Submitted by Laurent Pellegrino noticeable.news +// Notion Labs, Inc : https://www.notion.so/ +// Submitted by Jess Yao +notion.site + // Now-DNS : https://now-dns.com // Submitted by Steve Russell dnsking.ch mypi.co n4t.co 001www.com -ddnslive.com myiphost.com forumz.info -16-b.it -32-b.it -64-b.it soundcast.me tcp4.me dnsup.net @@ -13104,123 +14536,30 @@ x443.pw now-dns.top ntdll.top freeddns.us -crafting.xyz -zapto.xyz // nsupdate.info : https://www.nsupdate.info/ // Submitted by Thomas Waldmann nsupdate.info nerdpol.ovh -// No-IP.com : https://noip.com/ -// Submitted by Deven Reza -blogsyte.com -brasilia.me -cable-modem.org -ciscofreak.com -collegefan.org -couchpotatofries.org -damnserver.com -ddns.me -ditchyourip.com -dnsfor.me -dnsiskinky.com -dvrcam.info -dynns.com -eating-organic.net -fantasyleague.cc -geekgalaxy.com -golffan.us -health-carereform.com -homesecuritymac.com -homesecuritypc.com -hopto.me -ilovecollege.info -loginto.me -mlbfan.org -mmafan.biz -myactivedirectory.com -mydissent.net -myeffect.net -mymediapc.net -mypsx.net -mysecuritycamera.com -mysecuritycamera.net -mysecuritycamera.org -net-freaks.com -nflfan.org -nhlfan.net -no-ip.ca -no-ip.co.uk -no-ip.net -noip.us -onthewifi.com -pgafan.net -point2this.com -pointto.us -privatizehealthinsurance.net -quicksytes.com -read-books.org -securitytactics.com -serveexchange.com -servehumour.com -servep2p.com -servesarcasm.com -stufftoread.com -ufcfan.org -unusualperson.com -workisboring.com -3utilities.com -bounceme.net -ddns.net -ddnsking.com -gotdns.ch -hopto.org -myftp.biz -myftp.org -myvnc.com -no-ip.biz -no-ip.info -no-ip.org -noip.me -redirectme.net -servebeer.com -serveblog.net -servecounterstrike.com -serveftp.com -servegame.com -servehalflife.com -servehttp.com -serveirc.com -serveminecraft.net -servemp3.com -servepics.com -servequake.com -sytes.net -webhop.me -zapto.org - -// NodeArt : https://nodeart.io -// Submitted by Konstantin Nosov -stage.nodeart.io +// NYC.mn : https://dot.nyc.mn/ +// Submitted by NYC.mn Subdomain Service +nyc.mn -// Nucleos Inc. : https://nucleos.com -// Submitted by Piotr Zduniak -pcloud.host +// O3O.Foundation : https://o3o.foundation/ +// Submitted by the prvcy.page Registry Team +prvcy.page -// NYC.mn : http://www.information.nyc.mn -// Submitted by Matthew Brown -nyc.mn +// Obl.ong : +// Submitted by Reese Armstrong +obl.ong // Observable, Inc. : https://observablehq.com // Submitted by Mike Bostock +observablehq.cloud static.observableusercontent.com -// Octopodal Solutions, LLC. : https://ulterius.io/ -// Submitted by Andrew Sampson -cya.gg - -// OMG.LOL : +// OMG.LOL : https://omg.lol // Submitted by Adam Newbold omg.lol @@ -13234,30 +14573,33 @@ omniwe.site // One.com: https://www.one.com/ // Submitted by Jacob Bunk Nielsen -123hjemmeside.dk -123hjemmeside.no -123homepage.it -123kotisivu.fi -123minsida.se -123miweb.es -123paginaweb.pt -123sait.ru -123siteweb.fr 123webseite.at -123webseite.de 123website.be +simplesite.com.br 123website.ch +simplesite.com +123webseite.de +123hjemmeside.dk +123miweb.es +123kotisivu.fi +123siteweb.fr +simplesite.gr +123homepage.it 123website.lu 123website.nl +123hjemmeside.no service.one -simplesite.com -simplesite.com.br -simplesite.gr simplesite.pl +123paginaweb.pt +123minsida.se -// One Fold Media : http://www.onefoldmedia.com/ -// Submitted by Eddie Jones -nid.io +// Open Domains : https://open-domains.net +// Submitted by William Harrison +is-a-fullstack.dev +is-cool.dev +is-not-a.dev +localplayer.dev +is-local.org // Open Social : https://www.getopensocial.com/ // Submitted by Alexander Varwijk @@ -13267,6 +14609,12 @@ opensocial.site // Submitted by Sven Marnach opencraft.hosting +// OpenHost : https://registry.openhost.uk +// Submitted by OpenHost Registry Team +16-b.it +32-b.it +64-b.it + // OpenResearch GmbH: https://openresearch.com/ // Submitted by Philipp Schmid orsites.com @@ -13275,10 +14623,26 @@ orsites.com // Submitted by Yngve Pettersen operaunite.com +// Oracle Dyn : https://cloud.oracle.com/home https://dyn.com/dns/ +// Submitted by Gregory Drake +// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label +*.customer-oci.com +*.oci.customer-oci.com +*.ocp.customer-oci.com +*.ocs.customer-oci.com +*.oraclecloudapps.com +*.oraclegovcloudapps.com +*.oraclegovcloudapps.uk + // Orange : https://www.orange.com // Submitted by Alexandre Linte tech.orange +// OsSav Technology Ltd. : https://ossav.com/ +// TLD Nic: http://nic.can.re - TLD Whois Server: whois.can.re +// Submitted by OsSav Technology Ltd. +can.re + // Oursky Limited : https://authgear.com/, https://skygear.io/ // Submitted by Authgear Team , Skygear Developer authgear-staging.com @@ -13291,8 +14655,8 @@ outsystemscloud.com // OVHcloud: https://ovhcloud.com // Submitted by Vincent Cassé -*.webpaas.ovh.net *.hosting.ovh.net +*.webpaas.ovh.net // OwnProvider GmbH: http://www.ownprovider.com // Submitted by Jan Moennich @@ -13315,37 +14679,31 @@ oy.lc // Submitted by Derek Myers pgfog.com -// Pagefront : https://www.pagefronthq.com/ -// Submitted by Jason Kriss -pagefrontapp.com - // PageXL : https://pagexl.com // Submitted by Yann Guichard pagexl.com +// Pantheon Systems, Inc. : https://pantheon.io/ +// Submitted by Gary Dylina +gotpantheon.com +pantheonsite.io + // Paywhirl, Inc : https://paywhirl.com/ // Submitted by Daniel Netzer *.paywhirl.com // pcarrier.ca Software Inc: https://pcarrier.ca/ // Submitted by Pierre Carrier -bar0.net -bar1.net -bar2.net -rdv.to - -// .pl domains (grandfathered) -art.pl -gliwice.pl -krakow.pl -poznan.pl -wroc.pl -zakopane.pl +*.xmit.co +xmit.dev +madethis.site +srv.us +gh.srv.us +gl.srv.us -// Pantheon Systems, Inc. : https://pantheon.io/ -// Submitted by Gary Dylina -pantheonsite.io -gotpantheon.com +// PE Ulyanov Kirill Sergeevich : https://airy.host +// Submitted by Kirill Ulyanov +lk3.ru // Peplink | Pepwave : http://peplink.com/ // Submitted by Steve Leung @@ -13355,17 +14713,14 @@ mypep.link // Submitted by Kenneth Van Alstyne perspecta.cloud -// PE Ulyanov Kirill Sergeevich : https://airy.host -// Submitted by Kirill Ulyanov -lk3.ru - // Planet-Work : https://www.planet-work.com/ // Submitted by Frédéric VANNIÈRE on-web.fr // Platform.sh : https://platform.sh // Submitted by Nikola Kotur -bc.platform.sh +*.upsun.app +upsunapp.com ent.platform.sh eu.platform.sh us.platform.sh @@ -13378,15 +14733,9 @@ platter-app.com platter-app.dev platterp.us -// Plesk : https://www.plesk.com/ -// Submitted by Anton Akhtyamov -pdns.page -plesk.page -pleskns.com - -// Port53 : https://port53.io/ -// Submitted by Maximilian Schieder -dyn53.io +// Pley AB : https://www.pley.com/ +// Submitted by Henning Pohl +pley.games // Porter : https://porter.run/ // Submitted by Rudraksh MK @@ -13403,8 +14752,8 @@ pstmn.io mock.pstmn.io httpbin.org -//prequalifyme.today : https://prequalifyme.today -//Submitted by DeepakTiwari deepak@ivylead.io +// prequalifyme.today : https://prequalifyme.today +// Submitted by DeepakTiwari deepak@ivylead.io prequalifyme.today // prgmr.com : https://prgmr.com/ @@ -13415,14 +14764,6 @@ xen.prgmr.com // Submitted by registry priv.at -// privacytools.io : https://www.privacytools.io/ -// Submitted by Jonah Aragon -prvcy.page - -// Protocol Labs : https://protocol.ai/ -// Submitted by Michael Burns -*.dweb.link - // Protonet GmbH : http://protonet.io // Submitted by Martin Meier protonet.io @@ -13441,34 +14782,6 @@ pubtls.org pythonanywhere.com eu.pythonanywhere.com -// QOTO, Org. -// Submitted by Jeffrey Phillips Freeman -qoto.io - -// Qualifio : https://qualifio.com/ -// Submitted by Xavier De Cock -qualifioapp.com - -// QuickBackend: https://www.quickbackend.com -// Submitted by Dani Biro -qbuser.com - -// Rad Web Hosting: https://radwebhosting.com -// Submitted by Scott Claeys -cloudsite.builders - -// Redgate Software: https://red-gate.com -// Submitted by Andrew Farries -instances.spawn.cc - -// Redstar Consultants : https://www.redstarconsultants.com/ -// Submitted by Jons Slemmer -instantcloud.cn - -// Russian Academy of Sciences -// Submitted by Tech Support -ras.ru - // QA2 // Submitted by Daniel Dent (https://www.danieldent.com/) qa2.com @@ -13479,11 +14792,30 @@ qcx.io *.sys.qcx.io // QNAP System Inc : https://www.qnap.com -// Submitted by Nick Chang -dev-myqnapcloud.com +// Submitted by Nick Chang +myqnapcloud.cn alpha-myqnapcloud.com +dev-myqnapcloud.com +mycloudnas.com +mynascloud.com myqnapcloud.com +// QOTO, Org. +// Submitted by Jeffrey Phillips Freeman +qoto.io + +// Qualifio : https://qualifio.com/ +// Submitted by Xavier De Cock +qualifioapp.com + +// Quality Unit : https://qualityunit.com +// Submitted by Vasyl Tsalko +ladesk.com + +// QuickBackend: https://www.quickbackend.com +// Submitted by Dani Biro +qbuser.com + // Quip : https://quip.com // Submitted by Patrick Linehan *.quipelements.com @@ -13498,35 +14830,85 @@ vaporcloud.io rackmaze.com rackmaze.net -// Rakuten Games, Inc : https://dev.viberplay.io -// Submitted by Joshua Zhang -g.vbrplsbx.io +// Rad Web Hosting: https://radwebhosting.com +// Submitted by Scott Claeys +cloudsite.builders +myradweb.net +servername.us + +// Radix FZC : http://domains.in.net +// Submitted by Gavin Brown +web.in +in.net + +// Raidboxes GmbH : https://raidboxes.de +// Submitted by Auke Tembrink +myrdbx.io +site.rb-hosting.io // Rancher Labs, Inc : https://rancher.com // Submitted by Vincent Fiduccia -*.on-k3s.io *.on-rancher.cloud +*.on-k3s.io *.on-rio.io +// RavPage : https://www.ravpage.co.il +// Submitted by Roni Horowitz +ravpage.co.il + // Read The Docs, Inc : https://www.readthedocs.org // Submitted by David Fischer +readthedocs-hosted.com readthedocs.io // Red Hat, Inc. OpenShift : https://openshift.redhat.com/ // Submitted by Tim Kramer rhcloud.com +// Redgate Software: https://red-gate.com +// Submitted by Andrew Farries +instances.spawn.cc + // Render : https://render.com // Submitted by Anurag Goel -app.render.com onrender.com +app.render.com // Repl.it : https://repl.it -// Submitted by Lincoln Bergeson +// Submitted by Lincoln Bergeson +replit.app +id.replit.app firewalledreplit.co id.firewalledreplit.co repl.co id.repl.co +replit.dev +archer.replit.dev +bones.replit.dev +canary.replit.dev +global.replit.dev +hacker.replit.dev +id.replit.dev +janeway.replit.dev +kim.replit.dev +kira.replit.dev +kirk.replit.dev +odo.replit.dev +paris.replit.dev +picard.replit.dev +pike.replit.dev +prerelease.replit.dev +reed.replit.dev +riker.replit.dev +sisko.replit.dev +spock.replit.dev +staging.replit.dev +sulu.replit.dev +tarpit.replit.dev +teams.replit.dev +tucker.replit.dev +wesley.replit.dev +worf.replit.dev repl.run // Resin.io : https://resin.io @@ -13538,11 +14920,6 @@ devices.resinstaging.io // Submitted by Chris Kastorff hzc.io -// Revitalised Limited : http://www.revitalised.co.uk -// Submitted by Jack Price -wellbeingzone.eu -wellbeingzone.co.uk - // Rico Developments Limited : https://adimo.co // Submitted by Colin Brown adimo.co.uk @@ -13551,6 +14928,11 @@ adimo.co.uk // Submitted by Micah Anderson itcouldbewor.se +// Roar Domains LLC : https://roar.basketball/ +// Submitted by Gavin Brown +aus.basketball +nz.basketball + // Rochester Institute of Technology : http://www.rit.edu/ // Submitted by Jennifer Herting git-pages.rit.edu @@ -13572,11 +14954,78 @@ rocky.page спб.рус я.рус +// Russian Academy of Sciences +// Submitted by Tech Support +ras.ru + +// Sakura Frp : https://www.natfrp.com +// Submitted by Bobo Liu +nyat.app + +// SAKURA Internet Inc. : https://www.sakura.ad.jp/ +// Submitted by Internet Service Department +180r.com +dojin.com +sakuratan.com +sakuraweb.com +x0.com +2-d.jp +bona.jp +crap.jp +daynight.jp +eek.jp +flop.jp +halfmoon.jp +jeez.jp +matrix.jp +mimoza.jp +ivory.ne.jp +mail-box.ne.jp +mints.ne.jp +mokuren.ne.jp +opal.ne.jp +sakura.ne.jp +sumomo.ne.jp +topaz.ne.jp +netgamers.jp +nyanta.jp +o0o0.jp +rdy.jp +rgr.jp +rulez.jp +s3.isk01.sakurastorage.jp +s3.isk02.sakurastorage.jp +saloon.jp +sblo.jp +skr.jp +tank.jp +uh-oh.jp +undo.jp +rs.webaccel.jp +user.webaccel.jp +websozai.jp +xii.jp +squares.net +jpn.org +kirara.st +x0.to +from.tv +sakura.tv + // Salesforce.com, Inc. https://salesforce.com/ -// Submitted by Michael Biven +// Submitted by Salesforce Public Suffix List Team *.builder.code.com *.dev-builder.code.com *.stg-builder.code.com +*.001.test.code-builder-stg.platform.salesforce.com +*.d.crm.dev +*.w.crm.dev +*.wa.crm.dev +*.wb.crm.dev +*.wc.crm.dev +*.wd.crm.dev +*.we.crm.dev +*.wf.crm.dev // Sandstorm Development Group, Inc. : https://sandcats.io/ // Submitted by Asheesh Laroia @@ -13584,14 +15033,15 @@ sandcats.io // SBE network solutions GmbH : https://www.sbe.de/ // Submitted by Norman Meilick -logoip.de logoip.com +logoip.de // Scaleway : https://www.scaleway.com/ // Submitted by Rémy Léone fr-par-1.baremetal.scw.cloud fr-par-2.baremetal.scw.cloud nl-ams-1.baremetal.scw.cloud +cockpit.fr-par.scw.cloud fnc.fr-par.scw.cloud functions.fnc.fr-par.scw.cloud k8s.fr-par.scw.cloud @@ -13602,11 +15052,13 @@ whm.fr-par.scw.cloud priv.instances.scw.cloud pub.instances.scw.cloud k8s.scw.cloud +cockpit.nl-ams.scw.cloud k8s.nl-ams.scw.cloud nodes.k8s.nl-ams.scw.cloud s3.nl-ams.scw.cloud s3-website.nl-ams.scw.cloud whm.nl-ams.scw.cloud +cockpit.pl-waw.scw.cloud k8s.pl-waw.scw.cloud nodes.k8s.pl-waw.scw.cloud s3.pl-waw.scw.cloud @@ -13628,6 +15080,10 @@ service.gov.scot // Submitted by Shante Adam scrysec.com +// Scrypted : https://scrypted.app +// Submitted by Koushik Dutta +client.scrypted.io + // Securepoint GmbH : https://www.securepoint.de // Submitted by Erik Anders firewall-gateway.com @@ -13649,17 +15105,17 @@ seidat.net // Submitted by Yuriy Romadin sellfy.store -// Senseering GmbH : https://www.senseering.de -// Submitted by Felix Mönckemeyer -senseering.net - // Sendmsg: https://www.sendmsg.co.il // Submitted by Assaf Stern minisite.ms -// Service Magnet : https://myservicemagnet.com -// Submitted by Dave Sanders -magnet.page +// Senseering GmbH : https://www.senseering.de +// Submitted by Felix Mönckemeyer +senseering.net + +// Servebolt AS: https://servebolt.com +// Submitted by Daniel Kjeserud +servebolt.cloud // Service Online LLC : http://drs.ua/ // Submitted by Serhii Bulakh @@ -13667,10 +15123,13 @@ biz.ua co.ua pp.ua -// Shift Crypto AG : https://shiftcrypto.ch -// Submitted by alex -shiftcrypto.dev -shiftcrypto.io +// Shanghai Accounting Society : https://www.sasf.org.cn +// Submitted by Information Administration +as.sh.cn + +// Sheezy.Art : https://sheezy.art +// Submitted by Nyoom +sheezy.games // ShiftEdit : https://shiftedit.net/ // Submitted by Adam Jimenez @@ -13690,6 +15149,7 @@ shopitsite.com // shopware AG : https://shopware.com // Submitted by Jens Küper +shopware.shop shopware.store // Siemens Mobility GmbH @@ -13708,24 +15168,32 @@ vipsinaapp.com // Submitted by Skylar Challand siteleaf.net -// Skyhat : http://www.skyhat.io -// Submitted by Shante Adam -bounty-full.com -alpha.bounty-full.com -beta.bounty-full.com - // Small Technology Foundation : https://small-tech.org // Submitted by Aral Balkan small-web.org +// Smallregistry by Promopixel SARL: https://www.smallregistry.net +// Former AFNIC's SLDs +// Submitted by Jérôme Lipowicz +aeroport.fr +avocat.fr +chambagri.fr +chirurgiens-dentistes.fr +experts-comptables.fr +medecin.fr +notaires.fr +pharmacien.fr +port.fr +veterinaire.fr + // Smoove.io : https://www.smoove.io/ // Submitted by Dan Kozak vp4.me // Snowflake Inc : https://www.snowflake.com/ -// Submitted by Faith Olapade -snowflake.app -privatelink.snowflake.app +// Submitted by Sam Haar +*.snowflake.app +*.privatelink.snowflake.app streamlit.app streamlitapp.com @@ -13733,41 +15201,18 @@ streamlitapp.com // Submitted by Ian Streeter try-snowplow.com -// SourceHut : https://sourcehut.org -// Submitted by Drew DeVault -srht.site - -// Stackhero : https://www.stackhero.io -// Submitted by Adrien Gillon -stackhero-network.com - -// Staclar : https://staclar.com -// Submitted by Q Misell -musician.io -// Submitted by Matthias Merkel -novecore.site - -// staticland : https://static.land -// Submitted by Seth Vincent -static.land -dev.static.land -sites.static.land - -// Storebase : https://www.storebase.io -// Submitted by Tony Schirmer -storebase.store - -// Strategic System Consulting (eApps Hosting): https://www.eapps.com/ -// Submitted by Alex Oancea -vps-host.net -atl.jelastic.vps-host.net -njs.jelastic.vps-host.net -ric.jelastic.vps-host.net +// Software Consulting Michal Zalewski : https://www.mafelo.com +// Submitted by Michal Zalewski +mafelo.net // Sony Interactive Entertainment LLC : https://sie.com/ // Submitted by David Coles playstation-cloud.com +// SourceHut : https://sourcehut.org +// Submitted by Drew DeVault +srht.site + // SourceLair PC : https://www.sourcelair.com // Submitted by Antonis Kalipetis apps.lair.io @@ -13777,6 +15222,10 @@ apps.lair.io // Submitted by Reza Akhavan spacekit.io +// SparrowHost : https://sparrowhost.in/ +// Submitted by Anant Pandey +ind.mom + // SpeedPartner GmbH: https://www.speedpartner.de/ // Submitted by Stefan Neufeind customer.speedpartner.de @@ -13803,23 +15252,86 @@ myspreadshop.pl myspreadshop.se myspreadshop.co.uk +// StackBlitz : https://stackblitz.com +// Submitted by Dominic Elm +w-corp-staticblitz.com +w-credentialless-staticblitz.com +w-staticblitz.com + +// Stackhero : https://www.stackhero.io +// Submitted by Adrien Gillon +stackhero-network.com + +// STACKIT GmbH & Co. KG : https://www.stackit.de/en/ +// Submitted by STACKIT-DNS Team (Simon Stier) +runs.onstackit.cloud +stackit.gg +stackit.rocks +stackit.run +stackit.zone + +// Staclar : https://staclar.com +// Submitted by Q Misell +// Submitted by Matthias Merkel +musician.io +novecore.site + // Standard Library : https://stdlib.com // Submitted by Jacob Lee api.stdlib.com +// stereosense GmbH : https://www.involve.me +// Submitted by Florian Burmann +feedback.ac +forms.ac +assessments.cx +calculators.cx +funnels.cx +paynow.cx +quizzes.cx +researched.cx +tests.cx +surveys.so + +// Storebase : https://www.storebase.io +// Submitted by Tony Schirmer +storebase.store + +// Storipress : https://storipress.com +// Submitted by Benno Liu +storipress.app + // Storj Labs Inc. : https://storj.io/ // Submitted by Philip Hutchins storj.farm -// Studenten Net Twente : http://www.snt.utwente.nl/ -// Submitted by Silke Hofstra -utwente.io +// Strapi : https://strapi.io/ +// Submitted by Florent Baldino +strapiapp.com +media.strapiapp.com + +// Strategic System Consulting (eApps Hosting): https://www.eapps.com/ +// Submitted by Alex Oancea +vps-host.net +atl.jelastic.vps-host.net +njs.jelastic.vps-host.net +ric.jelastic.vps-host.net + +// Streak : https://streak.com +// Submitted by Blake Kadatz +streak-link.com +streaklinks.com +streakusercontent.com // Student-Run Computing Facility : https://www.srcf.net/ // Submitted by Edwin Balani soc.srcf.net user.srcf.net +// Studenten Net Twente : http://www.snt.utwente.nl/ +// Submitted by Silke Hofstra +utwente.io + // Sub 6 Limited: http://www.sub6.com // Submitted by Dan Miller temp-dns.com @@ -13829,12 +15341,6 @@ temp-dns.com supabase.co supabase.in supabase.net -su.paba.se - -// Symfony, SAS : https://symfony.com/ -// Submitted by Fabien Potencier -*.s5y.io -*.sensiosite.cloud // Syncloud : https://syncloud.org // Submitted by Boris Rybalkin @@ -13856,31 +15362,40 @@ dsmynas.net familyds.net dsmynas.org familyds.org -vpnplus.to direct.quickconnect.to +vpnplus.to // Tabit Technologies Ltd. : https://tabit.cloud/ // Submitted by Oren Agiv -tabitorder.co.il -mytabit.co.il mytabit.com +mytabit.co.il +tabitorder.co.il // TAIFUN Software AG : http://taifun-software.de // Submitted by Bjoern Henke taifun-dns.de // Tailscale Inc. : https://www.tailscale.com -// Submitted by David Anderson -beta.tailscale.net +// Submitted by David Anderson ts.net +*.c.ts.net -// TASK geographical domains (www.task.gda.pl/uslugi/dns) +// TASK geographical domains (https://www.task.gda.pl/uslugi/dns) gda.pl gdansk.pl gdynia.pl med.pl sopot.pl +// Tave Creative Corp : https://tave.com/ +// Submitted by Adrian Ziemkowski +taveusercontent.com + +// tawk.to, Inc : https://www.tawk.to +// Submitted by tawk.to developer team +p.tawk.email +p.tawkto.email + // team.blue https://team.blue // Submitted by Cedric Dubois site.tb-hosting.com @@ -13903,11 +15418,11 @@ telebit.io reservd.com thingdustdata.com cust.dev.thingdust.io +reservd.dev.thingdust.io cust.disrec.thingdust.io +reservd.disrec.thingdust.io cust.prod.thingdust.io cust.testing.thingdust.io -reservd.dev.thingdust.io -reservd.disrec.thingdust.io reservd.testing.thingdust.io // ticket i/O GmbH : https://ticket.io @@ -13921,13 +15436,12 @@ azimuth.network tlon.network // Tor Project, Inc. : https://torproject.org -// Submitted by Antoine Beaupré torproject.net pages.torproject.net // TownNews.com : http://www.townnews.com // Submitted by Dustin Ward -bloxcms.com townnews-staging.com // TrafficPlex GmbH : https://www.trafficplex.de/ @@ -13953,14 +15467,11 @@ webspace.rocks lima.zone // TransIP : https://www.transip.nl -// Submitted by Rory Breuk +// Submitted by Rory Breuk and Cedric Dubois *.transurl.be *.transurl.eu -*.transurl.nl - -// TransIP: https://www.transip.nl -// Submitted by Cedric Dubois site.transip.me +*.transurl.nl // TuxFamily : http://tuxfamily.org // Submitted by TuxFamily administrators @@ -13969,8 +15480,6 @@ tuxfamily.org // TwoDNS : https://www.twodns.de/ // Submitted by TwoDNS-Support dd-dns.de -diskstation.eu -diskstation.org dray-dns.de draydns.de dyn-vpn.de @@ -13981,6 +15490,8 @@ my-wan.de syno-ds.de synology-diskstation.de synology-ds.de +diskstation.eu +diskstation.org // Typedream : https://typedream.com // Submitted by Putri Karunia @@ -13992,20 +15503,29 @@ pro.typeform.com // Uberspace : https://uberspace.de // Submitted by Moritz Werner -uber.space *.uberspace.de +uber.space // UDR Limited : http://www.udr.hk.com // Submitted by registry hk.com -hk.org -ltd.hk inc.hk +ltd.hk +hk.org // UK Intis Telecom LTD : https://it.com // Submitted by ITComdomains it.com +// Unison Computing, PBC : https://unison.cloud +// Submitted by Simon Højberg +unison-services.cloud + +// United Gameserver GmbH : https://united-gameserver.de +// Submitted by Stefan Schwarz +virtual-user.de +virtualuser.de + // UNIVERSAL DOMAIN REGISTRY : https://www.udr.org.yt/ // see also: whois -h whois.udr.org.yt help // Submitted by Atanunu Igbunuroghene @@ -14015,10 +15535,14 @@ biz.wf sch.wf org.yt -// United Gameserver GmbH : https://united-gameserver.de -// Submitted by Stefan Schwarz -virtualuser.de -virtual-user.de +// University of Banja Luka : https://unibl.org +// Domains for Republic of Srpska administrative entity. +// Submitted by Marko Ivanovic +rs.ba + +// University of Bielsko-Biala regional domain: http://dns.bielsko.pl/ +// Submitted by Marcin +bielsko.pl // Upli : https://upli.io // Submitted by Lenny Bakkalian @@ -14029,20 +15553,31 @@ upli.io urown.cloud dnsupdate.info -// .US -// Submitted by Ed Moore -lib.de.us +// US REGISTRY LLC : http://us.org +// Submitted by Gavin Brown +us.org -// VeryPositive SIA : http://very.lv -// Submitted by Danko Aleksejevs -2038.io +// V.UA Domain Administrator : https://domain.v.ua/ +// Submitted by Serhii Rostilo +v.ua + +// Val Town, Inc : https://val.town/ +// Submitted by Tom MacWright +express.val.run +web.val.run // Vercel, Inc : https://vercel.com/ -// Submitted by Connor Davis +// Submitted by Max Leiter vercel.app +v0.build vercel.dev +vusercontent.net now.sh +// VeryPositive SIA : http://very.lv +// Submitted by Danko Aleksejevs +2038.io + // Viprinet Europe GmbH : http://www.viprinet.com // Submitted by Simon Kissel router.management @@ -14055,52 +15590,6 @@ v-info.info // Submitted by Nathan van Bakel voorloper.cloud -// Voxel.sh DNS : https://voxel.sh/dns/ -// Submitted by Mia Rehlinger -neko.am -nyaa.am -be.ax -cat.ax -es.ax -eu.ax -gg.ax -mc.ax -us.ax -xy.ax -nl.ci -xx.gl -app.gp -blog.gt -de.gt -to.gt -be.gy -cc.hn -blog.kg -io.kg -jp.kg -tv.kg -uk.kg -us.kg -de.ls -at.md -de.md -jp.md -to.md -indie.porn -vxl.sh -ch.tc -me.tc -we.tc -nyan.to -at.vg -blog.vu -dev.vu -me.vu - -// V.UA Domain Administrator : https://domain.v.ua/ -// Submitted by Serhii Rostilo -v.ua - // Vultr Objects : https://www.vultr.com/products/object-storage/ // Submitted by Niels Maumenee *.vultrobjects.com @@ -14109,42 +15598,70 @@ v.ua // Submitted by Masayuki Note wafflecell.com -// WebHare bv: https://www.webhare.com/ +// Webflow, Inc. : https://www.webflow.com +// Submitted by Webflow Security Team +webflow.io +webflowtest.io + +// WebHare bv : https://www.webhare.com/ // Submitted by Arnold Hendriks *.webhare.dev -// WebHotelier Technologies Ltd: https://www.webhotelier.net/ +// WebHotelier Technologies Ltd : https://www.webhotelier.net/ // Submitted by Apostolos Tsakpinis -reserve-online.net -reserve-online.com bookonline.app hotelwithflight.com +reserve-online.com +reserve-online.net + +// WebPros International, LLC : https://webpros.com/ +// Submitted by Nicolas Rochelemagne +cprapid.com +pleskns.com +wp2.host +pdns.page +plesk.page +wpsquared.site -// WeDeploy by Liferay, Inc. : https://www.wedeploy.com -// Submitted by Henrique Vicente -wedeploy.io -wedeploy.me -wedeploy.sh +// WebWaddle Ltd : https://webwaddle.com/ +// Submitted by Merlin Glander +*.wadl.top // Western Digital Technologies, Inc : https://www.wdc.com // Submitted by Jung Jin remotewd.com +// Whatbox Inc. : https://whatbox.ca/ +// Submitted by Anthony Ryan +box.ca + // WIARD Enterprises : https://wiardweb.com // Submitted by Kidd Hustle pages.wiardweb.com // Wikimedia Labs : https://wikitech.wikimedia.org // Submitted by Arturo Borrero Gonzalez -wmflabs.org toolforge.org wmcloud.org +wmflabs.org + +// William Harrison : https://wdh.gg +// Submitted by William Harrison +wdh.app // WISP : https://wisp.gg // Submitted by Stepan Fedotov panel.gg daemon.panel.gg +// Wix.com, Inc. : https://www.wix.com +// Submitted by Shahar Talmi / Alon Kochba +wixsite.com +wixstudio.com +editorx.io +wixstudio.io +wix.run + // Wizard Zines : https://wizardzines.com // Submitted by Julia Evans messwithdns.com @@ -14170,11 +15687,6 @@ weeklylottery.org.uk wpenginepowered.com js.wpenginepowered.com -// Wix.com, Inc. : https://www.wix.com -// Submitted by Shahar Talmi -wixsite.com -editorx.io - // XenonCloud GbR: https://xenoncloud.net // Submitted by Julian Uphoff half.host @@ -14191,7 +15703,7 @@ cistron.nl demon.nl xs4all.space -// Yandex.Cloud LLC: https://cloud.yandex.com +// Yandex.Cloud LLC : https://cloud.yandex.com // Submitted by Alexander Lodin yandexcloud.net storage.yandexcloud.net @@ -14207,13 +15719,7 @@ yolasite.com // Yombo : https://yombo.net // Submitted by Mitch Schwenk -ybo.faith yombo.me -homelink.one -ybo.party -ybo.review -ybo.science -ybo.trade // Yunohost : https://yunohost.org // Submitted by Valentin Grimaud @@ -14226,6 +15732,14 @@ noho.st za.net za.org +// ZAP-Hosting GmbH & Co. KG : https://zap-hosting.com +// Submitted by Julian Alker +zap.cloud + +// Zeabur : https://zeabur.com/ +// Submitted by Zeabur Team +zeabur.app + // Zine EOOD : https://zine.bg/ // Submitted by Martin Angelov bss.design From 0240fc62405b95e877a15b19125e623cc87bdae1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 21:03:56 -0500 Subject: [PATCH 103/134] Update dependency org.jsoup:jsoup to v1.18.3 (#8601) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 33f1eadb6a96..5521cc37e75d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,7 +57,7 @@ hamcrestLibrary = "org.hamcrest:hamcrest-library:3.0" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" jettyClient = "org.eclipse.jetty:jetty-client:9.4.56.v20240826" jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.23" -jsoup = "org.jsoup:jsoup:1.18.1" +jsoup = "org.jsoup:jsoup:1.18.3" junit = "junit:junit:4.13.2" junit-ktx = "androidx.test.ext:junit-ktx:1.2.1" junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "org-junit-jupiter" } From 9a064c42ad1ae705030375d217d10c9683a7ce3d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 21:29:01 -0500 Subject: [PATCH 104/134] Update dependency com.puppycrawl.tools:checkstyle to v10.20.2 (#8603) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5521cc37e75d..64236a2e71f8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] biz-aQute-bnd = "6.4.0" -checkStyle = "10.19.0" +checkStyle = "10.20.2" com-squareup-moshi = "1.15.1" com-squareup-okio = "3.9.1" de-mannodermaus-junit5 = "1.6.0" From 4069b8529dc7a8d34ec4471df3e2967f4af63f35 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 22:03:28 -0500 Subject: [PATCH 105/134] Update dependency com.vanniktech:gradle-maven-publish-plugin to v0.30.0 (#8604) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 64236a2e71f8..a32837f07402 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -48,7 +48,7 @@ gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.0.1" gradlePlugin-graal = "com.palantir.graal:gradle-graal:0.12.0" gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } gradlePlugin-kotlinSerialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } -gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.29.0" +gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.30.0" gradlePlugin-mavenSympathy = "io.github.usefulness.maven-sympathy:io.github.usefulness.maven-sympathy.gradle.plugin:0.3.0" gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" From 06402b57a7c49bf43fc2c678c309c4b161516e65 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Dec 2024 22:15:36 -0500 Subject: [PATCH 106/134] Update dependency net.ltgt.gradle:gradle-errorprone-plugin to v4.1.0 (#8605) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a32837f07402..f4b21b528d05 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -44,7 +44,7 @@ gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.2" gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.16.3" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } gradlePlugin-dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.20" -gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.0.1" +gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.1.0" gradlePlugin-graal = "com.palantir.graal:gradle-graal:0.12.0" gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } gradlePlugin-kotlinSerialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } From db1776e0239321a4691b855851af8fa99ae45fac Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Wed, 4 Dec 2024 16:54:56 -1000 Subject: [PATCH 107/134] Acquire fewer locks in TaskRunner (#8394) * Acquire fewer locks in TaskRunner Previously each run did this: - acquire a lock to take a task - acquire a lock to finish a task - if crashed, acquire a lock to start a new thread So to run 10 tasks without any crashes, we'd acquire the lock 20 times. With this update, we do this: - acquire a lock to take the first task - acquire a lock to release task N and take task N + 1 So to run 10 tasks without any crashes, we now acquire the lock 11 times. * Spotless * Fixup interruptStopsThread test Don't assert the state of the global TaskRunner, it's already polluted from the side-effects of earlier tests. --------- Co-authored-by: Jesse Wilson --- .../okhttp3/internal/concurrent/TaskRunner.kt | 67 +++++++++---------- .../internal/concurrent/TaskRunnerTest.kt | 10 +-- .../internal/connection/ConnectionPoolTest.kt | 26 ++++--- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt index dc62f8c1a528..01137cea4f4b 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt @@ -30,7 +30,6 @@ import okhttp3.internal.connection.Locks.newLockCondition import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.okHttpName import okhttp3.internal.threadFactory -import okhttp3.internal.threadName /** * A set of worker threads that are shared among a set of task queues. @@ -74,31 +73,36 @@ class TaskRunner( private val runnable: Runnable = object : Runnable { override fun run() { - var incrementedRunCallCount = false - while (true) { - val task = - this@TaskRunner.withLock { - if (!incrementedRunCallCount) { - incrementedRunCallCount = true - runCallCount++ + var task: Task = + withLock { + runCallCount++ + awaitTaskToRun() + } ?: return + + val currentThread = Thread.currentThread() + val oldName = currentThread.name + try { + while (true) { + currentThread.name = task.name + val delayNanos = + logger.logElapsed(task, task.queue!!) { + task.runOnce() } + + // A task ran successfully. Update the execution state and take the next task. + task = withLock { + afterRun(task, delayNanos, true) awaitTaskToRun() } ?: return - - logger.logElapsed(task, task.queue!!) { - var completedNormally = false - try { - runTask(task) - completedNormally = true - } finally { - // If the task is crashing start another thread to service the queues. - if (!completedNormally) { - this@TaskRunner.withLock { - startAnotherThread() - } - } - } } + } catch (thrown: Throwable) { + // A task failed. Update execution state and re-throw the exception. + withLock { + afterRun(task, -1L, false) + } + throw thrown + } finally { + currentThread.name = oldName } } } @@ -132,22 +136,10 @@ class TaskRunner( busyQueues.add(queue) } - private fun runTask(task: Task) { - threadName(task.name) { - var delayNanos = -1L - try { - delayNanos = task.runOnce() - } finally { - this.withLock { - afterRun(task, delayNanos) - } - } - } - } - private fun afterRun( task: Task, delayNanos: Long, + completedNormally: Boolean, ) { lock.assertHeld() @@ -165,6 +157,11 @@ class TaskRunner( if (queue.futureTasks.isNotEmpty()) { readyQueues.add(queue) + + // If the task crashed, start another thread to run the next task. + if (!completedNormally) { + startAnotherThread() + } } } diff --git a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt index 36b0c4c72b00..8675eb99caed 100644 --- a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt @@ -95,11 +95,11 @@ class TaskRunnerTest { assertThat(testLogHandler.takeAll()).containsExactly( "FINE: Q10000 scheduled after 100 µs: task", "FINE: Q10000 starting : task", - "FINE: Q10000 run again after 50 µs: task", "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 run again after 50 µs: task", "FINE: Q10000 starting : task", - "FINE: Q10000 run again after 150 µs: task", "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 run again after 150 µs: task", "FINE: Q10000 starting : task", "FINE: Q10000 finished run in 0 µs: task", ) @@ -137,8 +137,8 @@ class TaskRunnerTest { "FINE: Q10000 scheduled after 100 µs: task", "FINE: Q10000 starting : task", "FINE: Q10000 scheduled after 50 µs: task", - "FINE: Q10000 already scheduled : task", "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 already scheduled : task", "FINE: Q10000 starting : task", "FINE: Q10000 finished run in 0 µs: task", ) @@ -176,8 +176,8 @@ class TaskRunnerTest { "FINE: Q10000 scheduled after 100 µs: task", "FINE: Q10000 starting : task", "FINE: Q10000 scheduled after 200 µs: task", - "FINE: Q10000 run again after 50 µs: task", "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 run again after 50 µs: task", "FINE: Q10000 starting : task", "FINE: Q10000 finished run in 0 µs: task", ) @@ -306,8 +306,8 @@ class TaskRunnerTest { assertThat(testLogHandler.takeAll()).containsExactly( "FINE: Q10000 scheduled after 100 µs: task", "FINE: Q10000 starting : task", - "FINE: Q10000 run again after 50 µs: task", "FINE: Q10000 finished run in 0 µs: task", + "FINE: Q10000 run again after 50 µs: task", "FINE: Q10000 starting : task", "FINE: Q10000 finished run in 0 µs: task", ) diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt index 7ecceb09f3ea..74718ae1acf8 100644 --- a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt +++ b/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt @@ -28,6 +28,7 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.TestUtil.awaitGarbageCollection import okhttp3.internal.concurrent.TaskRunner +import okhttp3.internal.concurrent.TaskRunner.RealBackend import okhttp3.internal.connection.Locks.withLock import okhttp3.internal.http2.Http2 import okhttp3.internal.http2.Http2Connection @@ -184,24 +185,29 @@ class ConnectionPoolTest { } @Test fun interruptStopsThread() { - val realTaskRunner = TaskRunner.INSTANCE + val taskRunnerThreads = mutableListOf() + val taskRunner = + TaskRunner( + RealBackend { runnable -> + Thread(runnable, "interruptStopsThread TaskRunner") + .also { taskRunnerThreads += it } + }, + ) + val pool = factory.newConnectionPool( - taskRunner = TaskRunner.INSTANCE, + taskRunner = taskRunner, maxIdleConnections = 2, ) factory.newConnection(pool, routeA1) - assertThat(realTaskRunner.activeQueues()).isNotEmpty() + assertThat(taskRunner.activeQueues()).isNotEmpty() + assertThat(taskRunnerThreads).isNotEmpty() Thread.sleep(100) - val threads = arrayOfNulls(Thread.activeCount() * 2) - Thread.enumerate(threads) - for (t in threads) { - if (t != null && t.name == "OkHttp TaskRunner") { - t.interrupt() - } + for (t in taskRunnerThreads) { + t.interrupt() } Thread.sleep(100) - assertThat(realTaskRunner.activeQueues()).isEmpty() + assertThat(taskRunner.activeQueues()).isEmpty() } @Test fun connectionPreWarmingHttp1() { From e1da8bc50ee4e7fc284e07a824846037186bf1c6 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sun, 8 Dec 2024 14:59:35 +0000 Subject: [PATCH 108/134] Dependency bumps (#8611) --- build.gradle.kts | 7 ++++--- buildSrc/build.gradle.kts | 6 +++++- gradle.properties | 10 ++++------ gradle/libs.versions.toml | 15 ++++++++------- gradle/wrapper/gradle-wrapper.properties | 2 +- okcurl/build.gradle.kts | 2 +- .../kotlin/okhttp3/coroutines/ExecuteAsyncTest.kt | 3 +++ okhttp/build.gradle.kts | 8 ++++---- 8 files changed, 30 insertions(+), 23 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 42c6bdee9feb..3f316981fb88 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,13 +3,14 @@ import com.diffplug.gradle.spotless.SpotlessExtension import com.vanniktech.maven.publish.MavenPublishBaseExtension import com.vanniktech.maven.publish.SonatypeHost -import java.net.URI import kotlinx.validation.ApiValidationExtension import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.jetbrains.dokka.gradle.DokkaTaskPartial +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferExtension +import java.net.URI buildscript { dependencies { @@ -143,8 +144,8 @@ subprojects { } tasks.withType { - kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() + compilerOptions { + jvmTarget.set(JvmTarget.JVM_1_8) freeCompilerArgs = listOf( "-Xjvm-default=all", ) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index e30c56b5d823..90a3bde87bea 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -23,5 +23,9 @@ repositories { } dependencies { - implementation("biz.aQute.bnd:biz.aQute.bnd.gradle:6.4.0") + // TODO (https://github.com/square/okhttp/issues/8612) we will need a consistent version + // 7.1.0 is used because it avoids this error + // Could not create an instance of type aQute.bnd.gradle.BundleTaskExtension. + // Cannot change attributes of configuration ':native-image-tests:compileClasspath' after it has been locked for mutation + implementation("biz.aQute.bnd:biz.aQute.bnd.gradle:7.1.0") } diff --git a/gradle.properties b/gradle.properties index d963d6a5a396..c7af0b38dfb6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,13 +1,11 @@ org.gradle.caching=true -org.gradle.jvmargs='-Dfile.encoding=UTF-8' org.gradle.parallel=true -android.enableJetifier=true + android.useAndroidX=true -kotlin.mpp.stability.nowarn=true -kotlin.js.compiler=ir -kotlin.incremental.js.ir=true + androidBuild=false graalBuild=false loomBuild=false containerTests=false -android.experimental.lint.version=8.2.0 + +org.gradle.jvmargs='-Dfile.encoding=UTF-8' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f4b21b528d05..8f30028e5411 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,17 +1,18 @@ [versions] +# 7.0.0 is JDK 17+ https://github.com/bndtools/bnd/wiki/Changes-in-7.0.0 biz-aQute-bnd = "6.4.0" checkStyle = "10.20.2" com-squareup-moshi = "1.15.1" com-squareup-okio = "3.9.1" de-mannodermaus-junit5 = "1.6.0" graalvm = "22.3.2" -kotlinx-serialization = "1.6.3" -ksp = "1.9.24-1.0.20" +kotlinx-serialization = "1.7.3" +ksp = "2.1.0-1.0.29" mockserverClient = "5.15.0" org-bouncycastle = "1.76" org-conscrypt = "2.5.2" -org-jetbrains-coroutines = "1.8.1" -org-jetbrains-kotlin = "1.9.25" +org-jetbrains-coroutines = "1.9.0" +org-jetbrains-kotlin = "2.1.0" org-junit-jupiter = "5.11.3" retrofit = "2.11.0" testcontainers = "1.20.4" @@ -38,7 +39,7 @@ conscrypt-openjdk = { module = "org.conscrypt:conscrypt-openjdk-uber", version.r converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" } eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.21.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" -gradlePlugin-android = "com.android.tools.build:gradle:8.2.0" +gradlePlugin-android = "com.android.tools.build:gradle:8.7.3" gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.2.0" gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.2" gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.16.3" @@ -87,14 +88,14 @@ openjsse = "org.openjsse:openjsse:1.1.14" playservices-safetynet = "com.google.android.gms:play-services-safetynet:18.1.0" retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } robolectric-android = "org.robolectric:android-all:14-robolectric-10818077" -robolectric = "org.robolectric:robolectric:4.12.2" +robolectric = "org.robolectric:robolectric:4.14.1" signature-android-apilevel21 = "net.sf.androidscents.signature:android-api-level-21:5.0.1_r2" signature-android-apilevel24 = "net.sf.androidscents.signature:android-api-level-24:7.0_r2" squareup-moshi = { module = "com.squareup.moshi:moshi", version.ref = "com-squareup-moshi" } squareup-moshi-compiler = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "com-squareup-moshi" } squareup-moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "com-squareup-moshi" } squareup-okhttp-icu = "com.squareup.okhttpicu:okhttp-icu:0.2.0" -squareup-kotlinPoet = "com.squareup:kotlinpoet:1.17.0" +squareup-kotlinPoet = "com.squareup:kotlinpoet:1.18.1" squareup-okio = { module = "com.squareup.okio:okio", version.ref = "com-squareup-okio" } squareup-okio-fakefilesystem = { module = "com.squareup.okio:okio-fakefilesystem", version.ref = "com-squareup-okio" } squareup-okio-nodefilesystem = { module = "com.squareup.okio:okio-nodefilesystem", version.ref = "com-squareup-okio" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e6aba2515d54..c1d5e0185987 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/okcurl/build.gradle.kts b/okcurl/build.gradle.kts index 77734c77c77d..868ee0ee0d71 100644 --- a/okcurl/build.gradle.kts +++ b/okcurl/build.gradle.kts @@ -12,7 +12,7 @@ plugins { val copyResourcesTemplates = tasks.register("copyResourcesTemplates") { from("src/main/resources-templates") - into("$buildDir/generated/resources-templates") + into(layout.buildDirectory.dir("generated/resources-templates")) expand("projectVersion" to "${project.version}") filteringCharset = Charsets.UTF_8.toString() } diff --git a/okhttp-coroutines/src/test/kotlin/okhttp3/coroutines/ExecuteAsyncTest.kt b/okhttp-coroutines/src/test/kotlin/okhttp3/coroutines/ExecuteAsyncTest.kt index 6f436ba0bf60..1a4d252ec1d2 100644 --- a/okhttp-coroutines/src/test/kotlin/okhttp3/coroutines/ExecuteAsyncTest.kt +++ b/okhttp-coroutines/src/test/kotlin/okhttp3/coroutines/ExecuteAsyncTest.kt @@ -14,6 +14,8 @@ * limitations under the License. * */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package okhttp3.coroutines import assertk.assertThat @@ -25,6 +27,7 @@ import kotlin.test.assertFailsWith import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.job diff --git a/okhttp/build.gradle.kts b/okhttp/build.gradle.kts index 084db6e649d4..60a7aa6cf63c 100644 --- a/okhttp/build.gradle.kts +++ b/okhttp/build.gradle.kts @@ -19,7 +19,7 @@ fun ByteArray.toByteStringExpression(): String { val copyKotlinTemplates = tasks.register("copyKotlinTemplates") { from("src/main/kotlinTemplates") - into("$buildDir/generated/sources/kotlinTemplates") + into(layout.buildDirectory.dir("generated/sources/kotlinTemplates")) // Tag as an input to regenerate after an update inputs.file("src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") @@ -44,9 +44,9 @@ dependencies { generateIdnaMappingTableConfiguration(projects.okhttpIdnaMappingTable) } val generateIdnaMappingTable by tasks.creating(JavaExec::class.java) { - outputs.dir("$buildDir/generated/sources/idnaMappingTable") + outputs.dir(layout.buildDirectory.dir("generated/sources/idnaMappingTable")) mainClass.set("okhttp3.internal.idn.GenerateIdnaMappingTableCode") - args("$buildDir/generated/sources/idnaMappingTable") + args(layout.buildDirectory.dir("generated/sources/idnaMappingTable").get()) classpath = generateIdnaMappingTableConfiguration } @@ -109,7 +109,7 @@ val osgiTestDeploy: Configuration by configurations.creating val copyOsgiTestDeployment by tasks.creating(Copy::class.java) { from(osgiTestDeploy) - into("$buildDir/resources/test/okhttp3/osgi/deployments") + into(layout.buildDirectory.dir("resources/test/okhttp3/osgi/deployments")) } tasks.getByName("test") { dependsOn(copyOsgiTestDeployment) From 169ece974752bc5b61d5c4e07c676049ee6bfd9d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 8 Dec 2024 20:07:30 -0500 Subject: [PATCH 109/134] Update com.squareup.moshi to v1.15.2 (#8614) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8f30028e5411..2da867ae4261 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ # 7.0.0 is JDK 17+ https://github.com/bndtools/bnd/wiki/Changes-in-7.0.0 biz-aQute-bnd = "6.4.0" checkStyle = "10.20.2" -com-squareup-moshi = "1.15.1" +com-squareup-moshi = "1.15.2" com-squareup-okio = "3.9.1" de-mannodermaus-junit5 = "1.6.0" graalvm = "22.3.2" From 117d9efcc8c709882033ab836bf5bbf80d764b46 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 08:52:14 +0000 Subject: [PATCH 110/134] Update dependency org.eclipse.platform:org.eclipse.osgi to v3.22.0 (#8615) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2da867ae4261..35864dbc17fb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,7 +37,7 @@ codehaus-signature-java18 = "org.codehaus.mojo.signature:java18:1.0" conscrypt-android = { module = "org.conscrypt:conscrypt-android", version.ref = "org-conscrypt" } conscrypt-openjdk = { module = "org.conscrypt:conscrypt-openjdk-uber", version.ref = "org-conscrypt" } converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" } -eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.21.0" +eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.22.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" gradlePlugin-android = "com.android.tools.build:gradle:8.7.3" gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.2.0" From 38bab5dec182c63525a06d30ebde01d2839d2a77 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 15 Dec 2024 15:12:30 +0200 Subject: [PATCH 111/134] Update plugin org.gradle.toolchains.foojay-resolver-convention to v0.9.0 (#8616) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 89ddf571639f..0b7f1566c4f3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,7 +3,7 @@ import java.util.Properties rootProject.name = "okhttp-parent" plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version("0.8.0") + id("org.gradle.toolchains.foojay-resolver-convention") version("0.9.0") } include(":mockwebserver") From fb22f4973e96f6b81a856e400463d6b386d33507 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 21 Dec 2024 10:56:29 +0200 Subject: [PATCH 112/134] Update to official GraalVM tooling (#8613) --- .github/workflows/build.yml | 27 +++- build.gradle.kts | 15 +- gradle/libs.versions.toml | 7 +- native-image-tests/README.md | 11 +- native-image-tests/build.gradle.kts | 60 +++---- .../okhttp3/nativeImage/TestRegistration.kt | 23 +++ .../src/main/kotlin/okhttp3/DotListener.kt | 77 --------- .../main/kotlin/okhttp3/GenerateClassList.kt | 56 ------- .../src/main/kotlin/okhttp3/RunTests.kt | 153 ------------------ .../main/kotlin/okhttp3/TestRegistration.kt | 109 ------------- .../src/main/resources/testlist.txt | 86 ---------- .../nativeImage/NativeImageTestsTest.kt | 58 ------- .../nativeImage}/PublicSuffixDatabaseTest.kt | 2 +- .../kotlin/okhttp3/nativeImage}/SampleTest.kt | 8 +- .../okhttp/nit/resource-config.json | 3 +- okcurl/build.gradle.kts | 21 +-- okcurl/src/main/kotlin/okhttp3/curl/Main.kt | 54 ++++--- .../kotlin/okhttp3/curl/MainCommandLine.kt | 1 + .../src/test/kotlin/okhttp3/curl/MainTest.kt | 1 + .../test/kotlin/okhttp3/curl/OkcurlTest.kt | 1 + .../okhttp3/dnsoverhttps/DnsOverHttpsTest.kt | 3 + .../logging/HttpLoggingInterceptorTest.kt | 7 +- .../logging/LoggingEventListenerTest.kt | 3 + .../sse/internal/EventSourceHttpTest.kt | 3 + .../sse/internal/EventSourcesHttpTest.kt | 3 + .../okhttp3/internal/graal/OkHttpFeature.kt | 8 +- .../okhttp/okhttp/native-image.properties | 2 +- 27 files changed, 167 insertions(+), 635 deletions(-) create mode 100644 native-image-tests/src/graal/java/okhttp3/nativeImage/TestRegistration.kt delete mode 100644 native-image-tests/src/main/kotlin/okhttp3/DotListener.kt delete mode 100644 native-image-tests/src/main/kotlin/okhttp3/GenerateClassList.kt delete mode 100644 native-image-tests/src/main/kotlin/okhttp3/RunTests.kt delete mode 100644 native-image-tests/src/main/kotlin/okhttp3/TestRegistration.kt delete mode 100644 native-image-tests/src/main/resources/testlist.txt delete mode 100644 native-image-tests/src/test/kotlin/okhttp3/nativeImage/NativeImageTestsTest.kt rename native-image-tests/src/{main/kotlin/okhttp3 => test/kotlin/okhttp3/nativeImage}/PublicSuffixDatabaseTest.kt (97%) rename native-image-tests/src/{main/kotlin/okhttp3 => test/kotlin/okhttp3/nativeImage}/SampleTest.kt (87%) rename native-image-tests/src/{main => test}/resources/META-INF/native-image/okhttp/nit/resource-config.json (69%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 72cc4c33c378..6f7946fa7691 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,6 +78,15 @@ jobs: distribution: 'zulu' java-version: 17 + - uses: graalvm/setup-graalvm@v1 + with: + distribution: 'graalvm' + java-version: 21 + github-token: ${{ secrets.GITHUB_TOKEN }} + cache: 'gradle' + native-image-job-reports: true + components: 'native-image' + - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 @@ -446,20 +455,26 @@ jobs: distribution: 'zulu' java-version: 17 + - uses: graalvm/setup-graalvm@v1 + with: + distribution: 'graalvm' + java-version: 21 + github-token: ${{ secrets.GITHUB_TOKEN }} + cache: 'gradle' + native-image-job-reports: true + components: 'native-image' + - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - name: Build okcurl - run: ./gradlew okcurl:nativeImage + run: ./gradlew okcurl:nativeBuild - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - - name: Build ConsoleLauncher - run: ./gradlew -PgraalBuild=true native-image-tests:nativeImage - - - name: Run Checks - run: ./native-image-tests/build/graal/ConsoleLauncher + - name: Run native-image tests + run: ./gradlew -PgraalBuild=true native-image-tests:nativeTest testandroid: runs-on: ubuntu-latest diff --git a/build.gradle.kts b/build.gradle.kts index 3f316981fb88..4ae7ce2c73d4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,7 +19,6 @@ buildscript { classpath(libs.gradlePlugin.kotlinSerialization) classpath(libs.gradlePlugin.androidJunit5) classpath(libs.gradlePlugin.android) - classpath(libs.gradlePlugin.graal) classpath(libs.gradlePlugin.bnd) classpath(libs.gradlePlugin.shadow) classpath(libs.gradlePlugin.animalsniffer) @@ -28,6 +27,7 @@ buildscript { classpath(libs.gradlePlugin.mavenPublish) classpath(libs.gradlePlugin.binaryCompatibilityValidator) classpath(libs.gradlePlugin.mavenSympathy) + classpath(libs.gradlePlugin.graalvmBuildTools) } repositories { @@ -143,9 +143,16 @@ subprojects { signature(rootProject.libs.codehaus.signature.java18) { artifact { type = "signature" } } } + val javaVersionSetting = when (project.name) { + "okcurl", "native-image-tests" -> "11" + else -> "1.8" + } + val projectJvmTarget = JvmTarget.fromTarget(javaVersionSetting) + val projectJavaVersion = JavaVersion.toVersion(javaVersionSetting) + tasks.withType { compilerOptions { - jvmTarget.set(JvmTarget.JVM_1_8) + jvmTarget.set(projectJvmTarget) freeCompilerArgs = listOf( "-Xjvm-default=all", ) @@ -214,8 +221,8 @@ subprojects { } tasks.withType { - sourceCompatibility = JavaVersion.VERSION_1_8.toString() - targetCompatibility = JavaVersion.VERSION_1_8.toString() + sourceCompatibility = projectJavaVersion.toString() + targetCompatibility = projectJavaVersion.toString() } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 35864dbc17fb..a8fcf8b45950 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ checkStyle = "10.20.2" com-squareup-moshi = "1.15.2" com-squareup-okio = "3.9.1" de-mannodermaus-junit5 = "1.6.0" -graalvm = "22.3.2" +graalvm = "24.1.1" kotlinx-serialization = "1.7.3" ksp = "2.1.0-1.0.29" mockserverClient = "5.15.0" @@ -32,13 +32,14 @@ bouncycastle-bcprov = { module = "org.bouncycastle:bcprov-jdk15to18", version.re bouncycastle-bctls = { module = "org.bouncycastle:bctls-jdk15to18", version.ref = "org-bouncycastle" } brotli-dec = "org.brotli:dec:0.1.2" checkStyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkStyle" } -clikt = "com.github.ajalt.clikt:clikt:4.4.0" +clikt = "com.github.ajalt.clikt:clikt:5.0.2" codehaus-signature-java18 = "org.codehaus.mojo.signature:java18:1.0" conscrypt-android = { module = "org.conscrypt:conscrypt-android", version.ref = "org-conscrypt" } conscrypt-openjdk = { module = "org.conscrypt:conscrypt-openjdk-uber", version.ref = "org-conscrypt" } converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" } eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.22.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" +graal-sdk = { module = "org.graalvm.sdk:graal-sdk", version.ref = "graalvm" } gradlePlugin-android = "com.android.tools.build:gradle:8.7.3" gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.2.0" gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.2" @@ -46,7 +47,7 @@ gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compat gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } gradlePlugin-dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.20" gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.1.0" -gradlePlugin-graal = "com.palantir.graal:gradle-graal:0.12.0" +gradlePlugin-graalvmBuildTools = "org.graalvm.buildtools.native:org.graalvm.buildtools.native.gradle.plugin:0.10.4" gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } gradlePlugin-kotlinSerialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "org-jetbrains-kotlin" } gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.30.0" diff --git a/native-image-tests/README.md b/native-image-tests/README.md index b6a9ff6f5e7b..d0555882bcb0 100644 --- a/native-image-tests/README.md +++ b/native-image-tests/README.md @@ -3,21 +3,12 @@ Native Image Tests This executes OkHttp's test suite inside a Graalvm image. -Build the Native Image ----------------------- - -Compile the classes and metadata into a Graalvm native image. - -``` -./gradlew --info native-image-tests:nativeImage -``` - Execute ------- The native image runs JUnit 5 tests in the project. ``` -./native-image-tests/build/graal/ConsoleLauncher +./gradlew --info native-image-tests:nativeTest ``` diff --git a/native-image-tests/build.gradle.kts b/native-image-tests/build.gradle.kts index e585002458a8..250aea22ac39 100644 --- a/native-image-tests/build.gradle.kts +++ b/native-image-tests/build.gradle.kts @@ -1,10 +1,26 @@ -import org.apache.tools.ant.taskdefs.condition.Os - plugins { - id("com.palantir.graal") + id("org.graalvm.buildtools.native") kotlin("jvm") } +animalsniffer { + isIgnoreFailures = true +} + +val graal by sourceSets.creating + +sourceSets { + named("graal") {} + test { + java.srcDirs( + "../okhttp-brotli/src/test/java", + "../okhttp-dnsoverhttps/src/test/java", + "../okhttp-logging-interceptor/src/test/java", + "../okhttp-sse/src/test/java", + ) + } +} + dependencies { implementation(libs.junit.jupiter.api) implementation(libs.junit.jupiter.engine) @@ -21,7 +37,6 @@ dependencies { implementation(projects.mockwebserver3) implementation(projects.mockwebserver) implementation(projects.okhttpJavaNetCookiejar) - implementation(projects.mockwebserver3Junit4) implementation(projects.mockwebserver3Junit5) implementation(libs.aqute.resolve) implementation(libs.junit.jupiter.api) @@ -30,33 +45,24 @@ dependencies { implementation(libs.kotlin.test.common) implementation(libs.kotlin.test.junit) - implementation(libs.nativeImageSvm) - compileOnly(libs.findbugs.jsr305) -} -animalsniffer { - isIgnoreFailures = true + "graalCompileOnly"(libs.nativeImageSvm) + "graalCompileOnly"(libs.graal.sdk) + nativeImageTestCompileOnly(graal.output.classesDirs) } -sourceSets { - main { - java.srcDirs( - "../okhttp-brotli/src/test/java", - "../okhttp-dnsoverhttps/src/test/java", - "../okhttp-logging-interceptor/src/test/java", - "../okhttp-sse/src/test/java", - ) - } -} +graalvmNative { + testSupport = true -graal { - mainClass("okhttp3.RunTestsKt") - outputName("ConsoleLauncher") - graalVersion(libs.versions.graalvm.get()) - javaVersion("11") + binaries { + named("test") { + buildArgs.add("--features=okhttp3.nativeImage.TestRegistration") + buildArgs.add("--initialize-at-build-time=org.junit.platform.engine.TestTag") + buildArgs.add("--strict-image-heap") - option("--no-fallback") - option("--report-unsupported-elements-at-runtime") - option("-H:+ReportExceptionStackTraces") + // speed up development testing + buildArgs.add("-Ob") + } + } } diff --git a/native-image-tests/src/graal/java/okhttp3/nativeImage/TestRegistration.kt b/native-image-tests/src/graal/java/okhttp3/nativeImage/TestRegistration.kt new file mode 100644 index 000000000000..7f8f29f5b657 --- /dev/null +++ b/native-image-tests/src/graal/java/okhttp3/nativeImage/TestRegistration.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 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.nativeImage + +import org.graalvm.nativeimage.hosted.Feature + +class TestRegistration : Feature { + override fun beforeAnalysis(access: Feature.BeforeAnalysisAccess) { + } +} diff --git a/native-image-tests/src/main/kotlin/okhttp3/DotListener.kt b/native-image-tests/src/main/kotlin/okhttp3/DotListener.kt deleted file mode 100644 index ed1bb03a3b77..000000000000 --- a/native-image-tests/src/main/kotlin/okhttp3/DotListener.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2020 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.OutputStream -import java.io.PrintStream -import org.junit.platform.engine.TestExecutionResult -import org.junit.platform.launcher.TestExecutionListener -import org.junit.platform.launcher.TestIdentifier -import org.junit.platform.launcher.TestPlan - -object DotListener : TestExecutionListener { - private var originalSystemErr: PrintStream? = null - private var originalSystemOut: PrintStream? = null - private var testCount = 0 - - override fun executionSkipped( - testIdentifier: TestIdentifier, - reason: String, - ) { - printStatus("-") - } - - private fun printStatus(s: String) { - if (++testCount % 80 == 0) { - printStatus("\n") - } - originalSystemErr?.print(s) - } - - override fun executionFinished( - testIdentifier: TestIdentifier, - testExecutionResult: TestExecutionResult, - ) { - if (!testIdentifier.isContainer) { - when (testExecutionResult.status!!) { - TestExecutionResult.Status.ABORTED -> printStatus("-") - TestExecutionResult.Status.FAILED -> printStatus("F") - TestExecutionResult.Status.SUCCESSFUL -> printStatus(".") - } - } - } - - override fun testPlanExecutionFinished(testPlan: TestPlan) { - originalSystemErr?.println() - } - - fun install() { - originalSystemOut = System.out - originalSystemErr = System.err - - System.setOut(object : PrintStream(OutputStream.nullOutputStream()) {}) - System.setErr(object : PrintStream(OutputStream.nullOutputStream()) {}) - } - - fun uninstall() { - originalSystemOut.let { - System.setOut(it) - } - originalSystemErr.let { - System.setErr(it) - } - } -} diff --git a/native-image-tests/src/main/kotlin/okhttp3/GenerateClassList.kt b/native-image-tests/src/main/kotlin/okhttp3/GenerateClassList.kt deleted file mode 100644 index 109a2cd3828e..000000000000 --- a/native-image-tests/src/main/kotlin/okhttp3/GenerateClassList.kt +++ /dev/null @@ -1,56 +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. - */ -package okhttp3 - -import java.io.File -import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor -import org.junit.platform.engine.discovery.DiscoverySelectors - -// TODO move to junit5 tags -val avoidedTests = - setOf( - "okhttp3.BouncyCastleTest", - "okhttp3.ConscryptTest", - "okhttp3.CorrettoTest", - "okhttp3.OpenJSSETest", - "okhttp3.internal.platform.Jdk8WithJettyBootPlatformTest", - "okhttp3.internal.platform.Jdk9PlatformTest", - "okhttp3.internal.platform.PlatformTest", - "okhttp3.internal.platform.android.AndroidSocketAdapterTest", - "okhttp3.osgi.OsgiTest", - // Hanging. - "okhttp3.CookiesTest", - // Hanging. - "okhttp3.WholeOperationTimeoutTest", - ) - -/** - * Run periodically to refresh the known set of working tests. - * - * TODO use filtering to allow skipping acceptable problem tests - */ -fun main() { - val knownTestFile = File("native-image-tests/src/main/resources/testlist.txt") - val testSelector = DiscoverySelectors.selectPackage("okhttp3") - val testClasses = - findTests(listOf(testSelector)) - .filter { it.isContainer } - .mapNotNull { (it as? ClassBasedTestDescriptor)?.testClass?.name } - .filterNot { it in avoidedTests } - .sorted() - .distinct() - knownTestFile.writeText(testClasses.joinToString("\n")) -} diff --git a/native-image-tests/src/main/kotlin/okhttp3/RunTests.kt b/native-image-tests/src/main/kotlin/okhttp3/RunTests.kt deleted file mode 100644 index 4fdd4c6b9651..000000000000 --- a/native-image-tests/src/main/kotlin/okhttp3/RunTests.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2020 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.File -import java.io.PrintWriter -import kotlin.system.exitProcess -import org.junit.jupiter.engine.JupiterTestEngine -import org.junit.platform.console.options.Theme -import org.junit.platform.engine.DiscoverySelector -import org.junit.platform.engine.TestDescriptor -import org.junit.platform.engine.TestEngine -import org.junit.platform.engine.discovery.DiscoverySelectors.selectClass -import org.junit.platform.launcher.Launcher -import org.junit.platform.launcher.LauncherDiscoveryRequest -import org.junit.platform.launcher.PostDiscoveryFilter -import org.junit.platform.launcher.TestExecutionListener -import org.junit.platform.launcher.core.EngineDiscoveryOrchestrator -import org.junit.platform.launcher.core.LauncherConfig -import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder -import org.junit.platform.launcher.core.LauncherFactory -import org.junit.platform.launcher.listeners.SummaryGeneratingListener - -/** - * Graal main method to run tests with minimal reflection and automatic settings. - * Uses the test list in native-image-tests/src/main/resources/testlist.txt. - */ -fun main(vararg args: String) { - System.setProperty("junit.jupiter.extensions.autodetection.enabled", "true") - - val inputFile = if (args.isNotEmpty()) File(args[0]) else null - val selectors = testSelectors(inputFile) - - val summaryListener = SummaryGeneratingListener() - val treeListener = treeListener() - - val jupiterTestEngine = buildTestEngine() - - val config = - LauncherConfig.builder() - .enableTestExecutionListenerAutoRegistration(false) - .enableTestEngineAutoRegistration(false) - .enablePostDiscoveryFilterAutoRegistration(false) - .addTestEngines(jupiterTestEngine) - .addTestExecutionListeners(DotListener, summaryListener, treeListener) - .build() - val launcher: Launcher = LauncherFactory.create(config) - - val request: LauncherDiscoveryRequest = buildRequest(selectors) - - DotListener.install() - - try { - launcher.execute(request) - } finally { - DotListener.uninstall() - } - - val summary = summaryListener.summary - summary.printTo(PrintWriter(System.out)) - - exitProcess(if (summary.testsFailedCount != 0L) -1 else 0) -} - -/** - * Builds the Junit Test Engine for the native image. - */ -fun buildTestEngine(): TestEngine = JupiterTestEngine() - -/** - * Returns a fixed set of test classes from testlist.txt, skipping any not found in the - * current classpath. The IDE runs with less classes to avoid conflicting module ownership. - */ -fun testSelectors(inputFile: File? = null): List { - val sampleTestClass = SampleTest::class.java - - val lines = - inputFile?.readLines() ?: sampleTestClass.getResource("/testlist.txt").readText().lines() - - val flatClassnameList = - lines - .filter { it.isNotBlank() } - - return flatClassnameList - .mapNotNull { - try { - selectClass(Class.forName(it, false, sampleTestClass.classLoader)) - } catch (cnfe: ClassNotFoundException) { - println("Missing test class: $cnfe") - null - } - } -} - -/** - * Builds a Junit Test Plan request for a fixed set of classes, or potentially a recursive package. - */ -fun buildRequest(selectors: List): LauncherDiscoveryRequest { - val request: LauncherDiscoveryRequest = - LauncherDiscoveryRequestBuilder.request() - // TODO replace junit.jupiter.extensions.autodetection.enabled with API approach. -// .enableImplicitConfigurationParameters(false) - .selectors(selectors) - .build() - return request -} - -/** - * Flattens a test filter into a list of specific test descriptors, usually individual method in a - * test class annotated with @Test. - */ -fun findTests(selectors: List): List { - val request: LauncherDiscoveryRequest = buildRequest(selectors) - val testEngine = buildTestEngine() - val filters = listOf() - val discoveryOrchestrator = EngineDiscoveryOrchestrator(listOf(testEngine), filters) - val discovered = discoveryOrchestrator.discover(request, EngineDiscoveryOrchestrator.Phase.EXECUTION) - - return discovered.getEngineTestDescriptor(testEngine).descendants.toList() -} - -/** - * Builds the awkwardly package private TreePrintingListener listener which we would like to use - * from ConsoleLauncher. - * - * https://github.com/junit-team/junit5/issues/2469 - */ -fun treeListener(): TestExecutionListener { - val colorPalette = - Class.forName("org.junit.platform.console.tasks.ColorPalette").getField("DEFAULT").apply { - isAccessible = true - }.get(null) - return Class.forName( - "org.junit.platform.console.tasks.TreePrintingListener", - ).declaredConstructors.first() - .apply { - isAccessible = true - } - .newInstance(PrintWriter(System.out), colorPalette, Theme.UNICODE) as TestExecutionListener -} diff --git a/native-image-tests/src/main/kotlin/okhttp3/TestRegistration.kt b/native-image-tests/src/main/kotlin/okhttp3/TestRegistration.kt deleted file mode 100644 index 0f882d4be118..000000000000 --- a/native-image-tests/src/main/kotlin/okhttp3/TestRegistration.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2020 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 com.oracle.svm.core.annotate.AutomaticFeature -import java.io.File -import java.lang.IllegalStateException -import org.graalvm.nativeimage.hosted.Feature -import org.graalvm.nativeimage.hosted.RuntimeClassInitialization -import org.graalvm.nativeimage.hosted.RuntimeReflection - -@AutomaticFeature -class TestRegistration : Feature { - override fun beforeAnalysis(access: Feature.BeforeAnalysisAccess) { - // Presumably needed for parsing the testlist.txt file. - RuntimeClassInitialization.initializeAtBuildTime(access.findClassByName("kotlin.text.Charsets")) - - registerKnownTests(access) - - registerJupiterClasses(access) - - registerParamProvider(access, "okhttp3.SampleTestProvider") - registerParamProvider(access, "okhttp3.internal.http.CancelModelParamProvider") - registerParamProvider(access, "okhttp3.internal.cache.FileSystemParamProvider") - registerParamProvider(access, "okhttp3.internal.http2.HttpOverHttp2Test\$ProtocolParamProvider") - registerParamProvider(access, "okhttp3.internal.cache.FileSystemParamProvider") - registerParamProvider(access, "okhttp3.WebPlatformUrlTest\$TestDataParamProvider") - } - - private fun registerParamProvider( - access: Feature.BeforeAnalysisAccess, - provider: String, - ) { - val providerClass = access.findClassByName(provider) - if (providerClass != null) { - registerTest(access, providerClass) - } else { - println("Missing $provider") - } - } - - private fun registerJupiterClasses(access: Feature.BeforeAnalysisAccess) { - registerStandardClass(access, "org.junit.jupiter.params.ParameterizedTestExtension") - registerStandardClass(access, "org.junit.platform.console.tasks.TreePrintingListener") - } - - private fun registerStandardClass( - access: Feature.BeforeAnalysisAccess, - name: String, - ) { - val clazz: Class<*> = access.findClassByName(name) ?: throw IllegalStateException("Missing class $name") - RuntimeReflection.register(clazz) - clazz.declaredConstructors.forEach { - RuntimeReflection.register(it) - } - } - - private fun registerKnownTests(access: Feature.BeforeAnalysisAccess) { - val knownTestFile = File("src/main/resources/testlist.txt").absoluteFile - knownTestFile.readLines().forEach { - try { - val testClass = access.findClassByName(it) - - if (testClass != null) { - access.registerAsUsed(testClass) - registerTest(access, testClass) - } - } catch (e: Exception) { - // If you throw an exception here then native image building fails half way through - // silently without rewriting the binary. So we report noisily, but keep going and prefer - // running most tests still. - e.printStackTrace() - } - } - } - - private fun registerTest( - access: Feature.BeforeAnalysisAccess, - java: Class<*>, - ) { - access.registerAsUsed(java) - RuntimeReflection.register(java) - java.constructors.forEach { - RuntimeReflection.register(it) - } - java.declaredMethods.forEach { - RuntimeReflection.register(it) - } - java.declaredFields.forEach { - RuntimeReflection.register(it) - } - java.methods.forEach { - RuntimeReflection.register(it) - } - } -} diff --git a/native-image-tests/src/main/resources/testlist.txt b/native-image-tests/src/main/resources/testlist.txt deleted file mode 100644 index fdf740f21105..000000000000 --- a/native-image-tests/src/main/resources/testlist.txt +++ /dev/null @@ -1,86 +0,0 @@ -okhttp3.AddressTest -okhttp3.CacheControlTest -okhttp3.CacheCorruptionTest -okhttp3.CacheTest -okhttp3.CallHandshakeTest -okhttp3.CallKotlinTest -okhttp3.CallTest -okhttp3.CertificateChainCleanerTest -okhttp3.CertificatePinnerKotlinTest -okhttp3.CertificatePinnerTest -okhttp3.CipherSuiteTest -okhttp3.ConnectionCoalescingTest -okhttp3.ConnectionReuseTest -okhttp3.ConnectionSpecTest -okhttp3.CookieTest -okhttp3.DispatcherTest -okhttp3.DuplexTest -okhttp3.EventListenerTest -okhttp3.FormBodyTest -okhttp3.HandshakeTest -okhttp3.HeadersKotlinTest -okhttp3.HeadersTest -okhttp3.HttpUrlTest -okhttp3.InsecureForHostTest -okhttp3.InterceptorTest -okhttp3.KotlinDeprecationErrorTest -okhttp3.KotlinSourceModernTest -okhttp3.MediaTypeGetTest -okhttp3.MediaTypeTest -okhttp3.MultipartBodyTest -okhttp3.MultipartReaderTest -okhttp3.OkHttpClientTest -okhttp3.OkHttpTest -okhttp3.ProtocolTest -okhttp3.PublicSuffixDatabaseTest -okhttp3.PublicInternalApiTest -okhttp3.RequestTest -okhttp3.ResponseBodyTest -okhttp3.ResponseTest -okhttp3.SampleTest -okhttp3.ServerTruncatesRequestTest -okhttp3.SocksProxyTest -okhttp3.URLConnectionTest -okhttp3.WebPlatformUrlTest -okhttp3.brotli.BrotliInterceptorJavaApiTest -okhttp3.brotli.BrotliInterceptorTest -okhttp3.dnsoverhttps.DnsOverHttpsTest -okhttp3.dnsoverhttps.DnsRecordCodecTest -okhttp3.internal.UtilTest -okhttp3.internal.authenticator.JavaNetAuthenticatorTest -okhttp3.internal.cache.DiskLruCacheTest -okhttp3.internal.cache2.FileOperatorTest -okhttp3.internal.cache2.RelayTest -okhttp3.internal.concurrent.TaskLoggerTest -okhttp3.internal.concurrent.TaskRunnerRealBackendTest -okhttp3.internal.concurrent.TaskRunnerTest -okhttp3.internal.connection.ConnectionPoolTest -okhttp3.internal.connection.ConnectionSpecSelectorTest -okhttp3.internal.connection.RouteExceptionTest -okhttp3.internal.connection.RouteSelectorTest -okhttp3.internal.http.CancelTest -okhttp3.internal.http.HttpDateTest -okhttp3.internal.http.StatusLineTest -okhttp3.internal.http.ThreadInterruptTest -okhttp3.internal.http2.FrameLogTest -okhttp3.internal.http2.HpackTest -okhttp3.internal.http2.Http2ConnectionTest -okhttp3.internal.http2.Http2Test -okhttp3.internal.http2.HttpOverHttp2Test -okhttp3.internal.http2.HuffmanTest -okhttp3.internal.http2.SettingsTest -okhttp3.internal.publicsuffix.PublicSuffixDatabaseTest -okhttp3.internal.tls.CertificatePinnerChainValidationTest -okhttp3.internal.tls.ClientAuthTest -okhttp3.internal.tls.HostnameVerifierTest -okhttp3.internal.ws.MessageDeflaterInflaterTest -okhttp3.internal.ws.RealWebSocketTest -okhttp3.internal.ws.WebSocketExtensionsTest -okhttp3.internal.ws.WebSocketHttpTest -okhttp3.internal.ws.WebSocketReaderTest -okhttp3.internal.ws.WebSocketWriterTest -okhttp3.logging.HttpLoggingInterceptorTest -okhttp3.logging.IsProbablyUtf8Test -okhttp3.logging.LoggingEventListenerTest -okhttp3.sse.internal.EventSourceHttpTest -okhttp3.sse.internal.ServerSentEventIteratorTest diff --git a/native-image-tests/src/test/kotlin/okhttp3/nativeImage/NativeImageTestsTest.kt b/native-image-tests/src/test/kotlin/okhttp3/nativeImage/NativeImageTestsTest.kt deleted file mode 100644 index 6ba5f223e5f7..000000000000 --- a/native-image-tests/src/test/kotlin/okhttp3/nativeImage/NativeImageTestsTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2020 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.nativeImage - -import okhttp3.SampleTest -import okhttp3.findTests -import okhttp3.testSelectors -import okhttp3.treeListener -import org.junit.jupiter.api.Assertions.assertNotNull -import org.junit.jupiter.api.Test -import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor -import org.junit.platform.engine.discovery.DiscoverySelectors - -class NativeImageTestsTest { - @Test - fun testFindsFixedTestsForImage() { - val testSelector = testSelectors() - val x = findTests(testSelector) - - x.find { it is ClassBasedTestDescriptor && it.testClass == SampleTest::class.java } - } - - @Test - fun testFindsModuleTests() { - val testSelector = DiscoverySelectors.selectPackage("okhttp3") - val x = findTests(listOf(testSelector)) - - x.find { it is ClassBasedTestDescriptor && it.testClass == SampleTest::class.java } - } - - @Test - fun testFindsProjectTests() { - val testSelector = DiscoverySelectors.selectPackage("okhttp3") - val x = findTests(listOf(testSelector)) - - x.find { it is ClassBasedTestDescriptor && it.testClass == SampleTest::class.java } - } - - @Test - fun testTreeListener() { - val listener = treeListener() - - assertNotNull(listener) - } -} diff --git a/native-image-tests/src/main/kotlin/okhttp3/PublicSuffixDatabaseTest.kt b/native-image-tests/src/test/kotlin/okhttp3/nativeImage/PublicSuffixDatabaseTest.kt similarity index 97% rename from native-image-tests/src/main/kotlin/okhttp3/PublicSuffixDatabaseTest.kt rename to native-image-tests/src/test/kotlin/okhttp3/nativeImage/PublicSuffixDatabaseTest.kt index 175de8da30fc..be9388bd9c36 100644 --- a/native-image-tests/src/main/kotlin/okhttp3/PublicSuffixDatabaseTest.kt +++ b/native-image-tests/src/test/kotlin/okhttp3/nativeImage/PublicSuffixDatabaseTest.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3 +package okhttp3.nativeImage import assertk.assertThat import assertk.assertions.isEqualTo diff --git a/native-image-tests/src/main/kotlin/okhttp3/SampleTest.kt b/native-image-tests/src/test/kotlin/okhttp3/nativeImage/SampleTest.kt similarity index 87% rename from native-image-tests/src/main/kotlin/okhttp3/SampleTest.kt rename to native-image-tests/src/test/kotlin/okhttp3/nativeImage/SampleTest.kt index 73c07198e738..2e40576afd3e 100644 --- a/native-image-tests/src/main/kotlin/okhttp3/SampleTest.kt +++ b/native-image-tests/src/test/kotlin/okhttp3/nativeImage/SampleTest.kt @@ -13,18 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3 +package okhttp3.nativeImage import assertk.assertThat import assertk.assertions.isEqualTo import mockwebserver3.MockResponse import mockwebserver3.MockWebServer +import mockwebserver3.junit5.internal.MockWebServerExtension import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.OkHttpClientTestRule +import okhttp3.Request +import okhttp3.SimpleProvider import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.RegisterExtension import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ArgumentsSource +@ExtendWith(MockWebServerExtension::class) class SampleTest { @JvmField @RegisterExtension val clientRule = OkHttpClientTestRule() diff --git a/native-image-tests/src/main/resources/META-INF/native-image/okhttp/nit/resource-config.json b/native-image-tests/src/test/resources/META-INF/native-image/okhttp/nit/resource-config.json similarity index 69% rename from native-image-tests/src/main/resources/META-INF/native-image/okhttp/nit/resource-config.json rename to native-image-tests/src/test/resources/META-INF/native-image/okhttp/nit/resource-config.json index a91b6a761b04..500ef92fbef5 100644 --- a/native-image-tests/src/main/resources/META-INF/native-image/okhttp/nit/resource-config.json +++ b/native-image-tests/src/test/resources/META-INF/native-image/okhttp/nit/resource-config.json @@ -1,6 +1,5 @@ { "resources": [ - {"pattern": "testlist.txt"}, {"pattern": "web-platform-test-urltestdata.txt"} ] -} \ No newline at end of file +} diff --git a/okcurl/build.gradle.kts b/okcurl/build.gradle.kts index 868ee0ee0d71..f43d25a61bea 100644 --- a/okcurl/build.gradle.kts +++ b/okcurl/build.gradle.kts @@ -6,7 +6,7 @@ plugins { kotlin("jvm") id("org.jetbrains.dokka") id("com.vanniktech.maven.publish.base") - id("com.palantir.graal") + id("org.graalvm.buildtools.native") id("com.github.johnrengelman.shadow") } @@ -53,19 +53,12 @@ tasks.shadowJar { mergeServiceFiles() } -graal { - mainClass("okhttp3.curl.MainCommandLineKt") - outputName("okcurl") - graalVersion(libs.versions.graalvm.get()) - javaVersion("11") - - option("--no-fallback") - - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - // May be possible without, but autodetection is problematic on Windows 10 - // see https://github.com/palantir/gradle-graal - // see https://www.graalvm.org/docs/reference-manual/native-image/#prerequisites - windowsVsVarsPath("C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat") +graalvmNative { + binaries { + named("main") { + imageName = "okcurl" + mainClass = "okhttp3.curl.MainCommandLineKt" + } } } diff --git a/okcurl/src/main/kotlin/okhttp3/curl/Main.kt b/okcurl/src/main/kotlin/okhttp3/curl/Main.kt index 126af4c31dbb..c9b09179334a 100644 --- a/okcurl/src/main/kotlin/okhttp3/curl/Main.kt +++ b/okcurl/src/main/kotlin/okhttp3/curl/Main.kt @@ -16,9 +16,12 @@ package okhttp3.curl import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.core.Context import com.github.ajalt.clikt.parameters.arguments.argument +import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.flag +import com.github.ajalt.clikt.parameters.options.help import com.github.ajalt.clikt.parameters.options.multiple import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.int @@ -39,42 +42,54 @@ import okhttp3.internal.platform.Platform import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.LoggingEventListener -class Main : CliktCommand(name = NAME, help = "A curl for the next-generation web.") { - val method: String? by option("-X", "--request", help = "Specify request command to use") +class Main : CliktCommand(name = NAME) { + override val printHelpOnEmptyArgs = true - val data: String? by option("-d", "--data", help = "HTTP POST data") + override fun help(context: Context): String = "A curl for the next-generation web." - val headers: List? by option("-H", "--header", help = "Custom header to pass to server").multiple() + val method: String? by option("-X", "--request").help("Specify request command to use") - val userAgent: String by option("-A", "--user-agent", help = "User-Agent to send to server").default(NAME + "/" + versionString()) + val data: String? by option("-d", "--data").help("HTTP POST data") + + val headers: List? by option("-H", "--header").help("Custom header to pass to server").multiple() + + val userAgent: String by option( + "-A", + "--user-agent", + ).help( + "User-Agent to send to server", + ).default(NAME + "/" + versionString()) val connectTimeout: Int by option( "--connect-timeout", - help = "Maximum time allowed for connection (seconds)", + ).help( + "Maximum time allowed for connection (seconds)", ).int().default(DEFAULT_TIMEOUT) - val readTimeout: Int by option("--read-timeout", help = "Maximum time allowed for reading data (seconds)").int().default(DEFAULT_TIMEOUT) + val readTimeout: Int by option("--read-timeout").help("Maximum time allowed for reading data (seconds)").int() + .default(DEFAULT_TIMEOUT) val callTimeout: Int by option( "--call-timeout", - help = "Maximum time allowed for the entire call (seconds)", + ).help( + "Maximum time allowed for the entire call (seconds)", ).int().default(DEFAULT_TIMEOUT) - val followRedirects: Boolean by option("-L", "--location", help = "Follow redirects").flag() + val followRedirects: Boolean by option("-L", "--location").help("Follow redirects").flag() - val allowInsecure: Boolean by option("-k", "--insecure", help = "Allow connections to SSL sites without certs").flag() + val allowInsecure: Boolean by option("-k", "--insecure").help("Allow connections to SSL sites without certs").flag() - val showHeaders: Boolean by option("-i", "--include", help = "Include protocol headers in the output").flag() + val showHeaders: Boolean by option("-i", "--include").help("Include protocol headers in the output").flag() - val showHttp2Frames: Boolean by option("--frames", help = "Log HTTP/2 frames to STDERR").flag() + val showHttp2Frames: Boolean by option("--frames").help("Log HTTP/2 frames to STDERR").flag() - val referer: String? by option("-e", "--referer", help = "Referer URL") + val referer: String? by option("-e", "--referer").help("Referer URL") - val verbose: Boolean by option("-v", "--verbose", help = "Makes $NAME verbose during the operation").flag() + val verbose: Boolean by option("-v", "--verbose").help("Makes $NAME verbose during the operation").flag() - val sslDebug: Boolean by option(help = "Output SSL Debug").flag() + val sslDebug: Boolean by option("--sslDebug").help("Output SSL Debug").flag() - val url: String? by argument(name = "url", help = "Remote resource URL") + val url: String? by argument(name = "url").help("Remote resource URL") var client: Call.Factory? = null @@ -129,17 +144,20 @@ class Main : CliktCommand(name = NAME, help = "A curl for the next-generation we return prop.getProperty("version", "dev") } + @Suppress("TrustAllX509TrustManager", "CustomX509TrustManager") private fun createInsecureTrustManager(): X509TrustManager = object : X509TrustManager { override fun checkClientTrusted( chain: Array, authType: String, - ) {} + ) { + } override fun checkServerTrusted( chain: Array, authType: String, - ) {} + ) { + } override fun getAcceptedIssuers(): Array = arrayOf() } diff --git a/okcurl/src/main/kotlin/okhttp3/curl/MainCommandLine.kt b/okcurl/src/main/kotlin/okhttp3/curl/MainCommandLine.kt index 983048a8143d..b56011c07b9d 100644 --- a/okcurl/src/main/kotlin/okhttp3/curl/MainCommandLine.kt +++ b/okcurl/src/main/kotlin/okhttp3/curl/MainCommandLine.kt @@ -15,6 +15,7 @@ */ package okhttp3.curl +import com.github.ajalt.clikt.core.main import kotlin.system.exitProcess fun main(args: Array) { diff --git a/okcurl/src/test/kotlin/okhttp3/curl/MainTest.kt b/okcurl/src/test/kotlin/okhttp3/curl/MainTest.kt index 0a2598a2e694..ae31c41c2521 100644 --- a/okcurl/src/test/kotlin/okhttp3/curl/MainTest.kt +++ b/okcurl/src/test/kotlin/okhttp3/curl/MainTest.kt @@ -19,6 +19,7 @@ import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isNull import assertk.assertions.startsWith +import com.github.ajalt.clikt.core.parse import java.io.IOException import kotlin.test.Test import okhttp3.RequestBody diff --git a/okcurl/src/test/kotlin/okhttp3/curl/OkcurlTest.kt b/okcurl/src/test/kotlin/okhttp3/curl/OkcurlTest.kt index d632e8bae9f8..f7a68dbcbc0a 100644 --- a/okcurl/src/test/kotlin/okhttp3/curl/OkcurlTest.kt +++ b/okcurl/src/test/kotlin/okhttp3/curl/OkcurlTest.kt @@ -15,6 +15,7 @@ */ package okhttp3.curl +import com.github.ajalt.clikt.core.main import kotlin.test.Test class OkcurlTest { diff --git a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt index 34d602b36fe9..76f1a3b5392b 100644 --- a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt +++ b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsOverHttpsTest.kt @@ -31,6 +31,7 @@ import java.net.UnknownHostException import java.util.concurrent.TimeUnit import mockwebserver3.MockResponse import mockwebserver3.MockWebServer +import mockwebserver3.junit5.internal.MockWebServerExtension import okhttp3.Cache import okhttp3.Dns import okhttp3.OkHttpClient @@ -45,9 +46,11 @@ import org.junit.jupiter.api.Assertions.fail import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.RegisterExtension @Tag("Slowish") +@ExtendWith(MockWebServerExtension::class) class DnsOverHttpsTest { @RegisterExtension val platform = PlatformRule() diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt index 0c8549a171c7..dd73d7b418b5 100644 --- a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/HttpLoggingInterceptorTest.kt @@ -19,11 +19,12 @@ import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isLessThan import assertk.assertions.isLessThanOrEqualTo -import assertk.assertions.isSameAs +import assertk.assertions.isSameInstanceAs import assertk.assertions.matches import java.net.UnknownHostException import mockwebserver3.MockResponse import mockwebserver3.MockWebServer +import mockwebserver3.junit5.internal.MockWebServerExtension import okhttp3.HttpUrl import okhttp3.Interceptor import okhttp3.MediaType @@ -44,8 +45,10 @@ import org.junit.jupiter.api.Assertions.fail import org.junit.jupiter.api.Assumptions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.RegisterExtension +@ExtendWith(MockWebServerExtension::class) class HttpLoggingInterceptorTest { @RegisterExtension val platform = PlatformRule() @@ -104,7 +107,7 @@ class HttpLoggingInterceptorTest { @Test fun setLevelShouldReturnSameInstanceOfInterceptor() { for (level in Level.entries) { - assertThat(applicationInterceptor.setLevel(level)).isSameAs(applicationInterceptor) + assertThat(applicationInterceptor.setLevel(level)).isSameInstanceAs(applicationInterceptor) } } diff --git a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.kt b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.kt index 91b7463510f6..361ccd1cd973 100644 --- a/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.kt +++ b/okhttp-logging-interceptor/src/test/java/okhttp3/logging/LoggingEventListenerTest.kt @@ -23,6 +23,7 @@ import java.util.Arrays import mockwebserver3.MockResponse import mockwebserver3.MockWebServer import mockwebserver3.SocketPolicy.FailHandshake +import mockwebserver3.junit5.internal.MockWebServerExtension import okhttp3.HttpUrl import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient @@ -36,9 +37,11 @@ import okhttp3.testing.PlatformRule import org.junit.jupiter.api.Assertions.fail import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.RegisterExtension @Suppress("ktlint:standard:max-line-length") +@ExtendWith(MockWebServerExtension::class) class LoggingEventListenerTest { @RegisterExtension val platform = PlatformRule() diff --git a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceHttpTest.kt b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceHttpTest.kt index d4fbca2a1d4c..6484ecdee1f0 100644 --- a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceHttpTest.kt +++ b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourceHttpTest.kt @@ -21,6 +21,7 @@ import assertk.assertions.isEqualTo import java.util.concurrent.TimeUnit import mockwebserver3.MockResponse import mockwebserver3.MockWebServer +import mockwebserver3.junit5.internal.MockWebServerExtension import okhttp3.OkHttpClientTestRule import okhttp3.RecordingEventListener import okhttp3.Request @@ -31,10 +32,12 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.RegisterExtension import org.junitpioneer.jupiter.RetryingTest @Tag("Slowish") +@ExtendWith(MockWebServerExtension::class) class EventSourceHttpTest { @RegisterExtension val platform = PlatformRule() diff --git a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourcesHttpTest.kt b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourcesHttpTest.kt index 4b17e25665eb..3ceb99ea15d9 100644 --- a/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourcesHttpTest.kt +++ b/okhttp-sse/src/test/java/okhttp3/sse/internal/EventSourcesHttpTest.kt @@ -17,6 +17,7 @@ package okhttp3.sse.internal import mockwebserver3.MockResponse import mockwebserver3.MockWebServer +import mockwebserver3.junit5.internal.MockWebServerExtension import okhttp3.OkHttpClientTestRule import okhttp3.Request import okhttp3.sse.EventSources.processResponse @@ -25,9 +26,11 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.RegisterExtension @Tag("Slowish") +@ExtendWith(MockWebServerExtension::class) class EventSourcesHttpTest { @RegisterExtension val platform = PlatformRule() diff --git a/okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt b/okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt index 857ab26a2793..5845330584b2 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt +++ b/okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt @@ -18,7 +18,6 @@ package okhttp3.internal.graal import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement import org.graalvm.nativeimage.hosted.Feature -import org.graalvm.nativeimage.hosted.RuntimeResourceAccess /** * Automatic configuration of OkHttp for native images. @@ -27,10 +26,5 @@ import org.graalvm.nativeimage.hosted.RuntimeResourceAccess */ class OkHttpFeature : Feature { @IgnoreJRERequirement - override fun beforeAnalysis(access: Feature.BeforeAnalysisAccess?) { - RuntimeResourceAccess.addResource( - ClassLoader.getSystemClassLoader().getUnnamedModule(), - "okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz", - ) - } + override fun beforeAnalysis(access: Feature.BeforeAnalysisAccess?) = Unit } diff --git a/okhttp/src/main/resources/META-INF/native-image/okhttp/okhttp/native-image.properties b/okhttp/src/main/resources/META-INF/native-image/okhttp/okhttp/native-image.properties index fdb2df990d20..75cbefcdc5c1 100644 --- a/okhttp/src/main/resources/META-INF/native-image/okhttp/okhttp/native-image.properties +++ b/okhttp/src/main/resources/META-INF/native-image/okhttp/okhttp/native-image.properties @@ -1 +1 @@ -Args = -H:+AddAllCharsets -H:EnableURLProtocols=http,https --enable-https --features=okhttp3.internal.graal.OkHttpFeature +Args = -H:+AddAllCharsets --enable-http --enable-https --features=okhttp3.internal.graal.OkHttpFeature --report-unsupported-elements-at-runtime From 2281a4c2e4c09d7c7b310aa3a81941db28f5e9d4 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Tue, 24 Dec 2024 12:17:11 +0200 Subject: [PATCH 113/134] Build native-image on JDK 11+ (#8625) --- build.gradle.kts | 18 +++++++++++------- okcurl/build.gradle.kts | 20 +++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4ae7ce2c73d4..735e1c57e6cc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -77,6 +77,9 @@ allprojects { } } +val platform = System.getProperty("okhttp.platform", "jdk9") +val testJavaVersion = System.getProperty("test.java.version", "21").toInt() + /** Configure building for Java+Kotlin projects. */ subprojects { val project = this@subprojects @@ -143,10 +146,14 @@ subprojects { signature(rootProject.libs.codehaus.signature.java18) { artifact { type = "signature" } } } - val javaVersionSetting = when (project.name) { - "okcurl", "native-image-tests" -> "11" - else -> "1.8" - } + val javaVersionSetting = + if (testJavaVersion > 8 && (project.name == "okcurl" || project.name == "native-image-tests")) { + // Depends on native-image-tools which is 11+, but avoids on Java 8 tests + "11" + } else { + "1.8" + } + val projectJvmTarget = JvmTarget.fromTarget(javaVersionSetting) val projectJavaVersion = JavaVersion.toVersion(javaVersionSetting) @@ -159,9 +166,6 @@ subprojects { } } - val platform = System.getProperty("okhttp.platform", "jdk9") - val testJavaVersion = System.getProperty("test.java.version", "21").toInt() - val testRuntimeOnly: Configuration by configurations.getting dependencies { testRuntimeOnly(rootProject.libs.junit.jupiter.engine) diff --git a/okcurl/build.gradle.kts b/okcurl/build.gradle.kts index f43d25a61bea..0968878d599b 100644 --- a/okcurl/build.gradle.kts +++ b/okcurl/build.gradle.kts @@ -1,15 +1,16 @@ import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.KotlinJvm -import org.apache.tools.ant.taskdefs.condition.Os +import org.graalvm.buildtools.gradle.dsl.GraalVMExtension plugins { kotlin("jvm") id("org.jetbrains.dokka") id("com.vanniktech.maven.publish.base") - id("org.graalvm.buildtools.native") id("com.github.johnrengelman.shadow") } +val testJavaVersion = System.getProperty("test.java.version", "21").toInt() + val copyResourcesTemplates = tasks.register("copyResourcesTemplates") { from("src/main/resources-templates") into(layout.buildDirectory.dir("generated/resources-templates")) @@ -53,11 +54,16 @@ tasks.shadowJar { mergeServiceFiles() } -graalvmNative { - binaries { - named("main") { - imageName = "okcurl" - mainClass = "okhttp3.curl.MainCommandLineKt" + +if (testJavaVersion >= 11) { + apply(plugin = "org.graalvm.buildtools.native") + + configure { + binaries { + named("main") { + imageName = "okcurl" + mainClass = "okhttp3.curl.MainCommandLineKt" + } } } } From 94ed57b7d246cb1bf4b6f943678f36bb4a7dc901 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 10:17:29 +0000 Subject: [PATCH 114/134] Update dependency org.robolectric:android-all to v15 (#8623) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a8fcf8b45950..c497f41b2889 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -88,7 +88,7 @@ nativeImageSvm = { module = "org.graalvm.nativeimage:svm", version.ref = "graalv openjsse = "org.openjsse:openjsse:1.1.14" playservices-safetynet = "com.google.android.gms:play-services-safetynet:18.1.0" retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } -robolectric-android = "org.robolectric:android-all:14-robolectric-10818077" +robolectric-android = "org.robolectric:android-all:15-robolectric-12650502" robolectric = "org.robolectric:robolectric:4.14.1" signature-android-apilevel21 = "net.sf.androidscents.signature:android-api-level-21:5.0.1_r2" signature-android-apilevel24 = "net.sf.androidscents.signature:android-api-level-24:7.0_r2" From 843140bb6138b68fe4db4b81e76a92b0c49203cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 10:17:46 +0000 Subject: [PATCH 115/134] Update dependency com.puppycrawl.tools:checkstyle to v10.21.0 (#8622) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c497f41b2889..0045fd0fc10b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] # 7.0.0 is JDK 17+ https://github.com/bndtools/bnd/wiki/Changes-in-7.0.0 biz-aQute-bnd = "6.4.0" -checkStyle = "10.20.2" +checkStyle = "10.21.0" com-squareup-moshi = "1.15.2" com-squareup-okio = "3.9.1" de-mannodermaus-junit5 = "1.6.0" From a88c5d37f84c4cd9a452ed86a66ffbfc8defcd73 Mon Sep 17 00:00:00 2001 From: hoding <47974623+seokjun7410@users.noreply.github.com> Date: Tue, 24 Dec 2024 19:35:34 +0900 Subject: [PATCH 116/134] Upload progress recipe (#8493) --- .../java/okhttp3/recipes/UploadProgress.java | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 samples/guide/src/main/java/okhttp3/recipes/UploadProgress.java diff --git a/samples/guide/src/main/java/okhttp3/recipes/UploadProgress.java b/samples/guide/src/main/java/okhttp3/recipes/UploadProgress.java new file mode 100644 index 000000000000..134c5ea165d0 --- /dev/null +++ b/samples/guide/src/main/java/okhttp3/recipes/UploadProgress.java @@ -0,0 +1,138 @@ +/* + * 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.recipes; + +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okio.Buffer; +import okio.BufferedSink; +import okio.ForwardingSink; +import okio.Okio; +import okio.Sink; +import java.io.File; +import java.io.IOException; + +public final class UploadProgress { + private static final String IMGUR_CLIENT_ID = "9199fdef135c122"; + private static final MediaType MEDIA_TYPE_PNG = MediaType.get("image/png"); + + private final OkHttpClient client = new OkHttpClient(); + + public void run() throws Exception { + // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image + final ProgressListener progressListener = new ProgressListener() { + boolean firstUpdate = true; + + @Override public void update(long bytesWritten, long contentLength, boolean done) { + if (done) { + System.out.println("completed"); + } else { + if (firstUpdate) { + firstUpdate = false; + if (contentLength == -1) { + System.out.println("content-length: unknown"); + } else { + System.out.format("content-length: %d\n", contentLength); + } + } + + System.out.println(bytesWritten); + + if (contentLength != -1) { + System.out.format("%d%% done\n", (100 * bytesWritten) / contentLength); + } + } + } + }; + + RequestBody requestBody = RequestBody.create( + new File("docs/images/logo-square.png"), + MEDIA_TYPE_PNG); + + Request request = new Request.Builder() + .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID) + .url("https://api.imgur.com/3/image") + .post(new ProgressRequestBody(requestBody, progressListener)) + .build(); + + Response response = client.newCall(request).execute(); + if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); + + System.out.println(response.body().string()); + } + + public static void main(String... args) throws Exception { + new UploadProgress().run(); + } + + private static class ProgressRequestBody extends RequestBody { + + private final ProgressListener progressListener; + private final RequestBody delegate; + + public ProgressRequestBody(RequestBody delegate, ProgressListener progressListener) { + this.delegate = delegate; + this.progressListener = progressListener; + } + + @Override + public MediaType contentType() { + return delegate.contentType(); + } + + @Override + public long contentLength() throws IOException { + return delegate.contentLength(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + BufferedSink bufferedSink = Okio.buffer(sink(sink)); + delegate.writeTo(bufferedSink); + bufferedSink.flush(); + } + + public Sink sink(Sink sink) { + return new ForwardingSink(sink) { + private long totalBytesWritten = 0L; + private boolean completed = false; + + @Override + public void write(Buffer source, long byteCount) throws IOException { + super.write(source, byteCount); + totalBytesWritten += byteCount; + progressListener.update(totalBytesWritten, contentLength(), completed); + } + + @Override + public void close() throws IOException { + super.close(); + if (!completed) { + completed = true; + progressListener.update(totalBytesWritten, contentLength(), completed); + } + } + }; + } + } + + interface ProgressListener { + void update(long bytesWritten, long contentLength, boolean done); + } +} From 0cb5c62aa3a89d3f41abeb5f2d33fb041ea6aa8d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 10:37:08 +0000 Subject: [PATCH 117/134] Update dependency com.google.guava:guava to v33.4.0-jre (#8627) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0045fd0fc10b..8e2afdf7d584 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -54,7 +54,7 @@ gradlePlugin-mavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.30.0" gradlePlugin-mavenSympathy = "io.github.usefulness.maven-sympathy:io.github.usefulness.maven-sympathy.gradle.plugin:0.3.0" gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" -guava-jre = "com.google.guava:guava:33.3.1-jre" +guava-jre = "com.google.guava:guava:33.4.0-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:3.0" httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" jettyClient = "org.eclipse.jetty:jetty-client:9.4.56.v20240826" From 85f4ebe03694cd28f02eb41588ecc1755be2211f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 10:39:05 +0000 Subject: [PATCH 118/134] Update dependency org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin to v0.17.0 (#8629) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Yuri Schimke --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8e2afdf7d584..f4f85384ea00 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -43,7 +43,7 @@ graal-sdk = { module = "org.graalvm.sdk:graal-sdk", version.ref = "graalvm" } gradlePlugin-android = "com.android.tools.build:gradle:8.7.3" gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.2.0" gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.2" -gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.16.3" +gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.17.0" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } gradlePlugin-dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.20" gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.1.0" From 5db9a9c488e2a1577e09a728aa0d437c784dd54f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 10:39:15 +0000 Subject: [PATCH 119/134] Update junit5 monorepo (#8626) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f4f85384ea00..3ae852dc6bf6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ org-bouncycastle = "1.76" org-conscrypt = "2.5.2" org-jetbrains-coroutines = "1.9.0" org-jetbrains-kotlin = "2.1.0" -org-junit-jupiter = "5.11.3" +org-junit-jupiter = "5.11.4" retrofit = "2.11.0" testcontainers = "1.20.4" @@ -65,8 +65,8 @@ junit-ktx = "androidx.test.ext:junit-ktx:1.2.1" junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "org-junit-jupiter" } junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "org-junit-jupiter" } junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "org-junit-jupiter" } -junit-platform-console = "org.junit.platform:junit-platform-console:1.11.3" -junit-vintage-engine = "org.junit.vintage:junit-vintage-engine:5.11.3" +junit-platform-console = "org.junit.platform:junit-platform-console:1.11.4" +junit-vintage-engine = "org.junit.vintage:junit-vintage-engine:5.11.4" junit-pioneer = "org.junit-pioneer:junit-pioneer:1.9.1" junit5android-core = { module = "de.mannodermaus.junit5:android-test-core", version.ref = "de-mannodermaus-junit5" } junit5android-runner = { module = "de.mannodermaus.junit5:android-test-runner", version.ref = "de-mannodermaus-junit5" } From debb6c55f95e874790e0879a45ab7b0a1c407a05 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 10:44:39 +0000 Subject: [PATCH 120/134] Update dependency com.squareup:kotlinpoet to v2 (#8617) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ae852dc6bf6..3de44f7e4ab8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -96,7 +96,7 @@ squareup-moshi = { module = "com.squareup.moshi:moshi", version.ref = "com-squar squareup-moshi-compiler = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "com-squareup-moshi" } squareup-moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "com-squareup-moshi" } squareup-okhttp-icu = "com.squareup.okhttpicu:okhttp-icu:0.2.0" -squareup-kotlinPoet = "com.squareup:kotlinpoet:1.18.1" +squareup-kotlinPoet = "com.squareup:kotlinpoet:2.0.0" squareup-okio = { module = "com.squareup.okio:okio", version.ref = "com-squareup-okio" } squareup-okio-fakefilesystem = { module = "com.squareup.okio:okio-fakefilesystem", version.ref = "com-squareup-okio" } squareup-okio-nodefilesystem = { module = "com.squareup.okio:okio-nodefilesystem", version.ref = "com-squareup-okio" } From 060b4a23bd0bef93303fb88a5bfb85969aadb4c2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 10:47:02 +0000 Subject: [PATCH 121/134] Update dependency gradle to v8.12 (#8628) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 6 ++++-- gradlew.bat | 22 ++++++++++++---------- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 34592 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 delta 34555 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c1d5e0185987..e0fd02028bca 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a426907..f3b75f3b0d4f 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 93e3f59f135d..9d21a21834d5 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail From 6947be1baa3bd5e63e5fca41639fbde7cd0dd580 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Thu, 26 Dec 2024 19:24:49 +0200 Subject: [PATCH 122/134] Follow task avoidance guidance. (#8632) * Follow task avoidance guidance. https://docs.gradle.org/current/userguide/task_configuration_avoidance.html#sec:old_vs_new_configuration_api_overview --- build.gradle.kts | 12 ++++++++++-- gradle/libs.versions.toml | 2 ++ okcurl/build.gradle.kts | 3 ++- okhttp/build.gradle.kts | 25 ++++++++++++++----------- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 735e1c57e6cc..13122ea3fdf9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -57,7 +57,7 @@ allprojects { google() } - tasks.create("downloadDependencies") { + tasks.register("downloadDependencies") { description = "Download all dependencies to the Gradle cache" doLast { for (configuration in configurations) { @@ -96,6 +96,15 @@ subprojects { apply(plugin = "biz.aQute.bnd.builder") apply(plugin = "io.github.usefulness.maven-sympathy") + // Skip samples parent + if (project.buildFile.exists()) { + apply(plugin = "com.android.lint") + + dependencies { + "lintChecks"(rootProject.libs.androidx.lint.gradle) + } + } + tasks.withType { options.encoding = Charsets.UTF_8.toString() } @@ -266,7 +275,6 @@ subprojects { } plugins.withId("com.vanniktech.maven.publish.base") { - val publishingExtension = extensions.getByType(PublishingExtension::class.java) configure { publishToMavenCentral(SonatypeHost.S01, automaticRelease = true) signAllPublications() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3de44f7e4ab8..9ce30ad49d65 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ de-mannodermaus-junit5 = "1.6.0" graalvm = "24.1.1" kotlinx-serialization = "1.7.3" ksp = "2.1.0-1.0.29" +lintGradle = "1.0.0-alpha03" mockserverClient = "5.15.0" org-bouncycastle = "1.76" org-conscrypt = "2.5.2" @@ -23,6 +24,7 @@ androidx-activity = "androidx.activity:activity-ktx:1.9.3" androidx-annotation = "androidx.annotation:annotation:1.9.1" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" +androidx-lint-gradle = { module = "androidx.lint:lint-gradle", version.ref = "lintGradle" } androidx-test-runner = "androidx.test:runner:1.6.2" animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.24" aqute-resolve = { module = "biz.aQute.bnd:biz.aQute.resolve", version.ref = "biz-aQute-bnd" } diff --git a/okcurl/build.gradle.kts b/okcurl/build.gradle.kts index 0968878d599b..a9060b2abb90 100644 --- a/okcurl/build.gradle.kts +++ b/okcurl/build.gradle.kts @@ -1,6 +1,7 @@ import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.KotlinJvm import org.graalvm.buildtools.gradle.dsl.GraalVMExtension +import ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferExtension plugins { kotlin("jvm") @@ -39,7 +40,7 @@ dependencies { testImplementation(kotlin("test")) } -animalsniffer { +configure { isIgnoreFailures = true } diff --git a/okhttp/build.gradle.kts b/okhttp/build.gradle.kts index 60a7aa6cf63c..e1214a6fc1fe 100644 --- a/okhttp/build.gradle.kts +++ b/okhttp/build.gradle.kts @@ -1,9 +1,6 @@ import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.KotlinJvm -import java.io.DataInputStream -import java.io.FileInputStream import java.util.Base64 -import java.util.zip.GZIPInputStream plugins { kotlin("jvm") @@ -18,8 +15,10 @@ fun ByteArray.toByteStringExpression(): String { } val copyKotlinTemplates = tasks.register("copyKotlinTemplates") { + val kotlinTemplatesOutput = layout.buildDirectory.dir("generated/sources/kotlinTemplates") + from("src/main/kotlinTemplates") - into(layout.buildDirectory.dir("generated/sources/kotlinTemplates")) + into(kotlinTemplatesOutput) // Tag as an input to regenerate after an update inputs.file("src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") @@ -43,18 +42,20 @@ val generateIdnaMappingTableConfiguration: Configuration by configurations.creat dependencies { generateIdnaMappingTableConfiguration(projects.okhttpIdnaMappingTable) } -val generateIdnaMappingTable by tasks.creating(JavaExec::class.java) { - outputs.dir(layout.buildDirectory.dir("generated/sources/idnaMappingTable")) +val generateIdnaMappingTable = tasks.register("generateIdnaMappingTable") { + val idnaOutput = layout.buildDirectory.dir("generated/sources/idnaMappingTable") + + outputs.dir(idnaOutput) mainClass.set("okhttp3.internal.idn.GenerateIdnaMappingTableCode") - args(layout.buildDirectory.dir("generated/sources/idnaMappingTable").get()) + args(idnaOutput.get()) classpath = generateIdnaMappingTableConfiguration } kotlin { sourceSets { getByName("main") { - kotlin.srcDir(copyKotlinTemplates.get().outputs) - kotlin.srcDir(generateIdnaMappingTable.outputs) + kotlin.srcDir(copyKotlinTemplates.map { it.outputs }) + kotlin.srcDir(generateIdnaMappingTable.map { it.outputs }) } } } @@ -107,11 +108,13 @@ normalization { // Expose OSGi jars to the test environment. val osgiTestDeploy: Configuration by configurations.creating -val copyOsgiTestDeployment by tasks.creating(Copy::class.java) { +val test by tasks.existing(Test::class) +val copyOsgiTestDeployment = tasks.register("copyOsgiTestDeployment") { from(osgiTestDeploy) into(layout.buildDirectory.dir("resources/test/okhttp3/osgi/deployments")) } -tasks.getByName("test") { + +test.configure { dependsOn(copyOsgiTestDeployment) } From 5b2a1e139e9721455990a1b3d1462be47d27c599 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Fri, 27 Dec 2024 15:39:56 +0200 Subject: [PATCH 123/134] Split okhttp core into Android and JVM (#8600) --- .../okhttp/android/testapp/MainActivity.kt | 4 + build.gradle.kts | 116 +- buildSrc/settings.gradle.kts | 1 + gradle.properties | 1 + gradle/libs.versions.toml | 3 +- mockwebserver-junit4/build.gradle.kts | 1 + okcurl/build.gradle.kts | 1 - okhttp-android/build.gradle.kts | 13 +- .../android/AndroidSocketAdapterTest.kt | 48 +- .../android/RobolectricOkHttpClientTest.kt | 2 +- okhttp-idna-mapping-table/build.gradle.kts | 2 + okhttp-osgi-tests/build.gradle.kts | 68 + .../src/test/kotlin}/okhttp3/osgi/OsgiTest.kt | 0 okhttp-testing-support/build.gradle.kts | 2 + .../okhttp3/internal/concurrent/TaskFaker.kt | 8 +- .../kotlin/okhttp3/testing/PlatformRule.kt | 8 +- okhttp/api/{ => android}/okhttp.api | 0 okhttp/api/jvm/okhttp.api | 1294 +++++++++++++++++ okhttp/build.gradle.kts | 290 ++-- .../META-INF/proguard => }/okhttp3.pro | 1 + okhttp/src/androidMain/AndroidManifest.xml | 4 + .../internal/platform/Android10Platform.kt | 0 .../internal/platform/AndroidPlatform.kt | 0 .../internal/platform/PlatformRegistry.kt | 13 + .../android/Android10SocketAdapter.kt | 0 .../android/AndroidCertificateChainCleaner.kt | 0 .../internal/platform/android/AndroidLog.kt | 0 .../platform/android/AndroidSocketAdapter.kt | 0 .../android/BouncyCastleSocketAdapter.kt | 15 +- .../android/ConscryptSocketAdapter.kt | 39 +- .../platform/android/DeferredSocketAdapter.kt | 0 .../platform/android/SocketAdapter.kt | 0 .../android/StandardAndroidSocketAdapter.kt | 0 .../kotlin/okhttp3/Address.kt | 0 .../kotlin/okhttp3/AsyncDns.kt | 0 .../kotlin/okhttp3/Authenticator.kt | 0 .../kotlin/okhttp3/Cache.kt | 0 .../kotlin/okhttp3/CacheControl.kt | 0 .../kotlin/okhttp3/Call.kt | 0 .../kotlin/okhttp3/Callback.kt | 0 .../kotlin/okhttp3/CertificatePinner.kt | 0 .../kotlin/okhttp3/Challenge.kt | 0 .../kotlin/okhttp3/CipherSuite.kt | 0 .../kotlin/okhttp3/Connection.kt | 0 .../kotlin/okhttp3/ConnectionListener.kt | 0 .../kotlin/okhttp3/ConnectionPool.kt | 0 .../kotlin/okhttp3/ConnectionSpec.kt | 0 .../kotlin/okhttp3/Cookie.kt | 0 .../kotlin/okhttp3/CookieJar.kt | 0 .../kotlin/okhttp3/Credentials.kt | 0 .../kotlin/okhttp3/Dispatcher.kt | 0 .../kotlin/okhttp3/Dns.kt | 0 .../kotlin/okhttp3/EventListener.kt | 0 .../kotlin/okhttp3/ExperimentalOkHttpApi.kt | 0 .../kotlin/okhttp3/FormBody.kt | 0 .../kotlin/okhttp3/Handshake.kt | 0 .../kotlin/okhttp3/Headers.kt | 0 .../kotlin/okhttp3/HttpUrl.kt | 0 .../kotlin/okhttp3/Interceptor.kt | 0 .../kotlin/okhttp3/MediaType.kt | 0 .../kotlin/okhttp3/MultipartBody.kt | 0 .../kotlin/okhttp3/MultipartReader.kt | 0 .../kotlin/okhttp3/OkHttp.kt | 0 .../kotlin/okhttp3/OkHttpClient.kt | 7 - .../kotlin/okhttp3/Protocol.kt | 0 .../kotlin/okhttp3/Request.kt | 0 .../kotlin/okhttp3/RequestBody.kt | 0 .../kotlin/okhttp3/Response.kt | 0 .../kotlin/okhttp3/ResponseBody.kt | 0 .../kotlin/okhttp3/Route.kt | 0 .../kotlin/okhttp3/TlsVersion.kt | 0 .../kotlin/okhttp3/WebSocket.kt | 0 .../kotlin/okhttp3/WebSocketListener.kt | 0 .../okhttp3/internal/-CacheControlCommon.kt | 0 .../okhttp3/internal/-ChallengeCommon.kt | 0 .../kotlin/okhttp3/internal/-HeadersCommon.kt | 0 .../okhttp3/internal/-HostnamesCommon.kt | 0 .../okhttp3/internal/-MediaTypeCommon.kt | 0 .../kotlin/okhttp3/internal/-NormalizeJvm.kt | 0 .../okhttp3/internal/-RequestBodyCommon.kt | 0 .../kotlin/okhttp3/internal/-RequestCommon.kt | 0 .../okhttp3/internal/-ResponseBodyCommon.kt | 0 .../okhttp3/internal/-ResponseCommon.kt | 0 .../kotlin/okhttp3/internal/-UtilCommon.kt | 0 .../kotlin/okhttp3/internal/-UtilJvm.kt | 0 .../internal/NativeImageTestsAccessors.kt | 0 .../internal/SuppressSignatureCheck.kt | 0 .../authenticator/JavaNetAuthenticator.kt | 0 .../internal/cache/CacheInterceptor.kt | 0 .../okhttp3/internal/cache/CacheRequest.kt | 0 .../okhttp3/internal/cache/CacheStrategy.kt | 0 .../okhttp3/internal/cache/DiskLruCache.kt | 0 .../okhttp3/internal/cache/FaultHidingSink.kt | 0 .../okhttp3/internal/cache2/FileOperator.kt | 0 .../kotlin/okhttp3/internal/cache2/Relay.kt | 0 .../okhttp3/internal/concurrent/Task.kt | 0 .../okhttp3/internal/concurrent/TaskLogger.kt | 0 .../okhttp3/internal/concurrent/TaskQueue.kt | 0 .../okhttp3/internal/concurrent/TaskRunner.kt | 0 .../internal/connection/CallConnectionUser.kt | 0 .../internal/connection/ConnectInterceptor.kt | 0 .../internal/connection/ConnectPlan.kt | 0 .../internal/connection/ConnectionUser.kt | 0 .../okhttp3/internal/connection/Exchange.kt | 0 .../internal/connection/ExchangeFinder.kt | 0 .../okhttp3/internal/connection/FailedPlan.kt | 0 .../connection/FastFallbackExchangeFinder.kt | 0 .../connection/ForceConnectRoutePlanner.kt | 0 .../internal/connection/InetAddressOrder.kt | 0 .../okhttp3/internal/connection/Locks.kt | 2 +- .../internal/connection/PoolConnectionUser.kt | 0 .../okhttp3/internal/connection/RealCall.kt | 0 .../internal/connection/RealConnection.kt | 0 .../internal/connection/RealConnectionPool.kt | 0 .../internal/connection/RealRoutePlanner.kt | 0 .../internal/connection/RetryTlsHandshake.kt | 0 .../okhttp3/internal/connection/ReusePlan.kt | 0 .../internal/connection/RouteDatabase.kt | 0 .../internal/connection/RoutePlanner.kt | 0 .../internal/connection/RouteSelector.kt | 0 .../connection/SequentialExchangeFinder.kt | 0 .../internal/http/BridgeInterceptor.kt | 0 .../internal/http/CallServerInterceptor.kt | 0 .../okhttp3/internal/http/DateFormatting.kt | 0 .../okhttp3/internal/http/ExchangeCodec.kt | 0 .../okhttp3/internal/http/HttpHeaders.kt | 0 .../okhttp3/internal/http/HttpMethod.kt | 0 .../okhttp3/internal/http/HttpStatusCodes.kt | 0 .../internal/http/RealInterceptorChain.kt | 0 .../okhttp3/internal/http/RealResponseBody.kt | 0 .../okhttp3/internal/http/RequestLine.kt | 0 .../http/RetryAndFollowUpInterceptor.kt | 0 .../okhttp3/internal/http/StatusLine.kt | 0 .../okhttp3/internal/http1/HeadersReader.kt | 0 .../internal/http1/Http1ExchangeCodec.kt | 0 .../http2/ConnectionShutdownException.kt | 0 .../okhttp3/internal/http2/ErrorCode.kt | 0 .../internal/http2/FlowControlListener.kt | 0 .../kotlin/okhttp3/internal/http2/Header.kt | 0 .../kotlin/okhttp3/internal/http2/Hpack.kt | 0 .../kotlin/okhttp3/internal/http2/Http2.kt | 0 .../okhttp3/internal/http2/Http2Connection.kt | 0 .../internal/http2/Http2ExchangeCodec.kt | 0 .../okhttp3/internal/http2/Http2Reader.kt | 0 .../okhttp3/internal/http2/Http2Stream.kt | 0 .../okhttp3/internal/http2/Http2Writer.kt | 0 .../kotlin/okhttp3/internal/http2/Huffman.kt | 0 .../okhttp3/internal/http2/PushObserver.kt | 0 .../kotlin/okhttp3/internal/http2/Settings.kt | 0 .../internal/http2/StreamResetException.kt | 0 .../http2/flowcontrol/WindowCounter.kt | 0 .../okhttp3/internal/idn/IdnaMappingTable.kt | 0 .../kotlin/okhttp3/internal/idn/Punycode.kt | 0 .../kotlin/okhttp3/internal/internal.kt | 0 .../okhttp3/internal/platform/Platform.kt | 80 +- .../internal/platform/PlatformRegistry.kt | 7 + .../internal/proxy/NullProxySelector.kt | 0 .../publicsuffix/PublicSuffixDatabase.kt | 0 .../internal/publicsuffix/PublicSuffixList.kt | 0 .../tls/BasicCertificateChainCleaner.kt | 0 .../internal/tls/BasicTrustRootIndex.kt | 0 .../internal/tls/CertificateChainCleaner.kt | 0 .../internal/tls/OkHostnameVerifier.kt | 0 .../okhttp3/internal/tls/TrustRootIndex.kt | 0 .../kotlin/okhttp3/internal/url/-Url.kt | 0 .../okhttp3/internal/ws/MessageDeflater.kt | 0 .../okhttp3/internal/ws/MessageInflater.kt | 0 .../okhttp3/internal/ws/RealWebSocket.kt | 0 .../internal/ws/WebSocketExtensions.kt | 0 .../okhttp3/internal/ws/WebSocketProtocol.kt | 0 .../okhttp3/internal/ws/WebSocketReader.kt | 0 .../okhttp3/internal/ws/WebSocketWriter.kt | 0 .../okhttp3/internal/-InternalVersion.kt | 0 .../publicsuffix/EmbeddedPublicSuffixList.kt | 0 .../kotlin/okhttp3/internal/graal/GraalSvm.kt | 10 - .../okhttp3/internal/graal/OkHttpFeature.kt | 0 .../internal/platform/BouncyCastlePlatform.kt | 0 .../internal/platform/ConscryptPlatform.kt | 0 .../platform/Jdk8WithJettyBootPlatform.kt | 0 .../okhttp3/internal/platform/Jdk9Platform.kt | 0 .../internal/platform/OpenJSSEPlatform.kt | 0 .../internal/platform/PlatformRegistry.kt | 68 + .../okhttp/okhttp/native-image.properties | 1 + .../okhttp/okhttp/reflect-config.json | 0 .../okhttp/okhttp/resource-config.json | 0 .../kotlin}/okhttp3/AddressTest.kt | 0 .../kotlin}/okhttp3/AutobahnTester.kt | 0 .../kotlin}/okhttp3/BouncyCastleTest.kt | 0 .../kotlin}/okhttp3/CacheControlJvmTest.kt | 0 .../kotlin}/okhttp3/CacheControlTest.kt | 0 .../kotlin}/okhttp3/CacheCorruptionTest.kt | 0 .../kotlin}/okhttp3/CacheTest.kt | 0 .../kotlin}/okhttp3/CallHandshakeTest.kt | 0 .../kotlin}/okhttp3/CallKotlinTest.kt | 0 .../kotlin}/okhttp3/CallTest.kt | 0 .../okhttp3/CertificateChainCleanerTest.kt | 0 .../okhttp3/CertificatePinnerKotlinTest.kt | 0 .../kotlin}/okhttp3/CertificatePinnerTest.kt | 0 .../kotlin}/okhttp3/ChannelSocketFactory.kt | 0 .../kotlin}/okhttp3/CipherSuiteTest.kt | 0 .../kotlin}/okhttp3/CommonRequestBodyTest.kt | 0 .../okhttp3/ConnectionCoalescingTest.kt | 0 .../kotlin}/okhttp3/ConnectionListenerTest.kt | 0 .../kotlin}/okhttp3/ConnectionReuseTest.kt | 0 .../kotlin}/okhttp3/ConnectionSpecTest.kt | 0 .../kotlin}/okhttp3/ConscryptTest.kt | 0 .../kotlin}/okhttp3/CookieTest.kt | 0 .../kotlin}/okhttp3/CookiesTest.kt | 0 .../kotlin}/okhttp3/CorrettoTest.kt | 0 .../kotlin}/okhttp3/DispatcherCleanupTest.kt | 0 .../kotlin}/okhttp3/DispatcherTest.kt | 0 .../kotlin}/okhttp3/DuplexTest.kt | 0 .../kotlin}/okhttp3/EventListenerTest.kt | 0 .../kotlin}/okhttp3/FakeRoutePlanner.kt | 0 .../FallbackTestClientSocketFactory.kt | 0 .../kotlin}/okhttp3/FastFallbackTest.kt | 0 .../kotlin}/okhttp3/FormBodyTest.kt | 0 .../kotlin}/okhttp3/HandshakeTest.kt | 0 .../kotlin}/okhttp3/HeadersChallengesTest.kt | 0 .../kotlin}/okhttp3/HeadersJvmTest.kt | 0 .../kotlin}/okhttp3/HeadersKotlinTest.kt | 0 .../kotlin}/okhttp3/HeadersRequestTest.kt | 0 .../kotlin}/okhttp3/HeadersTest.kt | 0 .../kotlin}/okhttp3/HttpUrlJvmTest.kt | 0 .../kotlin}/okhttp3/HttpUrlTest.kt | 0 .../kotlin}/okhttp3/InsecureForHostTest.kt | 0 .../kotlin}/okhttp3/InterceptorTest.kt | 0 .../kotlin}/okhttp3/JSSETest.kt | 0 .../okhttp3/KotlinDeprecationErrorTest.kt | 0 .../kotlin}/okhttp3/KotlinSourceModernTest.kt | 0 .../kotlin}/okhttp3/LoomTest.kt | 0 .../kotlin}/okhttp3/MediaTypeGetTest.kt | 0 .../kotlin}/okhttp3/MediaTypeJvmTest.kt | 0 .../kotlin}/okhttp3/MediaTypeTest.kt | 0 .../kotlin}/okhttp3/MultipartBodyTest.kt | 0 .../kotlin}/okhttp3/MultipartReaderTest.kt | 0 .../kotlin}/okhttp3/OkHttpClientTest.kt | 0 .../kotlin}/okhttp3/OkHttpTest.kt | 0 .../kotlin}/okhttp3/OpenJSSETest.kt | 0 .../kotlin}/okhttp3/ProtocolTest.kt | 0 .../kotlin}/okhttp3/PublicInternalApiTest.kt | 0 .../kotlin}/okhttp3/RecordedResponse.kt | 0 .../kotlin}/okhttp3/RecordingCallback.kt | 0 .../kotlin}/okhttp3/RecordingExecutor.kt | 0 .../kotlin}/okhttp3/RequestBodyTest.kt | 0 .../kotlin}/okhttp3/RequestCommonTest.kt | 0 .../kotlin}/okhttp3/RequestTest.kt | 0 .../kotlin}/okhttp3/ResponseBodyJvmTest.kt | 0 .../kotlin}/okhttp3/ResponseBodyTest.kt | 0 .../kotlin}/okhttp3/ResponseCommonTest.kt | 0 .../kotlin}/okhttp3/ResponseJvmTest.kt | 0 .../kotlin}/okhttp3/RouteFailureTest.kt | 0 .../okhttp3/ServerTruncatesRequestTest.kt | 0 .../kotlin}/okhttp3/SessionReuseTest.kt | 0 .../kotlin}/okhttp3/SocketChannelTest.kt | 0 .../kotlin}/okhttp3/SocksProxy.kt | 0 .../kotlin}/okhttp3/SocksProxyTest.kt | 0 .../kotlin}/okhttp3/TestLogHandler.kt | 0 .../kotlin}/okhttp3/TestTls13Request.kt | 0 .../kotlin}/okhttp3/URLConnectionTest.kt | 0 .../okhttp3/UrlComponentEncodingTester.kt | 0 .../okhttp3/UrlComponentEncodingTesterJvm.kt | 0 .../kotlin}/okhttp3/WebPlatformToAsciiData.kt | 2 +- .../kotlin}/okhttp3/WebPlatformToAsciiTest.kt | 0 .../kotlin}/okhttp3/WebPlatformUrlTest.kt | 0 .../kotlin}/okhttp3/WebPlatformUrlTestData.kt | 0 .../okhttp3/WholeOperationTimeoutTest.kt | 0 .../okhttp3/internal/DoubleInetAddressDns.kt | 0 .../kotlin}/okhttp3/internal/HostnamesTest.kt | 0 .../internal/RecordingAuthenticator.kt | 0 .../kotlin}/okhttp3/internal/UtilTest.kt | 0 .../authenticator/JavaNetAuthenticatorTest.kt | 0 .../internal/cache/DiskLruCacheTest.kt | 0 .../internal/cache2/FileOperatorTest.kt | 0 .../okhttp3/internal/cache2/RelayTest.kt | 0 .../internal/concurrent/TaskLoggerTest.kt | 0 .../concurrent/TaskRunnerRealBackendTest.kt | 0 .../internal/concurrent/TaskRunnerTest.kt | 0 .../internal/connection/ConnectionPoolTest.kt | 0 .../FastFallbackExchangeFinderTest.kt | 0 .../connection/InetAddressOrderTest.kt | 0 .../connection/RetryConnectionTest.kt | 0 .../internal/connection/RouteSelectorTest.kt | 0 .../okhttp3/internal/http/CancelTest.kt | 0 .../internal/http/ExternalHttp2Example.kt | 0 .../okhttp3/internal/http/HttpDateTest.kt | 0 .../okhttp3/internal/http/StatusLineTest.kt | 0 .../internal/http/ThreadInterruptTest.kt | 0 .../okhttp3/internal/http2/BaseTestHandler.kt | 0 .../okhttp3/internal/http2/FrameLogTest.kt | 0 .../okhttp3/internal/http2/HpackTest.kt | 0 .../internal/http2/Http2ConnectionTest.kt | 0 .../okhttp3/internal/http2/Http2Test.kt | 0 .../internal/http2/HttpOverHttp2Test.kt | 0 .../okhttp3/internal/http2/HuffmanTest.kt | 0 .../okhttp3/internal/http2/MockHttp2Peer.kt | 0 .../okhttp3/internal/http2/SettingsTest.kt | 0 .../internal/idn/IdnaMappingTableTest.kt | 0 .../okhttp3/internal/idn/PunycodeTest.kt | 0 .../okhttp3/internal/io/FaultyFileSystem.kt | 0 .../platform/Jdk8WithJettyBootPlatformTest.kt | 0 .../internal/platform/Jdk9PlatformTest.kt | 0 .../okhttp3/internal/platform/PlatformTest.kt | 0 .../publicsuffix/PublicSuffixDatabaseTest.kt | 0 .../publicsuffix/PublicSuffixListGenerator.kt | 0 .../publicsuffix/ResourcePublicSuffixList.kt | 0 .../CertificatePinnerChainValidationTest.kt | 0 .../okhttp3/internal/tls/ClientAuthTest.kt | 0 .../internal/tls/HostnameVerifierTest.kt | 0 .../ws/MessageDeflaterInflaterTest.kt | 0 .../okhttp3/internal/ws/RealWebSocketTest.kt | 0 .../internal/ws/WebSocketExtensionsTest.kt | 0 .../okhttp3/internal/ws/WebSocketHttpTest.kt | 0 .../internal/ws/WebSocketReaderTest.kt | 0 .../okhttp3/internal/ws/WebSocketRecorder.kt | 0 .../internal/ws/WebSocketWriterTest.kt | 0 .../okhttp3/internal/publicsuffix/NOTICE | 0 .../publicsuffix/PublicSuffixDatabase.gz | Bin .../publicsuffix/public_suffix_list.dat | 0 .../resources/web-platform-test-toascii.json | 0 .../web-platform-test-urltestdata.txt | 0 settings.gradle.kts | 24 +- 322 files changed, 1824 insertions(+), 311 deletions(-) create mode 100644 buildSrc/settings.gradle.kts rename {okhttp/src/test/java/okhttp3/internal/platform => okhttp-android/src/test/kotlin/okhttp3}/android/AndroidSocketAdapterTest.kt (76%) create mode 100644 okhttp-osgi-tests/build.gradle.kts rename {okhttp/src/test/java => okhttp-osgi-tests/src/test/kotlin}/okhttp3/osgi/OsgiTest.kt (100%) rename okhttp/api/{ => android}/okhttp.api (100%) create mode 100644 okhttp/api/jvm/okhttp.api rename okhttp/{src/main/resources/META-INF/proguard => }/okhttp3.pro (85%) create mode 100644 okhttp/src/androidMain/AndroidManifest.xml rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/Android10Platform.kt (100%) rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/AndroidPlatform.kt (100%) create mode 100644 okhttp/src/androidMain/kotlin/okhttp3/internal/platform/PlatformRegistry.kt rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt (100%) rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/android/AndroidCertificateChainCleaner.kt (100%) rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/android/AndroidLog.kt (100%) rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt (100%) rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt (81%) rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt (64%) rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt (100%) rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt (100%) rename okhttp/src/{main => androidMain}/kotlin/okhttp3/internal/platform/android/StandardAndroidSocketAdapter.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Address.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/AsyncDns.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Authenticator.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Cache.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/CacheControl.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Call.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Callback.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/CertificatePinner.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Challenge.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/CipherSuite.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Connection.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/ConnectionListener.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/ConnectionPool.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/ConnectionSpec.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Cookie.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/CookieJar.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Credentials.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Dispatcher.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Dns.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/EventListener.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/ExperimentalOkHttpApi.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/FormBody.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Handshake.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Headers.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/HttpUrl.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Interceptor.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/MediaType.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/MultipartBody.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/MultipartReader.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/OkHttp.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/OkHttpClient.kt (99%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Protocol.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Request.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/RequestBody.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Response.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/ResponseBody.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/Route.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/TlsVersion.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/WebSocket.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/WebSocketListener.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-CacheControlCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-ChallengeCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-HeadersCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-HostnamesCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-MediaTypeCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-NormalizeJvm.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-RequestBodyCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-RequestCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-ResponseBodyCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-ResponseCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-UtilCommon.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/-UtilJvm.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/SuppressSignatureCheck.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticator.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/cache/CacheInterceptor.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/cache/CacheRequest.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/cache/CacheStrategy.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/cache/DiskLruCache.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/cache/FaultHidingSink.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/cache2/FileOperator.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/cache2/Relay.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/concurrent/Task.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/concurrent/TaskLogger.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/concurrent/TaskQueue.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/concurrent/TaskRunner.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/CallConnectionUser.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/ConnectInterceptor.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/ConnectPlan.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/ConnectionUser.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/Exchange.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/ExchangeFinder.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/FailedPlan.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinder.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/ForceConnectRoutePlanner.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/InetAddressOrder.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/Locks.kt (97%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/PoolConnectionUser.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/RealCall.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/RealConnection.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/RealConnectionPool.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/RetryTlsHandshake.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/ReusePlan.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/RouteDatabase.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/RoutePlanner.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/RouteSelector.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/connection/SequentialExchangeFinder.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/BridgeInterceptor.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/CallServerInterceptor.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/DateFormatting.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/ExchangeCodec.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/HttpHeaders.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/HttpMethod.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/HttpStatusCodes.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/RealInterceptorChain.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/RealResponseBody.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/RequestLine.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http/StatusLine.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http1/HeadersReader.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/ConnectionShutdownException.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/ErrorCode.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/FlowControlListener.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Header.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Hpack.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Http2.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Http2Connection.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Http2ExchangeCodec.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Http2Reader.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Http2Stream.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Http2Writer.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Huffman.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/PushObserver.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/Settings.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/StreamResetException.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/http2/flowcontrol/WindowCounter.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/idn/IdnaMappingTable.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/idn/Punycode.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/internal.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/platform/Platform.kt (78%) create mode 100644 okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/PlatformRegistry.kt rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/proxy/NullProxySelector.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/tls/BasicCertificateChainCleaner.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/tls/BasicTrustRootIndex.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/tls/CertificateChainCleaner.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/tls/TrustRootIndex.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/url/-Url.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/ws/MessageDeflater.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/ws/MessageInflater.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/ws/RealWebSocket.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/ws/WebSocketExtensions.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/ws/WebSocketProtocol.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/ws/WebSocketReader.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlin/okhttp3/internal/ws/WebSocketWriter.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlinTemplates/okhttp3/internal/-InternalVersion.kt (100%) rename okhttp/src/{main => commonJvmAndroid}/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt (100%) rename okhttp/src/{main => jvmMain}/kotlin/okhttp3/internal/graal/GraalSvm.kt (86%) rename okhttp/src/{main => jvmMain}/kotlin/okhttp3/internal/graal/OkHttpFeature.kt (100%) rename okhttp/src/{main => jvmMain}/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt (100%) rename okhttp/src/{main => jvmMain}/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt (100%) rename okhttp/src/{main => jvmMain}/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt (100%) rename okhttp/src/{main => jvmMain}/kotlin/okhttp3/internal/platform/Jdk9Platform.kt (100%) rename okhttp/src/{main => jvmMain}/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt (100%) create mode 100644 okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/PlatformRegistry.kt create mode 100644 okhttp/src/jvmMain/resources/META-INF/native-image/okhttp/okhttp/native-image.properties rename okhttp/src/{main => jvmMain}/resources/META-INF/native-image/okhttp/okhttp/reflect-config.json (100%) rename okhttp/src/{main => jvmMain}/resources/META-INF/native-image/okhttp/okhttp/resource-config.json (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/AddressTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/AutobahnTester.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/BouncyCastleTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CacheControlJvmTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CacheControlTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CacheCorruptionTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CacheTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CallHandshakeTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CallKotlinTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CallTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CertificateChainCleanerTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CertificatePinnerKotlinTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CertificatePinnerTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ChannelSocketFactory.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CipherSuiteTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CommonRequestBodyTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ConnectionCoalescingTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ConnectionListenerTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ConnectionReuseTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ConnectionSpecTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ConscryptTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CookieTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CookiesTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/CorrettoTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/DispatcherCleanupTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/DispatcherTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/DuplexTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/EventListenerTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/FakeRoutePlanner.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/FallbackTestClientSocketFactory.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/FastFallbackTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/FormBodyTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/HandshakeTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/HeadersChallengesTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/HeadersJvmTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/HeadersKotlinTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/HeadersRequestTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/HeadersTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/HttpUrlJvmTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/HttpUrlTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/InsecureForHostTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/InterceptorTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/JSSETest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/KotlinDeprecationErrorTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/KotlinSourceModernTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/LoomTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/MediaTypeGetTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/MediaTypeJvmTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/MediaTypeTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/MultipartBodyTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/MultipartReaderTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/OkHttpClientTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/OkHttpTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/OpenJSSETest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ProtocolTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/PublicInternalApiTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/RecordedResponse.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/RecordingCallback.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/RecordingExecutor.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/RequestBodyTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/RequestCommonTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/RequestTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ResponseBodyJvmTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ResponseBodyTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ResponseCommonTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ResponseJvmTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/RouteFailureTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/ServerTruncatesRequestTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/SessionReuseTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/SocketChannelTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/SocksProxy.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/SocksProxyTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/TestLogHandler.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/TestTls13Request.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/URLConnectionTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/UrlComponentEncodingTester.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/UrlComponentEncodingTesterJvm.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/WebPlatformToAsciiData.kt (93%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/WebPlatformToAsciiTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/WebPlatformUrlTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/WebPlatformUrlTestData.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/WholeOperationTimeoutTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/DoubleInetAddressDns.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/HostnamesTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/RecordingAuthenticator.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/UtilTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/authenticator/JavaNetAuthenticatorTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/cache/DiskLruCacheTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/cache2/FileOperatorTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/cache2/RelayTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/concurrent/TaskLoggerTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/concurrent/TaskRunnerRealBackendTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/concurrent/TaskRunnerTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/connection/ConnectionPoolTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/connection/InetAddressOrderTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/connection/RetryConnectionTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/connection/RouteSelectorTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http/CancelTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http/ExternalHttp2Example.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http/HttpDateTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http/StatusLineTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http/ThreadInterruptTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http2/BaseTestHandler.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http2/FrameLogTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http2/HpackTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http2/Http2ConnectionTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http2/Http2Test.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http2/HttpOverHttp2Test.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http2/HuffmanTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http2/MockHttp2Peer.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/http2/SettingsTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/idn/IdnaMappingTableTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/idn/PunycodeTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/io/FaultyFileSystem.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/platform/Jdk8WithJettyBootPlatformTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/platform/Jdk9PlatformTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/platform/PlatformTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/tls/CertificatePinnerChainValidationTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/tls/ClientAuthTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/tls/HostnameVerifierTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/ws/MessageDeflaterInflaterTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/ws/RealWebSocketTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/ws/WebSocketExtensionsTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/ws/WebSocketHttpTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/ws/WebSocketReaderTest.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/ws/WebSocketRecorder.kt (100%) rename okhttp/src/{test/java => jvmTest/kotlin}/okhttp3/internal/ws/WebSocketWriterTest.kt (100%) rename okhttp/src/{test => jvmTest}/resources/okhttp3/internal/publicsuffix/NOTICE (100%) rename okhttp/src/{test => jvmTest}/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz (100%) rename okhttp/src/{test => jvmTest}/resources/okhttp3/internal/publicsuffix/public_suffix_list.dat (100%) rename okhttp/src/{test => jvmTest}/resources/web-platform-test-toascii.json (100%) rename okhttp/src/{test => jvmTest}/resources/web-platform-test-urltestdata.txt (100%) diff --git a/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt b/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt index d9ed518156ff..cf896359b4b1 100644 --- a/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt +++ b/android-test-app/src/main/kotlin/okhttp/android/testapp/MainActivity.kt @@ -23,6 +23,7 @@ import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response +import okhttp3.internal.platform.AndroidPlatform import okio.IOException class MainActivity : ComponentActivity() { @@ -31,6 +32,9 @@ class MainActivity : ComponentActivity() { val client = OkHttpClient() + // Ensure we are compiling against the right variant + println(AndroidPlatform.isSupported) + val url = "https://github.com/square/okhttp".toHttpUrl() println(url.topPrivateDomain()) diff --git a/build.gradle.kts b/build.gradle.kts index 13122ea3fdf9..dd647ba4fe41 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,6 +8,7 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.jetbrains.dokka.gradle.DokkaTaskPartial import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.kotlinExtension +import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferExtension import java.net.URI @@ -93,11 +94,16 @@ subprojects { apply(plugin = "checkstyle") apply(plugin = "ru.vyarus.animalsniffer") - apply(plugin = "biz.aQute.bnd.builder") - apply(plugin = "io.github.usefulness.maven-sympathy") + + // The 'java' plugin has been applied, but it is not compatible with the Android plugins. + // These are applied inside the okhttp module for that case specifically + if (project.name != "okhttp") { + apply(plugin = "biz.aQute.bnd.builder") + apply(plugin = "io.github.usefulness.maven-sympathy") + } // Skip samples parent - if (project.buildFile.exists()) { + if (project.buildFile.exists() && project.name != "okhttp") { apply(plugin = "com.android.lint") dependencies { @@ -109,9 +115,11 @@ subprojects { options.encoding = Charsets.UTF_8.toString() } - configure { - toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) + if (plugins.hasPlugin(JavaBasePlugin::class.java)) { + extensions.configure { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } } } @@ -126,33 +134,38 @@ subprojects { } } - configure { - config = resources.text.fromArchiveEntry(checkstyleConfig, "google_checks.xml") - toolVersion = rootProject.libs.versions.checkStyle.get() - sourceSets = listOf(project.sourceSets["main"]) - } + // Handled in :okhttp directly + if (project.name != "okhttp") { + configure { + config = resources.text.fromArchiveEntry(checkstyleConfig, "google_checks.xml") + toolVersion = rootProject.libs.versions.checkStyle.get() + sourceSets = listOf(project.sourceSets["main"]) + } - // Animal Sniffer confirms we generally don't use APIs not on Java 8. - configure { - annotation = "okhttp3.internal.SuppressSignatureCheck" - sourceSets = listOf(project.sourceSets["main"]) + // Animal Sniffer confirms we generally don't use APIs not on Java 8. + configure { + annotation = "okhttp3.internal.SuppressSignatureCheck" + sourceSets = listOf(project.sourceSets["main"]) + } } - val signature: Configuration by configurations.getting dependencies { // No dependency requirements for testing-support. if (project.name == "okhttp-testing-support") return@dependencies + // okhttp configured specifically. + if (project.name == "okhttp") return@dependencies + if (project.name == "mockwebserver3-junit5") { // JUnit 5's APIs need java.util.function.Function and java.util.Optional from API 24. - signature(rootProject.libs.signature.android.apilevel24) { artifact { type = "signature" } } + "signature"(rootProject.libs.signature.android.apilevel24) { artifact { type = "signature" } } } else { // Everything else requires Android API 21+. - signature(rootProject.libs.signature.android.apilevel21) { artifact { type = "signature" } } + "signature"(rootProject.libs.signature.android.apilevel21) { artifact { type = "signature" } } } // OkHttp requires Java 8+. - signature(rootProject.libs.codehaus.signature.java18) { artifact { type = "signature" } } + "signature"(rootProject.libs.codehaus.signature.java18) { artifact { type = "signature" } } } val javaVersionSetting = @@ -175,10 +188,15 @@ subprojects { } } - val testRuntimeOnly: Configuration by configurations.getting - dependencies { - testRuntimeOnly(rootProject.libs.junit.jupiter.engine) - testRuntimeOnly(rootProject.libs.junit.vintage.engine) + val platform = System.getProperty("okhttp.platform", "jdk9") + val testJavaVersion = System.getProperty("test.java.version", "21").toInt() + + if (project.name != "okhttp") { + val testRuntimeOnly: Configuration by configurations.getting + dependencies { + testRuntimeOnly(rootProject.libs.junit.jupiter.engine) + testRuntimeOnly(rootProject.libs.junit.vintage.engine) + } } tasks.withType { @@ -211,25 +229,30 @@ subprojects { tasks.withType().configureEach { environment("OKHTTP_ROOT", rootDir) } + tasks.withType().configureEach { + environment("OKHTTP_ROOT", rootDir) + } - if (platform == "jdk8alpn") { - // Add alpn-boot on Java 8 so we can use HTTP/2 without a stable API. - val alpnBootVersion = alpnBootVersion() - if (alpnBootVersion != null) { - val alpnBootJar = configurations.detachedConfiguration( - dependencies.create("org.mortbay.jetty.alpn:alpn-boot:$alpnBootVersion") - ).singleFile - tasks.withType { - jvmArgs("-Xbootclasspath/p:${alpnBootJar}") + if (project.name != "okhttp") { + if (platform == "jdk8alpn") { + // Add alpn-boot on Java 8 so we can use HTTP/2 without a stable API. + val alpnBootVersion = alpnBootVersion() + if (alpnBootVersion != null) { + val alpnBootJar = configurations.detachedConfiguration( + dependencies.create("org.mortbay.jetty.alpn:alpn-boot:$alpnBootVersion") + ).singleFile + tasks.withType { + jvmArgs("-Xbootclasspath/p:${alpnBootJar}") + } + } + } else if (platform == "conscrypt") { + dependencies { +// testRuntimeOnly(rootProject.libs.conscrypt.openjdk) + } + } else if (platform == "openjsse") { + dependencies { +// testRuntimeOnly(rootProject.libs.openjsse) } - } - } else if (platform == "conscrypt") { - dependencies { - testRuntimeOnly(rootProject.libs.conscrypt.openjdk) - } - } else if (platform == "openjsse") { - dependencies { - testRuntimeOnly(rootProject.libs.openjsse) } } @@ -246,6 +269,11 @@ subprojects { languageSettings.optIn("okhttp3.ExperimentalOkHttpApi") } } + plugins.withId("org.jetbrains.kotlin.multiplatform") { + kotlinExtension.sourceSets.configureEach { + languageSettings.optIn("okhttp3.ExperimentalOkHttpApi") + } + } plugins.withId("org.jetbrains.kotlin.android") { kotlinExtension.sourceSets.configureEach { languageSettings.optIn("okhttp3.ExperimentalOkHttpApi") @@ -316,6 +344,14 @@ subprojects { } } +plugins.withId("org.jetbrains.kotlin.jvm") { + val test = tasks.named("test") + tasks.register("jvmTest") { + description = "Get 'gradlew jvmTest' to run the tests of JVM-only modules" + dependsOn(test) + } +} + tasks.wrapper { distributionType = Wrapper.DistributionType.ALL } diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 000000000000..ae6fdeecb742 --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "okhttp-buildSrc" diff --git a/gradle.properties b/gradle.properties index c7af0b38dfb6..439ab99d084e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,7 @@ org.gradle.caching=true org.gradle.parallel=true android.useAndroidX=true +kotlin.mpp.applyDefaultHierarchyTemplate=false androidBuild=false graalBuild=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9ce30ad49d65..a8745321b8de 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -47,7 +47,7 @@ gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11 gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.2" gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.17.0" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } -gradlePlugin-dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.20" +gradlePlugin-dokka = "org.jetbrains.dokka:dokka-gradle-plugin:2.0.0" gradlePlugin-errorprone = "net.ltgt.gradle:gradle-errorprone-plugin:4.1.0" gradlePlugin-graalvmBuildTools = "org.graalvm.buildtools.native:org.graalvm.buildtools.native.gradle.plugin:0.10.4" gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "org-jetbrains-kotlin" } @@ -78,7 +78,6 @@ kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = " kotlin-stdlib-osgi = { module = "org.jetbrains.kotlin:kotlin-osgi-bundle", version.ref = "org-jetbrains-kotlin" } kotlin-test-annotations = { module = "org.jetbrains.kotlin:kotlin-test-annotations-common", version.ref = "org-jetbrains-kotlin" } kotlin-test-common = { module = "org.jetbrains.kotlin:kotlin-test-common", version.ref = "org-jetbrains-kotlin" } -kotlin-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref = "org-jetbrains-kotlin" } kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "org-jetbrains-kotlin" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "org-jetbrains-coroutines" } kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "org-jetbrains-coroutines" } diff --git a/mockwebserver-junit4/build.gradle.kts b/mockwebserver-junit4/build.gradle.kts index ced54ebe9c95..389710bbe6d4 100644 --- a/mockwebserver-junit4/build.gradle.kts +++ b/mockwebserver-junit4/build.gradle.kts @@ -19,6 +19,7 @@ dependencies { api(libs.junit) testImplementation(libs.assertk) + testImplementation(libs.junit.vintage.engine) } mavenPublishing { diff --git a/okcurl/build.gradle.kts b/okcurl/build.gradle.kts index a9060b2abb90..0cfa1a5d19a2 100644 --- a/okcurl/build.gradle.kts +++ b/okcurl/build.gradle.kts @@ -55,7 +55,6 @@ tasks.shadowJar { mergeServiceFiles() } - if (testJavaVersion >= 11) { apply(plugin = "org.graalvm.buildtools.native") diff --git a/okhttp-android/build.gradle.kts b/okhttp-android/build.gradle.kts index 59a27124e4ff..d4360b71c694 100644 --- a/okhttp-android/build.gradle.kts +++ b/okhttp-android/build.gradle.kts @@ -64,6 +64,8 @@ dependencies { testImplementation(libs.robolectric) testImplementation(libs.androidx.espresso.core) testImplementation(libs.squareup.okio.fakefilesystem) + testImplementation(projects.okhttpTestingSupport) + testImplementation(rootProject.libs.conscrypt.openjdk) androidTestImplementation(projects.okhttpTls) androidTestImplementation(libs.assertk) @@ -71,7 +73,10 @@ dependencies { androidTestImplementation(libs.androidx.test.runner) } -mavenPublishing { - // AGP 7.2 embeds Dokka 4, which breaks publishing. Android modules are hardcoded to generate Javadoc instead of Gfm. - configure(com.vanniktech.maven.publish.AndroidSingleVariantLibrary(publishJavadocJar=false)) -} +// TODO remove this whole module after merging with okhttp +// Conflicts with KMP :okhttp outputs + +//mavenPublishing { +// // AGP 7.2 embeds Dokka 4, which breaks publishing. Android modules are hardcoded to generate Javadoc instead of Gfm. +// configure(com.vanniktech.maven.publish.AndroidSingleVariantLibrary(publishJavadocJar=false)) +//} diff --git a/okhttp/src/test/java/okhttp3/internal/platform/android/AndroidSocketAdapterTest.kt b/okhttp-android/src/test/kotlin/okhttp3/android/AndroidSocketAdapterTest.kt similarity index 76% rename from okhttp/src/test/java/okhttp3/internal/platform/android/AndroidSocketAdapterTest.kt rename to okhttp-android/src/test/kotlin/okhttp3/android/AndroidSocketAdapterTest.kt index 0d1b3e57f0ec..5c52f3e710af 100644 --- a/okhttp/src/test/java/okhttp3/internal/platform/android/AndroidSocketAdapterTest.kt +++ b/okhttp-android/src/test/kotlin/okhttp3/android/AndroidSocketAdapterTest.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3.internal.platform.android +package okhttp3.android import java.security.Provider import javax.net.ssl.SSLContext @@ -22,7 +22,11 @@ import okhttp3.DelegatingSSLSocket import okhttp3.DelegatingSSLSocketFactory import okhttp3.Protocol.HTTP_1_1 import okhttp3.Protocol.HTTP_2 -import okhttp3.testing.PlatformRule +import okhttp3.internal.platform.android.AndroidSocketAdapter +import okhttp3.internal.platform.android.ConscryptSocketAdapter +import okhttp3.internal.platform.android.DeferredSocketAdapter +import okhttp3.internal.platform.android.SocketAdapter +import okhttp3.internal.platform.android.StandardAndroidSocketAdapter import org.conscrypt.Conscrypt import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -30,20 +34,13 @@ import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Assume.assumeFalse import org.junit.Assume.assumeTrue -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.extension.RegisterExtension -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.MethodSource - -class AndroidSocketAdapterTest { - @RegisterExtension @JvmField - val platform = PlatformRule() - - @BeforeEach - fun setUp() { - platform.assumeConscrypt() - } +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.ParameterizedRobolectricTestRunner +import org.robolectric.ParameterizedRobolectricTestRunner.Parameters +@RunWith(ParameterizedRobolectricTestRunner::class) +class AndroidSocketAdapterTest(val adapter: SocketAdapter) { val context: SSLContext by lazy { val provider: Provider = Conscrypt.newProviderBuilder().provideTrustManager(true).build() @@ -52,9 +49,8 @@ class AndroidSocketAdapterTest { } } - @ParameterizedTest - @MethodSource("data") - fun testMatchesSupportedSocket(adapter: SocketAdapter) { + @Test + fun testMatchesSupportedSocket() { val socketFactory = context.socketFactory val sslSocket = socketFactory.createSocket() as SSLSocket @@ -65,27 +61,24 @@ class AndroidSocketAdapterTest { assertNull(adapter.getSelectedProtocol(sslSocket)) } - @ParameterizedTest - @MethodSource("data") - fun testMatchesSupportedAndroidSocketFactory(adapter: SocketAdapter) { + @Test + fun testMatchesSupportedAndroidSocketFactory() { assumeTrue(adapter is StandardAndroidSocketAdapter) assertTrue(adapter.matchesSocketFactory(context.socketFactory)) assertNotNull(adapter.trustManager(context.socketFactory)) } - @ParameterizedTest - @MethodSource("data") - fun testDoesntMatchSupportedCustomSocketFactory(adapter: SocketAdapter) { + @Test + fun testDoesntMatchSupportedCustomSocketFactory() { assumeFalse(adapter is StandardAndroidSocketAdapter) assertFalse(adapter.matchesSocketFactory(context.socketFactory)) assertNull(adapter.trustManager(context.socketFactory)) } - @ParameterizedTest - @MethodSource("data") - fun testCustomSocket(adapter: SocketAdapter) { + @Test + fun testCustomSocket() { val socketFactory = DelegatingSSLSocketFactory(context.socketFactory) assertFalse(adapter.matchesSocketFactory(socketFactory)) @@ -101,6 +94,7 @@ class AndroidSocketAdapterTest { companion object { @JvmStatic + @Parameters(name = "{0}") fun data(): Collection { return listOfNotNull( DeferredSocketAdapter(ConscryptSocketAdapter.factory), diff --git a/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt b/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt index 1ffaefa723e9..0a8faf0d65ab 100644 --- a/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt +++ b/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt @@ -40,7 +40,7 @@ import org.robolectric.annotation.Config @RunWith(RobolectricTestRunner::class) @Config( - sdk = [30], + sdk = [21, 26, 30, 33, 35], ) class RobolectricOkHttpClientTest { private lateinit var context: Context diff --git a/okhttp-idna-mapping-table/build.gradle.kts b/okhttp-idna-mapping-table/build.gradle.kts index 250c18a60af5..7154371ce8b2 100644 --- a/okhttp-idna-mapping-table/build.gradle.kts +++ b/okhttp-idna-mapping-table/build.gradle.kts @@ -9,6 +9,8 @@ dependencies { testImplementation(libs.assertk) testImplementation(libs.junit.jupiter.api) testImplementation(libs.junit.jupiter.params) + + testImplementation(rootProject.libs.junit.jupiter.engine) } animalsniffer { diff --git a/okhttp-osgi-tests/build.gradle.kts b/okhttp-osgi-tests/build.gradle.kts new file mode 100644 index 000000000000..94b45096ebec --- /dev/null +++ b/okhttp-osgi-tests/build.gradle.kts @@ -0,0 +1,68 @@ +plugins { + kotlin("jvm") +} + +dependencies { + implementation(projects.okhttp) + implementation(projects.okhttpBrotli) + implementation(projects.okhttpCoroutines) + implementation(projects.okhttpDnsoverhttps) + implementation(projects.loggingInterceptor) + implementation(projects.okhttpSse) + implementation(projects.okhttpTls) + implementation(projects.okhttpUrlconnection) + + testImplementation(projects.okhttpTestingSupport) + testImplementation(libs.junit) + testImplementation(libs.kotlin.test.common) + testImplementation(libs.kotlin.test.junit) + testImplementation(libs.assertk) + + testImplementation(libs.aqute.resolve) +} + +normalization { + runtimeClasspath { + /* + - The below two ignored files are generated during test execution + by the test: okhttp/src/test/java/okhttp3/osgi/OsgiTest.java + + - The compressed index.xml file contains a timestamp property which + changes with every test execution, such that running the test + actually changes the test classpath itself. This means that it + can"t benefit from incremental build acceleration, because on every + execution it sees that the classpath has changed, and so to be + safe, it needs to re-run. + + - This is unfortunate, because actually it would be safe to declare + the task as up-to-date, because these two files, which are based on + the generated index.xml, are outputs, not inputs. We can be sure of + this because they are deleted in the @BeforeEach method of the + OsgiTest test class. + + - To enable the benefit of incremental builds, we can ask Gradle + to ignore these two files when considering whether the classpath + has changed. That is the purpose of this normalization block. + */ + ignore("okhttp3/osgi/workspace/cnf/repo/index.xml.gz") + ignore("okhttp3/osgi/workspace/cnf/repo/index.xml.gz.sha") + } +} + +// Expose OSGi jars to the test environment. +val osgiTestDeploy: Configuration by configurations.creating + +val test = tasks.named("test") +val copyOsgiTestDeployment = tasks.register("copyOsgiTestDeployment") { + from(osgiTestDeploy) + into(layout.buildDirectory.dir("resources/test/okhttp3/osgi/deployments")) +} + +test.configure { + dependsOn(copyOsgiTestDeployment) +} + +dependencies { + osgiTestDeploy(libs.eclipseOsgi) + osgiTestDeploy(libs.kotlin.stdlib.osgi) +} diff --git a/okhttp/src/test/java/okhttp3/osgi/OsgiTest.kt b/okhttp-osgi-tests/src/test/kotlin/okhttp3/osgi/OsgiTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/osgi/OsgiTest.kt rename to okhttp-osgi-tests/src/test/kotlin/okhttp3/osgi/OsgiTest.kt diff --git a/okhttp-testing-support/build.gradle.kts b/okhttp-testing-support/build.gradle.kts index 68d2cb4bc2ee..87c287063693 100644 --- a/okhttp-testing-support/build.gradle.kts +++ b/okhttp-testing-support/build.gradle.kts @@ -14,6 +14,8 @@ dependencies { api(libs.conscrypt.openjdk) api(libs.openjsse) + api(rootProject.libs.junit.jupiter.engine) + api(variantOf(libs.amazonCorretto) { classifier("linux-x86_64") }) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt index e9be10d078cd..b1b96c7f82b9 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt @@ -360,15 +360,17 @@ class TaskFaker : Closeable { timeout: Long, unit: TimeUnit, ): T? { - taskRunner.withLock { + return taskRunner.withLock { val waitUntil = nanoTime + unit.toNanos(timeout) while (true) { val result = poll() - if (result != null) return result - if (nanoTime >= waitUntil) return null + if (result != null) return@withLock result + if (nanoTime >= waitUntil) return@withLock null val editCountBefore = editCount yieldUntil { nanoTime >= waitUntil || editCount > editCountBefore } } + // TODO report compiler bug + TODO("Can't get here") } } diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/testing/PlatformRule.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/testing/PlatformRule.kt index bbcda679fcfb..2b9f42d66439 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/testing/PlatformRule.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/testing/PlatformRule.kt @@ -26,6 +26,7 @@ import okhttp3.internal.platform.Jdk8WithJettyBootPlatform import okhttp3.internal.platform.Jdk9Platform import okhttp3.internal.platform.OpenJSSEPlatform import okhttp3.internal.platform.Platform +import okhttp3.internal.platform.PlatformRegistry import okhttp3.tls.HandshakeCertificates import okhttp3.tls.HeldCertificate import okhttp3.tls.internal.TlsUtil.localhost @@ -435,9 +436,14 @@ open class PlatformRule } @JvmStatic - fun getPlatformSystemProperty(): String { + fun getPlatformSystemProperty(): String? { var property: String? = System.getProperty(PROPERTY_NAME) + if (PlatformRegistry.isAndroid) { + // Platforms below are unavailable on Android + return null + } + if (property == null) { property = when (Platform.get()) { diff --git a/okhttp/api/okhttp.api b/okhttp/api/android/okhttp.api similarity index 100% rename from okhttp/api/okhttp.api rename to okhttp/api/android/okhttp.api diff --git a/okhttp/api/jvm/okhttp.api b/okhttp/api/jvm/okhttp.api new file mode 100644 index 000000000000..fcc0709091a4 --- /dev/null +++ b/okhttp/api/jvm/okhttp.api @@ -0,0 +1,1294 @@ +public final class okhttp3/Address { + public final fun -deprecated_certificatePinner ()Lokhttp3/CertificatePinner; + public final fun -deprecated_connectionSpecs ()Ljava/util/List; + public final fun -deprecated_dns ()Lokhttp3/Dns; + public final fun -deprecated_hostnameVerifier ()Ljavax/net/ssl/HostnameVerifier; + public final fun -deprecated_protocols ()Ljava/util/List; + public final fun -deprecated_proxy ()Ljava/net/Proxy; + public final fun -deprecated_proxyAuthenticator ()Lokhttp3/Authenticator; + public final fun -deprecated_proxySelector ()Ljava/net/ProxySelector; + public final fun -deprecated_socketFactory ()Ljavax/net/SocketFactory; + public final fun -deprecated_sslSocketFactory ()Ljavax/net/ssl/SSLSocketFactory; + public final fun -deprecated_url ()Lokhttp3/HttpUrl; + public fun (Ljava/lang/String;ILokhttp3/Dns;Ljavax/net/SocketFactory;Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/HostnameVerifier;Lokhttp3/CertificatePinner;Lokhttp3/Authenticator;Ljava/net/Proxy;Ljava/util/List;Ljava/util/List;Ljava/net/ProxySelector;)V + public final fun certificatePinner ()Lokhttp3/CertificatePinner; + public final fun connectionSpecs ()Ljava/util/List; + public final fun dns ()Lokhttp3/Dns; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public final fun hostnameVerifier ()Ljavax/net/ssl/HostnameVerifier; + public final fun protocols ()Ljava/util/List; + public final fun proxy ()Ljava/net/Proxy; + public final fun proxyAuthenticator ()Lokhttp3/Authenticator; + public final fun proxySelector ()Ljava/net/ProxySelector; + public final fun socketFactory ()Ljavax/net/SocketFactory; + public final fun sslSocketFactory ()Ljavax/net/ssl/SSLSocketFactory; + public fun toString ()Ljava/lang/String; + public final fun url ()Lokhttp3/HttpUrl; +} + +public abstract interface class okhttp3/AsyncDns { + public static final field Companion Lokhttp3/AsyncDns$Companion; + public static final field TYPE_A I + public static final field TYPE_AAAA I + public abstract fun query (Ljava/lang/String;Lokhttp3/AsyncDns$Callback;)V +} + +public abstract interface class okhttp3/AsyncDns$Callback { + public abstract fun onFailure (Ljava/lang/String;Ljava/io/IOException;)V + public abstract fun onResponse (Ljava/lang/String;Ljava/util/List;)V +} + +public final class okhttp3/AsyncDns$Companion { + public static final field TYPE_A I + public static final field TYPE_AAAA I + public final fun toDns ([Lokhttp3/AsyncDns;)Lokhttp3/Dns; +} + +public final class okhttp3/AsyncDns$DnsClass : java/lang/Enum { + public static final field IPV4 Lokhttp3/AsyncDns$DnsClass; + public static final field IPV6 Lokhttp3/AsyncDns$DnsClass; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public final fun getType ()I + public static fun valueOf (Ljava/lang/String;)Lokhttp3/AsyncDns$DnsClass; + public static fun values ()[Lokhttp3/AsyncDns$DnsClass; +} + +public abstract interface class okhttp3/Authenticator { + public static final field Companion Lokhttp3/Authenticator$Companion; + public static final field JAVA_NET_AUTHENTICATOR Lokhttp3/Authenticator; + public static final field NONE Lokhttp3/Authenticator; + public abstract fun authenticate (Lokhttp3/Route;Lokhttp3/Response;)Lokhttp3/Request; +} + +public final class okhttp3/Authenticator$Companion { +} + +public final class okhttp3/Cache : java/io/Closeable, java/io/Flushable { + public static final field Companion Lokhttp3/Cache$Companion; + public final fun -deprecated_directory ()Ljava/io/File; + public fun (Ljava/io/File;J)V + public fun (Lokio/FileSystem;Lokio/Path;J)V + public fun close ()V + public final fun delete ()V + public final fun directory ()Ljava/io/File; + public final fun directoryPath ()Lokio/Path; + public final fun evictAll ()V + public fun flush ()V + public final fun hitCount ()I + public final fun initialize ()V + public final fun isClosed ()Z + public static final fun key (Lokhttp3/HttpUrl;)Ljava/lang/String; + public final fun maxSize ()J + public final fun networkCount ()I + public final fun requestCount ()I + public final fun size ()J + public final fun urls ()Ljava/util/Iterator; + public final fun writeAbortCount ()I + public final fun writeSuccessCount ()I +} + +public final class okhttp3/Cache$Companion { + public final fun hasVaryAll (Lokhttp3/Response;)Z + public final fun key (Lokhttp3/HttpUrl;)Ljava/lang/String; + public final fun varyHeaders (Lokhttp3/Response;)Lokhttp3/Headers; + public final fun varyMatches (Lokhttp3/Response;Lokhttp3/Headers;Lokhttp3/Request;)Z +} + +public final class okhttp3/CacheControl { + public static final field Companion Lokhttp3/CacheControl$Companion; + public static final field FORCE_CACHE Lokhttp3/CacheControl; + public static final field FORCE_NETWORK Lokhttp3/CacheControl; + public final fun -deprecated_immutable ()Z + public final fun -deprecated_maxAgeSeconds ()I + public final fun -deprecated_maxStaleSeconds ()I + public final fun -deprecated_minFreshSeconds ()I + public final fun -deprecated_mustRevalidate ()Z + public final fun -deprecated_noCache ()Z + public final fun -deprecated_noStore ()Z + public final fun -deprecated_noTransform ()Z + public final fun -deprecated_onlyIfCached ()Z + public final fun -deprecated_sMaxAgeSeconds ()I + public final fun immutable ()Z + public final fun isPrivate ()Z + public final fun isPublic ()Z + public final fun maxAgeSeconds ()I + public final fun maxStaleSeconds ()I + public final fun minFreshSeconds ()I + public final fun mustRevalidate ()Z + public final fun noCache ()Z + public final fun noStore ()Z + public final fun noTransform ()Z + public final fun onlyIfCached ()Z + public static final fun parse (Lokhttp3/Headers;)Lokhttp3/CacheControl; + public final fun sMaxAgeSeconds ()I + public fun toString ()Ljava/lang/String; +} + +public final class okhttp3/CacheControl$Builder { + public fun ()V + public final fun build ()Lokhttp3/CacheControl; + public final fun immutable ()Lokhttp3/CacheControl$Builder; + public final fun maxAge (ILjava/util/concurrent/TimeUnit;)Lokhttp3/CacheControl$Builder; + public final fun maxAge-LRDsOJo (J)Lokhttp3/CacheControl$Builder; + public final fun maxStale (ILjava/util/concurrent/TimeUnit;)Lokhttp3/CacheControl$Builder; + public final fun maxStale-LRDsOJo (J)Lokhttp3/CacheControl$Builder; + public final fun minFresh (ILjava/util/concurrent/TimeUnit;)Lokhttp3/CacheControl$Builder; + public final fun minFresh-LRDsOJo (J)Lokhttp3/CacheControl$Builder; + public final fun noCache ()Lokhttp3/CacheControl$Builder; + public final fun noStore ()Lokhttp3/CacheControl$Builder; + public final fun noTransform ()Lokhttp3/CacheControl$Builder; + public final fun onlyIfCached ()Lokhttp3/CacheControl$Builder; +} + +public final class okhttp3/CacheControl$Companion { + public final fun parse (Lokhttp3/Headers;)Lokhttp3/CacheControl; +} + +public abstract interface class okhttp3/Call : java/lang/Cloneable { + public abstract fun cancel ()V + public abstract fun clone ()Lokhttp3/Call; + public abstract fun enqueue (Lokhttp3/Callback;)V + public abstract fun execute ()Lokhttp3/Response; + public abstract fun isCanceled ()Z + public abstract fun isExecuted ()Z + public abstract fun request ()Lokhttp3/Request; + public abstract fun timeout ()Lokio/Timeout; +} + +public abstract interface class okhttp3/Call$Factory { + public abstract fun newCall (Lokhttp3/Request;)Lokhttp3/Call; +} + +public abstract interface class okhttp3/Callback { + public abstract fun onFailure (Lokhttp3/Call;Ljava/io/IOException;)V + public abstract fun onResponse (Lokhttp3/Call;Lokhttp3/Response;)V +} + +public final class okhttp3/CertificatePinner { + public static final field Companion Lokhttp3/CertificatePinner$Companion; + public static final field DEFAULT Lokhttp3/CertificatePinner; + public final fun check (Ljava/lang/String;Ljava/util/List;)V + public final fun check (Ljava/lang/String;[Ljava/security/cert/Certificate;)V + public fun equals (Ljava/lang/Object;)Z + public final fun findMatchingPins (Ljava/lang/String;)Ljava/util/List; + public final fun getPins ()Ljava/util/Set; + public fun hashCode ()I + public static final fun pin (Ljava/security/cert/Certificate;)Ljava/lang/String; + public static final fun sha1Hash (Ljava/security/cert/X509Certificate;)Lokio/ByteString; + public static final fun sha256Hash (Ljava/security/cert/X509Certificate;)Lokio/ByteString; +} + +public final class okhttp3/CertificatePinner$Builder { + public fun ()V + public final fun add (Ljava/lang/String;[Ljava/lang/String;)Lokhttp3/CertificatePinner$Builder; + public final fun build ()Lokhttp3/CertificatePinner; + public final fun getPins ()Ljava/util/List; +} + +public final class okhttp3/CertificatePinner$Companion { + public final fun pin (Ljava/security/cert/Certificate;)Ljava/lang/String; + public final fun sha1Hash (Ljava/security/cert/X509Certificate;)Lokio/ByteString; + public final fun sha256Hash (Ljava/security/cert/X509Certificate;)Lokio/ByteString; +} + +public final class okhttp3/CertificatePinner$Pin { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public fun equals (Ljava/lang/Object;)Z + public final fun getHash ()Lokio/ByteString; + public final fun getHashAlgorithm ()Ljava/lang/String; + public final fun getPattern ()Ljava/lang/String; + public fun hashCode ()I + public final fun matchesCertificate (Ljava/security/cert/X509Certificate;)Z + public final fun matchesHostname (Ljava/lang/String;)Z + public fun toString ()Ljava/lang/String; +} + +public final class okhttp3/Challenge { + public final fun -deprecated_authParams ()Ljava/util/Map; + public final fun -deprecated_charset ()Ljava/nio/charset/Charset; + public final fun -deprecated_realm ()Ljava/lang/String; + public final fun -deprecated_scheme ()Ljava/lang/String; + public fun (Ljava/lang/String;Ljava/lang/String;)V + public fun (Ljava/lang/String;Ljava/util/Map;)V + public final fun authParams ()Ljava/util/Map; + public final fun charset ()Ljava/nio/charset/Charset; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public final fun realm ()Ljava/lang/String; + public final fun scheme ()Ljava/lang/String; + public fun toString ()Ljava/lang/String; + public final fun withCharset (Ljava/nio/charset/Charset;)Lokhttp3/Challenge; +} + +public final class okhttp3/CipherSuite { + public static final field Companion Lokhttp3/CipherSuite$Companion; + public static final field TLS_AES_128_CCM_8_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_AES_128_CCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_AES_128_GCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_AES_256_GCM_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_CHACHA20_POLY1305_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_DSS_WITH_DES_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DHE_RSA_WITH_DES_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_WITH_AES_128_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_WITH_AES_128_GCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_WITH_AES_256_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_WITH_AES_256_GCM_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_WITH_DES_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_DH_anon_WITH_RC4_128_MD5 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_NULL_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_ECDSA_WITH_RC4_128_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_NULL_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDHE_RSA_WITH_RC4_128_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_ECDH_ECDSA_WITH_NULL_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_ECDSA_WITH_RC4_128_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_RSA_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_ECDH_RSA_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_ECDH_RSA_WITH_NULL_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_RSA_WITH_RC4_128_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_anon_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_anon_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_anon_WITH_NULL_SHA Lokhttp3/CipherSuite; + public static final field TLS_ECDH_anon_WITH_RC4_128_SHA Lokhttp3/CipherSuite; + public static final field TLS_EMPTY_RENEGOTIATION_INFO_SCSV Lokhttp3/CipherSuite; + public static final field TLS_FALLBACK_SCSV Lokhttp3/CipherSuite; + public static final field TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 Lokhttp3/CipherSuite; + public static final field TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA Lokhttp3/CipherSuite; + public static final field TLS_KRB5_EXPORT_WITH_RC4_40_MD5 Lokhttp3/CipherSuite; + public static final field TLS_KRB5_EXPORT_WITH_RC4_40_SHA Lokhttp3/CipherSuite; + public static final field TLS_KRB5_WITH_3DES_EDE_CBC_MD5 Lokhttp3/CipherSuite; + public static final field TLS_KRB5_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_KRB5_WITH_DES_CBC_MD5 Lokhttp3/CipherSuite; + public static final field TLS_KRB5_WITH_DES_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_KRB5_WITH_RC4_128_MD5 Lokhttp3/CipherSuite; + public static final field TLS_KRB5_WITH_RC4_128_SHA Lokhttp3/CipherSuite; + public static final field TLS_PSK_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_PSK_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_PSK_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_PSK_WITH_RC4_128_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_EXPORT_WITH_DES40_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_EXPORT_WITH_RC4_40_MD5 Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_3DES_EDE_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_AES_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_AES_128_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_AES_128_GCM_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_AES_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_AES_256_CBC_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_AES_256_GCM_SHA384 Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_CAMELLIA_128_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_CAMELLIA_256_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_DES_CBC_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_NULL_MD5 Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_NULL_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_NULL_SHA256 Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_RC4_128_MD5 Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_RC4_128_SHA Lokhttp3/CipherSuite; + public static final field TLS_RSA_WITH_SEED_CBC_SHA Lokhttp3/CipherSuite; + public final fun -deprecated_javaName ()Ljava/lang/String; + public synthetic fun (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public static final fun forJavaName (Ljava/lang/String;)Lokhttp3/CipherSuite; + public final fun javaName ()Ljava/lang/String; + public fun toString ()Ljava/lang/String; +} + +public final class okhttp3/CipherSuite$Companion { + public final fun forJavaName (Ljava/lang/String;)Lokhttp3/CipherSuite; +} + +public abstract interface class okhttp3/Connection { + public abstract fun handshake ()Lokhttp3/Handshake; + public abstract fun protocol ()Lokhttp3/Protocol; + public abstract fun route ()Lokhttp3/Route; + public abstract fun socket ()Ljava/net/Socket; +} + +public abstract class okhttp3/ConnectionListener { + public static final field Companion Lokhttp3/ConnectionListener$Companion; + public fun ()V + public fun connectEnd (Lokhttp3/Connection;Lokhttp3/Route;Lokhttp3/Call;)V + public fun connectFailed (Lokhttp3/Route;Lokhttp3/Call;Ljava/io/IOException;)V + public fun connectStart (Lokhttp3/Route;Lokhttp3/Call;)V + public fun connectionAcquired (Lokhttp3/Connection;Lokhttp3/Call;)V + public fun connectionClosed (Lokhttp3/Connection;)V + public fun connectionReleased (Lokhttp3/Connection;Lokhttp3/Call;)V + public fun noNewExchanges (Lokhttp3/Connection;)V +} + +public final class okhttp3/ConnectionListener$Companion { + public final fun getNONE ()Lokhttp3/ConnectionListener; +} + +public final class okhttp3/ConnectionPool { + public fun ()V + public fun (IJLjava/util/concurrent/TimeUnit;)V + public fun (IJLjava/util/concurrent/TimeUnit;Lokhttp3/ConnectionListener;)V + public synthetic fun (IJLjava/util/concurrent/TimeUnit;Lokhttp3/ConnectionListener;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun connectionCount ()I + public final fun evictAll ()V + public final fun idleConnectionCount ()I + public final fun setPolicy (Lokhttp3/Address;Lokhttp3/ConnectionPool$AddressPolicy;)V +} + +public final class okhttp3/ConnectionPool$AddressPolicy { + public final field backoffDelayMillis J + public final field backoffJitterMillis I + public final field minimumConcurrentCalls I + public fun ()V + public fun (IJI)V + public synthetic fun (IJIILkotlin/jvm/internal/DefaultConstructorMarker;)V +} + +public final class okhttp3/ConnectionSpec { + public static final field CLEARTEXT Lokhttp3/ConnectionSpec; + public static final field COMPATIBLE_TLS Lokhttp3/ConnectionSpec; + public static final field Companion Lokhttp3/ConnectionSpec$Companion; + public static final field MODERN_TLS Lokhttp3/ConnectionSpec; + public static final field RESTRICTED_TLS Lokhttp3/ConnectionSpec; + public final fun -deprecated_cipherSuites ()Ljava/util/List; + public final fun -deprecated_supportsTlsExtensions ()Z + public final fun -deprecated_tlsVersions ()Ljava/util/List; + public final fun cipherSuites ()Ljava/util/List; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public final fun isCompatible (Ljavax/net/ssl/SSLSocket;)Z + public final fun isTls ()Z + public final fun supportsTlsExtensions ()Z + public final fun tlsVersions ()Ljava/util/List; + public fun toString ()Ljava/lang/String; +} + +public final class okhttp3/ConnectionSpec$Builder { + public fun (Lokhttp3/ConnectionSpec;)V + public final fun allEnabledCipherSuites ()Lokhttp3/ConnectionSpec$Builder; + public final fun allEnabledTlsVersions ()Lokhttp3/ConnectionSpec$Builder; + public final fun build ()Lokhttp3/ConnectionSpec; + public final fun cipherSuites ([Ljava/lang/String;)Lokhttp3/ConnectionSpec$Builder; + public final fun cipherSuites ([Lokhttp3/CipherSuite;)Lokhttp3/ConnectionSpec$Builder; + public final fun supportsTlsExtensions (Z)Lokhttp3/ConnectionSpec$Builder; + public final fun tlsVersions ([Ljava/lang/String;)Lokhttp3/ConnectionSpec$Builder; + public final fun tlsVersions ([Lokhttp3/TlsVersion;)Lokhttp3/ConnectionSpec$Builder; +} + +public final class okhttp3/ConnectionSpec$Companion { +} + +public final class okhttp3/Cookie { + public static final field Companion Lokhttp3/Cookie$Companion; + public final fun -deprecated_domain ()Ljava/lang/String; + public final fun -deprecated_expiresAt ()J + public final fun -deprecated_hostOnly ()Z + public final fun -deprecated_httpOnly ()Z + public final fun -deprecated_name ()Ljava/lang/String; + public final fun -deprecated_path ()Ljava/lang/String; + public final fun -deprecated_persistent ()Z + public final fun -deprecated_secure ()Z + public final fun -deprecated_value ()Ljava/lang/String; + public synthetic fun (Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;ZZZZLjava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun domain ()Ljava/lang/String; + public fun equals (Ljava/lang/Object;)Z + public final fun expiresAt ()J + public fun hashCode ()I + public final fun hostOnly ()Z + public final fun httpOnly ()Z + public final fun matches (Lokhttp3/HttpUrl;)Z + public final fun name ()Ljava/lang/String; + public final fun newBuilder ()Lokhttp3/Cookie$Builder; + public static final fun parse (Lokhttp3/HttpUrl;Ljava/lang/String;)Lokhttp3/Cookie; + public static final fun parseAll (Lokhttp3/HttpUrl;Lokhttp3/Headers;)Ljava/util/List; + public final fun path ()Ljava/lang/String; + public final fun persistent ()Z + public final fun sameSite ()Ljava/lang/String; + public final fun secure ()Z + public fun toString ()Ljava/lang/String; + public final fun value ()Ljava/lang/String; +} + +public final class okhttp3/Cookie$Builder { + public fun ()V + public final fun build ()Lokhttp3/Cookie; + public final fun domain (Ljava/lang/String;)Lokhttp3/Cookie$Builder; + public final fun expiresAt (J)Lokhttp3/Cookie$Builder; + public final fun hostOnlyDomain (Ljava/lang/String;)Lokhttp3/Cookie$Builder; + public final fun httpOnly ()Lokhttp3/Cookie$Builder; + public final fun name (Ljava/lang/String;)Lokhttp3/Cookie$Builder; + public final fun path (Ljava/lang/String;)Lokhttp3/Cookie$Builder; + public final fun sameSite (Ljava/lang/String;)Lokhttp3/Cookie$Builder; + public final fun secure ()Lokhttp3/Cookie$Builder; + public final fun value (Ljava/lang/String;)Lokhttp3/Cookie$Builder; +} + +public final class okhttp3/Cookie$Companion { + public final fun parse (Lokhttp3/HttpUrl;Ljava/lang/String;)Lokhttp3/Cookie; + public final fun parseAll (Lokhttp3/HttpUrl;Lokhttp3/Headers;)Ljava/util/List; +} + +public abstract interface class okhttp3/CookieJar { + public static final field Companion Lokhttp3/CookieJar$Companion; + public static final field NO_COOKIES Lokhttp3/CookieJar; + public abstract fun loadForRequest (Lokhttp3/HttpUrl;)Ljava/util/List; + public abstract fun saveFromResponse (Lokhttp3/HttpUrl;Ljava/util/List;)V +} + +public final class okhttp3/CookieJar$Companion { +} + +public final class okhttp3/Credentials { + public static final field INSTANCE Lokhttp3/Credentials; + public static final fun basic (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + public static final fun basic (Ljava/lang/String;Ljava/lang/String;Ljava/nio/charset/Charset;)Ljava/lang/String; + public static synthetic fun basic$default (Ljava/lang/String;Ljava/lang/String;Ljava/nio/charset/Charset;ILjava/lang/Object;)Ljava/lang/String; +} + +public final class okhttp3/Dispatcher { + public final fun -deprecated_executorService ()Ljava/util/concurrent/ExecutorService; + public fun ()V + public fun (Ljava/util/concurrent/ExecutorService;)V + public final fun cancelAll ()V + public final fun executorService ()Ljava/util/concurrent/ExecutorService; + public final fun getIdleCallback ()Ljava/lang/Runnable; + public final fun getMaxRequests ()I + public final fun getMaxRequestsPerHost ()I + public final fun queuedCalls ()Ljava/util/List; + public final fun queuedCallsCount ()I + public final fun runningCalls ()Ljava/util/List; + public final fun runningCallsCount ()I + public final fun setIdleCallback (Ljava/lang/Runnable;)V + public final fun setMaxRequests (I)V + public final fun setMaxRequestsPerHost (I)V +} + +public abstract interface class okhttp3/Dns { + public static final field Companion Lokhttp3/Dns$Companion; + public static final field SYSTEM Lokhttp3/Dns; + public abstract fun lookup (Ljava/lang/String;)Ljava/util/List; +} + +public final class okhttp3/Dns$Companion { +} + +public abstract class okhttp3/EventListener { + public static final field Companion Lokhttp3/EventListener$Companion; + public static final field NONE Lokhttp3/EventListener; + public fun ()V + public fun cacheConditionalHit (Lokhttp3/Call;Lokhttp3/Response;)V + public fun cacheHit (Lokhttp3/Call;Lokhttp3/Response;)V + public fun cacheMiss (Lokhttp3/Call;)V + public fun callEnd (Lokhttp3/Call;)V + public fun callFailed (Lokhttp3/Call;Ljava/io/IOException;)V + public fun callStart (Lokhttp3/Call;)V + public fun canceled (Lokhttp3/Call;)V + public fun connectEnd (Lokhttp3/Call;Ljava/net/InetSocketAddress;Ljava/net/Proxy;Lokhttp3/Protocol;)V + public fun connectFailed (Lokhttp3/Call;Ljava/net/InetSocketAddress;Ljava/net/Proxy;Lokhttp3/Protocol;Ljava/io/IOException;)V + public fun connectStart (Lokhttp3/Call;Ljava/net/InetSocketAddress;Ljava/net/Proxy;)V + public fun connectionAcquired (Lokhttp3/Call;Lokhttp3/Connection;)V + public fun connectionReleased (Lokhttp3/Call;Lokhttp3/Connection;)V + public fun dnsEnd (Lokhttp3/Call;Ljava/lang/String;Ljava/util/List;)V + public fun dnsStart (Lokhttp3/Call;Ljava/lang/String;)V + public fun proxySelectEnd (Lokhttp3/Call;Lokhttp3/HttpUrl;Ljava/util/List;)V + public fun proxySelectStart (Lokhttp3/Call;Lokhttp3/HttpUrl;)V + public fun requestBodyEnd (Lokhttp3/Call;J)V + public fun requestBodyStart (Lokhttp3/Call;)V + public fun requestFailed (Lokhttp3/Call;Ljava/io/IOException;)V + public fun requestHeadersEnd (Lokhttp3/Call;Lokhttp3/Request;)V + public fun requestHeadersStart (Lokhttp3/Call;)V + public fun responseBodyEnd (Lokhttp3/Call;J)V + public fun responseBodyStart (Lokhttp3/Call;)V + public fun responseFailed (Lokhttp3/Call;Ljava/io/IOException;)V + public fun responseHeadersEnd (Lokhttp3/Call;Lokhttp3/Response;)V + public fun responseHeadersStart (Lokhttp3/Call;)V + public fun satisfactionFailure (Lokhttp3/Call;Lokhttp3/Response;)V + public fun secureConnectEnd (Lokhttp3/Call;Lokhttp3/Handshake;)V + public fun secureConnectStart (Lokhttp3/Call;)V +} + +public final class okhttp3/EventListener$Companion { +} + +public abstract interface class okhttp3/EventListener$Factory { + public abstract fun create (Lokhttp3/Call;)Lokhttp3/EventListener; +} + +public abstract interface annotation class okhttp3/ExperimentalOkHttpApi : java/lang/annotation/Annotation { +} + +public final class okhttp3/FormBody : okhttp3/RequestBody { + public static final field Companion Lokhttp3/FormBody$Companion; + public final fun -deprecated_size ()I + public fun contentLength ()J + public fun contentType ()Lokhttp3/MediaType; + public final fun encodedName (I)Ljava/lang/String; + public final fun encodedValue (I)Ljava/lang/String; + public final fun name (I)Ljava/lang/String; + public final fun size ()I + public final fun value (I)Ljava/lang/String; + public fun writeTo (Lokio/BufferedSink;)V +} + +public final class okhttp3/FormBody$Builder { + public fun ()V + public fun (Ljava/nio/charset/Charset;)V + public synthetic fun (Ljava/nio/charset/Charset;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun add (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/FormBody$Builder; + public final fun addEncoded (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/FormBody$Builder; + public final fun build ()Lokhttp3/FormBody; +} + +public final class okhttp3/FormBody$Companion { +} + +public final class okhttp3/Handshake { + public static final field Companion Lokhttp3/Handshake$Companion; + public final fun -deprecated_cipherSuite ()Lokhttp3/CipherSuite; + public final fun -deprecated_localCertificates ()Ljava/util/List; + public final fun -deprecated_localPrincipal ()Ljava/security/Principal; + public final fun -deprecated_peerCertificates ()Ljava/util/List; + public final fun -deprecated_peerPrincipal ()Ljava/security/Principal; + public final fun -deprecated_tlsVersion ()Lokhttp3/TlsVersion; + public final fun cipherSuite ()Lokhttp3/CipherSuite; + public fun equals (Ljava/lang/Object;)Z + public static final fun get (Ljavax/net/ssl/SSLSession;)Lokhttp3/Handshake; + public static final fun get (Lokhttp3/TlsVersion;Lokhttp3/CipherSuite;Ljava/util/List;Ljava/util/List;)Lokhttp3/Handshake; + public fun hashCode ()I + public final fun localCertificates ()Ljava/util/List; + public final fun localPrincipal ()Ljava/security/Principal; + public final fun peerCertificates ()Ljava/util/List; + public final fun peerPrincipal ()Ljava/security/Principal; + public final fun tlsVersion ()Lokhttp3/TlsVersion; + public fun toString ()Ljava/lang/String; +} + +public final class okhttp3/Handshake$Companion { + public final fun -deprecated_get (Ljavax/net/ssl/SSLSession;)Lokhttp3/Handshake; + public final fun get (Ljavax/net/ssl/SSLSession;)Lokhttp3/Handshake; + public final fun get (Lokhttp3/TlsVersion;Lokhttp3/CipherSuite;Ljava/util/List;Ljava/util/List;)Lokhttp3/Handshake; +} + +public final class okhttp3/Headers : java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker { + public static final field Companion Lokhttp3/Headers$Companion; + public final fun -deprecated_size ()I + public final fun byteCount ()J + public fun equals (Ljava/lang/Object;)Z + public final fun get (Ljava/lang/String;)Ljava/lang/String; + public final fun getDate (Ljava/lang/String;)Ljava/util/Date; + public final fun getInstant (Ljava/lang/String;)Ljava/time/Instant; + public fun hashCode ()I + public fun iterator ()Ljava/util/Iterator; + public final fun name (I)Ljava/lang/String; + public final fun names ()Ljava/util/Set; + public final fun newBuilder ()Lokhttp3/Headers$Builder; + public static final fun of (Ljava/util/Map;)Lokhttp3/Headers; + public static final fun of ([Ljava/lang/String;)Lokhttp3/Headers; + public final fun size ()I + public final fun toMultimap ()Ljava/util/Map; + public fun toString ()Ljava/lang/String; + public final fun value (I)Ljava/lang/String; + public final fun values (Ljava/lang/String;)Ljava/util/List; +} + +public final class okhttp3/Headers$Builder { + public fun ()V + public final fun add (Ljava/lang/String;)Lokhttp3/Headers$Builder; + public final fun add (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Headers$Builder; + public final fun add (Ljava/lang/String;Ljava/time/Instant;)Lokhttp3/Headers$Builder; + public final fun add (Ljava/lang/String;Ljava/util/Date;)Lokhttp3/Headers$Builder; + public final fun addAll (Lokhttp3/Headers;)Lokhttp3/Headers$Builder; + public final fun addUnsafeNonAscii (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Headers$Builder; + public final fun build ()Lokhttp3/Headers; + public final fun get (Ljava/lang/String;)Ljava/lang/String; + public final fun removeAll (Ljava/lang/String;)Lokhttp3/Headers$Builder; + public final fun set (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Headers$Builder; + public final fun set (Ljava/lang/String;Ljava/time/Instant;)Lokhttp3/Headers$Builder; + public final fun set (Ljava/lang/String;Ljava/util/Date;)Lokhttp3/Headers$Builder; +} + +public final class okhttp3/Headers$Companion { + public final fun -deprecated_of (Ljava/util/Map;)Lokhttp3/Headers; + public final fun -deprecated_of ([Ljava/lang/String;)Lokhttp3/Headers; + public final fun of (Ljava/util/Map;)Lokhttp3/Headers; + public final fun of ([Ljava/lang/String;)Lokhttp3/Headers; +} + +public final class okhttp3/HttpUrl { + public static final field Companion Lokhttp3/HttpUrl$Companion; + public final fun -deprecated_encodedFragment ()Ljava/lang/String; + public final fun -deprecated_encodedPassword ()Ljava/lang/String; + public final fun -deprecated_encodedPath ()Ljava/lang/String; + public final fun -deprecated_encodedPathSegments ()Ljava/util/List; + public final fun -deprecated_encodedQuery ()Ljava/lang/String; + public final fun -deprecated_encodedUsername ()Ljava/lang/String; + public final fun -deprecated_fragment ()Ljava/lang/String; + public final fun -deprecated_host ()Ljava/lang/String; + public final fun -deprecated_password ()Ljava/lang/String; + public final fun -deprecated_pathSegments ()Ljava/util/List; + public final fun -deprecated_pathSize ()I + public final fun -deprecated_port ()I + public final fun -deprecated_query ()Ljava/lang/String; + public final fun -deprecated_queryParameterNames ()Ljava/util/Set; + public final fun -deprecated_querySize ()I + public final fun -deprecated_scheme ()Ljava/lang/String; + public final fun -deprecated_uri ()Ljava/net/URI; + public final fun -deprecated_url ()Ljava/net/URL; + public final fun -deprecated_username ()Ljava/lang/String; + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public static final fun defaultPort (Ljava/lang/String;)I + public final fun encodedFragment ()Ljava/lang/String; + public final fun encodedPassword ()Ljava/lang/String; + public final fun encodedPath ()Ljava/lang/String; + public final fun encodedPathSegments ()Ljava/util/List; + public final fun encodedQuery ()Ljava/lang/String; + public final fun encodedUsername ()Ljava/lang/String; + public fun equals (Ljava/lang/Object;)Z + public final fun fragment ()Ljava/lang/String; + public static final fun get (Ljava/lang/String;)Lokhttp3/HttpUrl; + public static final fun get (Ljava/net/URI;)Lokhttp3/HttpUrl; + public static final fun get (Ljava/net/URL;)Lokhttp3/HttpUrl; + public fun hashCode ()I + public final fun host ()Ljava/lang/String; + public final fun isHttps ()Z + public final fun newBuilder ()Lokhttp3/HttpUrl$Builder; + public final fun newBuilder (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public static final fun parse (Ljava/lang/String;)Lokhttp3/HttpUrl; + public final fun password ()Ljava/lang/String; + public final fun pathSegments ()Ljava/util/List; + public final fun pathSize ()I + public final fun port ()I + public final fun query ()Ljava/lang/String; + public final fun queryParameter (Ljava/lang/String;)Ljava/lang/String; + public final fun queryParameterName (I)Ljava/lang/String; + public final fun queryParameterNames ()Ljava/util/Set; + public final fun queryParameterValue (I)Ljava/lang/String; + public final fun queryParameterValues (Ljava/lang/String;)Ljava/util/List; + public final fun querySize ()I + public final fun redact ()Ljava/lang/String; + public final fun resolve (Ljava/lang/String;)Lokhttp3/HttpUrl; + public final fun scheme ()Ljava/lang/String; + public fun toString ()Ljava/lang/String; + public final fun topPrivateDomain ()Ljava/lang/String; + public final fun uri ()Ljava/net/URI; + public final fun url ()Ljava/net/URL; + public final fun username ()Ljava/lang/String; +} + +public final class okhttp3/HttpUrl$Builder { + public fun ()V + public final fun addEncodedPathSegment (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun addEncodedPathSegments (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun addEncodedQueryParameter (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun addPathSegment (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun addPathSegments (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun addQueryParameter (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun build ()Lokhttp3/HttpUrl; + public final fun encodedFragment (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun encodedPassword (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun encodedPath (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun encodedQuery (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun encodedUsername (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun fragment (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun host (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun password (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun port (I)Lokhttp3/HttpUrl$Builder; + public final fun query (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun removeAllEncodedQueryParameters (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun removeAllQueryParameters (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun removePathSegment (I)Lokhttp3/HttpUrl$Builder; + public final fun scheme (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun setEncodedPathSegment (ILjava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun setEncodedQueryParameter (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun setPathSegment (ILjava/lang/String;)Lokhttp3/HttpUrl$Builder; + public final fun setQueryParameter (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; + public fun toString ()Ljava/lang/String; + public final fun username (Ljava/lang/String;)Lokhttp3/HttpUrl$Builder; +} + +public final class okhttp3/HttpUrl$Companion { + public final fun -deprecated_get (Ljava/lang/String;)Lokhttp3/HttpUrl; + public final fun -deprecated_get (Ljava/net/URI;)Lokhttp3/HttpUrl; + public final fun -deprecated_get (Ljava/net/URL;)Lokhttp3/HttpUrl; + public final fun -deprecated_parse (Ljava/lang/String;)Lokhttp3/HttpUrl; + public final fun defaultPort (Ljava/lang/String;)I + public final fun get (Ljava/lang/String;)Lokhttp3/HttpUrl; + public final fun get (Ljava/net/URI;)Lokhttp3/HttpUrl; + public final fun get (Ljava/net/URL;)Lokhttp3/HttpUrl; + public final fun parse (Ljava/lang/String;)Lokhttp3/HttpUrl; +} + +public abstract interface class okhttp3/Interceptor { + public static final field Companion Lokhttp3/Interceptor$Companion; + public abstract fun intercept (Lokhttp3/Interceptor$Chain;)Lokhttp3/Response; +} + +public abstract interface class okhttp3/Interceptor$Chain { + public abstract fun call ()Lokhttp3/Call; + public abstract fun connectTimeoutMillis ()I + public abstract fun connection ()Lokhttp3/Connection; + public abstract fun proceed (Lokhttp3/Request;)Lokhttp3/Response; + public abstract fun readTimeoutMillis ()I + public abstract fun request ()Lokhttp3/Request; + public abstract fun withConnectTimeout (ILjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain; + public abstract fun withReadTimeout (ILjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain; + public abstract fun withWriteTimeout (ILjava/util/concurrent/TimeUnit;)Lokhttp3/Interceptor$Chain; + public abstract fun writeTimeoutMillis ()I +} + +public final class okhttp3/Interceptor$Companion { + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lokhttp3/Interceptor; +} + +public final class okhttp3/MediaType { + public static final field Companion Lokhttp3/MediaType$Companion; + public final fun -deprecated_subtype ()Ljava/lang/String; + public final fun -deprecated_type ()Ljava/lang/String; + public final fun charset ()Ljava/nio/charset/Charset; + public final fun charset (Ljava/nio/charset/Charset;)Ljava/nio/charset/Charset; + public static synthetic fun charset$default (Lokhttp3/MediaType;Ljava/nio/charset/Charset;ILjava/lang/Object;)Ljava/nio/charset/Charset; + public fun equals (Ljava/lang/Object;)Z + public static final fun get (Ljava/lang/String;)Lokhttp3/MediaType; + public fun hashCode ()I + public final fun parameter (Ljava/lang/String;)Ljava/lang/String; + public static final fun parse (Ljava/lang/String;)Lokhttp3/MediaType; + public final fun subtype ()Ljava/lang/String; + public fun toString ()Ljava/lang/String; + public final fun type ()Ljava/lang/String; +} + +public final class okhttp3/MediaType$Companion { + public final fun -deprecated_get (Ljava/lang/String;)Lokhttp3/MediaType; + public final fun -deprecated_parse (Ljava/lang/String;)Lokhttp3/MediaType; + public final fun get (Ljava/lang/String;)Lokhttp3/MediaType; + public final fun parse (Ljava/lang/String;)Lokhttp3/MediaType; +} + +public final class okhttp3/MultipartBody : okhttp3/RequestBody { + public static final field ALTERNATIVE Lokhttp3/MediaType; + public static final field Companion Lokhttp3/MultipartBody$Companion; + public static final field DIGEST Lokhttp3/MediaType; + public static final field FORM Lokhttp3/MediaType; + public static final field MIXED Lokhttp3/MediaType; + public static final field PARALLEL Lokhttp3/MediaType; + public final fun -deprecated_boundary ()Ljava/lang/String; + public final fun -deprecated_parts ()Ljava/util/List; + public final fun -deprecated_size ()I + public final fun -deprecated_type ()Lokhttp3/MediaType; + public final fun boundary ()Ljava/lang/String; + public fun contentLength ()J + public fun contentType ()Lokhttp3/MediaType; + public fun isOneShot ()Z + public final fun part (I)Lokhttp3/MultipartBody$Part; + public final fun parts ()Ljava/util/List; + public final fun size ()I + public final fun type ()Lokhttp3/MediaType; + public fun writeTo (Lokio/BufferedSink;)V +} + +public final class okhttp3/MultipartBody$Builder { + public fun ()V + public fun (Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun addFormDataPart (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/MultipartBody$Builder; + public final fun addFormDataPart (Ljava/lang/String;Ljava/lang/String;Lokhttp3/RequestBody;)Lokhttp3/MultipartBody$Builder; + public final fun addPart (Lokhttp3/Headers;Lokhttp3/RequestBody;)Lokhttp3/MultipartBody$Builder; + public final fun addPart (Lokhttp3/MultipartBody$Part;)Lokhttp3/MultipartBody$Builder; + public final fun addPart (Lokhttp3/RequestBody;)Lokhttp3/MultipartBody$Builder; + public final fun build ()Lokhttp3/MultipartBody; + public final fun setType (Lokhttp3/MediaType;)Lokhttp3/MultipartBody$Builder; +} + +public final class okhttp3/MultipartBody$Companion { +} + +public final class okhttp3/MultipartBody$Part { + public static final field Companion Lokhttp3/MultipartBody$Part$Companion; + public final fun -deprecated_body ()Lokhttp3/RequestBody; + public final fun -deprecated_headers ()Lokhttp3/Headers; + public synthetic fun (Lokhttp3/Headers;Lokhttp3/RequestBody;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun body ()Lokhttp3/RequestBody; + public static final fun create (Lokhttp3/Headers;Lokhttp3/RequestBody;)Lokhttp3/MultipartBody$Part; + public static final fun create (Lokhttp3/RequestBody;)Lokhttp3/MultipartBody$Part; + public static final fun createFormData (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/MultipartBody$Part; + public static final fun createFormData (Ljava/lang/String;Ljava/lang/String;Lokhttp3/RequestBody;)Lokhttp3/MultipartBody$Part; + public final fun headers ()Lokhttp3/Headers; +} + +public final class okhttp3/MultipartBody$Part$Companion { + public final fun create (Lokhttp3/Headers;Lokhttp3/RequestBody;)Lokhttp3/MultipartBody$Part; + public final fun create (Lokhttp3/RequestBody;)Lokhttp3/MultipartBody$Part; + public final fun createFormData (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/MultipartBody$Part; + public final fun createFormData (Ljava/lang/String;Ljava/lang/String;Lokhttp3/RequestBody;)Lokhttp3/MultipartBody$Part; +} + +public final class okhttp3/MultipartReader : java/io/Closeable { + public fun (Lokhttp3/ResponseBody;)V + public fun (Lokio/BufferedSource;Ljava/lang/String;)V + public final fun boundary ()Ljava/lang/String; + public fun close ()V + public final fun nextPart ()Lokhttp3/MultipartReader$Part; +} + +public final class okhttp3/MultipartReader$Part : java/io/Closeable { + public fun (Lokhttp3/Headers;Lokio/BufferedSource;)V + public final fun body ()Lokio/BufferedSource; + public fun close ()V + public final fun headers ()Lokhttp3/Headers; +} + +public final class okhttp3/OkHttp { + public static final field INSTANCE Lokhttp3/OkHttp; + public static final field VERSION Ljava/lang/String; +} + +public class okhttp3/OkHttpClient : okhttp3/Call$Factory, okhttp3/WebSocket$Factory { + public static final field Companion Lokhttp3/OkHttpClient$Companion; + public final fun -deprecated_authenticator ()Lokhttp3/Authenticator; + public final fun -deprecated_cache ()Lokhttp3/Cache; + public final fun -deprecated_callTimeoutMillis ()I + public final fun -deprecated_certificatePinner ()Lokhttp3/CertificatePinner; + public final fun -deprecated_connectTimeoutMillis ()I + public final fun -deprecated_connectionPool ()Lokhttp3/ConnectionPool; + public final fun -deprecated_connectionSpecs ()Ljava/util/List; + public final fun -deprecated_cookieJar ()Lokhttp3/CookieJar; + public final fun -deprecated_dispatcher ()Lokhttp3/Dispatcher; + public final fun -deprecated_dns ()Lokhttp3/Dns; + public final fun -deprecated_eventListenerFactory ()Lokhttp3/EventListener$Factory; + public final fun -deprecated_followRedirects ()Z + public final fun -deprecated_followSslRedirects ()Z + public final fun -deprecated_hostnameVerifier ()Ljavax/net/ssl/HostnameVerifier; + public final fun -deprecated_interceptors ()Ljava/util/List; + public final fun -deprecated_networkInterceptors ()Ljava/util/List; + public final fun -deprecated_pingIntervalMillis ()I + public final fun -deprecated_protocols ()Ljava/util/List; + public final fun -deprecated_proxy ()Ljava/net/Proxy; + public final fun -deprecated_proxyAuthenticator ()Lokhttp3/Authenticator; + public final fun -deprecated_proxySelector ()Ljava/net/ProxySelector; + public final fun -deprecated_readTimeoutMillis ()I + public final fun -deprecated_retryOnConnectionFailure ()Z + public final fun -deprecated_socketFactory ()Ljavax/net/SocketFactory; + public final fun -deprecated_sslSocketFactory ()Ljavax/net/ssl/SSLSocketFactory; + public final fun -deprecated_writeTimeoutMillis ()I + public fun ()V + public final fun address (Lokhttp3/HttpUrl;)Lokhttp3/Address; + public final fun authenticator ()Lokhttp3/Authenticator; + public final fun cache ()Lokhttp3/Cache; + public final fun callTimeoutMillis ()I + public final fun certificateChainCleaner ()Lokhttp3/internal/tls/CertificateChainCleaner; + public final fun certificatePinner ()Lokhttp3/CertificatePinner; + public final fun connectTimeoutMillis ()I + public final fun connectionPool ()Lokhttp3/ConnectionPool; + public final fun connectionSpecs ()Ljava/util/List; + public final fun cookieJar ()Lokhttp3/CookieJar; + public final fun dispatcher ()Lokhttp3/Dispatcher; + public final fun dns ()Lokhttp3/Dns; + public final fun eventListenerFactory ()Lokhttp3/EventListener$Factory; + public final fun fastFallback ()Z + public final fun followRedirects ()Z + public final fun followSslRedirects ()Z + public final fun hostnameVerifier ()Ljavax/net/ssl/HostnameVerifier; + public final fun interceptors ()Ljava/util/List; + public final fun minWebSocketMessageToCompress ()J + public final fun networkInterceptors ()Ljava/util/List; + public fun newBuilder ()Lokhttp3/OkHttpClient$Builder; + public fun newCall (Lokhttp3/Request;)Lokhttp3/Call; + public fun newWebSocket (Lokhttp3/Request;Lokhttp3/WebSocketListener;)Lokhttp3/WebSocket; + public final fun pingIntervalMillis ()I + public final fun protocols ()Ljava/util/List; + public final fun proxy ()Ljava/net/Proxy; + public final fun proxyAuthenticator ()Lokhttp3/Authenticator; + public final fun proxySelector ()Ljava/net/ProxySelector; + public final fun readTimeoutMillis ()I + public final fun retryOnConnectionFailure ()Z + public final fun socketFactory ()Ljavax/net/SocketFactory; + public final fun sslSocketFactory ()Ljavax/net/ssl/SSLSocketFactory; + public final fun webSocketCloseTimeout ()I + public final fun writeTimeoutMillis ()I + public final fun x509TrustManager ()Ljavax/net/ssl/X509TrustManager; +} + +public final class okhttp3/OkHttpClient$Builder { + public final fun -addInterceptor (Lkotlin/jvm/functions/Function1;)Lokhttp3/OkHttpClient$Builder; + public final fun -addNetworkInterceptor (Lkotlin/jvm/functions/Function1;)Lokhttp3/OkHttpClient$Builder; + public fun ()V + public final fun addInterceptor (Lokhttp3/Interceptor;)Lokhttp3/OkHttpClient$Builder; + public final fun addNetworkInterceptor (Lokhttp3/Interceptor;)Lokhttp3/OkHttpClient$Builder; + public final fun authenticator (Lokhttp3/Authenticator;)Lokhttp3/OkHttpClient$Builder; + public final fun build ()Lokhttp3/OkHttpClient; + public final fun cache (Lokhttp3/Cache;)Lokhttp3/OkHttpClient$Builder; + public final fun callTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/OkHttpClient$Builder; + public final fun callTimeout (Ljava/time/Duration;)Lokhttp3/OkHttpClient$Builder; + public final fun callTimeout-LRDsOJo (J)Lokhttp3/OkHttpClient$Builder; + public final fun certificatePinner (Lokhttp3/CertificatePinner;)Lokhttp3/OkHttpClient$Builder; + public final fun connectTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/OkHttpClient$Builder; + public final fun connectTimeout (Ljava/time/Duration;)Lokhttp3/OkHttpClient$Builder; + public final fun connectTimeout-LRDsOJo (J)Lokhttp3/OkHttpClient$Builder; + public final fun connectionPool (Lokhttp3/ConnectionPool;)Lokhttp3/OkHttpClient$Builder; + public final fun connectionSpecs (Ljava/util/List;)Lokhttp3/OkHttpClient$Builder; + public final fun cookieJar (Lokhttp3/CookieJar;)Lokhttp3/OkHttpClient$Builder; + public final fun dispatcher (Lokhttp3/Dispatcher;)Lokhttp3/OkHttpClient$Builder; + public final fun dns (Lokhttp3/Dns;)Lokhttp3/OkHttpClient$Builder; + public final fun eventListener (Lokhttp3/EventListener;)Lokhttp3/OkHttpClient$Builder; + public final fun eventListenerFactory (Lokhttp3/EventListener$Factory;)Lokhttp3/OkHttpClient$Builder; + public final fun fastFallback (Z)Lokhttp3/OkHttpClient$Builder; + public final fun followRedirects (Z)Lokhttp3/OkHttpClient$Builder; + public final fun followSslRedirects (Z)Lokhttp3/OkHttpClient$Builder; + public final fun hostnameVerifier (Ljavax/net/ssl/HostnameVerifier;)Lokhttp3/OkHttpClient$Builder; + public final fun interceptors ()Ljava/util/List; + public final fun minWebSocketMessageToCompress (J)Lokhttp3/OkHttpClient$Builder; + public final fun networkInterceptors ()Ljava/util/List; + public final fun pingInterval (JLjava/util/concurrent/TimeUnit;)Lokhttp3/OkHttpClient$Builder; + public final fun pingInterval (Ljava/time/Duration;)Lokhttp3/OkHttpClient$Builder; + public final fun pingInterval-LRDsOJo (J)Lokhttp3/OkHttpClient$Builder; + public final fun protocols (Ljava/util/List;)Lokhttp3/OkHttpClient$Builder; + public final fun proxy (Ljava/net/Proxy;)Lokhttp3/OkHttpClient$Builder; + public final fun proxyAuthenticator (Lokhttp3/Authenticator;)Lokhttp3/OkHttpClient$Builder; + public final fun proxySelector (Ljava/net/ProxySelector;)Lokhttp3/OkHttpClient$Builder; + public final fun readTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/OkHttpClient$Builder; + public final fun readTimeout (Ljava/time/Duration;)Lokhttp3/OkHttpClient$Builder; + public final fun readTimeout-LRDsOJo (J)Lokhttp3/OkHttpClient$Builder; + public final fun retryOnConnectionFailure (Z)Lokhttp3/OkHttpClient$Builder; + public final fun socketFactory (Ljavax/net/SocketFactory;)Lokhttp3/OkHttpClient$Builder; + public final fun sslSocketFactory (Ljavax/net/ssl/SSLSocketFactory;)Lokhttp3/OkHttpClient$Builder; + public final fun sslSocketFactory (Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lokhttp3/OkHttpClient$Builder; + public final fun webSocketCloseTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/OkHttpClient$Builder; + public final fun webSocketCloseTimeout (Ljava/time/Duration;)Lokhttp3/OkHttpClient$Builder; + public final fun webSocketCloseTimeout-LRDsOJo (J)Lokhttp3/OkHttpClient$Builder; + public final fun writeTimeout (JLjava/util/concurrent/TimeUnit;)Lokhttp3/OkHttpClient$Builder; + public final fun writeTimeout (Ljava/time/Duration;)Lokhttp3/OkHttpClient$Builder; + public final fun writeTimeout-LRDsOJo (J)Lokhttp3/OkHttpClient$Builder; +} + +public final class okhttp3/OkHttpClient$Companion { +} + +public final class okhttp3/Protocol : java/lang/Enum { + public static final field Companion Lokhttp3/Protocol$Companion; + public static final field H2_PRIOR_KNOWLEDGE Lokhttp3/Protocol; + public static final field HTTP_1_0 Lokhttp3/Protocol; + public static final field HTTP_1_1 Lokhttp3/Protocol; + public static final field HTTP_2 Lokhttp3/Protocol; + public static final field HTTP_3 Lokhttp3/Protocol; + public static final field QUIC Lokhttp3/Protocol; + public static final field SPDY_3 Lokhttp3/Protocol; + public static final fun get (Ljava/lang/String;)Lokhttp3/Protocol; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public fun toString ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lokhttp3/Protocol; + public static fun values ()[Lokhttp3/Protocol; +} + +public final class okhttp3/Protocol$Companion { + public final fun get (Ljava/lang/String;)Lokhttp3/Protocol; +} + +public final class okhttp3/Request { + public final fun -deprecated_body ()Lokhttp3/RequestBody; + public final fun -deprecated_cacheControl ()Lokhttp3/CacheControl; + public final fun -deprecated_headers ()Lokhttp3/Headers; + public final fun -deprecated_method ()Ljava/lang/String; + public final fun -deprecated_url ()Lokhttp3/HttpUrl; + public fun (Lokhttp3/HttpUrl;Lokhttp3/Headers;Ljava/lang/String;Lokhttp3/RequestBody;)V + public synthetic fun (Lokhttp3/HttpUrl;Lokhttp3/Headers;Ljava/lang/String;Lokhttp3/RequestBody;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun body ()Lokhttp3/RequestBody; + public final fun cacheControl ()Lokhttp3/CacheControl; + public final fun cacheUrlOverride ()Lokhttp3/HttpUrl; + public final fun header (Ljava/lang/String;)Ljava/lang/String; + public final fun headers ()Lokhttp3/Headers; + public final fun headers (Ljava/lang/String;)Ljava/util/List; + public final fun isHttps ()Z + public final fun method ()Ljava/lang/String; + public final fun newBuilder ()Lokhttp3/Request$Builder; + public final fun tag ()Ljava/lang/Object; + public final fun tag (Ljava/lang/Class;)Ljava/lang/Object; + public final fun tag (Lkotlin/reflect/KClass;)Ljava/lang/Object; + public fun toString ()Ljava/lang/String; + public final fun url ()Lokhttp3/HttpUrl; +} + +public class okhttp3/Request$Builder { + public fun ()V + public fun addHeader (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Request$Builder; + public fun build ()Lokhttp3/Request; + public fun cacheControl (Lokhttp3/CacheControl;)Lokhttp3/Request$Builder; + public final fun cacheUrlOverride (Lokhttp3/HttpUrl;)Lokhttp3/Request$Builder; + public final fun delete ()Lokhttp3/Request$Builder; + public fun delete (Lokhttp3/RequestBody;)Lokhttp3/Request$Builder; + public static synthetic fun delete$default (Lokhttp3/Request$Builder;Lokhttp3/RequestBody;ILjava/lang/Object;)Lokhttp3/Request$Builder; + public fun get ()Lokhttp3/Request$Builder; + public fun head ()Lokhttp3/Request$Builder; + public fun header (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Request$Builder; + public fun headers (Lokhttp3/Headers;)Lokhttp3/Request$Builder; + public fun method (Ljava/lang/String;Lokhttp3/RequestBody;)Lokhttp3/Request$Builder; + public fun patch (Lokhttp3/RequestBody;)Lokhttp3/Request$Builder; + public fun post (Lokhttp3/RequestBody;)Lokhttp3/Request$Builder; + public fun put (Lokhttp3/RequestBody;)Lokhttp3/Request$Builder; + public fun removeHeader (Ljava/lang/String;)Lokhttp3/Request$Builder; + public fun tag (Ljava/lang/Class;Ljava/lang/Object;)Lokhttp3/Request$Builder; + public fun tag (Ljava/lang/Object;)Lokhttp3/Request$Builder; + public final fun tag (Lkotlin/reflect/KClass;Ljava/lang/Object;)Lokhttp3/Request$Builder; + public fun url (Ljava/lang/String;)Lokhttp3/Request$Builder; + public fun url (Ljava/net/URL;)Lokhttp3/Request$Builder; + public fun url (Lokhttp3/HttpUrl;)Lokhttp3/Request$Builder; +} + +public abstract class okhttp3/RequestBody { + public static final field Companion Lokhttp3/RequestBody$Companion; + public fun ()V + public fun contentLength ()J + public abstract fun contentType ()Lokhttp3/MediaType; + public static final fun create (Ljava/io/File;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public static final fun create (Ljava/io/FileDescriptor;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public static final fun create (Ljava/lang/String;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public static final fun create (Lokhttp3/MediaType;Ljava/io/File;)Lokhttp3/RequestBody; + public static final fun create (Lokhttp3/MediaType;Ljava/lang/String;)Lokhttp3/RequestBody; + public static final fun create (Lokhttp3/MediaType;Lokio/ByteString;)Lokhttp3/RequestBody; + public static final fun create (Lokhttp3/MediaType;[B)Lokhttp3/RequestBody; + public static final fun create (Lokhttp3/MediaType;[BI)Lokhttp3/RequestBody; + public static final fun create (Lokhttp3/MediaType;[BII)Lokhttp3/RequestBody; + public static final fun create (Lokio/ByteString;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public static final fun create (Lokio/Path;Lokio/FileSystem;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public static final fun create ([B)Lokhttp3/RequestBody; + public static final fun create ([BLokhttp3/MediaType;)Lokhttp3/RequestBody; + public static final fun create ([BLokhttp3/MediaType;I)Lokhttp3/RequestBody; + public static final fun create ([BLokhttp3/MediaType;II)Lokhttp3/RequestBody; + public static final fun gzip (Lokhttp3/RequestBody;)Lokhttp3/RequestBody; + public fun isDuplex ()Z + public fun isOneShot ()Z + public abstract fun writeTo (Lokio/BufferedSink;)V +} + +public final class okhttp3/RequestBody$Companion { + public final fun create (Ljava/io/File;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public final fun create (Ljava/io/FileDescriptor;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public final fun create (Ljava/lang/String;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public final fun create (Lokhttp3/MediaType;Ljava/io/File;)Lokhttp3/RequestBody; + public final fun create (Lokhttp3/MediaType;Ljava/lang/String;)Lokhttp3/RequestBody; + public final fun create (Lokhttp3/MediaType;Lokio/ByteString;)Lokhttp3/RequestBody; + public final fun create (Lokhttp3/MediaType;[B)Lokhttp3/RequestBody; + public final fun create (Lokhttp3/MediaType;[BI)Lokhttp3/RequestBody; + public final fun create (Lokhttp3/MediaType;[BII)Lokhttp3/RequestBody; + public final fun create (Lokio/ByteString;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public final fun create (Lokio/Path;Lokio/FileSystem;Lokhttp3/MediaType;)Lokhttp3/RequestBody; + public final fun create ([B)Lokhttp3/RequestBody; + public final fun create ([BLokhttp3/MediaType;)Lokhttp3/RequestBody; + public final fun create ([BLokhttp3/MediaType;I)Lokhttp3/RequestBody; + public final fun create ([BLokhttp3/MediaType;II)Lokhttp3/RequestBody; + public static synthetic fun create$default (Lokhttp3/RequestBody$Companion;Ljava/io/File;Lokhttp3/MediaType;ILjava/lang/Object;)Lokhttp3/RequestBody; + public static synthetic fun create$default (Lokhttp3/RequestBody$Companion;Ljava/io/FileDescriptor;Lokhttp3/MediaType;ILjava/lang/Object;)Lokhttp3/RequestBody; + public static synthetic fun create$default (Lokhttp3/RequestBody$Companion;Ljava/lang/String;Lokhttp3/MediaType;ILjava/lang/Object;)Lokhttp3/RequestBody; + public static synthetic fun create$default (Lokhttp3/RequestBody$Companion;Lokhttp3/MediaType;[BIIILjava/lang/Object;)Lokhttp3/RequestBody; + public static synthetic fun create$default (Lokhttp3/RequestBody$Companion;Lokio/ByteString;Lokhttp3/MediaType;ILjava/lang/Object;)Lokhttp3/RequestBody; + public static synthetic fun create$default (Lokhttp3/RequestBody$Companion;Lokio/Path;Lokio/FileSystem;Lokhttp3/MediaType;ILjava/lang/Object;)Lokhttp3/RequestBody; + public static synthetic fun create$default (Lokhttp3/RequestBody$Companion;[BLokhttp3/MediaType;IIILjava/lang/Object;)Lokhttp3/RequestBody; + public final fun gzip (Lokhttp3/RequestBody;)Lokhttp3/RequestBody; +} + +public final class okhttp3/Response : java/io/Closeable { + public final fun -deprecated_body ()Lokhttp3/ResponseBody; + public final fun -deprecated_cacheControl ()Lokhttp3/CacheControl; + public final fun -deprecated_cacheResponse ()Lokhttp3/Response; + public final fun -deprecated_code ()I + public final fun -deprecated_handshake ()Lokhttp3/Handshake; + public final fun -deprecated_headers ()Lokhttp3/Headers; + public final fun -deprecated_message ()Ljava/lang/String; + public final fun -deprecated_networkResponse ()Lokhttp3/Response; + public final fun -deprecated_priorResponse ()Lokhttp3/Response; + public final fun -deprecated_protocol ()Lokhttp3/Protocol; + public final fun -deprecated_receivedResponseAtMillis ()J + public final fun -deprecated_request ()Lokhttp3/Request; + public final fun -deprecated_sentRequestAtMillis ()J + public final fun body ()Lokhttp3/ResponseBody; + public final fun cacheControl ()Lokhttp3/CacheControl; + public final fun cacheResponse ()Lokhttp3/Response; + public final fun challenges ()Ljava/util/List; + public fun close ()V + public final fun code ()I + public final fun handshake ()Lokhttp3/Handshake; + public final fun header (Ljava/lang/String;)Ljava/lang/String; + public final fun header (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + public static synthetic fun header$default (Lokhttp3/Response;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String; + public final fun headers ()Lokhttp3/Headers; + public final fun headers (Ljava/lang/String;)Ljava/util/List; + public final fun isRedirect ()Z + public final fun isSuccessful ()Z + public final fun message ()Ljava/lang/String; + public final fun networkResponse ()Lokhttp3/Response; + public final fun newBuilder ()Lokhttp3/Response$Builder; + public final fun peekBody (J)Lokhttp3/ResponseBody; + public final fun priorResponse ()Lokhttp3/Response; + public final fun protocol ()Lokhttp3/Protocol; + public final fun receivedResponseAtMillis ()J + public final fun request ()Lokhttp3/Request; + public final fun sentRequestAtMillis ()J + public fun toString ()Ljava/lang/String; + public final fun trailers ()Lokhttp3/Headers; +} + +public class okhttp3/Response$Builder { + public fun ()V + public fun addHeader (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Response$Builder; + public fun body (Lokhttp3/ResponseBody;)Lokhttp3/Response$Builder; + public fun build ()Lokhttp3/Response; + public fun cacheResponse (Lokhttp3/Response;)Lokhttp3/Response$Builder; + public fun code (I)Lokhttp3/Response$Builder; + public fun handshake (Lokhttp3/Handshake;)Lokhttp3/Response$Builder; + public fun header (Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Response$Builder; + public fun headers (Lokhttp3/Headers;)Lokhttp3/Response$Builder; + public fun message (Ljava/lang/String;)Lokhttp3/Response$Builder; + public fun networkResponse (Lokhttp3/Response;)Lokhttp3/Response$Builder; + public fun priorResponse (Lokhttp3/Response;)Lokhttp3/Response$Builder; + public fun protocol (Lokhttp3/Protocol;)Lokhttp3/Response$Builder; + public fun receivedResponseAtMillis (J)Lokhttp3/Response$Builder; + public fun removeHeader (Ljava/lang/String;)Lokhttp3/Response$Builder; + public fun request (Lokhttp3/Request;)Lokhttp3/Response$Builder; + public fun sentRequestAtMillis (J)Lokhttp3/Response$Builder; + public fun trailers (Lkotlin/jvm/functions/Function0;)Lokhttp3/Response$Builder; +} + +public abstract class okhttp3/ResponseBody : java/io/Closeable { + public static final field Companion Lokhttp3/ResponseBody$Companion; + public fun ()V + public final fun byteStream ()Ljava/io/InputStream; + public final fun byteString ()Lokio/ByteString; + public final fun bytes ()[B + public final fun charStream ()Ljava/io/Reader; + public fun close ()V + public abstract fun contentLength ()J + public abstract fun contentType ()Lokhttp3/MediaType; + public static final fun create (Ljava/lang/String;Lokhttp3/MediaType;)Lokhttp3/ResponseBody; + public static final fun create (Lokhttp3/MediaType;JLokio/BufferedSource;)Lokhttp3/ResponseBody; + public static final fun create (Lokhttp3/MediaType;Ljava/lang/String;)Lokhttp3/ResponseBody; + public static final fun create (Lokhttp3/MediaType;Lokio/ByteString;)Lokhttp3/ResponseBody; + public static final fun create (Lokhttp3/MediaType;[B)Lokhttp3/ResponseBody; + public static final fun create (Lokio/BufferedSource;Lokhttp3/MediaType;J)Lokhttp3/ResponseBody; + public static final fun create (Lokio/ByteString;Lokhttp3/MediaType;)Lokhttp3/ResponseBody; + public static final fun create ([BLokhttp3/MediaType;)Lokhttp3/ResponseBody; + public abstract fun source ()Lokio/BufferedSource; + public final fun string ()Ljava/lang/String; +} + +public final class okhttp3/ResponseBody$Companion { + public final fun create (Ljava/lang/String;Lokhttp3/MediaType;)Lokhttp3/ResponseBody; + public final fun create (Lokhttp3/MediaType;JLokio/BufferedSource;)Lokhttp3/ResponseBody; + public final fun create (Lokhttp3/MediaType;Ljava/lang/String;)Lokhttp3/ResponseBody; + public final fun create (Lokhttp3/MediaType;Lokio/ByteString;)Lokhttp3/ResponseBody; + public final fun create (Lokhttp3/MediaType;[B)Lokhttp3/ResponseBody; + public final fun create (Lokio/BufferedSource;Lokhttp3/MediaType;J)Lokhttp3/ResponseBody; + public final fun create (Lokio/ByteString;Lokhttp3/MediaType;)Lokhttp3/ResponseBody; + public final fun create ([BLokhttp3/MediaType;)Lokhttp3/ResponseBody; + public static synthetic fun create$default (Lokhttp3/ResponseBody$Companion;Ljava/lang/String;Lokhttp3/MediaType;ILjava/lang/Object;)Lokhttp3/ResponseBody; + public static synthetic fun create$default (Lokhttp3/ResponseBody$Companion;Lokio/BufferedSource;Lokhttp3/MediaType;JILjava/lang/Object;)Lokhttp3/ResponseBody; + public static synthetic fun create$default (Lokhttp3/ResponseBody$Companion;Lokio/ByteString;Lokhttp3/MediaType;ILjava/lang/Object;)Lokhttp3/ResponseBody; + public static synthetic fun create$default (Lokhttp3/ResponseBody$Companion;[BLokhttp3/MediaType;ILjava/lang/Object;)Lokhttp3/ResponseBody; +} + +public final class okhttp3/Route { + public final fun -deprecated_address ()Lokhttp3/Address; + public final fun -deprecated_proxy ()Ljava/net/Proxy; + public final fun -deprecated_socketAddress ()Ljava/net/InetSocketAddress; + public fun (Lokhttp3/Address;Ljava/net/Proxy;Ljava/net/InetSocketAddress;)V + public final fun address ()Lokhttp3/Address; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public final fun proxy ()Ljava/net/Proxy; + public final fun requiresTunnel ()Z + public final fun socketAddress ()Ljava/net/InetSocketAddress; + public fun toString ()Ljava/lang/String; +} + +public final class okhttp3/TlsVersion : java/lang/Enum { + public static final field Companion Lokhttp3/TlsVersion$Companion; + public static final field SSL_3_0 Lokhttp3/TlsVersion; + public static final field TLS_1_0 Lokhttp3/TlsVersion; + public static final field TLS_1_1 Lokhttp3/TlsVersion; + public static final field TLS_1_2 Lokhttp3/TlsVersion; + public static final field TLS_1_3 Lokhttp3/TlsVersion; + public final fun -deprecated_javaName ()Ljava/lang/String; + public static final fun forJavaName (Ljava/lang/String;)Lokhttp3/TlsVersion; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public final fun javaName ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lokhttp3/TlsVersion; + public static fun values ()[Lokhttp3/TlsVersion; +} + +public final class okhttp3/TlsVersion$Companion { + public final fun forJavaName (Ljava/lang/String;)Lokhttp3/TlsVersion; +} + +public abstract interface class okhttp3/WebSocket { + public abstract fun cancel ()V + public abstract fun close (ILjava/lang/String;)Z + public abstract fun queueSize ()J + public abstract fun request ()Lokhttp3/Request; + public abstract fun send (Ljava/lang/String;)Z + public abstract fun send (Lokio/ByteString;)Z +} + +public abstract interface class okhttp3/WebSocket$Factory { + public abstract fun newWebSocket (Lokhttp3/Request;Lokhttp3/WebSocketListener;)Lokhttp3/WebSocket; +} + +public abstract class okhttp3/WebSocketListener { + public fun ()V + public fun onClosed (Lokhttp3/WebSocket;ILjava/lang/String;)V + public fun onClosing (Lokhttp3/WebSocket;ILjava/lang/String;)V + public fun onFailure (Lokhttp3/WebSocket;Ljava/lang/Throwable;Lokhttp3/Response;)V + public fun onMessage (Lokhttp3/WebSocket;Ljava/lang/String;)V + public fun onMessage (Lokhttp3/WebSocket;Lokio/ByteString;)V + public fun onOpen (Lokhttp3/WebSocket;Lokhttp3/Response;)V +} + diff --git a/okhttp/build.gradle.kts b/okhttp/build.gradle.kts index e1214a6fc1fe..cd9b9e66a8c7 100644 --- a/okhttp/build.gradle.kts +++ b/okhttp/build.gradle.kts @@ -1,15 +1,24 @@ +@file:Suppress("UnstableApiUsage") + +import aQute.bnd.gradle.BundleTaskExtension import com.vanniktech.maven.publish.JavadocJar -import com.vanniktech.maven.publish.KotlinJvm +import com.vanniktech.maven.publish.KotlinMultiplatform +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferExtension import java.util.Base64 plugins { - kotlin("jvm") + kotlin("multiplatform") + id("com.android.library") kotlin("plugin.serialization") id("org.jetbrains.dokka") id("com.vanniktech.maven.publish.base") id("binary-compatibility-validator") } +val platform = System.getProperty("okhttp.platform", "jdk9") +val testJavaVersion = System.getProperty("test.java.version", "21").toInt() + fun ByteArray.toByteStringExpression(): String { return "\"${Base64.getEncoder().encodeToString(this@toByteStringExpression)}\".decodeBase64()!!" } @@ -17,15 +26,15 @@ fun ByteArray.toByteStringExpression(): String { val copyKotlinTemplates = tasks.register("copyKotlinTemplates") { val kotlinTemplatesOutput = layout.buildDirectory.dir("generated/sources/kotlinTemplates") - from("src/main/kotlinTemplates") + from("src/commonJvmAndroid/kotlinTemplates") into(kotlinTemplatesOutput) // Tag as an input to regenerate after an update - inputs.file("src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") + inputs.file("src/jvmTest/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") filteringCharset = Charsets.UTF_8.toString() - val databaseGz = project.file("src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") + val databaseGz = project.file("src/jvmTest/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") val listBytes = databaseGz.readBytes().toByteStringExpression() expand( @@ -52,125 +61,192 @@ val generateIdnaMappingTable = tasks.register("generateIdnaMappingTabl } kotlin { + jvmToolchain(8) + + jvm { +// withJava() /* <- cannot be used when the Android Plugin is present */ + } + + androidTarget { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } + } + sourceSets { - getByName("main") { + val commonJvmAndroid = create("commonJvmAndroid") { + dependsOn(commonMain.get()) + kotlin.srcDir(copyKotlinTemplates.map { it.outputs }) kotlin.srcDir(generateIdnaMappingTable.map { it.outputs }) + + dependencies { + api(libs.squareup.okio) + api(libs.kotlin.stdlib) + + compileOnly(libs.findbugs.jsr305) + compileOnly(libs.animalsniffer.annotations) + } + } + + androidMain { + dependsOn(commonJvmAndroid) + dependencies { + compileOnly(libs.bouncycastle.bcprov) + compileOnly(libs.bouncycastle.bctls) + compileOnly(libs.conscrypt.openjdk) + } + } + + jvmMain { + dependsOn(commonJvmAndroid) + + dependencies { + // These compileOnly dependencies must also be listed in the OSGi configuration above. + compileOnly(libs.conscrypt.openjdk) + compileOnly(libs.bouncycastle.bcprov) + compileOnly(libs.bouncycastle.bctls) + + // graal build support + compileOnly(libs.nativeImageSvm) + compileOnly(libs.openjsse) + } + } + + val jvmTest by getting { + dependencies { + implementation(projects.okhttpTestingSupport) + implementation(libs.assertk) + implementation(libs.kotlin.test.annotations) + implementation(libs.kotlin.test.common) + implementation(libs.kotlinx.serialization.core) + implementation(libs.kotlinx.serialization.json) + implementation(projects.okhttpJavaNetCookiejar) + implementation(projects.okhttpTls) + implementation(projects.okhttpUrlconnection) + implementation(projects.mockwebserver3) + implementation(projects.mockwebserver3Junit4) + implementation(projects.mockwebserver3Junit5) + implementation(projects.mockwebserver) + implementation(projects.loggingInterceptor) + implementation(projects.okhttpBrotli) + implementation(projects.okhttpDnsoverhttps) + implementation(projects.okhttpIdnaMappingTable) + implementation(projects.okhttpSse) + implementation(projects.okhttpCoroutines) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.squareup.moshi) + implementation(libs.squareup.moshi.kotlin) + implementation(libs.squareup.okio.fakefilesystem) + implementation(libs.conscrypt.openjdk) + implementation(libs.junit) + implementation(libs.junit.jupiter.api) + implementation(libs.junit.jupiter.params) + implementation(libs.kotlin.test.junit) + implementation(libs.openjsse) + compileOnly(libs.findbugs.jsr305) + + implementation(libs.junit.jupiter.engine) + implementation(libs.junit.vintage.engine) + + if (platform == "conscrypt") { + implementation(rootProject.libs.conscrypt.openjdk) + } else if (platform == "openjsse") { + implementation(rootProject.libs.openjsse) + } + } } } } -project.applyOsgi( - "Export-Package: okhttp3,okhttp3.internal.*;okhttpinternal=true;mandatory:=okhttpinternal", - "Import-Package: " + - "android.*;resolution:=optional," + - "com.oracle.svm.core.annotate;resolution:=optional," + - "com.oracle.svm.core.configure;resolution:=optional," + - "dalvik.system;resolution:=optional," + - "org.conscrypt;resolution:=optional," + - "org.bouncycastle.*;resolution:=optional," + - "org.openjsse.*;resolution:=optional," + - "org.graalvm.nativeimage;resolution:=optional," + - "org.graalvm.nativeimage.hosted;resolution:=optional," + - "sun.security.ssl;resolution:=optional,*", - "Automatic-Module-Name: okhttp3", - "Bundle-SymbolicName: com.squareup.okhttp3" -) - -normalization { - runtimeClasspath { - /* - - The below two ignored files are generated during test execution - by the test: okhttp/src/test/java/okhttp3/osgi/OsgiTest.java - - - The compressed index.xml file contains a timestamp property which - changes with every test execution, such that running the test - actually changes the test classpath itself. This means that it - can"t benefit from incremental build acceleration, because on every - execution it sees that the classpath has changed, and so to be - safe, it needs to re-run. - - - This is unfortunate, because actually it would be safe to declare - the task as up-to-date, because these two files, which are based on - the generated index.xml, are outputs, not inputs. We can be sure of - this because they are deleted in the @BeforeEach method of the - OsgiTest test class. - - - To enable the benefit of incremental builds, we can ask Gradle - to ignore these two files when considering whether the classpath - has changed. That is the purpose of this normalization block. - */ - ignore("okhttp3/osgi/workspace/cnf/repo/index.xml.gz") - ignore("okhttp3/osgi/workspace/cnf/repo/index.xml.gz.sha") +if (platform == "jdk8alpn") { + // Add alpn-boot on Java 8 so we can use HTTP/2 without a stable API. + val alpnBootVersion = alpnBootVersion() + if (alpnBootVersion != null) { + val alpnBootJar = configurations.detachedConfiguration( + dependencies.create("org.mortbay.jetty.alpn:alpn-boot:$alpnBootVersion") + ).singleFile + tasks.withType { + jvmArgs("-Xbootclasspath/p:${alpnBootJar}") + } } } -// Expose OSGi jars to the test environment. -val osgiTestDeploy: Configuration by configurations.creating +android { + compileSdk = 34 + + namespace = "okhttp.okhttp3" + + defaultConfig { + minSdk = 21 -val test by tasks.existing(Test::class) -val copyOsgiTestDeployment = tasks.register("copyOsgiTestDeployment") { - from(osgiTestDeploy) - into(layout.buildDirectory.dir("resources/test/okhttp3/osgi/deployments")) + consumerProguardFiles("okhttp3.pro") + } } -test.configure { - dependsOn(copyOsgiTestDeployment) +// Hack to make BundleTaskExtension pass briefly +project.extensions + .getByType(JavaPluginExtension::class.java) + .sourceSets.create("main") + +// Call the convention when the task has finished, to modify the jar to contain OSGi metadata. +tasks.named("jvmJar").configure { + val bundleExtension = extensions.create( + BundleTaskExtension.NAME, + BundleTaskExtension::class.java, + this, + ).apply { + classpath(libs.kotlin.stdlib.osgi.map { it.artifacts }, tasks.named("jvmMainClasses").map { it.outputs }) + bnd( + "Export-Package: okhttp3,okhttp3.internal.*;okhttpinternal=true;mandatory:=okhttpinternal", + "Import-Package: " + + "com.oracle.svm.core.annotate;resolution:=optional," + + "com.oracle.svm.core.configure;resolution:=optional," + + "dalvik.system;resolution:=optional," + + "org.conscrypt;resolution:=optional," + + "org.bouncycastle.*;resolution:=optional," + + "org.openjsse.*;resolution:=optional," + + "org.graalvm.nativeimage;resolution:=optional," + + "org.graalvm.nativeimage.hosted;resolution:=optional," + + "sun.security.ssl;resolution:=optional,*", + "Automatic-Module-Name: okhttp3", + "Bundle-SymbolicName: com.squareup.okhttp3" + ) + } + + doLast { + bundleExtension.buildAction().execute(this) + } } +val checkstyleConfig: Configuration by configurations.named("checkstyleConfig") dependencies { - api(libs.squareup.okio) - api(libs.kotlin.stdlib) - - // These compileOnly dependencies must also be listed in the OSGi configuration above. - compileOnly(libs.robolectric.android) - compileOnly(libs.bouncycastle.bcprov) - compileOnly(libs.bouncycastle.bctls) - compileOnly(libs.conscrypt.openjdk) - compileOnly(libs.openjsse) - compileOnly(libs.findbugs.jsr305) - compileOnly(libs.animalsniffer.annotations) - - // graal build support - compileOnly(libs.nativeImageSvm) - - testCompileOnly(libs.bouncycastle.bctls) - testImplementation(projects.okhttpTestingSupport) - testImplementation(libs.assertk) - testImplementation(libs.kotlin.test.annotations) - testImplementation(libs.kotlin.test.common) - testImplementation(libs.kotlinx.serialization.core) - testImplementation(libs.kotlinx.serialization.json) - testImplementation(projects.okhttpJavaNetCookiejar) - testImplementation(projects.okhttpTls) - testImplementation(projects.okhttpUrlconnection) - testImplementation(projects.mockwebserver3) - testImplementation(projects.mockwebserver3Junit4) - testImplementation(projects.mockwebserver3Junit5) - testImplementation(projects.mockwebserver) - testImplementation(projects.loggingInterceptor) - testImplementation(projects.okhttpBrotli) - testImplementation(projects.okhttpDnsoverhttps) - testImplementation(projects.okhttpIdnaMappingTable) - testImplementation(projects.okhttpSse) - testImplementation(projects.okhttpCoroutines) - testImplementation(libs.kotlinx.coroutines.core) - testImplementation(libs.squareup.moshi) - testImplementation(libs.squareup.moshi.kotlin) - testImplementation(libs.squareup.okio.fakefilesystem) - testImplementation(libs.conscrypt.openjdk) - testImplementation(libs.junit) - testImplementation(libs.junit.jupiter.api) - testImplementation(libs.junit.jupiter.params) - testImplementation(libs.kotlin.test.junit) - testImplementation(libs.openjsse) - testImplementation(libs.aqute.resolve) - testCompileOnly(libs.findbugs.jsr305) - - osgiTestDeploy(libs.eclipseOsgi) - osgiTestDeploy(libs.kotlin.stdlib.osgi) + // Everything else requires Android API 21+. + "signature"(rootProject.libs.signature.android.apilevel21) { artifact { type = "signature" } } + + // OkHttp requires Java 8+. + "signature"(rootProject.libs.codehaus.signature.java18) { artifact { type = "signature" } } + + checkstyleConfig(rootProject.libs.checkStyle) { + isTransitive = false + } +} + +// Animal Sniffer confirms we generally don't use APIs not on Java 8. +configure { + annotation = "okhttp3.internal.SuppressSignatureCheck" + sourceSets = listOf(project.sourceSets["main"]) +} + +configure { + config = resources.text.fromArchiveEntry(checkstyleConfig, "google_checks.xml") + toolVersion = rootProject.libs.versions.checkStyle.get() + // TODO switch out checkstyle to use something supporting KMP + sourceSets = listOf(project.sourceSets["main"]) } +apply(plugin = "io.github.usefulness.maven-sympathy") + mavenPublishing { - configure(KotlinJvm(javadocJar = JavadocJar.Empty())) + configure(KotlinMultiplatform(javadocJar = JavadocJar.Empty(), androidVariantsToPublish = listOf("release"))) } diff --git a/okhttp/src/main/resources/META-INF/proguard/okhttp3.pro b/okhttp/okhttp3.pro similarity index 85% rename from okhttp/src/main/resources/META-INF/proguard/okhttp3.pro rename to okhttp/okhttp3.pro index 280a52749be2..06eb9cc36d90 100644 --- a/okhttp/src/main/resources/META-INF/proguard/okhttp3.pro +++ b/okhttp/okhttp3.pro @@ -5,6 +5,7 @@ -dontwarn org.codehaus.mojo.animal_sniffer.* # OkHttp platform used only on JVM and when Conscrypt and other security providers are available. +# May be used with robolectric or deliberate use of Bouncy Castle on Android -dontwarn okhttp3.internal.platform.** -dontwarn org.conscrypt.** -dontwarn org.bouncycastle.** diff --git a/okhttp/src/androidMain/AndroidManifest.xml b/okhttp/src/androidMain/AndroidManifest.xml new file mode 100644 index 000000000000..6b7444be5b61 --- /dev/null +++ b/okhttp/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/Android10Platform.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/Android10Platform.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/Android10Platform.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/Android10Platform.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/AndroidPlatform.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/AndroidPlatform.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/PlatformRegistry.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/PlatformRegistry.kt new file mode 100644 index 000000000000..38ec6920953a --- /dev/null +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/PlatformRegistry.kt @@ -0,0 +1,13 @@ +package okhttp3.internal.platform + +import okhttp3.internal.platform.android.AndroidLog + +actual object PlatformRegistry { + actual fun findPlatform(): Platform { + AndroidLog.enable() + return Android10Platform.buildIfSupported() ?: AndroidPlatform.buildIfSupported()!! + } + + actual val isAndroid: Boolean + get() = true +} diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/Android10SocketAdapter.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidCertificateChainCleaner.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidCertificateChainCleaner.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidCertificateChainCleaner.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidCertificateChainCleaner.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidLog.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidLog.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidLog.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidLog.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/AndroidSocketAdapter.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt similarity index 81% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt index a2a4ffdfb018..fb0bab1a40ac 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/BouncyCastleSocketAdapter.kt @@ -17,7 +17,6 @@ package okhttp3.internal.platform.android import javax.net.ssl.SSLSocket import okhttp3.Protocol -import okhttp3.internal.platform.BouncyCastlePlatform import okhttp3.internal.platform.Platform import org.bouncycastle.jsse.BCSSLSocket @@ -27,7 +26,7 @@ import org.bouncycastle.jsse.BCSSLSocket class BouncyCastleSocketAdapter : SocketAdapter { override fun matchesSocket(sslSocket: SSLSocket): Boolean = sslSocket is BCSSLSocket - override fun isSupported(): Boolean = BouncyCastlePlatform.isSupported + override fun isSupported(): Boolean = isSupported override fun getSelectedProtocol(sslSocket: SSLSocket): String? { val s = sslSocket as BCSSLSocket @@ -60,10 +59,20 @@ class BouncyCastleSocketAdapter : SocketAdapter { val factory = object : DeferredSocketAdapter.Factory { override fun matchesSocket(sslSocket: SSLSocket): Boolean { - return BouncyCastlePlatform.isSupported && sslSocket is BCSSLSocket + return isSupported && sslSocket is BCSSLSocket } override fun create(sslSocket: SSLSocket): SocketAdapter = BouncyCastleSocketAdapter() } + + val isSupported: Boolean = + try { + // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. + Class.forName("org.bouncycastle.jsse.provider.BouncyCastleJsseProvider", false, javaClass.classLoader) + + true + } catch (_: ClassNotFoundException) { + false + } } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt similarity index 64% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt index 00781ee19b05..f14b9f8b9bc9 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/ConscryptSocketAdapter.kt @@ -17,7 +17,6 @@ package okhttp3.internal.platform.android import javax.net.ssl.SSLSocket import okhttp3.Protocol -import okhttp3.internal.platform.ConscryptPlatform import okhttp3.internal.platform.Platform import org.conscrypt.Conscrypt @@ -28,7 +27,7 @@ import org.conscrypt.Conscrypt class ConscryptSocketAdapter : SocketAdapter { override fun matchesSocket(sslSocket: SSLSocket): Boolean = Conscrypt.isConscrypt(sslSocket) - override fun isSupported(): Boolean = ConscryptPlatform.isSupported + override fun isSupported(): Boolean = isSupported override fun getSelectedProtocol(sslSocket: SSLSocket): String? = when { @@ -56,10 +55,44 @@ class ConscryptSocketAdapter : SocketAdapter { val factory = object : DeferredSocketAdapter.Factory { override fun matchesSocket(sslSocket: SSLSocket): Boolean { - return ConscryptPlatform.isSupported && Conscrypt.isConscrypt(sslSocket) + return isSupported && Conscrypt.isConscrypt(sslSocket) } override fun create(sslSocket: SSLSocket): SocketAdapter = ConscryptSocketAdapter() } + + val isSupported: Boolean = + try { + // Trigger an early exception over a fatal error, prefer a RuntimeException over Error. + Class.forName("org.conscrypt.Conscrypt\$Version", false, javaClass.classLoader) + + when { + // Bump this version if we ever have a binary incompatibility + Conscrypt.isAvailable() && atLeastVersion(2, 1, 0) -> true + else -> false + } + } catch (e: NoClassDefFoundError) { + false + } catch (e: ClassNotFoundException) { + false + } + + fun atLeastVersion( + major: Int, + minor: Int = 0, + patch: Int = 0, + ): Boolean { + val conscryptVersion = Conscrypt.version() ?: return false + + if (conscryptVersion.major() != major) { + return conscryptVersion.major() > major + } + + if (conscryptVersion.minor() != minor) { + return conscryptVersion.minor() > minor + } + + return conscryptVersion.patch() >= patch + } } } diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/DeferredSocketAdapter.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/SocketAdapter.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/android/StandardAndroidSocketAdapter.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/StandardAndroidSocketAdapter.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/android/StandardAndroidSocketAdapter.kt rename to okhttp/src/androidMain/kotlin/okhttp3/internal/platform/android/StandardAndroidSocketAdapter.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Address.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Address.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Address.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Address.kt diff --git a/okhttp/src/main/kotlin/okhttp3/AsyncDns.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/AsyncDns.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/AsyncDns.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/AsyncDns.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Authenticator.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Authenticator.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Authenticator.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Authenticator.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Cache.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cache.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Cache.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cache.kt diff --git a/okhttp/src/main/kotlin/okhttp3/CacheControl.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/CacheControl.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/CacheControl.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/CacheControl.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Call.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Call.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Call.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Call.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Callback.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Callback.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Callback.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Callback.kt diff --git a/okhttp/src/main/kotlin/okhttp3/CertificatePinner.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/CertificatePinner.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/CertificatePinner.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/CertificatePinner.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Challenge.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Challenge.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Challenge.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Challenge.kt diff --git a/okhttp/src/main/kotlin/okhttp3/CipherSuite.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/CipherSuite.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/CipherSuite.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/CipherSuite.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Connection.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Connection.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Connection.kt diff --git a/okhttp/src/main/kotlin/okhttp3/ConnectionListener.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionListener.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/ConnectionListener.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionListener.kt diff --git a/okhttp/src/main/kotlin/okhttp3/ConnectionPool.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionPool.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/ConnectionPool.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionPool.kt diff --git a/okhttp/src/main/kotlin/okhttp3/ConnectionSpec.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionSpec.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/ConnectionSpec.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/ConnectionSpec.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Cookie.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Cookie.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Cookie.kt diff --git a/okhttp/src/main/kotlin/okhttp3/CookieJar.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/CookieJar.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/CookieJar.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/CookieJar.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Credentials.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Credentials.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Credentials.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Credentials.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Dispatcher.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Dispatcher.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Dns.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dns.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Dns.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dns.kt diff --git a/okhttp/src/main/kotlin/okhttp3/EventListener.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/EventListener.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/EventListener.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/EventListener.kt diff --git a/okhttp/src/main/kotlin/okhttp3/ExperimentalOkHttpApi.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/ExperimentalOkHttpApi.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/ExperimentalOkHttpApi.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/ExperimentalOkHttpApi.kt diff --git a/okhttp/src/main/kotlin/okhttp3/FormBody.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/FormBody.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/FormBody.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/FormBody.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Handshake.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Handshake.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Handshake.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Handshake.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Headers.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Headers.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Headers.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Headers.kt diff --git a/okhttp/src/main/kotlin/okhttp3/HttpUrl.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/HttpUrl.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/HttpUrl.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/HttpUrl.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Interceptor.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Interceptor.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Interceptor.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Interceptor.kt diff --git a/okhttp/src/main/kotlin/okhttp3/MediaType.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/MediaType.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/MediaType.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/MediaType.kt diff --git a/okhttp/src/main/kotlin/okhttp3/MultipartBody.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/MultipartBody.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/MultipartBody.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/MultipartBody.kt diff --git a/okhttp/src/main/kotlin/okhttp3/MultipartReader.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/MultipartReader.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/MultipartReader.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/MultipartReader.kt diff --git a/okhttp/src/main/kotlin/okhttp3/OkHttp.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/OkHttp.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/OkHttp.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/OkHttp.kt diff --git a/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/OkHttpClient.kt similarity index 99% rename from okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/OkHttpClient.kt index 7f499c765c73..4f480d4a334d 100644 --- a/okhttp/src/main/kotlin/okhttp3/OkHttpClient.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/OkHttpClient.kt @@ -15,7 +15,6 @@ */ package okhttp3 -import android.annotation.SuppressLint import java.net.Proxy import java.net.ProxySelector import java.net.Socket @@ -1113,7 +1112,6 @@ open class OkHttpClient internal constructor( * * The default value is 0 which imposes no timeout. */ - @SuppressLint("NewApi") @IgnoreJRERequirement fun callTimeout(duration: Duration) = apply { @@ -1156,7 +1154,6 @@ open class OkHttpClient internal constructor( * The connect timeout is applied when connecting a TCP socket to the target host. The default * value is 10 seconds. */ - @SuppressLint("NewApi") @IgnoreJRERequirement fun connectTimeout(duration: Duration) = apply { @@ -1202,7 +1199,6 @@ open class OkHttpClient internal constructor( * @see Socket.setSoTimeout * @see Source.timeout */ - @SuppressLint("NewApi") @IgnoreJRERequirement fun readTimeout(duration: Duration) = apply { @@ -1249,7 +1245,6 @@ open class OkHttpClient internal constructor( * * @see Sink.timeout */ - @SuppressLint("NewApi") @IgnoreJRERequirement fun writeTimeout(duration: Duration) = apply { @@ -1303,7 +1298,6 @@ open class OkHttpClient internal constructor( * * The default value of 0 disables client-initiated pings. */ - @SuppressLint("NewApi") @IgnoreJRERequirement fun pingInterval(duration: Duration) = apply { @@ -1351,7 +1345,6 @@ open class OkHttpClient internal constructor( * wait for a graceful shutdown. If the server doesn't respond the web socket will be canceled. * The default value is 60 seconds. */ - @SuppressLint("NewApi") @IgnoreJRERequirement fun webSocketCloseTimeout(duration: Duration) = apply { diff --git a/okhttp/src/main/kotlin/okhttp3/Protocol.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Protocol.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Protocol.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Protocol.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Request.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Request.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Request.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Request.kt diff --git a/okhttp/src/main/kotlin/okhttp3/RequestBody.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/RequestBody.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/RequestBody.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/RequestBody.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Response.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Response.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Response.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Response.kt diff --git a/okhttp/src/main/kotlin/okhttp3/ResponseBody.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/ResponseBody.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/ResponseBody.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/ResponseBody.kt diff --git a/okhttp/src/main/kotlin/okhttp3/Route.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Route.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/Route.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/Route.kt diff --git a/okhttp/src/main/kotlin/okhttp3/TlsVersion.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/TlsVersion.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/TlsVersion.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/TlsVersion.kt diff --git a/okhttp/src/main/kotlin/okhttp3/WebSocket.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/WebSocket.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/WebSocket.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/WebSocket.kt diff --git a/okhttp/src/main/kotlin/okhttp3/WebSocketListener.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/WebSocketListener.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/WebSocketListener.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/WebSocketListener.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-CacheControlCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-CacheControlCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-CacheControlCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-ChallengeCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-ChallengeCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-ChallengeCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-ChallengeCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-HeadersCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-HeadersCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-HeadersCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-HeadersCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-HostnamesCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-HostnamesCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-HostnamesCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-HostnamesCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-MediaTypeCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-MediaTypeCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-MediaTypeCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-MediaTypeCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-NormalizeJvm.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-NormalizeJvm.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-NormalizeJvm.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-NormalizeJvm.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-RequestBodyCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-RequestBodyCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-RequestBodyCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-RequestBodyCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-RequestCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-RequestCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-RequestCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-RequestCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-ResponseBodyCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-ResponseBodyCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-ResponseBodyCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-ResponseBodyCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-ResponseCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-ResponseCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-ResponseCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-UtilCommon.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-UtilCommon.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-UtilCommon.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-UtilJvm.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/-UtilJvm.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/-UtilJvm.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/NativeImageTestsAccessors.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/SuppressSignatureCheck.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/SuppressSignatureCheck.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/SuppressSignatureCheck.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/SuppressSignatureCheck.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticator.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticator.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticator.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticator.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheInterceptor.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/CacheInterceptor.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/cache/CacheInterceptor.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/CacheInterceptor.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheRequest.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/CacheRequest.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/cache/CacheRequest.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/CacheRequest.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/CacheStrategy.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/cache/CacheStrategy.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/CacheStrategy.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/DiskLruCache.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/cache/DiskLruCache.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/DiskLruCache.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache/FaultHidingSink.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/FaultHidingSink.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/cache/FaultHidingSink.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache/FaultHidingSink.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache2/FileOperator.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache2/FileOperator.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/cache2/FileOperator.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache2/FileOperator.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/cache2/Relay.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache2/Relay.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/cache2/Relay.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/cache2/Relay.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/Task.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/concurrent/Task.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/concurrent/Task.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/concurrent/Task.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskLogger.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/concurrent/TaskLogger.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskLogger.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/concurrent/TaskLogger.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/concurrent/TaskQueue.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskQueue.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/concurrent/TaskQueue.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/concurrent/TaskRunner.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/concurrent/TaskRunner.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/concurrent/TaskRunner.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/CallConnectionUser.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/CallConnectionUser.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/CallConnectionUser.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectInterceptor.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectInterceptor.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectInterceptor.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectInterceptor.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectPlan.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectPlan.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectionUser.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectionUser.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/ConnectionUser.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ConnectionUser.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/Exchange.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/Exchange.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/Exchange.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/Exchange.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ExchangeFinder.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ExchangeFinder.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/ExchangeFinder.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ExchangeFinder.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/FailedPlan.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/FailedPlan.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/FailedPlan.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/FailedPlan.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinder.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinder.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinder.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinder.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ForceConnectRoutePlanner.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ForceConnectRoutePlanner.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/ForceConnectRoutePlanner.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ForceConnectRoutePlanner.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/InetAddressOrder.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/InetAddressOrder.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/InetAddressOrder.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/InetAddressOrder.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/Locks.kt similarity index 97% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/Locks.kt index 0a765eb8a820..9fc039419099 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/connection/Locks.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/Locks.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@file:OptIn(ExperimentalContracts::class) +@file:OptIn(ExperimentalContracts::class, ExperimentalContracts::class) package okhttp3.internal.connection diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/PoolConnectionUser.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/PoolConnectionUser.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/PoolConnectionUser.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/PoolConnectionUser.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealCall.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/RealCall.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealCall.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealConnection.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnection.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealConnection.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealConnectionPool.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/RealConnectionPool.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealConnectionPool.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RealRoutePlanner.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RetryTlsHandshake.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RetryTlsHandshake.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/RetryTlsHandshake.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RetryTlsHandshake.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/ReusePlan.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ReusePlan.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/ReusePlan.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/ReusePlan.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RouteDatabase.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/RouteDatabase.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RouteDatabase.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RoutePlanner.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RoutePlanner.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/RoutePlanner.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RoutePlanner.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/RouteSelector.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RouteSelector.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/RouteSelector.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/RouteSelector.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/connection/SequentialExchangeFinder.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/SequentialExchangeFinder.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/connection/SequentialExchangeFinder.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/connection/SequentialExchangeFinder.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/BridgeInterceptor.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/BridgeInterceptor.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/BridgeInterceptor.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/BridgeInterceptor.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/CallServerInterceptor.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/CallServerInterceptor.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/CallServerInterceptor.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/DateFormatting.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/DateFormatting.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/DateFormatting.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/DateFormatting.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/ExchangeCodec.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/ExchangeCodec.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/ExchangeCodec.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/ExchangeCodec.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/HttpHeaders.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/HttpHeaders.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/HttpHeaders.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/HttpHeaders.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/HttpMethod.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/HttpMethod.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/HttpMethod.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/HttpMethod.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/HttpStatusCodes.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/HttpStatusCodes.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/HttpStatusCodes.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/HttpStatusCodes.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/RealInterceptorChain.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RealInterceptorChain.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/RealInterceptorChain.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RealInterceptorChain.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/RealResponseBody.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RealResponseBody.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/RealResponseBody.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RealResponseBody.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/RequestLine.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RequestLine.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/RequestLine.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RequestLine.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/RetryAndFollowUpInterceptor.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http/StatusLine.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http/StatusLine.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http/StatusLine.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http1/HeadersReader.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http1/HeadersReader.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http1/HeadersReader.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http1/HeadersReader.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http1/Http1ExchangeCodec.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/ConnectionShutdownException.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/ConnectionShutdownException.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/ConnectionShutdownException.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/ConnectionShutdownException.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/ErrorCode.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/ErrorCode.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/ErrorCode.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/ErrorCode.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/FlowControlListener.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/FlowControlListener.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/FlowControlListener.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/FlowControlListener.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Header.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Header.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Header.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Header.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Hpack.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Hpack.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Hpack.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Hpack.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Http2.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2Connection.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Connection.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2Connection.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2ExchangeCodec.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2ExchangeCodec.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Http2ExchangeCodec.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2ExchangeCodec.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2Reader.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Reader.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2Reader.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2Stream.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Stream.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2Stream.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2Writer.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Http2Writer.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Http2Writer.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Huffman.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Huffman.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Huffman.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Huffman.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/PushObserver.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/PushObserver.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/PushObserver.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/PushObserver.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Settings.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/Settings.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/Settings.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/StreamResetException.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/StreamResetException.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/StreamResetException.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/StreamResetException.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/http2/flowcontrol/WindowCounter.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/flowcontrol/WindowCounter.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/http2/flowcontrol/WindowCounter.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/http2/flowcontrol/WindowCounter.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/idn/IdnaMappingTable.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/idn/IdnaMappingTable.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/idn/IdnaMappingTable.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/idn/IdnaMappingTable.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/idn/Punycode.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/idn/Punycode.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/idn/Punycode.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/idn/Punycode.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/internal.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/internal.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/internal.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/internal.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/Platform.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt similarity index 78% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/Platform.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt index 4483de380150..efcfac723c4e 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/platform/Platform.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt @@ -16,13 +16,11 @@ */ package okhttp3.internal.platform -import android.annotation.SuppressLint import java.io.IOException import java.net.InetSocketAddress import java.net.Socket import java.security.GeneralSecurityException import java.security.KeyStore -import java.security.Security import java.util.logging.Level import java.util.logging.Logger import javax.net.ssl.ExtendedSSLSession @@ -35,7 +33,6 @@ import javax.net.ssl.TrustManagerFactory import javax.net.ssl.X509TrustManager import okhttp3.OkHttpClient import okhttp3.Protocol -import okhttp3.internal.platform.android.AndroidLog import okhttp3.internal.readFieldOrNull import okhttp3.internal.tls.BasicCertificateChainCleaner import okhttp3.internal.tls.BasicTrustRootIndex @@ -129,7 +126,6 @@ open class Platform { open fun getSelectedProtocol(sslSocket: SSLSocket): String? = null /** For MockWebServer. This returns the inbound SNI names. */ - @SuppressLint("NewApi") @IgnoreJRERequirement // This function is overridden to require API >= 24. open fun getHandshakeServerNames(sslSocket: SSLSocket): List { val session = sslSocket.session as? ExtendedSSLSession ?: return listOf() @@ -214,83 +210,11 @@ open class Platform { fun alpnProtocolNames(protocols: List) = protocols.filter { it != Protocol.HTTP_1_0 }.map { it.toString() } - // This explicit check avoids activating in Android Studio with Android specific classes - // available when running plugins inside the IDE. val isAndroid: Boolean - get() = "Dalvik" == System.getProperty("java.vm.name") - - private val isConscryptPreferred: Boolean - get() { - val preferredProvider = Security.getProviders()[0].name - return "Conscrypt" == preferredProvider - } - - private val isOpenJSSEPreferred: Boolean - get() { - val preferredProvider = Security.getProviders()[0].name - return "OpenJSSE" == preferredProvider - } - - private val isBouncyCastlePreferred: Boolean - get() { - val preferredProvider = Security.getProviders()[0].name - return "BC" == preferredProvider - } + get() = PlatformRegistry.isAndroid /** Attempt to match the host runtime to a capable Platform implementation. */ - private fun findPlatform(): Platform = - if (isAndroid) { - findAndroidPlatform() - } else { - findJvmPlatform() - } - - private fun findAndroidPlatform(): Platform { - AndroidLog.enable() - return Android10Platform.buildIfSupported() ?: AndroidPlatform.buildIfSupported()!! - } - - private fun findJvmPlatform(): Platform { - if (isConscryptPreferred) { - val conscrypt = ConscryptPlatform.buildIfSupported() - - if (conscrypt != null) { - return conscrypt - } - } - - if (isBouncyCastlePreferred) { - val bc = BouncyCastlePlatform.buildIfSupported() - - if (bc != null) { - return bc - } - } - - if (isOpenJSSEPreferred) { - val openJSSE = OpenJSSEPlatform.buildIfSupported() - - if (openJSSE != null) { - return openJSSE - } - } - - // An Oracle JDK 9 like OpenJDK, or JDK 8 251+. - val jdk9 = Jdk9Platform.buildIfSupported() - - if (jdk9 != null) { - return jdk9 - } - - // An Oracle JDK 8 like OpenJDK, pre 251. - val jdkWithJettyBoot = Jdk8WithJettyBootPlatform.buildIfSupported() - - if (jdkWithJettyBoot != null) { - return jdkWithJettyBoot - } - - return Platform() - } + private fun findPlatform(): Platform = PlatformRegistry.findPlatform() /** * Returns the concatenation of 8-bit, length prefixed protocol names. diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/PlatformRegistry.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/PlatformRegistry.kt new file mode 100644 index 000000000000..ce90f02f93dd --- /dev/null +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/PlatformRegistry.kt @@ -0,0 +1,7 @@ +package okhttp3.internal.platform + +expect object PlatformRegistry { + fun findPlatform(): Platform + + val isAndroid: Boolean +} diff --git a/okhttp/src/main/kotlin/okhttp3/internal/proxy/NullProxySelector.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/proxy/NullProxySelector.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/proxy/NullProxySelector.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/proxy/NullProxySelector.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabase.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicCertificateChainCleaner.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/BasicCertificateChainCleaner.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/tls/BasicCertificateChainCleaner.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/BasicCertificateChainCleaner.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/BasicTrustRootIndex.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/BasicTrustRootIndex.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/tls/BasicTrustRootIndex.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/BasicTrustRootIndex.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/CertificateChainCleaner.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/CertificateChainCleaner.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/tls/CertificateChainCleaner.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/CertificateChainCleaner.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/OkHostnameVerifier.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/tls/TrustRootIndex.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/TrustRootIndex.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/tls/TrustRootIndex.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/tls/TrustRootIndex.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/url/-Url.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/url/-Url.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/url/-Url.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/url/-Url.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageDeflater.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/MessageDeflater.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/ws/MessageDeflater.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/MessageDeflater.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/MessageInflater.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/MessageInflater.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/ws/MessageInflater.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/MessageInflater.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/RealWebSocket.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/RealWebSocket.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/ws/RealWebSocket.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/RealWebSocket.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketExtensions.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/WebSocketExtensions.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketExtensions.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/WebSocketExtensions.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketProtocol.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/WebSocketProtocol.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketProtocol.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/WebSocketProtocol.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketReader.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/WebSocketReader.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketReader.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/WebSocketReader.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketWriter.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/WebSocketWriter.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/ws/WebSocketWriter.kt rename to okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/ws/WebSocketWriter.kt diff --git a/okhttp/src/main/kotlinTemplates/okhttp3/internal/-InternalVersion.kt b/okhttp/src/commonJvmAndroid/kotlinTemplates/okhttp3/internal/-InternalVersion.kt similarity index 100% rename from okhttp/src/main/kotlinTemplates/okhttp3/internal/-InternalVersion.kt rename to okhttp/src/commonJvmAndroid/kotlinTemplates/okhttp3/internal/-InternalVersion.kt diff --git a/okhttp/src/main/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt b/okhttp/src/commonJvmAndroid/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt similarity index 100% rename from okhttp/src/main/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt rename to okhttp/src/commonJvmAndroid/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/graal/GraalSvm.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/graal/GraalSvm.kt similarity index 86% rename from okhttp/src/main/kotlin/okhttp3/internal/graal/GraalSvm.kt rename to okhttp/src/jvmMain/kotlin/okhttp3/internal/graal/GraalSvm.kt index caad047228d7..0e3b58e02c06 100644 --- a/okhttp/src/main/kotlin/okhttp3/internal/graal/GraalSvm.kt +++ b/okhttp/src/jvmMain/kotlin/okhttp3/internal/graal/GraalSvm.kt @@ -18,8 +18,6 @@ package okhttp3.internal.graal import com.oracle.svm.core.annotate.Delete import com.oracle.svm.core.annotate.Substitute import com.oracle.svm.core.annotate.TargetClass -import okhttp3.internal.platform.Android10Platform -import okhttp3.internal.platform.AndroidPlatform import okhttp3.internal.platform.BouncyCastlePlatform import okhttp3.internal.platform.ConscryptPlatform import okhttp3.internal.platform.Jdk8WithJettyBootPlatform @@ -27,14 +25,6 @@ import okhttp3.internal.platform.Jdk9Platform import okhttp3.internal.platform.OpenJSSEPlatform import okhttp3.internal.platform.Platform -@TargetClass(AndroidPlatform::class) -@Delete -class TargetAndroidPlatform - -@TargetClass(Android10Platform::class) -@Delete -class TargetAndroid10Platform - @TargetClass(BouncyCastlePlatform::class) @Delete class TargetBouncyCastlePlatform diff --git a/okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/graal/OkHttpFeature.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/graal/OkHttpFeature.kt rename to okhttp/src/jvmMain/kotlin/okhttp3/internal/graal/OkHttpFeature.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt rename to okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/BouncyCastlePlatform.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt rename to okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/ConscryptPlatform.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt rename to okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatform.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk9Platform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/Jdk9Platform.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/Jdk9Platform.kt rename to okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/Jdk9Platform.kt diff --git a/okhttp/src/main/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt similarity index 100% rename from okhttp/src/main/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt rename to okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/OpenJSSEPlatform.kt diff --git a/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/PlatformRegistry.kt b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/PlatformRegistry.kt new file mode 100644 index 000000000000..721170b8a047 --- /dev/null +++ b/okhttp/src/jvmMain/kotlin/okhttp3/internal/platform/PlatformRegistry.kt @@ -0,0 +1,68 @@ +package okhttp3.internal.platform + +import java.security.Security + +actual object PlatformRegistry { + private val isConscryptPreferred: Boolean + get() { + val preferredProvider = Security.getProviders()[0].name + return "Conscrypt" == preferredProvider + } + + private val isOpenJSSEPreferred: Boolean + get() { + val preferredProvider = Security.getProviders()[0].name + return "OpenJSSE" == preferredProvider + } + + private val isBouncyCastlePreferred: Boolean + get() { + val preferredProvider = Security.getProviders()[0].name + return "BC" == preferredProvider + } + + actual fun findPlatform(): Platform { + if (isConscryptPreferred) { + val conscrypt = ConscryptPlatform.buildIfSupported() + + if (conscrypt != null) { + return conscrypt + } + } + + if (isBouncyCastlePreferred) { + val bc = BouncyCastlePlatform.buildIfSupported() + + if (bc != null) { + return bc + } + } + + if (isOpenJSSEPreferred) { + val openJSSE = OpenJSSEPlatform.buildIfSupported() + + if (openJSSE != null) { + return openJSSE + } + } + + // An Oracle JDK 9 like OpenJDK, or JDK 8 251+. + val jdk9 = Jdk9Platform.buildIfSupported() + + if (jdk9 != null) { + return jdk9 + } + + // An Oracle JDK 8 like OpenJDK, pre 251. + val jdkWithJettyBoot = Jdk8WithJettyBootPlatform.buildIfSupported() + + if (jdkWithJettyBoot != null) { + return jdkWithJettyBoot + } + + return Platform() + } + + actual val isAndroid: Boolean + get() = false +} diff --git a/okhttp/src/jvmMain/resources/META-INF/native-image/okhttp/okhttp/native-image.properties b/okhttp/src/jvmMain/resources/META-INF/native-image/okhttp/okhttp/native-image.properties new file mode 100644 index 000000000000..75cbefcdc5c1 --- /dev/null +++ b/okhttp/src/jvmMain/resources/META-INF/native-image/okhttp/okhttp/native-image.properties @@ -0,0 +1 @@ +Args = -H:+AddAllCharsets --enable-http --enable-https --features=okhttp3.internal.graal.OkHttpFeature --report-unsupported-elements-at-runtime diff --git a/okhttp/src/main/resources/META-INF/native-image/okhttp/okhttp/reflect-config.json b/okhttp/src/jvmMain/resources/META-INF/native-image/okhttp/okhttp/reflect-config.json similarity index 100% rename from okhttp/src/main/resources/META-INF/native-image/okhttp/okhttp/reflect-config.json rename to okhttp/src/jvmMain/resources/META-INF/native-image/okhttp/okhttp/reflect-config.json diff --git a/okhttp/src/main/resources/META-INF/native-image/okhttp/okhttp/resource-config.json b/okhttp/src/jvmMain/resources/META-INF/native-image/okhttp/okhttp/resource-config.json similarity index 100% rename from okhttp/src/main/resources/META-INF/native-image/okhttp/okhttp/resource-config.json rename to okhttp/src/jvmMain/resources/META-INF/native-image/okhttp/okhttp/resource-config.json diff --git a/okhttp/src/test/java/okhttp3/AddressTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/AddressTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/AddressTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/AddressTest.kt diff --git a/okhttp/src/test/java/okhttp3/AutobahnTester.kt b/okhttp/src/jvmTest/kotlin/okhttp3/AutobahnTester.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/AutobahnTester.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/AutobahnTester.kt diff --git a/okhttp/src/test/java/okhttp3/BouncyCastleTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/BouncyCastleTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/BouncyCastleTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/BouncyCastleTest.kt diff --git a/okhttp/src/test/java/okhttp3/CacheControlJvmTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CacheControlJvmTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CacheControlJvmTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CacheControlJvmTest.kt diff --git a/okhttp/src/test/java/okhttp3/CacheControlTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CacheControlTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CacheControlTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CacheControlTest.kt diff --git a/okhttp/src/test/java/okhttp3/CacheCorruptionTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CacheCorruptionTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CacheCorruptionTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CacheCorruptionTest.kt diff --git a/okhttp/src/test/java/okhttp3/CacheTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CacheTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CacheTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CacheTest.kt diff --git a/okhttp/src/test/java/okhttp3/CallHandshakeTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CallHandshakeTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CallHandshakeTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CallHandshakeTest.kt diff --git a/okhttp/src/test/java/okhttp3/CallKotlinTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CallKotlinTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CallKotlinTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CallKotlinTest.kt diff --git a/okhttp/src/test/java/okhttp3/CallTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CallTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CallTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CallTest.kt diff --git a/okhttp/src/test/java/okhttp3/CertificateChainCleanerTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CertificateChainCleanerTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CertificateChainCleanerTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CertificateChainCleanerTest.kt diff --git a/okhttp/src/test/java/okhttp3/CertificatePinnerKotlinTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CertificatePinnerKotlinTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CertificatePinnerKotlinTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CertificatePinnerKotlinTest.kt diff --git a/okhttp/src/test/java/okhttp3/CertificatePinnerTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CertificatePinnerTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CertificatePinnerTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CertificatePinnerTest.kt diff --git a/okhttp/src/test/java/okhttp3/ChannelSocketFactory.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ChannelSocketFactory.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ChannelSocketFactory.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ChannelSocketFactory.kt diff --git a/okhttp/src/test/java/okhttp3/CipherSuiteTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CipherSuiteTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CipherSuiteTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CipherSuiteTest.kt diff --git a/okhttp/src/test/java/okhttp3/CommonRequestBodyTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CommonRequestBodyTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CommonRequestBodyTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CommonRequestBodyTest.kt diff --git a/okhttp/src/test/java/okhttp3/ConnectionCoalescingTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ConnectionCoalescingTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ConnectionCoalescingTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ConnectionCoalescingTest.kt diff --git a/okhttp/src/test/java/okhttp3/ConnectionListenerTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ConnectionListenerTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ConnectionListenerTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ConnectionListenerTest.kt diff --git a/okhttp/src/test/java/okhttp3/ConnectionReuseTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ConnectionReuseTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ConnectionReuseTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ConnectionReuseTest.kt diff --git a/okhttp/src/test/java/okhttp3/ConnectionSpecTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ConnectionSpecTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ConnectionSpecTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ConnectionSpecTest.kt diff --git a/okhttp/src/test/java/okhttp3/ConscryptTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ConscryptTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ConscryptTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ConscryptTest.kt diff --git a/okhttp/src/test/java/okhttp3/CookieTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CookieTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CookieTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CookieTest.kt diff --git a/okhttp/src/test/java/okhttp3/CookiesTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CookiesTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CookiesTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CookiesTest.kt diff --git a/okhttp/src/test/java/okhttp3/CorrettoTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/CorrettoTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/CorrettoTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/CorrettoTest.kt diff --git a/okhttp/src/test/java/okhttp3/DispatcherCleanupTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/DispatcherCleanupTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/DispatcherCleanupTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/DispatcherCleanupTest.kt diff --git a/okhttp/src/test/java/okhttp3/DispatcherTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/DispatcherTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/DispatcherTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/DispatcherTest.kt diff --git a/okhttp/src/test/java/okhttp3/DuplexTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/DuplexTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/DuplexTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/DuplexTest.kt diff --git a/okhttp/src/test/java/okhttp3/EventListenerTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/EventListenerTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/EventListenerTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/EventListenerTest.kt diff --git a/okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt b/okhttp/src/jvmTest/kotlin/okhttp3/FakeRoutePlanner.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/FakeRoutePlanner.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/FakeRoutePlanner.kt diff --git a/okhttp/src/test/java/okhttp3/FallbackTestClientSocketFactory.kt b/okhttp/src/jvmTest/kotlin/okhttp3/FallbackTestClientSocketFactory.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/FallbackTestClientSocketFactory.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/FallbackTestClientSocketFactory.kt diff --git a/okhttp/src/test/java/okhttp3/FastFallbackTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/FastFallbackTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/FastFallbackTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/FastFallbackTest.kt diff --git a/okhttp/src/test/java/okhttp3/FormBodyTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/FormBodyTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/FormBodyTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/FormBodyTest.kt diff --git a/okhttp/src/test/java/okhttp3/HandshakeTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/HandshakeTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/HandshakeTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/HandshakeTest.kt diff --git a/okhttp/src/test/java/okhttp3/HeadersChallengesTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/HeadersChallengesTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/HeadersChallengesTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/HeadersChallengesTest.kt diff --git a/okhttp/src/test/java/okhttp3/HeadersJvmTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/HeadersJvmTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/HeadersJvmTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/HeadersJvmTest.kt diff --git a/okhttp/src/test/java/okhttp3/HeadersKotlinTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/HeadersKotlinTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/HeadersKotlinTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/HeadersKotlinTest.kt diff --git a/okhttp/src/test/java/okhttp3/HeadersRequestTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/HeadersRequestTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/HeadersRequestTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/HeadersRequestTest.kt diff --git a/okhttp/src/test/java/okhttp3/HeadersTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/HeadersTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/HeadersTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/HeadersTest.kt diff --git a/okhttp/src/test/java/okhttp3/HttpUrlJvmTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/HttpUrlJvmTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/HttpUrlJvmTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/HttpUrlJvmTest.kt diff --git a/okhttp/src/test/java/okhttp3/HttpUrlTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/HttpUrlTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/HttpUrlTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/HttpUrlTest.kt diff --git a/okhttp/src/test/java/okhttp3/InsecureForHostTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/InsecureForHostTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/InsecureForHostTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/InsecureForHostTest.kt diff --git a/okhttp/src/test/java/okhttp3/InterceptorTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/InterceptorTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/InterceptorTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/InterceptorTest.kt diff --git a/okhttp/src/test/java/okhttp3/JSSETest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/JSSETest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/JSSETest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/JSSETest.kt diff --git a/okhttp/src/test/java/okhttp3/KotlinDeprecationErrorTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/KotlinDeprecationErrorTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/KotlinDeprecationErrorTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/KotlinDeprecationErrorTest.kt diff --git a/okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/KotlinSourceModernTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/KotlinSourceModernTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/KotlinSourceModernTest.kt diff --git a/okhttp/src/test/java/okhttp3/LoomTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/LoomTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/LoomTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/LoomTest.kt diff --git a/okhttp/src/test/java/okhttp3/MediaTypeGetTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/MediaTypeGetTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/MediaTypeGetTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/MediaTypeGetTest.kt diff --git a/okhttp/src/test/java/okhttp3/MediaTypeJvmTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/MediaTypeJvmTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/MediaTypeJvmTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/MediaTypeJvmTest.kt diff --git a/okhttp/src/test/java/okhttp3/MediaTypeTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/MediaTypeTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/MediaTypeTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/MediaTypeTest.kt diff --git a/okhttp/src/test/java/okhttp3/MultipartBodyTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/MultipartBodyTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/MultipartBodyTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/MultipartBodyTest.kt diff --git a/okhttp/src/test/java/okhttp3/MultipartReaderTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/MultipartReaderTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/MultipartReaderTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/MultipartReaderTest.kt diff --git a/okhttp/src/test/java/okhttp3/OkHttpClientTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/OkHttpClientTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/OkHttpClientTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/OkHttpClientTest.kt diff --git a/okhttp/src/test/java/okhttp3/OkHttpTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/OkHttpTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/OkHttpTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/OkHttpTest.kt diff --git a/okhttp/src/test/java/okhttp3/OpenJSSETest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/OpenJSSETest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/OpenJSSETest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/OpenJSSETest.kt diff --git a/okhttp/src/test/java/okhttp3/ProtocolTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ProtocolTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ProtocolTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ProtocolTest.kt diff --git a/okhttp/src/test/java/okhttp3/PublicInternalApiTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/PublicInternalApiTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/PublicInternalApiTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/PublicInternalApiTest.kt diff --git a/okhttp/src/test/java/okhttp3/RecordedResponse.kt b/okhttp/src/jvmTest/kotlin/okhttp3/RecordedResponse.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/RecordedResponse.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/RecordedResponse.kt diff --git a/okhttp/src/test/java/okhttp3/RecordingCallback.kt b/okhttp/src/jvmTest/kotlin/okhttp3/RecordingCallback.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/RecordingCallback.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/RecordingCallback.kt diff --git a/okhttp/src/test/java/okhttp3/RecordingExecutor.kt b/okhttp/src/jvmTest/kotlin/okhttp3/RecordingExecutor.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/RecordingExecutor.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/RecordingExecutor.kt diff --git a/okhttp/src/test/java/okhttp3/RequestBodyTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/RequestBodyTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/RequestBodyTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/RequestBodyTest.kt diff --git a/okhttp/src/test/java/okhttp3/RequestCommonTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/RequestCommonTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/RequestCommonTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/RequestCommonTest.kt diff --git a/okhttp/src/test/java/okhttp3/RequestTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/RequestTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/RequestTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/RequestTest.kt diff --git a/okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ResponseBodyJvmTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ResponseBodyJvmTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ResponseBodyJvmTest.kt diff --git a/okhttp/src/test/java/okhttp3/ResponseBodyTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ResponseBodyTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ResponseBodyTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ResponseBodyTest.kt diff --git a/okhttp/src/test/java/okhttp3/ResponseCommonTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ResponseCommonTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ResponseCommonTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ResponseCommonTest.kt diff --git a/okhttp/src/test/java/okhttp3/ResponseJvmTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ResponseJvmTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ResponseJvmTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ResponseJvmTest.kt diff --git a/okhttp/src/test/java/okhttp3/RouteFailureTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/RouteFailureTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/RouteFailureTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/RouteFailureTest.kt diff --git a/okhttp/src/test/java/okhttp3/ServerTruncatesRequestTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/ServerTruncatesRequestTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/ServerTruncatesRequestTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/ServerTruncatesRequestTest.kt diff --git a/okhttp/src/test/java/okhttp3/SessionReuseTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/SessionReuseTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/SessionReuseTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/SessionReuseTest.kt diff --git a/okhttp/src/test/java/okhttp3/SocketChannelTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/SocketChannelTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/SocketChannelTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/SocketChannelTest.kt diff --git a/okhttp/src/test/java/okhttp3/SocksProxy.kt b/okhttp/src/jvmTest/kotlin/okhttp3/SocksProxy.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/SocksProxy.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/SocksProxy.kt diff --git a/okhttp/src/test/java/okhttp3/SocksProxyTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/SocksProxyTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/SocksProxyTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/SocksProxyTest.kt diff --git a/okhttp/src/test/java/okhttp3/TestLogHandler.kt b/okhttp/src/jvmTest/kotlin/okhttp3/TestLogHandler.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/TestLogHandler.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/TestLogHandler.kt diff --git a/okhttp/src/test/java/okhttp3/TestTls13Request.kt b/okhttp/src/jvmTest/kotlin/okhttp3/TestTls13Request.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/TestTls13Request.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/TestTls13Request.kt diff --git a/okhttp/src/test/java/okhttp3/URLConnectionTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/URLConnectionTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/URLConnectionTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/URLConnectionTest.kt diff --git a/okhttp/src/test/java/okhttp3/UrlComponentEncodingTester.kt b/okhttp/src/jvmTest/kotlin/okhttp3/UrlComponentEncodingTester.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/UrlComponentEncodingTester.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/UrlComponentEncodingTester.kt diff --git a/okhttp/src/test/java/okhttp3/UrlComponentEncodingTesterJvm.kt b/okhttp/src/jvmTest/kotlin/okhttp3/UrlComponentEncodingTesterJvm.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/UrlComponentEncodingTesterJvm.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/UrlComponentEncodingTesterJvm.kt diff --git a/okhttp/src/test/java/okhttp3/WebPlatformToAsciiData.kt b/okhttp/src/jvmTest/kotlin/okhttp3/WebPlatformToAsciiData.kt similarity index 93% rename from okhttp/src/test/java/okhttp3/WebPlatformToAsciiData.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/WebPlatformToAsciiData.kt index 474862b25444..1912ae0c7442 100644 --- a/okhttp/src/test/java/okhttp3/WebPlatformToAsciiData.kt +++ b/okhttp/src/jvmTest/kotlin/okhttp3/WebPlatformToAsciiData.kt @@ -34,7 +34,7 @@ class WebPlatformToAsciiData { companion object { fun load(): List { - val path = okHttpRoot / "okhttp/src/test/resources/web-platform-test-toascii.json" + val path = okHttpRoot / "okhttp/src/jvmTest/resources/web-platform-test-toascii.json" return SYSTEM_FILE_SYSTEM.read(path) { Json.decodeFromString>(readUtf8()) } diff --git a/okhttp/src/test/java/okhttp3/WebPlatformToAsciiTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/WebPlatformToAsciiTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/WebPlatformToAsciiTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/WebPlatformToAsciiTest.kt diff --git a/okhttp/src/test/java/okhttp3/WebPlatformUrlTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/WebPlatformUrlTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/WebPlatformUrlTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/WebPlatformUrlTest.kt diff --git a/okhttp/src/test/java/okhttp3/WebPlatformUrlTestData.kt b/okhttp/src/jvmTest/kotlin/okhttp3/WebPlatformUrlTestData.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/WebPlatformUrlTestData.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/WebPlatformUrlTestData.kt diff --git a/okhttp/src/test/java/okhttp3/WholeOperationTimeoutTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/WholeOperationTimeoutTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/WholeOperationTimeoutTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/WholeOperationTimeoutTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/DoubleInetAddressDns.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/DoubleInetAddressDns.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/DoubleInetAddressDns.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/DoubleInetAddressDns.kt diff --git a/okhttp/src/test/java/okhttp3/internal/HostnamesTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/HostnamesTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/HostnamesTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/HostnamesTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/RecordingAuthenticator.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/RecordingAuthenticator.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/RecordingAuthenticator.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/RecordingAuthenticator.kt diff --git a/okhttp/src/test/java/okhttp3/internal/UtilTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/UtilTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/UtilTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/UtilTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/authenticator/JavaNetAuthenticatorTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticatorTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/authenticator/JavaNetAuthenticatorTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/authenticator/JavaNetAuthenticatorTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/cache/DiskLruCacheTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/cache/DiskLruCacheTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/cache/DiskLruCacheTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/cache2/FileOperatorTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/cache2/FileOperatorTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/cache2/FileOperatorTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/cache2/FileOperatorTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/cache2/RelayTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/cache2/RelayTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/cache2/RelayTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskLoggerTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/concurrent/TaskLoggerTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/concurrent/TaskLoggerTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/concurrent/TaskLoggerTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerRealBackendTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/concurrent/TaskRunnerRealBackendTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerRealBackendTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/concurrent/TaskRunnerRealBackendTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/concurrent/TaskRunnerTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/concurrent/TaskRunnerTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/concurrent/TaskRunnerTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/ConnectionPoolTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/connection/ConnectionPoolTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/ConnectionPoolTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/FastFallbackExchangeFinderTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/connection/InetAddressOrderTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/InetAddressOrderTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/connection/InetAddressOrderTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/InetAddressOrderTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/connection/RetryConnectionTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/RetryConnectionTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/connection/RetryConnectionTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/RetryConnectionTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/connection/RouteSelectorTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/RouteSelectorTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/connection/RouteSelectorTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/connection/RouteSelectorTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http/CancelTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http/CancelTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http/CancelTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http/CancelTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http/ExternalHttp2Example.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http/ExternalHttp2Example.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http/ExternalHttp2Example.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http/ExternalHttp2Example.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http/HttpDateTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http/HttpDateTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http/HttpDateTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http/HttpDateTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http/StatusLineTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http/StatusLineTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http/StatusLineTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http/StatusLineTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http/ThreadInterruptTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http/ThreadInterruptTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http/ThreadInterruptTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http/ThreadInterruptTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http2/BaseTestHandler.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/BaseTestHandler.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http2/BaseTestHandler.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/BaseTestHandler.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http2/FrameLogTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/FrameLogTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http2/FrameLogTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/FrameLogTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http2/HpackTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/HpackTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http2/HpackTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/HpackTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/Http2ConnectionTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http2/Http2ConnectionTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/Http2ConnectionTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http2/Http2Test.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/Http2Test.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http2/Http2Test.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/Http2Test.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/HttpOverHttp2Test.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http2/HttpOverHttp2Test.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/HttpOverHttp2Test.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http2/HuffmanTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/HuffmanTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http2/HuffmanTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/HuffmanTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/MockHttp2Peer.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http2/MockHttp2Peer.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/MockHttp2Peer.kt diff --git a/okhttp/src/test/java/okhttp3/internal/http2/SettingsTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/SettingsTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/http2/SettingsTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/http2/SettingsTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/idn/IdnaMappingTableTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/idn/IdnaMappingTableTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/idn/IdnaMappingTableTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/idn/IdnaMappingTableTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/idn/PunycodeTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/idn/PunycodeTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/idn/PunycodeTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/idn/PunycodeTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/io/FaultyFileSystem.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/io/FaultyFileSystem.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/io/FaultyFileSystem.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/io/FaultyFileSystem.kt diff --git a/okhttp/src/test/java/okhttp3/internal/platform/Jdk8WithJettyBootPlatformTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatformTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/platform/Jdk8WithJettyBootPlatformTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/platform/Jdk8WithJettyBootPlatformTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/platform/Jdk9PlatformTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/platform/Jdk9PlatformTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/platform/Jdk9PlatformTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/platform/Jdk9PlatformTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/platform/PlatformTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/platform/PlatformTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/platform/PlatformTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/platform/PlatformTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/publicsuffix/PublicSuffixListGenerator.kt diff --git a/okhttp/src/test/java/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt diff --git a/okhttp/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/tls/CertificatePinnerChainValidationTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/tls/CertificatePinnerChainValidationTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/tls/CertificatePinnerChainValidationTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/tls/ClientAuthTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/tls/ClientAuthTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/tls/ClientAuthTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/tls/ClientAuthTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/tls/HostnameVerifierTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/tls/HostnameVerifierTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/tls/HostnameVerifierTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/tls/HostnameVerifierTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/ws/MessageDeflaterInflaterTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/MessageDeflaterInflaterTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/ws/MessageDeflaterInflaterTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/MessageDeflaterInflaterTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/RealWebSocketTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/ws/RealWebSocketTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/RealWebSocketTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketExtensionsTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketExtensionsTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/ws/WebSocketExtensionsTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketExtensionsTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketHttpTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/ws/WebSocketHttpTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketHttpTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketReaderTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketReaderTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/ws/WebSocketReaderTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketReaderTest.kt diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketRecorder.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketRecorder.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/ws/WebSocketRecorder.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketRecorder.kt diff --git a/okhttp/src/test/java/okhttp3/internal/ws/WebSocketWriterTest.kt b/okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketWriterTest.kt similarity index 100% rename from okhttp/src/test/java/okhttp3/internal/ws/WebSocketWriterTest.kt rename to okhttp/src/jvmTest/kotlin/okhttp3/internal/ws/WebSocketWriterTest.kt diff --git a/okhttp/src/test/resources/okhttp3/internal/publicsuffix/NOTICE b/okhttp/src/jvmTest/resources/okhttp3/internal/publicsuffix/NOTICE similarity index 100% rename from okhttp/src/test/resources/okhttp3/internal/publicsuffix/NOTICE rename to okhttp/src/jvmTest/resources/okhttp3/internal/publicsuffix/NOTICE diff --git a/okhttp/src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz b/okhttp/src/jvmTest/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz similarity index 100% rename from okhttp/src/test/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz rename to okhttp/src/jvmTest/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz diff --git a/okhttp/src/test/resources/okhttp3/internal/publicsuffix/public_suffix_list.dat b/okhttp/src/jvmTest/resources/okhttp3/internal/publicsuffix/public_suffix_list.dat similarity index 100% rename from okhttp/src/test/resources/okhttp3/internal/publicsuffix/public_suffix_list.dat rename to okhttp/src/jvmTest/resources/okhttp3/internal/publicsuffix/public_suffix_list.dat diff --git a/okhttp/src/test/resources/web-platform-test-toascii.json b/okhttp/src/jvmTest/resources/web-platform-test-toascii.json similarity index 100% rename from okhttp/src/test/resources/web-platform-test-toascii.json rename to okhttp/src/jvmTest/resources/web-platform-test-toascii.json diff --git a/okhttp/src/test/resources/web-platform-test-urltestdata.txt b/okhttp/src/jvmTest/resources/web-platform-test-urltestdata.txt similarity index 100% rename from okhttp/src/test/resources/web-platform-test-urltestdata.txt rename to okhttp/src/jvmTest/resources/web-platform-test-urltestdata.txt diff --git a/settings.gradle.kts b/settings.gradle.kts index 0b7f1566c4f3..442c415ab5e1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -37,6 +37,7 @@ include(":okhttp-hpacktests") include(":okhttp-idna-mapping-table") include(":okhttp-java-net-cookiejar") include(":okhttp-logging-interceptor") +include(":okhttp-osgi-tests") include(":okhttp-sse") include(":okhttp-testing-support") include(":okhttp-tls") @@ -61,31 +62,10 @@ val localProperties = Properties().apply { } } val sdkDir = localProperties.getProperty("sdk.dir") -if ((androidHome != null || sdkDir != null) && !isKnownBrokenIntelliJ()) { +if (androidHome != null || sdkDir != null) { include(":okhttp-android") include(":android-test") include(":android-test-app") } enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") - -/** - * Avoid a crash in IntelliJ triggered by Android submodules. - * - * ``` - * java.lang.AssertionError: Can't find built-in class kotlin.Cloneable - * at org.jetbrains.kotlin.builtins.KotlinBuiltIns.getBuiltInClassByFqName(KotlinBuiltIns.java:217) - * at org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMapper.mapJavaToKotlin(JavaToKotlinClassMapper.kt:41) - * ... - * ``` - */ -fun isKnownBrokenIntelliJ(): Boolean { - val ideaVersionString = System.getProperty("idea.version") ?: return false - - return try { - val (major, minor, _) = ideaVersionString.split(".", limit = 3) - KotlinVersion(major.toInt(), minor.toInt()) < KotlinVersion(2023, 2) - } catch (e: Exception) { - false // Unknown version, presumably compatible. - } -} From d212391897ea46db45b31f4856f8de15d646144e Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 28 Dec 2024 14:19:31 +0200 Subject: [PATCH 124/134] remove unneeded TODO (#8637) --- .../src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt index b1b96c7f82b9..cfb099be2e0d 100644 --- a/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt +++ b/okhttp-testing-support/src/main/kotlin/okhttp3/internal/concurrent/TaskFaker.kt @@ -369,8 +369,6 @@ class TaskFaker : Closeable { val editCountBefore = editCount yieldUntil { nanoTime >= waitUntil || editCount > editCountBefore } } - // TODO report compiler bug - TODO("Can't get here") } } From 8cc665f95a6e1311691b8eb83a0ec534eac4daa6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Dec 2024 15:22:24 +0000 Subject: [PATCH 125/134] Update org.bouncycastle to v1.79 (#8441) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update org.bouncycastle to v1.79 * Handle UnsupportedOperationException – if the underlying provider does not implement the operation * Handle BC requirements on the key manager --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Yuri Schimke --- gradle/libs.versions.toml | 2 +- .../java/mockwebserver3/MockResponseSniTest.kt | 16 +++++++++++++--- .../main/kotlin/okhttp3/tls/internal/TlsUtil.kt | 6 +++++- .../kotlin/okhttp3/internal/platform/Platform.kt | 8 +++++++- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a8745321b8de..f6e3b6a8a411 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ kotlinx-serialization = "1.7.3" ksp = "2.1.0-1.0.29" lintGradle = "1.0.0-alpha03" mockserverClient = "5.15.0" -org-bouncycastle = "1.76" +org-bouncycastle = "1.79" org-conscrypt = "2.5.2" org-jetbrains-coroutines = "1.9.0" org-jetbrains-kotlin = "2.1.0" diff --git a/mockwebserver/src/test/java/mockwebserver3/MockResponseSniTest.kt b/mockwebserver/src/test/java/mockwebserver3/MockResponseSniTest.kt index 1367de61c6cc..db3e63d32880 100644 --- a/mockwebserver/src/test/java/mockwebserver3/MockResponseSniTest.kt +++ b/mockwebserver/src/test/java/mockwebserver3/MockResponseSniTest.kt @@ -77,7 +77,10 @@ class MockResponseSniTest { assertThat(response.isSuccessful).isTrue() val recordedRequest = server.takeRequest() - assertThat(recordedRequest.handshakeServerNames).containsExactly(url.host) + // https://github.com/bcgit/bc-java/issues/1773 + if (!platform.isBouncyCastle()) { + assertThat(recordedRequest.handshakeServerNames).containsExactly(url.host) + } } /** @@ -126,7 +129,11 @@ class MockResponseSniTest { val recordedRequest = server.takeRequest() assertThat(recordedRequest.requestUrl!!.host).isEqualTo("header-host") - assertThat(recordedRequest.handshakeServerNames).containsExactly("url-host.com") + + // https://github.com/bcgit/bc-java/issues/1773 + if (!platform.isBouncyCastle()) { + assertThat(recordedRequest.handshakeServerNames).containsExactly("url-host.com") + } } /** No SNI for literal IPv6 addresses. */ @@ -149,7 +156,10 @@ class MockResponseSniTest { fun regularHostname() { val recordedRequest = requestToHostnameViaProxy("cash.app") assertThat(recordedRequest.requestUrl!!.host).isEqualTo("cash.app") - assertThat(recordedRequest.handshakeServerNames).containsExactly("cash.app") + // https://github.com/bcgit/bc-java/issues/1773 + if (!platform.isBouncyCastle()) { + assertThat(recordedRequest.handshakeServerNames).containsExactly("cash.app") + } } /** diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/TlsUtil.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/TlsUtil.kt index ad76e91bbf51..7b4fa57f96ec 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/TlsUtil.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/TlsUtil.kt @@ -96,7 +96,11 @@ object TlsUtil { keyStore.setKeyEntry("private", heldCertificate.keyPair.private, password, chain) } - val factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) + // https://github.com/bcgit/bc-java/issues/1160 + val isBouncyCastle = keyStore.provider.name == "BC" + val algorithm = if (isBouncyCastle) "PKIX" else KeyManagerFactory.getDefaultAlgorithm() + + val factory = KeyManagerFactory.getInstance(algorithm) factory.init(keyStore, password) val result = factory.keyManagers!! check(result.size == 1 && result[0] is X509KeyManager) { diff --git a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt index efcfac723c4e..71065ebc75b8 100644 --- a/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt +++ b/okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/platform/Platform.kt @@ -129,7 +129,13 @@ open class Platform { @IgnoreJRERequirement // This function is overridden to require API >= 24. open fun getHandshakeServerNames(sslSocket: SSLSocket): List { val session = sslSocket.session as? ExtendedSSLSession ?: return listOf() - return session.requestedServerNames.mapNotNull { (it as? SNIHostName)?.asciiName } + return try { + session.requestedServerNames.mapNotNull { (it as? SNIHostName)?.asciiName } + } catch (uoe: UnsupportedOperationException) { + // UnsupportedOperationException – if the underlying provider does not implement the operation + // https://github.com/bcgit/bc-java/issues/1773 + listOf() + } } @Throws(IOException::class) From daab95ebff3de82c27c67809c102055a09ba35d1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Dec 2024 15:39:03 +0000 Subject: [PATCH 126/134] Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4.1 (#8542) * Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4.1 * loosen tests --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Yuri Schimke --- gradle/libs.versions.toml | 2 +- .../src/test/kotlin/okhttp3/compare/ApacheHttpClientTest.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f6e3b6a8a411..a98076230e81 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -58,7 +58,7 @@ gradlePlugin-shadow = "gradle.plugin.com.github.johnrengelman:shadow:8.0.0" gradlePlugin-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.25.0" guava-jre = "com.google.guava:guava:33.4.0-jre" hamcrestLibrary = "org.hamcrest:hamcrest-library:3.0" -httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.3.1" +httpClient5 = "org.apache.httpcomponents.client5:httpclient5:5.4.1" jettyClient = "org.eclipse.jetty:jetty-client:9.4.56.v20240826" jnr-unixsocket = "com.github.jnr:jnr-unixsocket:0.38.23" jsoup = "org.jsoup:jsoup:1.18.3" diff --git a/samples/compare/src/test/kotlin/okhttp3/compare/ApacheHttpClientTest.kt b/samples/compare/src/test/kotlin/okhttp3/compare/ApacheHttpClientTest.kt index bf1031a20a31..81474b0d831f 100644 --- a/samples/compare/src/test/kotlin/okhttp3/compare/ApacheHttpClientTest.kt +++ b/samples/compare/src/test/kotlin/okhttp3/compare/ApacheHttpClientTest.kt @@ -58,7 +58,6 @@ class ApacheHttpClientTest { val recorded = server.takeRequest() assertThat(recorded.headers["Accept"]).isEqualTo("text/plain") assertThat(recorded.headers["Accept-Encoding"]).isEqualTo("gzip, x-gzip, deflate") - assertThat(recorded.headers["Connection"]).isEqualTo("keep-alive") assertThat(recorded.headers["User-Agent"]!!).startsWith("Apache-HttpClient/") } } From fecceb9a461b4f3ce4be22fac818f7bb99a5b4c8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Dec 2024 17:52:12 +0200 Subject: [PATCH 127/134] Update kotlinx-coroutines monorepo to v1.10.1 (#8640) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a98076230e81..87cdde74aee8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ lintGradle = "1.0.0-alpha03" mockserverClient = "5.15.0" org-bouncycastle = "1.79" org-conscrypt = "2.5.2" -org-jetbrains-coroutines = "1.9.0" +org-jetbrains-coroutines = "1.10.1" org-jetbrains-kotlin = "2.1.0" org-junit-jupiter = "5.11.4" retrofit = "2.11.0" From ce019afb97705490d47d653aaad13f3b81e15255 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Dec 2024 17:54:37 +0200 Subject: [PATCH 128/134] Update dependency com.puppycrawl.tools:checkstyle to v10.21.1 (#8638) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 87cdde74aee8..5b77fc690704 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] # 7.0.0 is JDK 17+ https://github.com/bndtools/bnd/wiki/Changes-in-7.0.0 biz-aQute-bnd = "6.4.0" -checkStyle = "10.21.0" +checkStyle = "10.21.1" com-squareup-moshi = "1.15.2" com-squareup-okio = "3.9.1" de-mannodermaus-junit5 = "1.6.0" From aa3f6c0dc8f06f261d099bb8e837b0ad1b3be1d2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Dec 2024 17:47:31 +0000 Subject: [PATCH 129/134] Update dependency de.mannodermaus.gradle.plugins:android-junit5 to v1.11.3.0 (#8639) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5b77fc690704..0327e5203a72 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -43,7 +43,7 @@ eclipseOsgi = "org.eclipse.platform:org.eclipse.osgi:3.22.0" findbugs-jsr305 = "com.google.code.findbugs:jsr305:3.0.2" graal-sdk = { module = "org.graalvm.sdk:graal-sdk", version.ref = "graalvm" } gradlePlugin-android = "com.android.tools.build:gradle:8.7.3" -gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.2.0" +gradlePlugin-androidJunit5 = "de.mannodermaus.gradle.plugins:android-junit5:1.11.3.0" gradlePlugin-animalsniffer = "ru.vyarus:gradle-animalsniffer-plugin:1.7.2" gradlePlugin-binaryCompatibilityValidator = "org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.17.0" gradlePlugin-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "biz-aQute-bnd" } From 543b5b654e18dc2fe02009fca57a1b2783cca0a9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Dec 2024 17:51:02 +0000 Subject: [PATCH 130/134] Update mikepenz/action-junit-report action to v5 (#8641) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f7946fa7691..da84d66b72e4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -124,7 +124,7 @@ jobs: - name: Publish Test Report if: github.repository == 'square/okhttp' && github.ref == 'refs/heads/master' - uses: mikepenz/action-junit-report@v4 + uses: mikepenz/action-junit-report@v5 with: report_paths: '**/build/test-results/*/TEST-*.xml' check_name: OpenJDK 11 Test Report From b669048d63bfb2f81cb363e3107b7a7d36f6f34e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Dec 2024 18:01:00 +0000 Subject: [PATCH 131/134] Migrate config .github/renovate.json (#8643) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/renovate.json | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index 6774ca1bbcf4..04f314dd52f3 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,11 +1,13 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "config:base", + "config:recommended", ":dependencyDashboard", "schedule:weekly" ], - "labels": ["renovate"], + "labels": [ + "renovate" + ], "ignoreDeps": [ "com.squareup.okhttp3:okhttp", "com.squareup.okhttp3:okhttp-tls", @@ -13,28 +15,34 @@ ], "packageRules": [ { - "matchPackagePatterns": [ - "biz.*" - ], - "groupName": "bnd" + "groupName": "bnd", + "matchPackageNames": [ + "/biz.*/" + ] }, { - "matchPackagePatterns": [ - "org.graalvm.*" - ], - "groupName": "graalvm" + "groupName": "graalvm", + "matchPackageNames": [ + "/org.graalvm.*/" + ] }, { - "matchPackageNames": ["org.objenesis:objenesis"], + "matchPackageNames": [ + "org.objenesis:objenesis" + ], "allowedVersions": "<=2.6" }, { - "matchPackageNames": ["org.eclipse.jetty:jetty-client"], + "matchPackageNames": [ + "org.eclipse.jetty:jetty-client" + ], "allowedVersions": "<10.0", "description": "JDK 11 requirement" }, { - "matchPackageNames": ["org.junit-pioneer:junit-pioneer"], + "matchPackageNames": [ + "org.junit-pioneer:junit-pioneer" + ], "allowedVersions": "<2.0.0", "description": "JDK 11 requirement" } From 1786dd70e740db50509adc12df63d19aacc30b08 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Tue, 31 Dec 2024 01:28:56 +0200 Subject: [PATCH 132/134] Merge okhttp-android into okhttp (#8635) * Merge okhttp-android into okhttp. Since :okhttp is kmp, it isn't required to be separate. And also the okhttp-android/jvm artifact naming conflicts with it. --- .github/workflows/build.yml | 4 +- android-test-app/build.gradle.kts | 1 - android-test/build.gradle.kts | 17 +++- .../android/test}/AndroidAsyncDnsTest.kt | 3 +- android-test/src/main/AndroidManifest.xml | 1 + .../android/test}/AndroidAsyncDnsTest.kt | 5 +- .../android/test}/AndroidLoggingTest.kt | 20 ++--- .../android/test}/AndroidSocketAdapterTest.kt | 2 +- .../test}/RobolectricOkHttpClientTest.kt | 2 +- .../okhttp/android/test}/ShadowDnsResolver.kt | 2 +- okhttp-android/Module.md | 3 - okhttp-android/README.md | 13 --- okhttp-android/api/okhttp-android.api | 19 ----- okhttp-android/build.gradle.kts | 82 ------------------- .../src/androidTest/AndroidManifest.xml | 6 -- okhttp-android/src/main/AndroidManifest.xml | 6 -- .../kotlin/okhttp3/android/AndroidLogging.kt | 36 -------- okhttp/api/android/okhttp.api | 12 +++ okhttp/build.gradle.kts | 2 + okhttp/src/androidMain/AndroidManifest.xml | 2 + .../src/androidMain}/baseline-prof.txt | 0 .../kotlin/okhttp3/android/AndroidAsyncDns.kt | 0 .../internal/platform/AndroidPlatform.kt | 15 ++++ settings.gradle.kts | 1 - 24 files changed, 67 insertions(+), 187 deletions(-) rename {okhttp-android/src/androidTest/kotlin/okhttp3/android => android-test/src/androidTest/java/okhttp/android/test}/AndroidAsyncDnsTest.kt (98%) rename {okhttp-android/src/test/kotlin/okhttp3/android => android-test/src/test/kotlin/okhttp/android/test}/AndroidAsyncDnsTest.kt (92%) rename {okhttp-android/src/test/kotlin/okhttp3/android => android-test/src/test/kotlin/okhttp/android/test}/AndroidLoggingTest.kt (83%) rename {okhttp-android/src/test/kotlin/okhttp3/android => android-test/src/test/kotlin/okhttp/android/test}/AndroidSocketAdapterTest.kt (99%) rename {okhttp-android/src/test/kotlin/okhttp3/android => android-test/src/test/kotlin/okhttp/android/test}/RobolectricOkHttpClientTest.kt (98%) rename {okhttp-android/src/test/kotlin/okhttp3/android => android-test/src/test/kotlin/okhttp/android/test}/ShadowDnsResolver.kt (98%) delete mode 100644 okhttp-android/Module.md delete mode 100644 okhttp-android/README.md delete mode 100644 okhttp-android/api/okhttp-android.api delete mode 100644 okhttp-android/build.gradle.kts delete mode 100644 okhttp-android/src/androidTest/AndroidManifest.xml delete mode 100644 okhttp-android/src/main/AndroidManifest.xml delete mode 100644 okhttp-android/src/main/kotlin/okhttp3/android/AndroidLogging.kt rename {okhttp-android/src/main => okhttp/src/androidMain}/baseline-prof.txt (100%) rename {okhttp-android/src/main => okhttp/src/androidMain}/kotlin/okhttp3/android/AndroidAsyncDns.kt (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da84d66b72e4..38fb2d6f3b9d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -518,7 +518,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Gradle cache - run: ./gradlew -PandroidBuild=true :okhttp-android:test + run: ./gradlew -PandroidBuild=true :android-test:test - name: AVD cache uses: actions/cache@v4 @@ -545,7 +545,7 @@ jobs: with: api-level: ${{ matrix.api-level }} arch: ${{ matrix.api-level == '34' && 'x86_64' || 'x86' }} - script: ./gradlew -PandroidBuild=true :okhttp-android:connectedCheck :android-test:connectedCheck + script: ./gradlew -PandroidBuild=true :android-test:connectedCheck env: API_LEVEL: ${{ matrix.api-level }} diff --git a/android-test-app/build.gradle.kts b/android-test-app/build.gradle.kts index da419a24d774..901d70056735 100644 --- a/android-test-app/build.gradle.kts +++ b/android-test-app/build.gradle.kts @@ -41,7 +41,6 @@ android { dependencies { implementation(libs.playservices.safetynet) implementation(projects.okhttp) - implementation(projects.okhttpAndroid) implementation(libs.androidx.activity) androidTestImplementation(libs.androidx.junit) diff --git a/android-test/build.gradle.kts b/android-test/build.gradle.kts index c2aec16a1eb6..1dc021fd47b2 100644 --- a/android-test/build.gradle.kts +++ b/android-test/build.gradle.kts @@ -61,7 +61,20 @@ dependencies { implementation(libs.kotlin.reflect) implementation(libs.playservices.safetynet) implementation(projects.okhttp) - implementation(projects.okhttpAndroid) + + testImplementation(libs.junit) + testImplementation(libs.junit.ktx) + testImplementation(libs.assertk) + testImplementation(projects.okhttpTls) + testImplementation(projects.loggingInterceptor) + testImplementation(libs.androidx.test.runner) + testImplementation(libs.robolectric) + testImplementation(libs.androidx.espresso.core) + testImplementation(libs.squareup.okio.fakefilesystem) + testImplementation(projects.okhttpTestingSupport) + testImplementation(rootProject.libs.conscrypt.openjdk) + testImplementation(rootProject.libs.junit.jupiter.engine) + testImplementation(rootProject.libs.junit.vintage.engine) androidTestImplementation(projects.okhttpTestingSupport) { exclude("org.openjsse", "openjsse") @@ -72,13 +85,13 @@ dependencies { androidTestImplementation(libs.bouncycastle.bcprov) androidTestImplementation(libs.bouncycastle.bctls) androidTestImplementation(libs.conscrypt.android) + androidTestImplementation(projects.mockwebserver3Junit4) androidTestImplementation(projects.mockwebserver3Junit5) androidTestImplementation(projects.okhttpBrotli) androidTestImplementation(projects.okhttpDnsoverhttps) androidTestImplementation(projects.loggingInterceptor) androidTestImplementation(projects.okhttpSse) androidTestImplementation(projects.okhttpTls) - androidTestImplementation(projects.okhttpAndroid) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.httpClient5) diff --git a/okhttp-android/src/androidTest/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt b/android-test/src/androidTest/java/okhttp/android/test/AndroidAsyncDnsTest.kt similarity index 98% rename from okhttp-android/src/androidTest/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt rename to android-test/src/androidTest/java/okhttp/android/test/AndroidAsyncDnsTest.kt index 22a17ad11690..c144f7912bdb 100644 --- a/okhttp-android/src/androidTest/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt +++ b/android-test/src/androidTest/java/okhttp/android/test/AndroidAsyncDnsTest.kt @@ -14,7 +14,7 @@ * limitations under the License. * */ -package okhttp3.android +package okhttp.android.test import android.content.Context import android.net.ConnectivityManager @@ -36,6 +36,7 @@ import okhttp3.AsyncDns import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request +import okhttp3.android.AndroidAsyncDns import okhttp3.tls.HandshakeCertificates import okhttp3.tls.HeldCertificate import okio.IOException diff --git a/android-test/src/main/AndroidManifest.xml b/android-test/src/main/AndroidManifest.xml index 739f89763934..9a74ac7f8e7d 100644 --- a/android-test/src/main/AndroidManifest.xml +++ b/android-test/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ xmlns:tools="http://schemas.android.com/tools" package="okhttp.android.test"> + diff --git a/okhttp-android/src/test/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt b/android-test/src/test/kotlin/okhttp/android/test/AndroidAsyncDnsTest.kt similarity index 92% rename from okhttp-android/src/test/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt rename to android-test/src/test/kotlin/okhttp/android/test/AndroidAsyncDnsTest.kt index 43d9e5f3dd63..da3b0876d62c 100644 --- a/okhttp-android/src/test/kotlin/okhttp3/android/AndroidAsyncDnsTest.kt +++ b/android-test/src/test/kotlin/okhttp/android/test/AndroidAsyncDnsTest.kt @@ -13,13 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3.android +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +package okhttp.android.test import assertk.assertFailure import assertk.assertions.hasMessage import assertk.assertions.isInstanceOf import java.net.UnknownHostException import okhttp3.AsyncDns +import okhttp3.android.AndroidAsyncDns import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner diff --git a/okhttp-android/src/test/kotlin/okhttp3/android/AndroidLoggingTest.kt b/android-test/src/test/kotlin/okhttp/android/test/AndroidLoggingTest.kt similarity index 83% rename from okhttp-android/src/test/kotlin/okhttp3/android/AndroidLoggingTest.kt rename to android-test/src/test/kotlin/okhttp/android/test/AndroidLoggingTest.kt index 38b3223c038c..7ff13ae9a1f7 100644 --- a/okhttp-android/src/test/kotlin/okhttp3/android/AndroidLoggingTest.kt +++ b/android-test/src/test/kotlin/okhttp/android/test/AndroidLoggingTest.kt @@ -14,7 +14,7 @@ * limitations under the License. * */ -package okhttp3.android +package okhttp.android.test import android.util.Log import assertk.assertThat @@ -26,6 +26,7 @@ import okhttp3.ConnectionSpec import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request +import okhttp3.internal.platform.AndroidPlatform import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.LoggingEventListener import org.junit.Test @@ -36,18 +37,16 @@ import org.robolectric.shadows.ShadowLog @RunWith(RobolectricTestRunner::class) class AndroidLoggingTest { val clientBuilder = - OkHttpClient.Builder() - .connectionSpecs(listOf(ConnectionSpec.CLEARTEXT)) - .dns { - throw UnknownHostException("shortcircuit") - } + OkHttpClient.Builder().connectionSpecs(listOf(ConnectionSpec.CLEARTEXT)).dns { + throw UnknownHostException("shortcircuit") + } val request = Request("http://google.com/robots.txt".toHttpUrl()) @Test fun testHttpLoggingInterceptor() { val interceptor = - HttpLoggingInterceptor.androidLogging(tag = "testHttpLoggingInterceptor").apply { + HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BASIC } @@ -59,7 +58,7 @@ class AndroidLoggingTest { // expected } - val logs = ShadowLog.getLogsForTag("testHttpLoggingInterceptor") + val logs = ShadowLog.getLogsForTag(AndroidPlatform.Tag) assertThat(logs.map { it.type }).containsOnly(Log.INFO) assertThat(logs.map { it.msg }).containsExactly( "--> GET http://google.com/robots.txt", @@ -71,8 +70,7 @@ class AndroidLoggingTest { @Test fun testLoggingEventListener() { - val client = - clientBuilder.eventListenerFactory(LoggingEventListener.androidLogging(tag = "testLoggingEventListener")).build() + val client = clientBuilder.eventListenerFactory(LoggingEventListener.Factory()).build() try { client.newCall(request).execute() @@ -80,7 +78,7 @@ class AndroidLoggingTest { // expected } - val logs = ShadowLog.getLogsForTag("testLoggingEventListener") + val logs = ShadowLog.getLogsForTag(AndroidPlatform.Tag) assertThat(logs.map { it.type }).containsOnly(Log.INFO) assertThat( logs.map { diff --git a/okhttp-android/src/test/kotlin/okhttp3/android/AndroidSocketAdapterTest.kt b/android-test/src/test/kotlin/okhttp/android/test/AndroidSocketAdapterTest.kt similarity index 99% rename from okhttp-android/src/test/kotlin/okhttp3/android/AndroidSocketAdapterTest.kt rename to android-test/src/test/kotlin/okhttp/android/test/AndroidSocketAdapterTest.kt index 5c52f3e710af..2fe7b7513f4f 100644 --- a/okhttp-android/src/test/kotlin/okhttp3/android/AndroidSocketAdapterTest.kt +++ b/android-test/src/test/kotlin/okhttp/android/test/AndroidSocketAdapterTest.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3.android +package okhttp.android.test import java.security.Provider import javax.net.ssl.SSLContext diff --git a/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt b/android-test/src/test/kotlin/okhttp/android/test/RobolectricOkHttpClientTest.kt similarity index 98% rename from okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt rename to android-test/src/test/kotlin/okhttp/android/test/RobolectricOkHttpClientTest.kt index 0a8faf0d65ab..e4eba10e44ba 100644 --- a/okhttp-android/src/test/kotlin/okhttp3/android/RobolectricOkHttpClientTest.kt +++ b/android-test/src/test/kotlin/okhttp/android/test/RobolectricOkHttpClientTest.kt @@ -14,7 +14,7 @@ * limitations under the License. * */ -package okhttp3.android +package okhttp.android.test import android.app.Application import android.content.Context diff --git a/okhttp-android/src/test/kotlin/okhttp3/android/ShadowDnsResolver.kt b/android-test/src/test/kotlin/okhttp/android/test/ShadowDnsResolver.kt similarity index 98% rename from okhttp-android/src/test/kotlin/okhttp3/android/ShadowDnsResolver.kt rename to android-test/src/test/kotlin/okhttp/android/test/ShadowDnsResolver.kt index 6d5eac39afce..cf8b84f04df4 100644 --- a/okhttp-android/src/test/kotlin/okhttp3/android/ShadowDnsResolver.kt +++ b/android-test/src/test/kotlin/okhttp/android/test/ShadowDnsResolver.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package okhttp3.android +package okhttp.android.test import android.net.DnsResolver import android.net.Network diff --git a/okhttp-android/Module.md b/okhttp-android/Module.md deleted file mode 100644 index 4529ef4a1d60..000000000000 --- a/okhttp-android/Module.md +++ /dev/null @@ -1,3 +0,0 @@ -# Module okhttp-android - -OkHttp Android library. diff --git a/okhttp-android/README.md b/okhttp-android/README.md deleted file mode 100644 index 46efc377dd0d..000000000000 --- a/okhttp-android/README.md +++ /dev/null @@ -1,13 +0,0 @@ -OkHttp Android -============== - -Enhanced APIs for using OkHttp on Android. - -At the moment, this will mostly likely only be useful for fastFallback. - -Download --------- - -```kotlin -implementation("com.squareup.okhttp3:okhttp-android:4.12.0") -``` diff --git a/okhttp-android/api/okhttp-android.api b/okhttp-android/api/okhttp-android.api deleted file mode 100644 index a3884fa7c672..000000000000 --- a/okhttp-android/api/okhttp-android.api +++ /dev/null @@ -1,19 +0,0 @@ -public final class okhttp3/android/AndroidAsyncDns : okhttp3/AsyncDns { - public static final field Companion Lokhttp3/android/AndroidAsyncDns$Companion; - public fun (Lokhttp3/AsyncDns$DnsClass;Landroid/net/Network;)V - public synthetic fun (Lokhttp3/AsyncDns$DnsClass;Landroid/net/Network;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun query (Ljava/lang/String;Lokhttp3/AsyncDns$Callback;)V -} - -public final class okhttp3/android/AndroidAsyncDns$Companion { - public final fun getIPv4 ()Lokhttp3/android/AndroidAsyncDns; - public final fun getIPv6 ()Lokhttp3/android/AndroidAsyncDns; -} - -public final class okhttp3/android/AndroidLoggingKt { - public static final fun androidLogging (Lokhttp3/logging/HttpLoggingInterceptor$Companion;ILjava/lang/String;)Lokhttp3/logging/HttpLoggingInterceptor; - public static final fun androidLogging (Lokhttp3/logging/LoggingEventListener$Companion;ILjava/lang/String;)Lokhttp3/logging/LoggingEventListener$Factory; - public static synthetic fun androidLogging$default (Lokhttp3/logging/HttpLoggingInterceptor$Companion;ILjava/lang/String;ILjava/lang/Object;)Lokhttp3/logging/HttpLoggingInterceptor; - public static synthetic fun androidLogging$default (Lokhttp3/logging/LoggingEventListener$Companion;ILjava/lang/String;ILjava/lang/Object;)Lokhttp3/logging/LoggingEventListener$Factory; -} - diff --git a/okhttp-android/build.gradle.kts b/okhttp-android/build.gradle.kts deleted file mode 100644 index d4360b71c694..000000000000 --- a/okhttp-android/build.gradle.kts +++ /dev/null @@ -1,82 +0,0 @@ -@file:SuppressLint("OldTargetApi") - -import android.annotation.SuppressLint -import com.vanniktech.maven.publish.JavadocJar - -plugins { - id("com.android.library") - kotlin("android") - id("org.jetbrains.dokka") - id("com.vanniktech.maven.publish.base") - id("binary-compatibility-validator") -} - -android { - compileSdk = 34 - - namespace = "okhttp.android" - - defaultConfig { - minSdk = 21 - - // Make sure to use the AndroidJUnitRunner (or a sub-class) in order to hook in the JUnit 5 Test Builder - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - - buildFeatures { - buildConfig = false - } - - testOptions { - unitTests { - isIncludeAndroidResources = true - } - - targetSdk = 34 - } - } - - compileOptions { - targetCompatibility(JavaVersion.VERSION_11) - sourceCompatibility(JavaVersion.VERSION_11) - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() - } -} - -dependencies { - api(libs.squareup.okio) - api(projects.okhttp) - api(projects.loggingInterceptor) - compileOnly(libs.androidx.annotation) - compileOnly(libs.findbugs.jsr305) - debugImplementation(libs.androidx.annotation) - debugImplementation(libs.findbugs.jsr305) - compileOnly(libs.animalsniffer.annotations) - compileOnly(libs.robolectric.android) - - testImplementation(libs.junit) - testImplementation(libs.junit.ktx) - testImplementation(libs.assertk) - testImplementation(projects.okhttpTls) - testImplementation(libs.androidx.test.runner) - testImplementation(libs.robolectric) - testImplementation(libs.androidx.espresso.core) - testImplementation(libs.squareup.okio.fakefilesystem) - testImplementation(projects.okhttpTestingSupport) - testImplementation(rootProject.libs.conscrypt.openjdk) - - androidTestImplementation(projects.okhttpTls) - androidTestImplementation(libs.assertk) - androidTestImplementation(projects.mockwebserver3Junit4) - androidTestImplementation(libs.androidx.test.runner) -} - -// TODO remove this whole module after merging with okhttp -// Conflicts with KMP :okhttp outputs - -//mavenPublishing { -// // AGP 7.2 embeds Dokka 4, which breaks publishing. Android modules are hardcoded to generate Javadoc instead of Gfm. -// configure(com.vanniktech.maven.publish.AndroidSingleVariantLibrary(publishJavadocJar=false)) -//} diff --git a/okhttp-android/src/androidTest/AndroidManifest.xml b/okhttp-android/src/androidTest/AndroidManifest.xml deleted file mode 100644 index 4daaca67f7ef..000000000000 --- a/okhttp-android/src/androidTest/AndroidManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/okhttp-android/src/main/AndroidManifest.xml b/okhttp-android/src/main/AndroidManifest.xml deleted file mode 100644 index 4fe7e5ca898e..000000000000 --- a/okhttp-android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/okhttp-android/src/main/kotlin/okhttp3/android/AndroidLogging.kt b/okhttp-android/src/main/kotlin/okhttp3/android/AndroidLogging.kt deleted file mode 100644 index f39cc43ccd0a..000000000000 --- a/okhttp-android/src/main/kotlin/okhttp3/android/AndroidLogging.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2022 Block, 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.android - -import android.util.Log -import okhttp3.logging.HttpLoggingInterceptor -import okhttp3.logging.LoggingEventListener - -/** - * An OkHttp [LoggingEventListener], with android Log as the target. - */ -fun LoggingEventListener.Companion.androidLogging( - priority: Int = Log.INFO, - tag: String = "OkHttp", -) = LoggingEventListener.Factory { Log.println(priority, tag, it) } - -/** - * An OkHttp [HttpLoggingInterceptor], with android Log as the target. - */ -fun HttpLoggingInterceptor.Companion.androidLogging( - priority: Int = Log.INFO, - tag: String = "OkHttp", -) = HttpLoggingInterceptor { Log.println(priority, tag, it) } diff --git a/okhttp/api/android/okhttp.api b/okhttp/api/android/okhttp.api index fcc0709091a4..5dabeaa98ce9 100644 --- a/okhttp/api/android/okhttp.api +++ b/okhttp/api/android/okhttp.api @@ -1292,3 +1292,15 @@ public abstract class okhttp3/WebSocketListener { public fun onOpen (Lokhttp3/WebSocket;Lokhttp3/Response;)V } +public final class okhttp3/android/AndroidAsyncDns : okhttp3/AsyncDns { + public static final field Companion Lokhttp3/android/AndroidAsyncDns$Companion; + public fun (Lokhttp3/AsyncDns$DnsClass;Landroid/net/Network;)V + public synthetic fun (Lokhttp3/AsyncDns$DnsClass;Landroid/net/Network;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun query (Ljava/lang/String;Lokhttp3/AsyncDns$Callback;)V +} + +public final class okhttp3/android/AndroidAsyncDns$Companion { + public final fun getIPv4 ()Lokhttp3/android/AndroidAsyncDns; + public final fun getIPv6 ()Lokhttp3/android/AndroidAsyncDns; +} + diff --git a/okhttp/build.gradle.kts b/okhttp/build.gradle.kts index cd9b9e66a8c7..d3dbdb38026c 100644 --- a/okhttp/build.gradle.kts +++ b/okhttp/build.gradle.kts @@ -3,6 +3,7 @@ import aQute.bnd.gradle.BundleTaskExtension import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.KotlinMultiplatform +import org.gradle.kotlin.dsl.compileOnly import org.jetbrains.kotlin.gradle.dsl.JvmTarget import ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferExtension import java.util.Base64 @@ -95,6 +96,7 @@ kotlin { compileOnly(libs.bouncycastle.bcprov) compileOnly(libs.bouncycastle.bctls) compileOnly(libs.conscrypt.openjdk) + implementation(libs.androidx.annotation) } } diff --git a/okhttp/src/androidMain/AndroidManifest.xml b/okhttp/src/androidMain/AndroidManifest.xml index 6b7444be5b61..705359b1c70a 100644 --- a/okhttp/src/androidMain/AndroidManifest.xml +++ b/okhttp/src/androidMain/AndroidManifest.xml @@ -1,4 +1,6 @@ + + diff --git a/okhttp-android/src/main/baseline-prof.txt b/okhttp/src/androidMain/baseline-prof.txt similarity index 100% rename from okhttp-android/src/main/baseline-prof.txt rename to okhttp/src/androidMain/baseline-prof.txt diff --git a/okhttp-android/src/main/kotlin/okhttp3/android/AndroidAsyncDns.kt b/okhttp/src/androidMain/kotlin/okhttp3/android/AndroidAsyncDns.kt similarity index 100% rename from okhttp-android/src/main/kotlin/okhttp3/android/AndroidAsyncDns.kt rename to okhttp/src/androidMain/kotlin/okhttp3/android/AndroidAsyncDns.kt diff --git a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt index 8a6f67a8670f..3539edc91156 100644 --- a/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt +++ b/okhttp/src/androidMain/kotlin/okhttp3/internal/platform/AndroidPlatform.kt @@ -17,6 +17,7 @@ package okhttp3.internal.platform import android.os.Build import android.security.NetworkSecurityPolicy +import android.util.Log import java.io.IOException import java.lang.reflect.InvocationTargetException import java.lang.reflect.Method @@ -119,6 +120,18 @@ class AndroidPlatform : Platform() { return super.getHandshakeServerNames(sslSocket) } + override fun log( + message: String, + level: Int, + t: Throwable?, + ) { + if (level == WARN) { + Log.w(Tag, message, t) + } else { + Log.i(Tag, message, t) + } + } + /** * A trust manager for Android applications that customize the trust manager. * @@ -147,6 +160,8 @@ class AndroidPlatform : Platform() { } companion object { + val Tag = "OkHttp" + val isSupported: Boolean = when { !isAndroid -> false diff --git a/settings.gradle.kts b/settings.gradle.kts index 442c415ab5e1..0bb5a2ddcecc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -63,7 +63,6 @@ val localProperties = Properties().apply { } val sdkDir = localProperties.getProperty("sdk.dir") if (androidHome != null || sdkDir != null) { - include(":okhttp-android") include(":android-test") include(":android-test-app") } From dd5a002d440f4e02f4a61f16b36325d2be4733a5 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Tue, 31 Dec 2024 16:50:53 +0200 Subject: [PATCH 133/134] Use Assets or Resources based on platform. (#8636) * Use Assets and Resources based on platform. Assets uncompressed on Android. Assuming that the AAR file will compress. Use Resources, compressed on JVM. --- .../java/okhttp/android/test/OkHttpTest.kt | 6 + gradle/libs.versions.toml | 2 + okhttp/build.gradle.kts | 58 ++++++--- okhttp/src/androidMain/AndroidManifest.xml | 17 ++- .../assets/PublicSuffixDatabase.list | Bin 0 -> 132737 bytes .../internal/platform/Android10Platform.kt | 5 +- .../internal/platform/AndroidPlatform.kt | 5 +- .../internal/platform/ContextAwarePlatform.kt | 22 ++++ .../internal/platform/PlatformInitializer.kt | 32 +++++ .../internal/platform/PlatformRegistry.kt | 22 ++++ .../publicsuffix/AssetPublicSuffixList.kt | 36 ++++++ .../publicsuffix/PublicSuffixList.android.kt | 19 +++ .../okhttp3/test/BaseJavaTest.android.kt | 31 +++++ .../publicsuffix/BasePublicSuffixList.kt} | 52 ++++---- .../publicsuffix/PublicSuffixDatabase.kt | 2 +- .../internal/publicsuffix/PublicSuffixList.kt | 4 + .../publicsuffix/ResourcePublicSuffixList.kt | 35 ++++++ .../publicsuffix/EmbeddedPublicSuffixList.kt | 54 --------- .../ConfiguredPublicSuffixDatabaseTest.kt | 110 +++++++++++++++++ .../ConfiguredPublicSuffixList.kt | 30 +++++ .../publicsuffix/PublicSuffixDatabaseTest.kt | 114 +++--------------- .../kotlin/okhttp3/test/BaseJavaTest.kt | 18 +++ .../publicsuffix/PublicSuffixList.jvm.kt | 19 +++ .../publicsuffix/PublicSuffixDatabase.gz | Bin .../kotlin/okhttp3/test/BaseJavaTest.kt | 18 +++ 25 files changed, 512 insertions(+), 199 deletions(-) create mode 100644 okhttp/src/androidMain/assets/PublicSuffixDatabase.list create mode 100644 okhttp/src/androidMain/kotlin/okhttp3/internal/platform/ContextAwarePlatform.kt create mode 100644 okhttp/src/androidMain/kotlin/okhttp3/internal/platform/PlatformInitializer.kt create mode 100644 okhttp/src/androidMain/kotlin/okhttp3/internal/publicsuffix/AssetPublicSuffixList.kt create mode 100644 okhttp/src/androidMain/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.android.kt create mode 100644 okhttp/src/androidUnitTest/kotlin/okhttp3/test/BaseJavaTest.android.kt rename okhttp/src/{jvmTest/kotlin/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt => commonJvmAndroid/kotlin/okhttp3/internal/publicsuffix/BasePublicSuffixList.kt} (76%) create mode 100644 okhttp/src/commonJvmAndroid/kotlin/okhttp3/internal/publicsuffix/ResourcePublicSuffixList.kt delete mode 100644 okhttp/src/commonJvmAndroid/kotlinTemplates/okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt create mode 100644 okhttp/src/commonTest/kotlin/okhttp3/internal/publicsuffix/ConfiguredPublicSuffixDatabaseTest.kt create mode 100644 okhttp/src/commonTest/kotlin/okhttp3/internal/publicsuffix/ConfiguredPublicSuffixList.kt rename okhttp/src/{jvmTest => commonTest}/kotlin/okhttp3/internal/publicsuffix/PublicSuffixDatabaseTest.kt (68%) create mode 100644 okhttp/src/commonTest/kotlin/okhttp3/test/BaseJavaTest.kt create mode 100644 okhttp/src/jvmMain/kotlin/okhttp3/internal/publicsuffix/PublicSuffixList.jvm.kt rename okhttp/src/{jvmTest => jvmMain}/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz (100%) create mode 100644 okhttp/src/jvmTest/kotlin/okhttp3/test/BaseJavaTest.kt diff --git a/android-test/src/androidTest/java/okhttp/android/test/OkHttpTest.kt b/android-test/src/androidTest/java/okhttp/android/test/OkHttpTest.kt index 82625ab745ac..1064756cb74d 100644 --- a/android-test/src/androidTest/java/okhttp/android/test/OkHttpTest.kt +++ b/android-test/src/androidTest/java/okhttp/android/test/OkHttpTest.kt @@ -15,7 +15,9 @@ */ package okhttp.android.test +import android.content.Context import android.os.Build +import androidx.test.core.app.ApplicationProvider import androidx.test.platform.app.InstrumentationRegistry import com.google.android.gms.common.GooglePlayServicesNotAvailableException import com.google.android.gms.security.ProviderInstaller @@ -63,6 +65,7 @@ import okhttp3.internal.http2.Http2 import okhttp3.internal.platform.Android10Platform import okhttp3.internal.platform.AndroidPlatform import okhttp3.internal.platform.Platform +import okhttp3.internal.platform.PlatformRegistry import okhttp3.logging.LoggingEventListener import okhttp3.testing.PlatformRule import okhttp3.tls.HandshakeCertificates @@ -117,6 +120,9 @@ class OkHttpTest { @BeforeEach fun setup(server: MockWebServer) { + // Needed because of Platform.resetForTests + PlatformRegistry.applicationContext = ApplicationProvider.getApplicationContext() + this.server = server } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0327e5203a72..cb7d2b7f7725 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ org-jetbrains-coroutines = "1.10.1" org-jetbrains-kotlin = "2.1.0" org-junit-jupiter = "5.11.4" retrofit = "2.11.0" +startupRuntime = "1.2.0" testcontainers = "1.20.4" [libraries] @@ -25,6 +26,7 @@ androidx-annotation = "androidx.annotation:annotation:1.9.1" androidx-espresso-core = "androidx.test.espresso:espresso-core:3.6.1" androidx-junit = "androidx.test.ext:junit:1.2.1" androidx-lint-gradle = { module = "androidx.lint:lint-gradle", version.ref = "lintGradle" } +androidx-startup-runtime = { module = "androidx.startup:startup-runtime", version.ref = "startupRuntime" } androidx-test-runner = "androidx.test:runner:1.6.2" animalsniffer-annotations = "org.codehaus.mojo:animal-sniffer-annotations:1.24" aqute-resolve = { module = "biz.aQute.bnd:biz.aQute.resolve", version.ref = "biz-aQute-bnd" } diff --git a/okhttp/build.gradle.kts b/okhttp/build.gradle.kts index d3dbdb38026c..c759ed4ce834 100644 --- a/okhttp/build.gradle.kts +++ b/okhttp/build.gradle.kts @@ -3,10 +3,8 @@ import aQute.bnd.gradle.BundleTaskExtension import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.KotlinMultiplatform -import org.gradle.kotlin.dsl.compileOnly import org.jetbrains.kotlin.gradle.dsl.JvmTarget import ru.vyarus.gradle.plugin.animalsniffer.AnimalSnifferExtension -import java.util.Base64 plugins { kotlin("multiplatform") @@ -15,35 +13,23 @@ plugins { id("org.jetbrains.dokka") id("com.vanniktech.maven.publish.base") id("binary-compatibility-validator") + id("io.github.gmazzo.aar2jar") version "1.0.1" } val platform = System.getProperty("okhttp.platform", "jdk9") val testJavaVersion = System.getProperty("test.java.version", "21").toInt() -fun ByteArray.toByteStringExpression(): String { - return "\"${Base64.getEncoder().encodeToString(this@toByteStringExpression)}\".decodeBase64()!!" -} - val copyKotlinTemplates = tasks.register("copyKotlinTemplates") { val kotlinTemplatesOutput = layout.buildDirectory.dir("generated/sources/kotlinTemplates") from("src/commonJvmAndroid/kotlinTemplates") into(kotlinTemplatesOutput) - // Tag as an input to regenerate after an update - inputs.file("src/jvmTest/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") - filteringCharset = Charsets.UTF_8.toString() - val databaseGz = project.file("src/jvmTest/resources/okhttp3/internal/publicsuffix/PublicSuffixDatabase.gz") - val listBytes = databaseGz.readBytes().toByteStringExpression() - expand( // Build & use okhttp3/internal/-InternalVersion.kt "projectVersion" to project.version, - - // Build okhttp3/internal/publicsuffix/EmbeddedPublicSuffixList.kt - "publicSuffixListBytes" to listBytes ) } @@ -90,6 +76,19 @@ kotlin { } } + commonTest { + dependencies { + implementation(projects.okhttpTestingSupport) + implementation(libs.assertk) + implementation(libs.kotlin.test.annotations) + implementation(libs.kotlin.test.common) + implementation(libs.kotlin.test.junit) + implementation(libs.junit) + implementation(libs.junit.jupiter.api) + implementation(libs.junit.jupiter.params) + } + } + androidMain { dependsOn(commonJvmAndroid) dependencies { @@ -97,6 +96,7 @@ kotlin { compileOnly(libs.bouncycastle.bctls) compileOnly(libs.conscrypt.openjdk) implementation(libs.androidx.annotation) + implementation(libs.androidx.startup.runtime) } } @@ -158,6 +158,20 @@ kotlin { } } } + + val androidUnitTest by getting { + dependencies { + implementation(libs.assertk) + implementation(libs.kotlin.test.annotations) + implementation(libs.kotlin.test.common) + implementation(libs.androidx.junit) + + implementation(libs.junit.jupiter.engine) + implementation(libs.junit.vintage.engine) + + implementation(libs.robolectric) + } + } } } @@ -184,6 +198,19 @@ android { consumerProguardFiles("okhttp3.pro") } + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } + + sourceSets { + named("main") { + manifest.srcFile("src/androidMain/AndroidManifest.xml") + assets.srcDir("src/androidMain/assets") + } + } } // Hack to make BundleTaskExtension pass briefly @@ -237,7 +264,6 @@ dependencies { // Animal Sniffer confirms we generally don't use APIs not on Java 8. configure { annotation = "okhttp3.internal.SuppressSignatureCheck" - sourceSets = listOf(project.sourceSets["main"]) } configure { diff --git a/okhttp/src/androidMain/AndroidManifest.xml b/okhttp/src/androidMain/AndroidManifest.xml index 705359b1c70a..7454e18f58b6 100644 --- a/okhttp/src/androidMain/AndroidManifest.xml +++ b/okhttp/src/androidMain/AndroidManifest.xml @@ -1,6 +1,17 @@ - + - + + + + + + + diff --git a/okhttp/src/androidMain/assets/PublicSuffixDatabase.list b/okhttp/src/androidMain/assets/PublicSuffixDatabase.list new file mode 100644 index 0000000000000000000000000000000000000000..5e99c0e45106e6e06f603253661dd2e2b1407667 GIT binary patch literal 132737 zcmb5XOLFVFwyv3R3t4beGQx_z9%t=yn?p&IM2jM|L`j}C!ton8Ryu38+x;{M* z=k4OyR_9HBIxL2&tp{SOnoNf$-l-3V6s^|RX6R3g*8zC7c^>-9dH4LwqH0c?wtrnz zhw82Gs@EasZ&&rO=<4%pf7IdbezLUhtL~5f{&@>u*Y$O=sx$_#Lv=i!E?rlj@-V$!PW7tq&Q&8|)01tv z)=#~y&y3npaZQ#5@8!5(U*}n}TAV%7JY7}KtGYX%s`iV4Ceteu@v9t~F{`$}tQUv+ zT)D^#Gx05h>r=HDnscpm7t`jm;>b|s`s%|u=dgI`Z?qzHk=9FUJgee(IoJBs-E>b+ zeh!{K6ooD5iYi)ix*gAb*B_dd7LICt8P5HIW!kTrRGal;#Y$yJdAzR9)v_9L?EvO= zP3CcUH2l@NU)EK9h(3+Q4ZLpqBV!q(yl%G5xoZ1WU3J5ePR~nu{aP;UQ~| zjUQmqzWSv6m!FsrMW)YJ1(}Q9&i*?WO5@W_-#ZSbyE6DcP(S$IFsOP5Tog z+jRF8c+tMHuU@O6+Bb_Ap_jcXz9(znsm6-MC-%(8{p~XBE-53EIK?jAy5@yhC$&|# zzHdOgYExT@vCy`4PSVD8-7jD26@3~j;=tqX+zYV;_MtY1`X`!6rtc=+q1m3QbJKST zl^oO$hraKI6}xUA-op(9+FeJ~meWxop|P&o_O~kfK=of%GTb%dpb5^G&9QFlSbs5BSbfy~*ymk>-7#ez==