Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import okhttp3.HttpUrl
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.dnsoverhttps.internal.DnsOverHttpsCall
import okhttp3.dnsoverhttps.internal.DnsOverHttpsTransport
import okhttp3.internal.dns.StateMachineDnsCall
import okhttp3.internal.dns.execute
import okhttp3.internal.publicsuffix.PublicSuffixDatabase

Expand All @@ -45,18 +46,21 @@ class DnsOverHttps internal constructor(
@get:JvmName("resolvePrivateAddresses") val resolvePrivateAddresses: Boolean,
@get:JvmName("resolvePublicAddresses") val resolvePublicAddresses: Boolean,
) : Dns {
override fun newCall(request: Dns.Request): Dns.Call {
val canceledException = validate(request.hostname)
return DnsOverHttpsCall(
request = request,
private val transport =
DnsOverHttpsTransport(
client = client,
dnsUrl = url,
post = post,
)

override fun newCall(request: Dns.Request): Dns.Call =
StateMachineDnsCall(
request = request,
transport = transport,
canceledException = validate(request.hostname),
includeIPv6 = includeIPv6,
includeServiceMetadata = includeServiceMetadata,
canceledException = canceledException,
)
}

/**
* Returns an exception if [hostname] should not be resolved.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,66 +13,44 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("ktlint:standard:filename")

package okhttp3.dnsoverhttps.internal

import java.io.IOException
import java.net.ProtocolException
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Dns
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Protocol
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import okhttp3.dnsoverhttps.DnsOverHttps
import okhttp3.dnsoverhttps.DnsOverHttps.Companion.DNS_MESSAGE
import okhttp3.dnsoverhttps.DnsOverHttps.Companion.MAX_RESPONSE_SIZE
import okhttp3.internal.OkHttpInternalApi
import okhttp3.internal.dns.DnsCallStateMachine
import okhttp3.internal.dns.DnsMessage
import okhttp3.internal.dns.DnsMessageReader
import okhttp3.internal.dns.DnsMessageWriter
import okhttp3.internal.dns.Question
import okhttp3.internal.dns.StateMachineDnsCall
import okhttp3.internal.platform.Platform
import okio.Buffer
import okio.BufferedSink

// TODO: in-memory caching that uses timeToLive.
// TODO: honor Https.priority and Https.targetName. Create new calls!

/**
* Implements [Dns.Call] by making multiple HTTPS calls.
*/
@OkHttpInternalApi
internal class DnsOverHttpsCall(
override val request: Dns.Request,
internal class DnsOverHttpsTransport(
private val client: OkHttpClient,
private val dnsUrl: HttpUrl,
private val post: Boolean,
includeIPv6: Boolean,
includeServiceMetadata: Boolean,
canceledException: IOException?,
) : Dns.Call,
DnsCallStateMachine.Transport<Call> {
private val stateMachine =
DnsCallStateMachine(
transport = this,
call = this,
canceledException = canceledException,
includeIPv6 = includeIPv6,
includeServiceMetadata = includeServiceMetadata,
)

) : StateMachineDnsCall.Transport<Call> {
override fun newQuery(question: Question): Call {
val dnsMessage = DnsMessage.query(question)
return client.newCall(
request =
Request
.Builder()
.header("Accept", DNS_MESSAGE.toString())
.header("Accept", DnsOverHttps.DNS_MESSAGE.toString())
.apply {
if (post) {
url(dnsUrl)
Expand All @@ -98,7 +76,7 @@ internal class DnsOverHttpsCall(

override fun enqueue(
query: Call,
callback: DnsCallStateMachine.Transport.Callback<Call>,
callback: StateMachineDnsCall.Transport.Callback<Call>,
) {
query.enqueue(
object : Callback {
Expand Down Expand Up @@ -129,16 +107,6 @@ internal class DnsOverHttpsCall(
override fun cancel(query: Call) {
query.cancel()
}

override fun enqueue(callback: Dns.Callback) {
stateMachine.start(callback)
}

override fun cancel() {
stateMachine.cancel()
}

override fun isCanceled() = stateMachine.canceled
}

internal fun DnsMessage.asQueryParameter(): String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("ktlint:standard:filename")

package okhttp3.internal.dns

import java.io.IOException
Expand All @@ -25,7 +27,7 @@ import kotlin.time.ExperimentalTime
import kotlin.time.TimeSource
import okhttp3.internal.OkHttpInternalApi
import okhttp3.internal.concurrent.TaskRunner
import okhttp3.internal.dns.DnsCallStateMachine.Transport
import okhttp3.internal.dns.StateMachineDnsCall.Transport

// TODO: evict old entries from cache using State.lastRequestedAt

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import okhttp3.Protocol
import okhttp3.internal.OkHttpInternalApi

/**
* State machine for DNS calls. This is intended for use with any transport for the queries, such
* as UDP or DNS over HTTPS.
* An application-layer DNS call that performs multiple transport-layer DNS queries in parallel.
* This delegates to an arbitrary transport like UDP or DNS over HTTPS.
*
* Concurrency
* -----------
Expand All @@ -53,28 +53,27 @@ import okhttp3.internal.OkHttpInternalApi
* that call is executing.
*/
@OkHttpInternalApi
class DnsCallStateMachine<Q>(
class StateMachineDnsCall<Q>(
override val request: Dns.Request,
private val transport: Transport<Q>,
private val call: Dns.Call,
private val canceledException: IOException?,
private val includeIPv6: Boolean,
private val includeServiceMetadata: Boolean,
) {
) : Dns.Call {
private val state = AtomicReference<State<Q>>(State.Idle())

val canceled: Boolean
get() = state.get().canceled
override fun isCanceled() = state.get().canceled

fun start(callback: Dns.Callback) {
override fun enqueue(callback: Dns.Callback) {
val questions =
buildList {
if (includeServiceMetadata) {
add(Question(call.request.hostname, TYPE_HTTPS))
add(Question(request.hostname, TYPE_HTTPS))
}
if (includeIPv6) {
add(Question(call.request.hostname, TYPE_AAAA))
add(Question(request.hostname, TYPE_AAAA))
}
add(Question(call.request.hostname, TYPE_A))
add(Question(request.hostname, TYPE_A))
}

val queries =
Expand Down Expand Up @@ -126,7 +125,7 @@ class DnsCallStateMachine<Q>(
}
}

fun cancel() {
override fun cancel() {
while (true) {
val previous = state.get()
val next = previous.cancel()
Expand Down Expand Up @@ -164,7 +163,7 @@ class DnsCallStateMachine<Q>(
when (resourceRecord) {
is ResourceRecord.Https -> {
Dns.Record.ServiceMetadata(
hostname = resourceRecord.targetName.takeIf { it != "" } ?: call.request.hostname,
hostname = resourceRecord.targetName.takeIf { it != "" } ?: request.hostname,
alpnIds =
resourceRecord.alpnIds?.mapNotNull { alpnId ->
try {
Expand All @@ -181,7 +180,7 @@ class DnsCallStateMachine<Q>(

is ResourceRecord.IpAddress -> {
Dns.Record.IpAddress(
hostname = call.request.hostname,
hostname = request.hostname,
address = resourceRecord.address,
)
}
Expand Down Expand Up @@ -268,15 +267,15 @@ class DnsCallStateMachine<Q>(
val lastAndNoExceptions = last && allExceptions.isEmpty()
if (allRecords.isNotEmpty() || lastAndNoExceptions) {
previous.callback.onRecords(
call = call,
call = this,
last = lastAndNoExceptions,
records = allRecords,
)
}

if (last && allExceptions.isNotEmpty()) {
previous.callback.onFailure(
call = call,
call = this,
exceptions = allExceptions,
)
}
Expand Down
Loading
Loading