1
0
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:
Jake Wharton
2019-05-21 21:51:18 -04:00
committed by Jesse Wilson
parent 42a41f3857
commit f2187bb6e3
9 changed files with 67 additions and 76 deletions

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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()
}
/**

View File

@@ -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 }

View File

@@ -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()

View File

@@ -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) {

View File

@@ -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) {