Skip to content
Open
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 @@ -348,6 +348,8 @@ class RealRoutePlanner internal constructor(

override fun sameHostAndPort(url: HttpUrl): Boolean {
val routeUrl = address.url
return url.port == routeUrl.port && url.host == routeUrl.host
return url.port == routeUrl.port &&
url.host == routeUrl.host &&
url.scheme == routeUrl.scheme
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ interface RoutePlanner {
fun hasNext(failedConnection: RealConnection? = null): Boolean

/**
* Returns true if the host and port are unchanged from when this was created. This is used to
* detect if followups need to do a full connection-finding process including DNS resolution, and
* certificate pin checks.
* Returns true if the host, port, and scheme are unchanged from when this was created. This is
* used to detect if followups need to do a full connection-finding process including DNS
* resolution, and certificate pin checks.
*/
fun sameHostAndPort(url: HttpUrl): Boolean

Expand Down
49 changes: 49 additions & 0 deletions okhttp/src/jvmTest/kotlin/okhttp3/CallTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import okhttp3.CallEvent.ResponseFailed
import okhttp3.CallEvent.ResponseHeadersEnd
import okhttp3.CallEvent.ResponseHeadersStart
import okhttp3.CallEvent.RetryDecision
import okhttp3.CallEvent.SecureConnectStart
import okhttp3.CertificatePinner.Companion.pin
import okhttp3.Credentials.basic
import okhttp3.Headers.Companion.headersOf
Expand Down Expand Up @@ -2208,6 +2209,54 @@ open class CallTest {
assertThat(server.takeRequest().exchangeIndex).isEqualTo(2)
}

@Test
fun redirectFromHttpToHttpsOnSameHostAndPortDoesNotReusePlaintextConnection() {
val httpsUrl =
server
.url("/second")
.newBuilder()
.scheme("https")
.build()
server.enqueue(
MockResponse(
code = 301,
headers = headersOf("Location", httpsUrl.toString()),
),
)
server.enqueue(MockResponse(body = "second-response"))

assertFailsWith<IOException> {
client.newCall(Request(url = server.url("/first"))).execute()
}

assertThat(server.takeRequest().requestLine).startsWith("GET /first HTTP/")
assertThat(eventRecorder.recordedEventTypes()).contains(SecureConnectStart::class)
}

@Test
fun redirectFromHttpsToHttpOnSameHostAndPortDoesNotReuseTlsConnection() {
enableTls()
val httpUrl =
server
.url("/second")
.newBuilder()
.scheme("http")
.build()
server.enqueue(
MockResponse(
code = 301,
headers = headersOf("Location", httpUrl.toString()),
),
)
server.enqueue(MockResponse(body = "second-response"))

assertFailsWith<IOException> {
client.newCall(Request(url = server.url("/first"))).execute()
}

assertThat(server.takeRequest().requestLine).startsWith("GET /first HTTP/")
}

@Test
fun postRedirectsToGet() {
server.enqueue(
Expand Down
3 changes: 2 additions & 1 deletion okhttp/src/jvmTest/kotlin/okhttp3/FakeRoutePlanner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ class FakeRoutePlanner(
override fun hasNext(failedConnection: RealConnection?): Boolean =
deferredPlans.isNotEmpty() || nextPlanIndex < plans.size || autoGeneratePlans

override fun sameHostAndPort(url: HttpUrl): Boolean = url.host == address.url.host && url.port == address.url.port
override fun sameHostAndPort(url: HttpUrl): Boolean =
url.host == address.url.host && url.port == address.url.port && url.scheme == address.url.scheme

override fun close() {
factory.close()
Expand Down
Loading