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 @@ -35,6 +35,7 @@ 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.platform.Platform
import okio.Buffer
import okio.BufferedSink
Expand All @@ -55,8 +56,7 @@ internal class DnsOverHttpsCall(
includeServiceMetadata: Boolean,
canceledException: IOException?,
) : Dns.Call,
DnsCallStateMachine.Transport<Call>,
Callback {
DnsCallStateMachine.Transport<Call> {
private val stateMachine =
DnsCallStateMachine(
transport = this,
Expand All @@ -66,8 +66,8 @@ internal class DnsOverHttpsCall(
includeServiceMetadata = includeServiceMetadata,
)

override fun newQuery(dnsMessage: DnsMessage): Call {
val queryParameter = dnsMessage.asQueryParameter()
override fun newQuery(question: Question): Call {
val dnsMessage = DnsMessage.query(question)
return client.newCall(
request =
Request
Expand All @@ -79,51 +79,57 @@ internal class DnsOverHttpsCall(
cacheUrlOverride(
dnsUrl
.newBuilder()
.addQueryParameter("query", queryParameter)
.addQueryParameter("hostname", question.name)
.addQueryParameter("type", question.type.toString())
.build(),
)
post(QueryRequestBody(dnsMessage))
} else {
val requestUrl =
dnsUrl
.newBuilder()
.addQueryParameter("dns", queryParameter)
.addQueryParameter("dns", dnsMessage.asQueryParameter())
.build()
url(requestUrl)
}
}.build(),
)
}

override fun enqueue(query: Call) {
query.enqueue(this)
override fun enqueue(
query: Call,
callback: DnsCallStateMachine.Transport.Callback<Call>,
) {
query.enqueue(
object : Callback {
override fun onFailure(
call: Call,
e: IOException,
) {
callback.onFailure(e)
}

override fun onResponse(
call: Call,
response: Response,
) {
val dnsMessage =
try {
decodeResponse(response)
} catch (e: IOException) {
return callback.onFailure(e)
}

callback.onResponse(dnsMessage)
}
},
)
}

override fun cancel(query: Call) {
query.cancel()
}

override fun onFailure(
call: Call,
e: IOException,
) {
stateMachine.onQueryFailure(call, e)
}

override fun onResponse(
call: Call,
response: Response,
) {
val dnsMessage =
try {
decodeResponse(response)
} catch (e: IOException) {
return stateMachine.onQueryFailure(call, e)
}

stateMachine.onQueryResponse(call, dnsMessage)
}

override fun enqueue(callback: Dns.Callback) {
stateMachine.start(callback)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import kotlin.test.assertFailsWith
import okhttp3.dnsoverhttps.internal.asQueryParameter
import okhttp3.internal.dns.DnsMessage
import okhttp3.internal.dns.DnsMessageReader
import okhttp3.internal.dns.Question
import okhttp3.internal.dns.RESPONSE_CODE_SUCCESS
import okhttp3.internal.dns.ResourceRecord
import okhttp3.internal.dns.TYPE_A
Expand All @@ -44,7 +45,7 @@ class DnsRecordCodecTest {
private fun encodeQuery(
host: String,
type: Int,
): String = DnsMessage.query(host, type).asQueryParameter()
): String = DnsMessage.query(Question(host, type)).asQueryParameter()

@Test
fun testGoogleDotComEncodingWithIPv6() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"INVISIBLE_MEMBER",
"INVISIBLE_REFERENCE",
)
@file:OptIn(ExperimentalTime::class)

package okhttp3.internal.concurrent

Expand All @@ -30,6 +31,9 @@ import java.util.concurrent.BlockingQueue
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.logging.Logger
import kotlin.time.AbstractLongTimeSource
import kotlin.time.DurationUnit
import kotlin.time.ExperimentalTime
import okhttp3.TestUtil.threadFactory

/**
Expand Down Expand Up @@ -82,6 +86,12 @@ class TaskFaker : Closeable {
/** Guarded by `this`. */
private var activeThreads = 0

/** Adapt this API to Kotlin's time API. */
val timeSource =
object : AbstractLongTimeSource(DurationUnit.NANOSECONDS) {
override fun read() = nanoTime
}

/** A task runner that posts tasks to this fake. Tasks won't be executed until requested. */
val taskRunner: TaskRunner =
TaskRunner(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ import okhttp3.internal.OkHttpInternalApi
*
* A few things conspire to make concurrency tricky:
*
* * Each DNS record type is queried in parallel; [onQueryResponse] and [onQueryFailure] may be
* called concurrently.
* * Each DNS record type is queried in parallel; [Transport.Callback.onResponse] and
* [Transport.Callback.onFailure] may be called concurrently.
* * Calls to [okhttp3.Dns.Callback] must be serialized.
* * We don't want to use locks to guard access to [okhttp3.Dns.Callback] functions.
*
Expand Down Expand Up @@ -66,20 +66,20 @@ class DnsCallStateMachine<Q>(
get() = state.get().canceled

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

val queries =
queryMessages.map { dnsMessage ->
transport.newQuery(dnsMessage)
questions.map { question ->
transport.newQuery(question)
}

while (true) {
Expand All @@ -100,7 +100,26 @@ class DnsCallStateMachine<Q>(
if (previous.canceled || canceledException != null) {
transport.cancel(query)
}
transport.enqueue(query)

transport.enqueue(
query = query,
callback =
object : Transport.Callback<Q> {
override fun onResponse(dnsResponse: DnsMessage) {
updateStateAndCallCallbacks(
completedQuery = query,
dnsResponse = dnsResponse,
)
}

override fun onFailure(e: IOException) {
updateStateAndCallCallbacks(
completedQuery = query,
newException = e,
)
}
},
)
}

return
Expand All @@ -122,18 +141,8 @@ class DnsCallStateMachine<Q>(
}
}

fun onQueryFailure(
query: Q,
e: IOException,
) {
updateStateAndCallCallbacks(
completedQuery = query,
newException = e,
)
}

fun onQueryResponse(
query: Q,
private fun updateStateAndCallCallbacks(
completedQuery: Q,
dnsResponse: DnsMessage,
) {
val resourceRecords =
Expand All @@ -145,7 +154,7 @@ class DnsCallStateMachine<Q>(
}
} catch (e: IOException) {
return updateStateAndCallCallbacks(
completedQuery = query,
completedQuery = completedQuery,
newException = e,
)
}
Expand Down Expand Up @@ -180,7 +189,7 @@ class DnsCallStateMachine<Q>(
}

updateStateAndCallCallbacks(
completedQuery = query,
completedQuery = completedQuery,
newRecords = dnsRecords,
)
}
Expand Down Expand Up @@ -322,11 +331,20 @@ class DnsCallStateMachine<Q>(
}

interface Transport<Q> {
fun newQuery(dnsMessage: DnsMessage): Q
fun newQuery(question: Question): Q

fun enqueue(query: Q)
fun enqueue(
query: Q,
callback: Callback<Q>,
)

fun cancel(query: Q)

interface Callback<Q> {
fun onFailure(e: IOException)

fun onResponse(dnsResponse: DnsMessage)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ data class DnsMessage(
get() = (flags and 0b0000_0000_0000_1111)

companion object {
fun query(
hostname: String,
type: Int,
): DnsMessage {
fun query(question: Question): DnsMessage {
// QR = 0 (Query)
// RD = 1 (Recursion Desired)
// OPCODE = 0 (standard query)
Expand All @@ -46,24 +43,20 @@ data class DnsMessage(
return DnsMessage(
id = 0,
flags = flags,
questions =
listOf(
Question(
name = hostname,
type = type,
),
),
questions = listOf(question),
)
}
}
}

@OkHttpInternalApi
data class Question(
val name: String,
val type: Int,
val `class`: Int = CLASS_IN,
)

@OkHttpInternalApi
sealed interface ResourceRecord {
val name: String
val timeToLive: Int
Expand Down
Loading
Loading