Skip to content

Commit

Permalink
Use Assets and Resources based on platform.
Browse files Browse the repository at this point in the history
Assets uncompressed on Android. Assuming that the AAR file will compress.

Use Resources, compressed on JVM.
  • Loading branch information
yschimke committed Dec 27, 2024
1 parent 094c783 commit 9441d0a
Show file tree
Hide file tree
Showing 21 changed files with 423 additions and 196 deletions.
55 changes: 40 additions & 15 deletions okhttp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -20,30 +18,17 @@ plugins {
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<Copy>("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
)
}

Expand Down Expand Up @@ -90,6 +75,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 {
Expand Down Expand Up @@ -158,6 +156,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)
}
}
}
}

Expand All @@ -184,6 +196,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
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package okhttp3.internal.platform

import android.annotation.SuppressLint
import android.content.Context
import android.os.Build
import android.security.NetworkSecurityPolicy
import android.util.CloseGuard
Expand All @@ -34,7 +35,9 @@ import okhttp3.internal.tls.CertificateChainCleaner

/** Android 10+ (API 29+). */
@SuppressSignatureCheck
class Android10Platform : Platform() {
class Android10Platform : Platform(), ContextAwarePlatform {
override var applicationContext: Context? = null

private val socketAdapters =
listOfNotNull(
Android10SocketAdapter.buildIfSupported(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package okhttp3.internal.platform

import android.content.Context
import android.os.Build
import android.security.NetworkSecurityPolicy
import android.util.Log
Expand Down Expand Up @@ -42,7 +43,9 @@ import okhttp3.internal.tls.TrustRootIndex

/** Android 5 to 9 (API 21 to 28). */
@SuppressSignatureCheck
class AndroidPlatform : Platform() {
class AndroidPlatform : Platform(), ContextAwarePlatform {
override var applicationContext: Context? = null

private val socketAdapters =
listOfNotNull(
StandardAndroidSocketAdapter.buildIfSupported(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package okhttp3.internal.platform

import android.content.Context

interface ContextAwarePlatform {
var applicationContext: Context?
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package okhttp3.internal.platform

import android.content.Context
import okhttp3.internal.platform.android.AndroidLog

actual object PlatformRegistry {
Expand All @@ -10,4 +11,10 @@ actual object PlatformRegistry {

actual val isAndroid: Boolean
get() = true

var applicationContext: Context?
get() = (Platform.get() as? ContextAwarePlatform)?.applicationContext
set(value) {
(Platform.get() as? ContextAwarePlatform)?.applicationContext = value
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 java.io.IOException
import okhttp3.internal.platform.PlatformRegistry
import okio.Source
import okio.source

internal class AssetPublicSuffixList(
override val path: String = PUBLIC_SUFFIX_RESOURCE,
) : BasePublicSuffixList() {
override fun listSource(): Source {
val assets =
PlatformRegistry.applicationContext?.assets ?: throw IOException("Platform applicationContext not initialized")

return assets.open(path).source()
}

companion object {
val PUBLIC_SUFFIX_RESOURCE = "/PublicSuffixDatabase.list"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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

internal actual val Default: PublicSuffixList = AssetPublicSuffixList()
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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.test

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import okhttp3.internal.platform.PlatformRegistry
import org.junit.Before
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
actual open class BaseJavaTest actual constructor() {
@Before
fun init() {
PlatformRegistry.applicationContext = ApplicationProvider.getApplicationContext<Context>()
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* 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 java.io.IOException
Expand All @@ -6,16 +21,10 @@ 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.Source
import okio.buffer

internal class ResourcePublicSuffixList(
val path: Path = PUBLIC_SUFFIX_RESOURCE,
val fileSystem: FileSystem = FileSystem.RESOURCES,
) : PublicSuffixList {
internal abstract class BasePublicSuffixList : PublicSuffixList {
/** True after we've attempted to read the list for the first time. */
private val listRead = AtomicBoolean(false)

Expand All @@ -35,7 +44,7 @@ internal class ResourcePublicSuffixList(
var publicSuffixExceptionListBytes: ByteString?

try {
GzipSource(fileSystem.source(path)).buffer().use { bufferedSource ->
listSource().buffer().use { bufferedSource ->
val totalBytes = bufferedSource.readInt()
publicSuffixListBytes = bufferedSource.readByteString(totalBytes.toLong())

Expand All @@ -52,6 +61,8 @@ internal class ResourcePublicSuffixList(
}
}

abstract fun listSource(): Source

override fun ensureLoaded() {
if (!listRead.get() && listRead.compareAndSet(false, true)) {
readTheListUninterruptibly()
Expand All @@ -65,10 +76,12 @@ internal class ResourcePublicSuffixList(

check(::bytes.isInitialized) {
// May have failed with an IOException
"Unable to load $PUBLIC_SUFFIX_RESOURCE resource from the classpath."
"Unable to load $path resource in ${this.javaClass.simpleName}."
}
}

abstract val path: Any

/**
* 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
Expand All @@ -85,7 +98,7 @@ internal class ResourcePublicSuffixList(
Thread.interrupted() // Temporarily clear the interrupted state.
interrupted = true
} catch (e: IOException) {
Platform.get().log("Failed to read public suffix list", Platform.WARN, e)
Platform.Companion.get().log("Failed to read public suffix list", Platform.Companion.WARN, e)
return
}
}
Expand All @@ -95,21 +108,4 @@ internal class ResourcePublicSuffixList(
}
}
}

/** 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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import okio.ByteString.Companion.encodeUtf8
* [publicsuffix_org]: https://publicsuffix.org/
*/
class PublicSuffixDatabase internal constructor(
private val publicSuffixList: PublicSuffixList,
private val publicSuffixList: PublicSuffixList = Default,
) {
/**
* Returns the effective top-level domain plus one (eTLD+1) by referencing the public suffix list.
Expand Down Expand Up @@ -153,7 +153,7 @@ class PublicSuffixDatabase internal constructor(

private const val EXCEPTION_MARKER = '!'

private val instance = PublicSuffixDatabase(EmbeddedPublicSuffixList)
private val instance = PublicSuffixDatabase(Default)

fun get(): PublicSuffixDatabase {
return instance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ internal interface PublicSuffixList {
val bytes: ByteString
val exceptionBytes: ByteString
}

internal expect val Default: PublicSuffixList
Loading

0 comments on commit 9441d0a

Please sign in to comment.