mirror of
https://github.com/square/okhttp.git
synced 2025-11-29 06:23:09 +03:00
Smattering of Kotlin part 2 (#5087)
* Migrate eventListenerFactory to extension function * Inline platformTrustManager * Migrate delimiterOffset to extension functions Also overhaul these and other string-manipulating functions to have default arguments for start/end indices. * Migrate hostHeader and toHeaders to extension functions
This commit is contained in:
committed by
Jesse Wilson
parent
42a41f3857
commit
f2187bb6e3
@@ -17,7 +17,6 @@ package okhttp3.tls
|
||||
|
||||
import okhttp3.CertificatePinner
|
||||
import okhttp3.internal.platform.Platform
|
||||
import okhttp3.internal.platformTrustManager
|
||||
import okhttp3.tls.internal.TlsUtil.newKeyManager
|
||||
import okhttp3.tls.internal.TlsUtil.newTrustManager
|
||||
import java.security.SecureRandom
|
||||
@@ -126,7 +125,7 @@ class HandshakeCertificates private constructor(
|
||||
* this problem with [certificate pinning][CertificatePinner].
|
||||
*/
|
||||
fun addPlatformTrustedCertificates() = apply {
|
||||
val platformTrustManager = platformTrustManager()
|
||||
val platformTrustManager = Platform.get().platformTrustManager()
|
||||
Collections.addAll(trustedCertificates, *platformTrustManager.acceptedIssuers)
|
||||
}
|
||||
|
||||
|
||||
@@ -79,8 +79,8 @@ class JavaNetCookieJar(private val cookieHandler: CookieHandler) : CookieJar {
|
||||
val limit = header.length
|
||||
var pairEnd: Int
|
||||
while (pos < limit) {
|
||||
pairEnd = delimiterOffset(header, pos, limit, ";,")
|
||||
val equalsSign = delimiterOffset(header, pos, pairEnd, '=')
|
||||
pairEnd = header.delimiterOffset(";,", pos, limit)
|
||||
val equalsSign = header.delimiterOffset('=', pos, pairEnd)
|
||||
val name = header.trimSubstring(pos, equalsSign)
|
||||
if (name.startsWith("$")) {
|
||||
pos = pairEnd + 1
|
||||
|
||||
@@ -336,14 +336,12 @@ data class Cookie private constructor(
|
||||
parse(System.currentTimeMillis(), url, setCookie)
|
||||
|
||||
internal fun parse(currentTimeMillis: Long, url: HttpUrl, setCookie: String): Cookie? {
|
||||
var pos = 0
|
||||
val limit = setCookie.length
|
||||
val cookiePairEnd = delimiterOffset(setCookie, pos, limit, ';')
|
||||
val cookiePairEnd = setCookie.delimiterOffset(';')
|
||||
|
||||
val pairEqualsSign = delimiterOffset(setCookie, pos, cookiePairEnd, '=')
|
||||
val pairEqualsSign = setCookie.delimiterOffset('=', endIndex = cookiePairEnd)
|
||||
if (pairEqualsSign == cookiePairEnd) return null
|
||||
|
||||
val cookieName = setCookie.trimSubstring(pos, pairEqualsSign)
|
||||
val cookieName = setCookie.trimSubstring(endIndex = pairEqualsSign)
|
||||
if (cookieName.isEmpty() || cookieName.indexOfControlOrNonAscii() != -1) return null
|
||||
|
||||
val cookieValue = setCookie.trimSubstring(pairEqualsSign + 1, cookiePairEnd)
|
||||
@@ -358,11 +356,12 @@ data class Cookie private constructor(
|
||||
var hostOnly = true
|
||||
var persistent = false
|
||||
|
||||
pos = cookiePairEnd + 1
|
||||
var pos = cookiePairEnd + 1
|
||||
val limit = setCookie.length
|
||||
while (pos < limit) {
|
||||
val attributePairEnd = delimiterOffset(setCookie, pos, limit, ';')
|
||||
val attributePairEnd = setCookie.delimiterOffset(';', pos, limit)
|
||||
|
||||
val attributeEqualsSign = delimiterOffset(setCookie, pos, attributePairEnd, '=')
|
||||
val attributeEqualsSign = setCookie.delimiterOffset('=', pos, attributePairEnd)
|
||||
val attributeName = setCookie.trimSubstring(pos, attributeEqualsSign)
|
||||
val attributeValue = if (attributeEqualsSign < attributePairEnd) {
|
||||
setCookie.trimSubstring(attributeEqualsSign + 1, attributePairEnd)
|
||||
|
||||
@@ -442,7 +442,7 @@ class HttpUrl internal constructor(
|
||||
get() {
|
||||
if (username.isEmpty()) return ""
|
||||
val usernameStart = scheme.length + 3 // "://".length() == 3.
|
||||
val usernameEnd = delimiterOffset(url, usernameStart, url.length, ":@")
|
||||
val usernameEnd = url.delimiterOffset(":@", usernameStart, url.length)
|
||||
return url.substring(usernameStart, usernameEnd)
|
||||
}
|
||||
|
||||
@@ -492,7 +492,7 @@ class HttpUrl internal constructor(
|
||||
@get:JvmName("encodedPath") val encodedPath: String
|
||||
get() {
|
||||
val pathStart = url.indexOf('/', scheme.length + 3) // "://".length() == 3.
|
||||
val pathEnd = delimiterOffset(url, pathStart, url.length, "?#")
|
||||
val pathEnd = url.delimiterOffset("?#", pathStart, url.length)
|
||||
return url.substring(pathStart, pathEnd)
|
||||
}
|
||||
|
||||
@@ -510,12 +510,12 @@ class HttpUrl internal constructor(
|
||||
@get:JvmName("encodedPathSegments") val encodedPathSegments: List<String>
|
||||
get() {
|
||||
val pathStart = url.indexOf('/', scheme.length + 3)
|
||||
val pathEnd = delimiterOffset(url, pathStart, url.length, "?#")
|
||||
val pathEnd = url.delimiterOffset("?#", pathStart, url.length)
|
||||
val result = ArrayList<String>()
|
||||
var i = pathStart
|
||||
while (i < pathEnd) {
|
||||
i++ // Skip the '/'.
|
||||
val segmentEnd = delimiterOffset(url, i, pathEnd, '/')
|
||||
val segmentEnd = url.delimiterOffset('/', i, pathEnd)
|
||||
result.add(url.substring(i, segmentEnd))
|
||||
i = segmentEnd
|
||||
}
|
||||
@@ -539,7 +539,7 @@ class HttpUrl internal constructor(
|
||||
get() {
|
||||
if (queryNamesAndValues == null) return null // No query.
|
||||
val queryStart = url.indexOf('?') + 1
|
||||
val queryEnd = delimiterOffset(url, queryStart, url.length, '#')
|
||||
val queryEnd = url.delimiterOffset('#', queryStart, url.length)
|
||||
return url.substring(queryStart, queryEnd)
|
||||
}
|
||||
|
||||
@@ -1020,7 +1020,7 @@ class HttpUrl internal constructor(
|
||||
private fun addPathSegments(pathSegments: String, alreadyEncoded: Boolean) = apply {
|
||||
var offset = 0
|
||||
do {
|
||||
val segmentEnd = delimiterOffset(pathSegments, offset, pathSegments.length, "/\\")
|
||||
val segmentEnd = pathSegments.delimiterOffset("/\\", offset, pathSegments.length)
|
||||
val addTrailingSlash = segmentEnd < pathSegments.length
|
||||
push(pathSegments, offset, segmentEnd, addTrailingSlash, alreadyEncoded)
|
||||
offset = segmentEnd + 1
|
||||
@@ -1257,8 +1257,8 @@ class HttpUrl internal constructor(
|
||||
}
|
||||
|
||||
internal fun parse(base: HttpUrl?, input: String): Builder {
|
||||
var pos = input.indexOfFirstNonAsciiWhitespace(0, input.length)
|
||||
val limit = input.indexOfLastNonAsciiWhitespace(pos, input.length)
|
||||
var pos = input.indexOfFirstNonAsciiWhitespace()
|
||||
val limit = input.indexOfLastNonAsciiWhitespace(pos)
|
||||
|
||||
// Scheme.
|
||||
val schemeDelimiterOffset = schemeDelimiterOffset(input, pos, limit)
|
||||
@@ -1298,7 +1298,7 @@ class HttpUrl internal constructor(
|
||||
// [username[:password]@]host[:port]
|
||||
pos += slashCount
|
||||
authority@ while (true) {
|
||||
val componentDelimiterOffset = delimiterOffset(input, pos, limit, "@/\\?#")
|
||||
val componentDelimiterOffset = input.delimiterOffset("@/\\?#", pos, limit)
|
||||
val c = if (componentDelimiterOffset != limit) {
|
||||
input[componentDelimiterOffset].toInt()
|
||||
} else {
|
||||
@@ -1308,7 +1308,7 @@ class HttpUrl internal constructor(
|
||||
'@'.toInt() -> {
|
||||
// User info precedes.
|
||||
if (!hasPassword) {
|
||||
val passwordColonOffset = delimiterOffset(input, pos, componentDelimiterOffset, ':')
|
||||
val passwordColonOffset = input.delimiterOffset(':', pos, componentDelimiterOffset)
|
||||
val canonicalUsername = input.canonicalize(
|
||||
pos = pos,
|
||||
limit = passwordColonOffset,
|
||||
@@ -1377,13 +1377,13 @@ class HttpUrl internal constructor(
|
||||
}
|
||||
|
||||
// Resolve the relative path.
|
||||
val pathDelimiterOffset = delimiterOffset(input, pos, limit, "?#")
|
||||
val pathDelimiterOffset = input.delimiterOffset("?#", pos, limit)
|
||||
resolvePath(input, pos, pathDelimiterOffset)
|
||||
pos = pathDelimiterOffset
|
||||
|
||||
// Query.
|
||||
if (pos < limit && input[pos] == '?') {
|
||||
val queryDelimiterOffset = delimiterOffset(input, pos, limit, '#')
|
||||
val queryDelimiterOffset = input.delimiterOffset('#', pos, limit)
|
||||
this.encodedQueryNamesAndValues = input.canonicalize(
|
||||
pos = pos + 1,
|
||||
limit = queryDelimiterOffset,
|
||||
@@ -1429,7 +1429,7 @@ class HttpUrl internal constructor(
|
||||
// Read path segments.
|
||||
var i = pos
|
||||
while (i < limit) {
|
||||
val pathSegmentDelimiterOffset = delimiterOffset(input, i, limit, "/\\")
|
||||
val pathSegmentDelimiterOffset = input.delimiterOffset("/\\", i, limit)
|
||||
val segmentHasTrailingSlash = pathSegmentDelimiterOffset < limit
|
||||
push(input, i, pathSegmentDelimiterOffset, segmentHasTrailingSlash, true)
|
||||
i = pathSegmentDelimiterOffset
|
||||
|
||||
@@ -17,12 +17,11 @@ package okhttp3
|
||||
|
||||
import okhttp3.Protocol.HTTP_1_1
|
||||
import okhttp3.Protocol.HTTP_2
|
||||
import okhttp3.internal.asFactory
|
||||
import okhttp3.internal.cache.InternalCache
|
||||
import okhttp3.internal.checkDuration
|
||||
import okhttp3.internal.eventListenerFactory
|
||||
import okhttp3.internal.immutableListOf
|
||||
import okhttp3.internal.platform.Platform
|
||||
import okhttp3.internal.platformTrustManager
|
||||
import okhttp3.internal.proxy.NullProxySelector
|
||||
import okhttp3.internal.tls.CertificateChainCleaner
|
||||
import okhttp3.internal.tls.OkHostnameVerifier
|
||||
@@ -164,7 +163,7 @@ open class OkHttpClient internal constructor(
|
||||
this.sslSocketFactory = builder.sslSocketFactory
|
||||
this.certificateChainCleaner = builder.certificateChainCleaner
|
||||
} else {
|
||||
val trustManager = platformTrustManager()
|
||||
val trustManager = Platform.get().platformTrustManager()
|
||||
Platform.get().configureTrustManager(trustManager)
|
||||
this.sslSocketFactory = newSslSocketFactory(trustManager)
|
||||
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager)
|
||||
@@ -280,8 +279,7 @@ open class OkHttpClient internal constructor(
|
||||
internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
|
||||
internal val interceptors: MutableList<Interceptor> = mutableListOf()
|
||||
internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
|
||||
internal var eventListenerFactory: EventListener.Factory = eventListenerFactory(
|
||||
EventListener.NONE)
|
||||
internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
|
||||
internal var proxySelector: ProxySelector = ProxySelector.getDefault() ?: NullProxySelector()
|
||||
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
|
||||
internal var cache: Cache? = null
|
||||
@@ -792,7 +790,7 @@ open class OkHttpClient internal constructor(
|
||||
* @see EventListener for semantics and restrictions on listener implementations.
|
||||
*/
|
||||
fun eventListener(eventListener: EventListener) = apply {
|
||||
this.eventListenerFactory = eventListenerFactory(eventListener)
|
||||
this.eventListenerFactory = eventListener.asFactory()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,7 +23,6 @@ import okhttp3.HttpUrl
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import okhttp3.internal.http2.Header
|
||||
import okhttp3.internal.platform.Platform
|
||||
import okio.BufferedSource
|
||||
import okio.ByteString.Companion.decodeHex
|
||||
import okio.Options
|
||||
@@ -38,7 +37,6 @@ import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import java.util.concurrent.ThreadFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.net.ssl.X509TrustManager
|
||||
import kotlin.text.Charsets.UTF_32BE
|
||||
import kotlin.text.Charsets.UTF_32LE
|
||||
|
||||
@@ -138,14 +136,14 @@ fun nonEmptyIntersection(
|
||||
return false
|
||||
}
|
||||
|
||||
fun hostHeader(url: HttpUrl, includeDefaultPort: Boolean): String {
|
||||
val host = if (":" in url.host) {
|
||||
"[${url.host}]"
|
||||
fun HttpUrl.toHostHeader(includeDefaultPort: Boolean = false): String {
|
||||
val host = if (":" in host) {
|
||||
"[$host]"
|
||||
} else {
|
||||
url.host
|
||||
host
|
||||
}
|
||||
return if (includeDefaultPort || url.port != HttpUrl.defaultPort(url.scheme)) {
|
||||
"$host:${url.port}"
|
||||
return if (includeDefaultPort || port != HttpUrl.defaultPort(scheme)) {
|
||||
"$host:$port"
|
||||
} else {
|
||||
host
|
||||
}
|
||||
@@ -162,58 +160,58 @@ fun concat(array: Array<String>, value: String): Array<String> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments [pos] until [this] is not ASCII whitespace. Stops at [limit].
|
||||
* Increments [startIndex] until [this] is not ASCII whitespace. Stops at [endIndex].
|
||||
*/
|
||||
fun String.indexOfFirstNonAsciiWhitespace(pos: Int, limit: Int): Int {
|
||||
for (i in pos until limit) {
|
||||
fun String.indexOfFirstNonAsciiWhitespace(startIndex: Int = 0, endIndex: Int = length): Int {
|
||||
for (i in startIndex until endIndex) {
|
||||
when (this[i]) {
|
||||
'\t', '\n', '\u000C', '\r', ' ' -> Unit
|
||||
else -> return i
|
||||
}
|
||||
}
|
||||
return limit
|
||||
return endIndex
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements [limit] until `input[limit - 1]` is not ASCII whitespace. Stops at [pos].
|
||||
* Decrements [endIndex] until `input[endIndex - 1]` is not ASCII whitespace. Stops at [startIndex].
|
||||
*/
|
||||
fun String.indexOfLastNonAsciiWhitespace(pos: Int, limit: Int): Int {
|
||||
for (i in limit - 1 downTo pos) {
|
||||
fun String.indexOfLastNonAsciiWhitespace(startIndex: Int = 0, endIndex: Int = length): Int {
|
||||
for (i in endIndex - 1 downTo startIndex) {
|
||||
when (this[i]) {
|
||||
'\t', '\n', '\u000C', '\r', ' ' -> Unit
|
||||
else -> return i + 1
|
||||
}
|
||||
}
|
||||
return pos
|
||||
return startIndex
|
||||
}
|
||||
|
||||
/** Equivalent to `string.substring(pos, limit).trim()`. */
|
||||
fun String.trimSubstring(pos: Int, limit: Int): String {
|
||||
val start = indexOfFirstNonAsciiWhitespace(pos, limit)
|
||||
val end = indexOfLastNonAsciiWhitespace(start, limit)
|
||||
/** Equivalent to `string.substring(startIndex, endIndex).trim()`. */
|
||||
fun String.trimSubstring(startIndex: Int = 0, endIndex: Int = length): String {
|
||||
val start = indexOfFirstNonAsciiWhitespace(startIndex, endIndex)
|
||||
val end = indexOfLastNonAsciiWhitespace(start, endIndex)
|
||||
return substring(start, end)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first character in [input] that contains a character in [delimiters].
|
||||
* Returns limit if there is no such character.
|
||||
* Returns the index of the first character in [this] that contains a character in [delimiters].
|
||||
* Returns endIndex if there is no such character.
|
||||
*/
|
||||
fun delimiterOffset(input: String, pos: Int, limit: Int, delimiters: String): Int {
|
||||
for (i in pos until limit) {
|
||||
if (input[i] in delimiters) return i
|
||||
fun String.delimiterOffset(delimiters: String, startIndex: Int = 0, endIndex: Int = length): Int {
|
||||
for (i in startIndex until endIndex) {
|
||||
if (this[i] in delimiters) return i
|
||||
}
|
||||
return limit
|
||||
return endIndex
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first character in [input] that is [delimiter]. Returns
|
||||
* limit if there is no such character.
|
||||
* Returns the index of the first character in [this] that is [delimiter]. Returns
|
||||
* endIndex if there is no such character.
|
||||
*/
|
||||
fun delimiterOffset(input: String, pos: Int, limit: Int, delimiter: Char): Int {
|
||||
for (i in pos until limit) {
|
||||
if (input[i] == delimiter) return i
|
||||
fun String.delimiterOffset(delimiter: Char, startIndex: Int = 0, endIndex: Int = length): Int {
|
||||
for (i in startIndex until endIndex) {
|
||||
if (this[i] == delimiter) return i
|
||||
}
|
||||
return limit
|
||||
return endIndex
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,11 +268,9 @@ fun decodeHexDigit(c: Char): Int = when (c) {
|
||||
else -> -1
|
||||
}
|
||||
|
||||
fun platformTrustManager(): X509TrustManager = Platform.get().platformTrustManager()
|
||||
|
||||
fun toHeaders(headerBlock: List<Header>): Headers {
|
||||
fun List<Header>.toHeaders(): Headers {
|
||||
val builder = Headers.Builder()
|
||||
for ((name, value) in headerBlock) {
|
||||
for ((name, value) in this) {
|
||||
addHeaderLenient(builder, name.utf8(), value.utf8())
|
||||
}
|
||||
return builder.build()
|
||||
@@ -289,5 +285,4 @@ fun HttpUrl.canReuseConnectionFor(other: HttpUrl): Boolean = host == other.host
|
||||
port == other.port &&
|
||||
scheme == other.scheme
|
||||
|
||||
fun eventListenerFactory(listener: EventListener): EventListener.Factory =
|
||||
EventListener.Factory { listener }
|
||||
fun EventListener.asFactory() = EventListener.Factory { this }
|
||||
|
||||
@@ -33,7 +33,7 @@ import okhttp3.Response
|
||||
import okhttp3.Route
|
||||
import okhttp3.internal.EMPTY_RESPONSE
|
||||
import okhttp3.internal.closeQuietly
|
||||
import okhttp3.internal.hostHeader
|
||||
import okhttp3.internal.toHostHeader
|
||||
import okhttp3.internal.http.ExchangeCodec
|
||||
import okhttp3.internal.http1.Http1ExchangeCodec
|
||||
import okhttp3.internal.http2.ConnectionShutdownException
|
||||
@@ -409,7 +409,7 @@ class RealConnection(
|
||||
): Request? {
|
||||
var nextRequest = tunnelRequest
|
||||
// Make an SSL Tunnel on the first message pair of each SSL + proxy connection.
|
||||
val requestLine = """CONNECT ${hostHeader(url, true)} HTTP/1.1"""
|
||||
val requestLine = "CONNECT ${url.toHostHeader(includeDefaultPort = true)} HTTP/1.1"
|
||||
while (true) {
|
||||
val source = this.source!!
|
||||
val sink = this.sink!!
|
||||
@@ -463,7 +463,7 @@ class RealConnection(
|
||||
val proxyConnectRequest = Request.Builder()
|
||||
.url(route.address().url)
|
||||
.method("CONNECT", null)
|
||||
.header("Host", hostHeader(route.address().url, true))
|
||||
.header("Host", route.address().url.toHostHeader(includeDefaultPort = true))
|
||||
.header("Proxy-Connection", "Keep-Alive") // For HTTP/1.0 proxies like Squid.
|
||||
.header("User-Agent", userAgent)
|
||||
.build()
|
||||
|
||||
@@ -24,7 +24,7 @@ import okhttp3.Response
|
||||
import okhttp3.internal.userAgent
|
||||
import okio.GzipSource
|
||||
|
||||
import okhttp3.internal.hostHeader
|
||||
import okhttp3.internal.toHostHeader
|
||||
import okio.buffer
|
||||
|
||||
/**
|
||||
@@ -57,7 +57,7 @@ class BridgeInterceptor(private val cookieJar: CookieJar) : Interceptor {
|
||||
}
|
||||
|
||||
if (userRequest.header("Host") == null) {
|
||||
requestBuilder.header("Host", hostHeader(userRequest.url(), false))
|
||||
requestBuilder.header("Host", userRequest.url().toHostHeader())
|
||||
}
|
||||
|
||||
if (userRequest.header("Connection") == null) {
|
||||
|
||||
@@ -621,7 +621,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable {
|
||||
if (streamId % 2 == nextStreamId % 2) return
|
||||
|
||||
// Create a stream.
|
||||
val headers = toHeaders(headerBlock)
|
||||
val headers = headerBlock.toHeaders()
|
||||
val newStream = Http2Stream(streamId, this@Http2Connection, false, inFinished, headers)
|
||||
lastGoodStreamId = streamId
|
||||
streams[streamId] = newStream
|
||||
@@ -640,7 +640,7 @@ class Http2Connection internal constructor(builder: Builder) : Closeable {
|
||||
}
|
||||
|
||||
// Update an existing stream.
|
||||
stream!!.receiveHeaders(toHeaders(headerBlock), inFinished)
|
||||
stream!!.receiveHeaders(headerBlock.toHeaders(), inFinished)
|
||||
}
|
||||
|
||||
override fun rstStream(streamId: Int, errorCode: ErrorCode) {
|
||||
|
||||
Reference in New Issue
Block a user