1
0
mirror of https://github.com/square/okhttp.git synced 2025-07-29 17:41:17 +03:00

Decompose the request line into individual properties (#8860)

* Decompose the request line into individual properties

Replace the 'path' property with the URL's encodedPath
property.

Rename the 'requestUrl' property to 'url'.

* Spotless

* Fix up DnsOverHttpsTest

* Fix some test failures
This commit is contained in:
Jesse Wilson
2025-06-16 20:47:36 -04:00
committed by GitHub
parent 33b093a86c
commit dfd1dffb3c
14 changed files with 230 additions and 111 deletions

View File

@ -102,9 +102,9 @@ internal fun mockwebserver3.RecordedRequest.unwrap(): RecordedRequest =
sequenceNumber = sequenceNumber, sequenceNumber = sequenceNumber,
failure = failure, failure = failure,
method = method, method = method,
path = path, path = url.encodedPath,
handshake = handshake, handshake = handshake,
requestUrl = requestUrl, requestUrl = url,
) )
private fun MockResponse.wrapSocketPolicy(): mockwebserver3.SocketPolicy = private fun MockResponse.wrapSocketPolicy(): mockwebserver3.SocketPolicy =

View File

@ -145,8 +145,8 @@ public class mockwebserver3/QueueDispatcher : mockwebserver3/Dispatcher {
} }
public final class mockwebserver3/RecordedRequest { public final class mockwebserver3/RecordedRequest {
public fun <init> (ILokhttp3/Handshake;Ljava/util/List;Lokhttp3/HttpUrl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lokhttp3/Headers;Lokio/ByteString;JLjava/util/List;Ljava/io/IOException;)V public fun <init> (ILokhttp3/Handshake;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lokhttp3/HttpUrl;Lokhttp3/Headers;Lokio/ByteString;JLjava/util/List;Ljava/io/IOException;)V
public synthetic fun <init> (ILokhttp3/Handshake;Ljava/util/List;Lokhttp3/HttpUrl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lokhttp3/Headers;Lokio/ByteString;JLjava/util/List;Ljava/io/IOException;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public synthetic fun <init> (ILokhttp3/Handshake;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lokhttp3/HttpUrl;Lokhttp3/Headers;Lokio/ByteString;JLjava/util/List;Ljava/io/IOException;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getBody ()Lokio/ByteString; public final fun getBody ()Lokio/ByteString;
public final fun getBodySize ()J public final fun getBodySize ()J
public final fun getChunkSizes ()Ljava/util/List; public final fun getChunkSizes ()Ljava/util/List;
@ -155,10 +155,11 @@ public final class mockwebserver3/RecordedRequest {
public final fun getHandshakeServerNames ()Ljava/util/List; public final fun getHandshakeServerNames ()Ljava/util/List;
public final fun getHeaders ()Lokhttp3/Headers; public final fun getHeaders ()Lokhttp3/Headers;
public final fun getMethod ()Ljava/lang/String; public final fun getMethod ()Ljava/lang/String;
public final fun getPath ()Ljava/lang/String;
public final fun getRequestLine ()Ljava/lang/String; public final fun getRequestLine ()Ljava/lang/String;
public final fun getRequestUrl ()Lokhttp3/HttpUrl;
public final fun getSequenceNumber ()I public final fun getSequenceNumber ()I
public final fun getTarget ()Ljava/lang/String;
public final fun getUrl ()Lokhttp3/HttpUrl;
public final fun getVersion ()Ljava/lang/String;
public fun toString ()Ljava/lang/String; public fun toString ()Ljava/lang/String;
} }

View File

@ -63,9 +63,12 @@ import mockwebserver3.SocketPolicy.ShutdownInputAtEnd
import mockwebserver3.SocketPolicy.ShutdownOutputAtEnd import mockwebserver3.SocketPolicy.ShutdownOutputAtEnd
import mockwebserver3.SocketPolicy.ShutdownServerAfterResponse import mockwebserver3.SocketPolicy.ShutdownServerAfterResponse
import mockwebserver3.SocketPolicy.StallSocketAtStart import mockwebserver3.SocketPolicy.StallSocketAtStart
import mockwebserver3.internal.DEFAULT_REQUEST_LINE
import mockwebserver3.internal.RecordedRequest import mockwebserver3.internal.RecordedRequest
import mockwebserver3.internal.RequestLine
import mockwebserver3.internal.ThrottledSink import mockwebserver3.internal.ThrottledSink
import mockwebserver3.internal.TriggerSink import mockwebserver3.internal.TriggerSink
import mockwebserver3.internal.decodeRequestLine
import mockwebserver3.internal.sleepWhileOpen import mockwebserver3.internal.sleepWhileOpen
import okhttp3.Headers import okhttp3.Headers
import okhttp3.Headers.Companion.headersOf import okhttp3.Headers.Companion.headersOf
@ -656,7 +659,7 @@ public class MockWebServer : Closeable {
) { ) {
val request = val request =
RecordedRequest( RecordedRequest(
"", DEFAULT_REQUEST_LINE,
headersOf(), headersOf(),
emptyList(), emptyList(),
0L, 0L,
@ -677,7 +680,7 @@ public class MockWebServer : Closeable {
sink: BufferedSink, sink: BufferedSink,
sequenceNumber: Int, sequenceNumber: Int,
): RecordedRequest { ): RecordedRequest {
var request = "" var request: RequestLine = DEFAULT_REQUEST_LINE
val headers = Headers.Builder() val headers = Headers.Builder()
var contentLength = -1L var contentLength = -1L
var chunked = false var chunked = false
@ -686,10 +689,11 @@ public class MockWebServer : Closeable {
var failure: IOException? = null var failure: IOException? = null
try { try {
request = source.readUtf8LineStrict() val requestLineString = source.readUtf8LineStrict()
if (request.isEmpty()) { if (requestLineString.isEmpty()) {
throw ProtocolException("no request because the stream is exhausted") throw ProtocolException("no request because the stream is exhausted")
} }
request = decodeRequestLine(requestLineString)
while (true) { while (true) {
val header = source.readUtf8LineStrict() val header = source.readUtf8LineStrict()
@ -752,8 +756,7 @@ public class MockWebServer : Closeable {
} }
} }
val method = request.substringBefore(' ') require(!hasBody || HttpMethod.permitsRequestBody(request.method)) {
require(!hasBody || HttpMethod.permitsRequestBody(method)) {
"Request must not have a body: $request" "Request must not have a body: $request"
} }
} catch (e: IOException) { } catch (e: IOException) {
@ -828,7 +831,7 @@ public class MockWebServer : Closeable {
minimumDeflateSize = 0L, minimumDeflateSize = 0L,
webSocketCloseTimeout = RealWebSocket.CANCEL_AFTER_CLOSE_MILLIS, webSocketCloseTimeout = RealWebSocket.CANCEL_AFTER_CLOSE_MILLIS,
) )
val name = "MockWebServer WebSocket ${request.path!!}" val name = "MockWebServer WebSocket ${request.url.encodedPath}"
webSocket.initReaderAndWriter(name, streams) webSocket.initReaderAndWriter(name, streams)
try { try {
webSocket.loopReader(fancyResponse) webSocket.loopReader(fancyResponse)
@ -1051,7 +1054,12 @@ public class MockWebServer : Closeable {
} }
val body = Buffer() val body = Buffer()
val requestLine = "$method $path HTTP/1.1" val requestLine =
RequestLine(
method = method,
target = path,
version = "HTTP/1.1",
)
var exception: IOException? = null var exception: IOException? = null
if (readBody && peek.socketHandler == null && peek.socketPolicy !is DoNotReadRequestBody) { if (readBody && peek.socketHandler == null && peek.socketPolicy !is DoNotReadRequestBody) {
try { try {
@ -1170,7 +1178,12 @@ public class MockWebServer : Closeable {
for ((name, value) in pushPromiseHeaders) { for ((name, value) in pushPromiseHeaders) {
pushedHeaders.add(Header(name, value)) pushedHeaders.add(Header(name, value))
} }
val requestLine = "${pushPromise.method} ${pushPromise.path} HTTP/1.1" val requestLine =
RequestLine(
method = pushPromise.method,
target = pushPromise.path,
version = "HTTP/1.1",
)
val chunkSizes = emptyList<Int>() // No chunked encoding for HTTP/2. val chunkSizes = emptyList<Int>() // No chunked encoding for HTTP/2.
requestQueue.add( requestQueue.add(
RecordedRequest( RecordedRequest(

View File

@ -42,10 +42,24 @@ public class RecordedRequest(
* cleartext and may be monitored or blocked by a proxy or other middlebox. * cleartext and may be monitored or blocked by a proxy or other middlebox.
*/ */
public val handshakeServerNames: List<String>, public val handshakeServerNames: List<String>,
public val requestUrl: HttpUrl?, public val method: String,
public val requestLine: String, /**
public val method: String?, * The request target from the original HTTP request.
public val path: String?, *
* For origin-form requests this is a path like `/index.html`, that is combined with the `Host`
* header to create the request URL.
*
* For HTTP proxy requests this will be either an absolute-form string like
* `http://example.com/index.html` (HTTP proxy) or an authority-form string like
* `example.com:443` (HTTPS proxy).
*
* For OPTIONS requests, this may be an asterisk, `*`.
*/
public val target: String,
/** A string like `HTTP/1.1`. */
public val version: String,
/** The request URL built using the request line, headers, and local host name. */
public val url: HttpUrl,
/** All headers. */ /** All headers. */
public val headers: Headers, public val headers: Headers,
/** The body of this request, or [ByteString.EMPTY] if it has none. This may be truncated. */ /** The body of this request, or [ByteString.EMPTY] if it has none. This may be truncated. */
@ -63,5 +77,8 @@ public class RecordedRequest(
*/ */
public val failure: IOException? = null, public val failure: IOException? = null,
) { ) {
public val requestLine: String
get() = "$method $target $version"
public override fun toString(): String = requestLine public override fun toString(): String = requestLine
} }

View File

@ -17,6 +17,7 @@ package mockwebserver3.internal
import java.io.IOException import java.io.IOException
import java.net.Inet6Address import java.net.Inet6Address
import java.net.ProtocolException
import java.net.Socket import java.net.Socket
import javax.net.ssl.SSLSocket import javax.net.ssl.SSLSocket
import mockwebserver3.RecordedRequest import mockwebserver3.RecordedRequest
@ -24,12 +25,13 @@ import okhttp3.Handshake
import okhttp3.Handshake.Companion.handshake import okhttp3.Handshake.Companion.handshake
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.internal.platform.Platform import okhttp3.internal.platform.Platform
import okio.Buffer import okio.Buffer
internal fun RecordedRequest( internal fun RecordedRequest(
requestLine: String, requestLine: RequestLine,
headers: Headers, headers: Headers,
chunkSizes: List<Int>, chunkSizes: List<Int>,
bodySize: Long, bodySize: Long,
@ -52,45 +54,22 @@ internal fun RecordedRequest(
handshakeServerNames = listOf() handshakeServerNames = listOf()
} }
val requestUrl: HttpUrl? val requestUrl =
val method: String? when (requestLine.method) {
val path: String? "CONNECT" -> "${socket.scheme}://${requestLine.target}/".toHttpUrlOrNull()
if (requestLine.isNotEmpty()) { else -> null
val methodEnd = requestLine.indexOf(' ')
val urlEnd = requestLine.indexOf(' ', methodEnd + 1)
method = requestLine.substring(0, methodEnd)
var urlPart = requestLine.substring(methodEnd + 1, urlEnd)
if (!urlPart.startsWith("/")) {
urlPart = "/"
} }
path = urlPart ?: requestLine.target.toHttpUrlOrNull()
?: requestUrl(socket, requestLine, headers)
val scheme = if (socket is SSLSocket) "https" else "http"
val localPort = socket.localPort
val hostAndPort =
headers[":authority"]
?: headers["Host"]
?: when (val inetAddress = socket.localAddress) {
is Inet6Address -> "[${inetAddress.hostAddress}]:$localPort"
else -> "${inetAddress.hostAddress}:$localPort"
}
// Allow null in failure case to allow for testing bad requests
requestUrl = "$scheme://$hostAndPort$path".toHttpUrlOrNull()
} else {
requestUrl = null
method = null
path = null
}
return RecordedRequest( return RecordedRequest(
sequenceNumber = sequenceNumber, sequenceNumber = sequenceNumber,
handshake = handshake, handshake = handshake,
handshakeServerNames = handshakeServerNames, handshakeServerNames = handshakeServerNames,
requestUrl = requestUrl, method = requestLine.method,
requestLine = requestLine, target = requestLine.target,
method = method, version = requestLine.version,
path = path, url = requestUrl,
headers = headers, headers = headers,
body = body.readByteString(), body = body.readByteString(),
bodySize = bodySize, bodySize = bodySize,
@ -98,3 +77,66 @@ internal fun RecordedRequest(
failure = failure, failure = failure,
) )
} }
internal fun decodeRequestLine(requestLine: String?): RequestLine {
val parts =
when {
requestLine != null -> requestLine.split(' ', limit = 3)
else -> return DEFAULT_REQUEST_LINE
}
if (parts.size != 3) {
throw ProtocolException("unexpected request line: $requestLine")
}
return RequestLine(
method = parts[0],
target = parts[1],
version = parts[2],
)
}
internal class RequestLine(
val method: String,
val target: String,
val version: String,
) {
override fun toString() = "$method $target $version"
}
internal val DEFAULT_REQUEST_LINE =
RequestLine(
method = "GET",
target = "/",
version = "HTTP/1.1",
)
private val Socket.scheme: String
get() =
when (this) {
is SSLSocket -> "https"
else -> "http"
}
private fun requestUrl(
socket: Socket,
requestLine: RequestLine,
headers: Headers,
): HttpUrl {
val hostAndPort =
headers[":authority"]
?: headers["Host"]
?: when (val inetAddress = socket.localAddress) {
is Inet6Address -> "[${inetAddress.hostAddress}]:${socket.localPort}"
else -> "${inetAddress.hostAddress}:${socket.localPort}"
}
// For OPTIONS, the request target may be a '*', like 'OPTIONS * HTTP/1.1'.
val path =
when {
requestLine.method == "OPTIONS" && requestLine.target == "*" -> "/"
else -> requestLine.target
}
return "${socket.scheme}://$hostAndPort$path".toHttpUrl()
}

View File

@ -63,7 +63,7 @@ class CustomDispatcherTest {
val dispatcher: Dispatcher = val dispatcher: Dispatcher =
object : Dispatcher() { object : Dispatcher() {
override fun dispatch(request: RecordedRequest): MockResponse { override fun dispatch(request: RecordedRequest): MockResponse {
if (request.path == firstRequest) { if (request.url.encodedPath == firstRequest) {
latch.await() latch.await()
} }
return MockResponse() return MockResponse()

View File

@ -135,7 +135,7 @@ class MockResponseSniTest {
assertThat(response.isSuccessful).isTrue() assertThat(response.isSuccessful).isTrue()
val recordedRequest = server.takeRequest() val recordedRequest = server.takeRequest()
assertThat(recordedRequest.requestUrl!!.host).isEqualTo("header-host") assertThat(recordedRequest.url.host).isEqualTo("header-host")
// https://github.com/bcgit/bc-java/issues/1773 // https://github.com/bcgit/bc-java/issues/1773
if (!platform.isBouncyCastle()) { if (!platform.isBouncyCastle()) {
@ -147,7 +147,7 @@ class MockResponseSniTest {
@Test @Test
fun ipv6() { fun ipv6() {
val recordedRequest = requestToHostnameViaProxy("2607:f8b0:400b:804::200e") val recordedRequest = requestToHostnameViaProxy("2607:f8b0:400b:804::200e")
assertThat(recordedRequest.requestUrl!!.host).isEqualTo("2607:f8b0:400b:804::200e") assertThat(recordedRequest.url.host).isEqualTo("2607:f8b0:400b:804::200e")
assertThat(recordedRequest.handshakeServerNames).isEmpty() assertThat(recordedRequest.handshakeServerNames).isEmpty()
} }
@ -155,14 +155,14 @@ class MockResponseSniTest {
@Test @Test
fun ipv4() { fun ipv4() {
val recordedRequest = requestToHostnameViaProxy("76.223.91.57") val recordedRequest = requestToHostnameViaProxy("76.223.91.57")
assertThat(recordedRequest.requestUrl!!.host).isEqualTo("76.223.91.57") assertThat(recordedRequest.url.host).isEqualTo("76.223.91.57")
assertThat(recordedRequest.handshakeServerNames).isEmpty() assertThat(recordedRequest.handshakeServerNames).isEmpty()
} }
@Test @Test
fun regularHostname() { fun regularHostname() {
val recordedRequest = requestToHostnameViaProxy("cash.app") val recordedRequest = requestToHostnameViaProxy("cash.app")
assertThat(recordedRequest.requestUrl!!.host).isEqualTo("cash.app") assertThat(recordedRequest.url.host).isEqualTo("cash.app")
// https://github.com/bcgit/bc-java/issues/1773 // https://github.com/bcgit/bc-java/issues/1773
if (!platform.isBouncyCastle()) { if (!platform.isBouncyCastle()) {
assertThat(recordedRequest.handshakeServerNames).containsExactly("cash.app") assertThat(recordedRequest.handshakeServerNames).containsExactly("cash.app")

View File

@ -543,8 +543,8 @@ class MockWebServerTest {
assertThat(request.requestLine).isEqualTo( assertThat(request.requestLine).isEqualTo(
"GET /a/deep/path?key=foo%20bar HTTP/1.1", "GET /a/deep/path?key=foo%20bar HTTP/1.1",
) )
val requestUrl = request.requestUrl val requestUrl = request.url
assertThat(requestUrl!!.scheme).isEqualTo("http") assertThat(requestUrl.scheme).isEqualTo("http")
assertThat(requestUrl.host).isEqualTo(server.hostName) assertThat(requestUrl.host).isEqualTo(server.hostName)
assertThat(requestUrl.port).isEqualTo(server.port) assertThat(requestUrl.port).isEqualTo(server.port)
assertThat(requestUrl.encodedPath).isEqualTo("/a/deep/path") assertThat(requestUrl.encodedPath).isEqualTo("/a/deep/path")
@ -663,7 +663,7 @@ class MockWebServerTest {
val reader = BufferedReader(InputStreamReader(connection.inputStream, UTF_8)) val reader = BufferedReader(InputStreamReader(connection.inputStream, UTF_8))
assertThat(reader.readLine()).isEqualTo("abc") assertThat(reader.readLine()).isEqualTo("abc")
val request = server.takeRequest() val request = server.takeRequest()
assertThat(request.requestUrl!!.scheme).isEqualTo("https") assertThat(request.url.scheme).isEqualTo("https")
val handshake = request.handshake val handshake = request.handshake
assertThat(handshake!!.tlsVersion).isNotNull() assertThat(handshake!!.tlsVersion).isNotNull()
assertThat(handshake.cipherSuite).isNotNull() assertThat(handshake.cipherSuite).isNotNull()
@ -727,7 +727,7 @@ class MockWebServerTest {
val reader = BufferedReader(InputStreamReader(connection.inputStream, UTF_8)) val reader = BufferedReader(InputStreamReader(connection.inputStream, UTF_8))
assertThat(reader.readLine()).isEqualTo("abc") assertThat(reader.readLine()).isEqualTo("abc")
val request = server.takeRequest() val request = server.takeRequest()
assertThat(request.requestUrl!!.scheme).isEqualTo("https") assertThat(request.url.scheme).isEqualTo("https")
val handshake = request.handshake val handshake = request.handshake
assertThat(handshake!!.tlsVersion).isNotNull() assertThat(handshake!!.tlsVersion).isNotNull()
assertThat(handshake.cipherSuite).isNotNull() assertThat(handshake.cipherSuite).isNotNull()
@ -756,7 +756,7 @@ class MockWebServerTest {
assertThat(response.body.string()).isEqualTo("Result") assertThat(response.body.string()).isEqualTo("Result")
} }
val recordedRequest = server.takeRequest() val recordedRequest = server.takeRequest()
assertThat(recordedRequest.requestUrl).isEqualTo("http://android.com/".toHttpUrl()) assertThat(recordedRequest.url).isEqualTo("http://android.com/".toHttpUrl())
} }
@Test @Test

View File

@ -20,7 +20,9 @@ import assertk.assertThat
import assertk.assertions.isEqualTo import assertk.assertions.isEqualTo
import java.net.InetAddress import java.net.InetAddress
import java.net.Socket import java.net.Socket
import mockwebserver3.internal.DEFAULT_REQUEST_LINE
import mockwebserver3.internal.RecordedRequest import mockwebserver3.internal.RecordedRequest
import mockwebserver3.internal.decodeRequestLine
import okhttp3.Headers import okhttp3.Headers
import okhttp3.Headers.Companion.headersOf import okhttp3.Headers.Companion.headersOf
import okio.Buffer import okio.Buffer
@ -37,8 +39,53 @@ class RecordedRequestTest {
localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)), localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)),
localPort = 80, localPort = 80,
) )
val request = RecordedRequest("GET / HTTP/1.1", headers, emptyList(), 0, Buffer(), 0, socket) val request = RecordedRequest(DEFAULT_REQUEST_LINE, headers, emptyList(), 0, Buffer(), 0, socket)
assertThat(request.requestUrl.toString()).isEqualTo("http://127.0.0.1/") assertThat(request.url.toString()).isEqualTo("http://127.0.0.1/")
}
@Test fun testAuthorityForm() {
val socket =
FakeSocket(
localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)),
localPort = 80,
)
val requestLine = decodeRequestLine("CONNECT example.com:8080 HTTP/1.1")
val request = RecordedRequest(requestLine, headers, emptyList(), 0, Buffer(), 0, socket)
assertThat(request.target).isEqualTo("example.com:8080")
assertThat(request.url.toString()).isEqualTo("http://example.com:8080/")
}
@Test fun testAbsoluteForm() {
val socket =
FakeSocket(
localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)),
localPort = 80,
)
val requestLine = decodeRequestLine("GET http://example.com:8080/index.html HTTP/1.1")
val request = RecordedRequest(requestLine, headers, emptyList(), 0, Buffer(), 0, socket)
assertThat(request.target).isEqualTo("http://example.com:8080/index.html")
assertThat(request.url.toString()).isEqualTo("http://example.com:8080/index.html")
}
@Test fun testAsteriskForm() {
val socket =
FakeSocket(
localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)),
localPort = 80,
)
val requestLine = decodeRequestLine("OPTIONS * HTTP/1.1")
val request =
RecordedRequest(
requestLine,
headers,
emptyList(),
0,
Buffer(),
0,
socket,
)
assertThat(request.target).isEqualTo("*")
assertThat(request.url.toString()).isEqualTo("http://127.0.0.1/")
} }
@Test fun testIpv6() { @Test fun testIpv6() {
@ -51,8 +98,8 @@ class RecordedRequestTest {
), ),
localPort = 80, localPort = 80,
) )
val request = RecordedRequest("GET / HTTP/1.1", headers, emptyList(), 0, Buffer(), 0, socket) val request = RecordedRequest(DEFAULT_REQUEST_LINE, headers, emptyList(), 0, Buffer(), 0, socket)
assertThat(request.requestUrl.toString()).isEqualTo("http://[::1]/") assertThat(request.url.toString()).isEqualTo("http://[::1]/")
} }
@Test fun testUsesLocal() { @Test fun testUsesLocal() {
@ -61,8 +108,8 @@ class RecordedRequestTest {
localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)), localAddress = InetAddress.getByAddress("127.0.0.1", byteArrayOf(127, 0, 0, 1)),
localPort = 80, localPort = 80,
) )
val request = RecordedRequest("GET / HTTP/1.1", headers, emptyList(), 0, Buffer(), 0, socket) val request = RecordedRequest(DEFAULT_REQUEST_LINE, headers, emptyList(), 0, Buffer(), 0, socket)
assertThat(request.requestUrl.toString()).isEqualTo("http://127.0.0.1/") assertThat(request.url.toString()).isEqualTo("http://127.0.0.1/")
} }
@Test fun testHostname() { @Test fun testHostname() {
@ -76,8 +123,8 @@ class RecordedRequestTest {
), ),
localPort = 80, localPort = 80,
) )
val request = RecordedRequest("GET / HTTP/1.1", headers, emptyList(), 0, Buffer(), 0, socket) val request = RecordedRequest(DEFAULT_REQUEST_LINE, headers, emptyList(), 0, Buffer(), 0, socket)
assertThat(request.requestUrl.toString()).isEqualTo("http://host-from-header.com/") assertThat(request.url.toString()).isEqualTo("http://host-from-header.com/")
} }
private class FakeSocket( private class FakeSocket(

View File

@ -85,8 +85,8 @@ class DnsOverHttpsTest {
assertThat(result).isEqualTo(listOf(address("157.240.1.18"))) assertThat(result).isEqualTo(listOf(address("157.240.1.18")))
val recordedRequest = server.takeRequest() val recordedRequest = server.takeRequest()
assertThat(recordedRequest.method).isEqualTo("GET") assertThat(recordedRequest.method).isEqualTo("GET")
assertThat(recordedRequest.path) assertThat(recordedRequest.url.encodedQuery)
.isEqualTo("/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ") .isEqualTo("ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ")
} }
@Test @Test
@ -114,10 +114,10 @@ class DnsOverHttpsTest {
assertThat(request1.method).isEqualTo("GET") assertThat(request1.method).isEqualTo("GET")
val request2 = server.takeRequest() val request2 = server.takeRequest()
assertThat(request2.method).isEqualTo("GET") assertThat(request2.method).isEqualTo("GET")
assertThat(listOf(request1.path, request2.path)) assertThat(listOf(request1.url.encodedQuery, request2.url.encodedQuery))
.containsExactlyInAnyOrder( .containsExactlyInAnyOrder(
"/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ", "ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ",
"/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AABwAAQ", "ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AABwAAQ",
) )
} }
@ -138,8 +138,8 @@ class DnsOverHttpsTest {
} }
val recordedRequest = server.takeRequest() val recordedRequest = server.takeRequest()
assertThat(recordedRequest.method).isEqualTo("GET") assertThat(recordedRequest.method).isEqualTo("GET")
assertThat(recordedRequest.path) assertThat(recordedRequest.url.encodedQuery)
.isEqualTo("/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ") .isEqualTo("ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ")
} }
@Test @Test
@ -197,8 +197,8 @@ class DnsOverHttpsTest {
assertThat(result).containsExactly(address("157.240.1.18")) assertThat(result).containsExactly(address("157.240.1.18"))
var recordedRequest = server.takeRequest() var recordedRequest = server.takeRequest()
assertThat(recordedRequest.method).isEqualTo("GET") assertThat(recordedRequest.method).isEqualTo("GET")
assertThat(recordedRequest.path) assertThat(recordedRequest.url.encodedQuery)
.isEqualTo("/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ") .isEqualTo("ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ")
assertThat(cacheEvents()).containsExactly("CacheMiss") assertThat(cacheEvents()).containsExactly("CacheMiss")
@ -212,8 +212,8 @@ class DnsOverHttpsTest {
assertThat(result).containsExactly(address("157.240.1.18")) assertThat(result).containsExactly(address("157.240.1.18"))
recordedRequest = server.takeRequest() recordedRequest = server.takeRequest()
assertThat(recordedRequest.method).isEqualTo("GET") assertThat(recordedRequest.method).isEqualTo("GET")
assertThat(recordedRequest.path) assertThat(recordedRequest.url.encodedQuery)
.isEqualTo("/lookup?ct&dns=AAABAAABAAAAAAAAA3d3dwZnb29nbGUDY29tAAABAAE") .isEqualTo("ct&dns=AAABAAABAAAAAAAAA3d3dwZnb29nbGUDY29tAAABAAE")
assertThat(cacheEvents()).containsExactly("CacheMiss") assertThat(cacheEvents()).containsExactly("CacheMiss")
} }
@ -239,8 +239,8 @@ class DnsOverHttpsTest {
assertThat(result).containsExactly(address("157.240.1.18")) assertThat(result).containsExactly(address("157.240.1.18"))
var recordedRequest = server.takeRequest() var recordedRequest = server.takeRequest()
assertThat(recordedRequest.method).isEqualTo("POST") assertThat(recordedRequest.method).isEqualTo("POST")
assertThat(recordedRequest.path) assertThat(recordedRequest.url.encodedQuery)
.isEqualTo("/lookup?ct") .isEqualTo("ct")
assertThat(cacheEvents()).containsExactly("CacheMiss") assertThat(cacheEvents()).containsExactly("CacheMiss")
@ -254,8 +254,8 @@ class DnsOverHttpsTest {
assertThat(result).containsExactly(address("157.240.1.18")) assertThat(result).containsExactly(address("157.240.1.18"))
recordedRequest = server.takeRequest(0, TimeUnit.MILLISECONDS)!! recordedRequest = server.takeRequest(0, TimeUnit.MILLISECONDS)!!
assertThat(recordedRequest.method).isEqualTo("POST") assertThat(recordedRequest.method).isEqualTo("POST")
assertThat(recordedRequest.path) assertThat(recordedRequest.url.encodedQuery)
.isEqualTo("/lookup?ct") .isEqualTo("ct")
assertThat(cacheEvents()).containsExactly("CacheMiss") assertThat(cacheEvents()).containsExactly("CacheMiss")
} }
@ -278,8 +278,8 @@ class DnsOverHttpsTest {
assertThat(result).containsExactly(address("157.240.1.18")) assertThat(result).containsExactly(address("157.240.1.18"))
var recordedRequest = server.takeRequest(0, TimeUnit.SECONDS) var recordedRequest = server.takeRequest(0, TimeUnit.SECONDS)
assertThat(recordedRequest!!.method).isEqualTo("GET") assertThat(recordedRequest!!.method).isEqualTo("GET")
assertThat(recordedRequest.path).isEqualTo( assertThat(recordedRequest.url.encodedQuery).isEqualTo(
"/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ", "ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ",
) )
assertThat(cacheEvents()).containsExactly("CacheMiss") assertThat(cacheEvents()).containsExactly("CacheMiss")
@ -298,8 +298,8 @@ class DnsOverHttpsTest {
assertThat(result).isEqualTo(listOf(address("157.240.1.18"))) assertThat(result).isEqualTo(listOf(address("157.240.1.18")))
recordedRequest = server.takeRequest(0, TimeUnit.SECONDS) recordedRequest = server.takeRequest(0, TimeUnit.SECONDS)
assertThat(recordedRequest!!.method).isEqualTo("GET") assertThat(recordedRequest!!.method).isEqualTo("GET")
assertThat(recordedRequest.path) assertThat(recordedRequest.url.encodedQuery)
.isEqualTo("/lookup?ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ") .isEqualTo("ct&dns=AAABAAABAAAAAAAABmdvb2dsZQNjb20AAAEAAQ")
assertThat(cacheEvents()).containsExactly("CacheMiss") assertThat(cacheEvents()).containsExactly("CacheMiss")
} }

View File

@ -15,7 +15,6 @@
*/ */
package okhttp3.internal.http package okhttp3.internal.http
import java.net.HttpURLConnection
import java.net.Proxy import java.net.Proxy
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Request import okhttp3.Request

View File

@ -2581,7 +2581,7 @@ open class CallTest {
assertThat(response.body.string()).isEqualTo("Page 2") assertThat(response.body.string()).isEqualTo("Page 2")
val redirectRequest = server2.takeRequest() val redirectRequest = server2.takeRequest()
assertThat(redirectRequest.headers["Authorization"]).isNull() assertThat(redirectRequest.headers["Authorization"]).isNull()
assertThat(redirectRequest.path).isEqualTo("/b") assertThat(redirectRequest.url.encodedPath).isEqualTo("/b")
} }
@Test @Test
@ -2902,7 +2902,7 @@ open class CallTest {
assertFailsWith<IOException> { assertFailsWith<IOException> {
call.execute() call.execute()
} }
assertThat(server.takeRequest().path).isEqualTo("/a") assertThat(server.takeRequest().url.encodedPath).isEqualTo("/a")
} }
@Test @Test
@ -2946,7 +2946,7 @@ open class CallTest {
} }
callA.enqueue(callback) callA.enqueue(callback)
callB.enqueue(callback) callB.enqueue(callback)
assertThat(server.takeRequest().path).isEqualTo("/a") assertThat(server.takeRequest().url.encodedPath).isEqualTo("/a")
callback.await(requestA.url).assertBody("A") callback.await(requestA.url).assertBody("A")
// At this point we know the callback is ready, and that it will receive a cancel failure. // At this point we know the callback is ready, and that it will receive a cancel failure.
callback.await(requestB.url).assertFailure("Canceled", "Socket closed") callback.await(requestB.url).assertFailure("Canceled", "Socket closed")
@ -2976,7 +2976,7 @@ open class CallTest {
} }
} }
call.enqueue(callback) call.enqueue(callback)
assertThat(server.takeRequest().path).isEqualTo("/a") assertThat(server.takeRequest().url.encodedPath).isEqualTo("/a")
callback.await(requestA.url).assertFailure( callback.await(requestA.url).assertFailure(
"Canceled", "Canceled",
"stream was reset: CANCEL", "stream was reset: CANCEL",
@ -3956,11 +3956,11 @@ open class CallTest {
val connect = server.takeRequest() val connect = server.takeRequest()
assertThat(connect.method).isEqualTo("CONNECT") assertThat(connect.method).isEqualTo("CONNECT")
assertThat(connect.headers["Proxy-Authorization"]).isEqualTo(credential) assertThat(connect.headers["Proxy-Authorization"]).isEqualTo(credential)
assertThat(connect.path).isEqualTo("/") assertThat(connect.url.encodedPath).isEqualTo("/")
val get = server.takeRequest() val get = server.takeRequest()
assertThat(get.method).isEqualTo("GET") assertThat(get.method).isEqualTo("GET")
assertThat(get.headers["Proxy-Authorization"]).isNull() assertThat(get.headers["Proxy-Authorization"]).isNull()
assertThat(get.path).isEqualTo("/foo") assertThat(get.url.encodedPath).isEqualTo("/foo")
} }
@Test @Test
@ -4267,7 +4267,7 @@ open class CallTest {
assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1") assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1")
assertThat(get.headers["Host"]).isEqualTo("[::1]:$port") assertThat(get.headers["Host"]).isEqualTo("[::1]:$port")
assertThat(get.headers[":authority"]).isNull() assertThat(get.headers[":authority"]).isNull()
assertThat(get.requestUrl).isEqualTo(url) assertThat(get.url).isEqualTo(url)
} }
@Test @Test
@ -4301,7 +4301,7 @@ open class CallTest {
assertThat(get.headers[":authority"]).isEqualTo( assertThat(get.headers[":authority"]).isEqualTo(
"[::1]:$port", "[::1]:$port",
) )
assertThat(get.requestUrl).isEqualTo(url) assertThat(get.url).isEqualTo(url)
} }
@Test @Test
@ -4335,7 +4335,7 @@ open class CallTest {
"127.0.0.1:$port", "127.0.0.1:$port",
) )
assertThat(get.headers[":authority"]).isNull() assertThat(get.headers[":authority"]).isNull()
assertThat(get.requestUrl).isEqualTo(url) assertThat(get.url).isEqualTo(url)
} }
@Test @Test
@ -4363,7 +4363,7 @@ open class CallTest {
assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1") assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1")
assertThat(get.headers["Host"]).isNull() assertThat(get.headers["Host"]).isNull()
assertThat(get.headers[":authority"]).isEqualTo("127.0.0.1:$port") assertThat(get.headers[":authority"]).isEqualTo("127.0.0.1:$port")
assertThat(get.requestUrl).isEqualTo(url) assertThat(get.url).isEqualTo(url)
} }
@Test @Test
@ -4391,7 +4391,7 @@ open class CallTest {
assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1") assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1")
assertThat(get.headers["Host"]).isEqualTo("any-host-name:$port") assertThat(get.headers["Host"]).isEqualTo("any-host-name:$port")
assertThat(get.headers[":authority"]).isNull() assertThat(get.headers[":authority"]).isNull()
assertThat(get.requestUrl).isEqualTo(url) assertThat(get.url).isEqualTo(url)
} }
@Test @Test
@ -4419,7 +4419,7 @@ open class CallTest {
assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1") assertThat(get.requestLine).isEqualTo("GET / HTTP/1.1")
assertThat(get.headers["Host"]).isNull() assertThat(get.headers["Host"]).isNull()
assertThat(get.headers[":authority"]).isEqualTo("any-host-name:$port") assertThat(get.headers[":authority"]).isEqualTo("any-host-name:$port")
assertThat(get.requestUrl).isEqualTo(url) assertThat(get.url).isEqualTo(url)
} }
/** Use a proxy to fake IPv6 connectivity, even if localhost doesn't have IPv6. */ /** Use a proxy to fake IPv6 connectivity, even if localhost doesn't have IPv6. */

View File

@ -653,7 +653,7 @@ class URLConnectionTest {
val response = getResponse(newRequest("/foo")) val response = getResponse(newRequest("/foo"))
assertContent("this response comes via SSL", response) assertContent("this response comes via SSL", response)
val failHandshakeRequest = server.takeRequest() val failHandshakeRequest = server.takeRequest()
assertThat(failHandshakeRequest.requestLine).isEmpty() assertThat(failHandshakeRequest.requestLine).isEqualTo("GET / HTTP/1.1")
val fallbackRequest = server.takeRequest() val fallbackRequest = server.takeRequest()
assertThat(fallbackRequest.requestLine).isEqualTo("GET /foo HTTP/1.1") assertThat(fallbackRequest.requestLine).isEqualTo("GET /foo HTTP/1.1")
assertThat(fallbackRequest.handshake?.tlsVersion).isIn(TlsVersion.TLS_1_2, TlsVersion.TLS_1_3) assertThat(fallbackRequest.handshake?.tlsVersion).isIn(TlsVersion.TLS_1_2, TlsVersion.TLS_1_3)
@ -2591,7 +2591,7 @@ class URLConnectionTest {
assertContent("Page 2", getResponse(newRequest("/a"))) assertContent("Page 2", getResponse(newRequest("/a")))
val redirectRequest = server2.takeRequest() val redirectRequest = server2.takeRequest()
assertThat(redirectRequest.headers["Authorization"]).isNull() assertThat(redirectRequest.headers["Authorization"]).isNull()
assertThat(redirectRequest.path).isEqualTo("/b") assertThat(redirectRequest.url.encodedPath).isEqualTo("/b")
} }
@Test @Test
@ -3513,9 +3513,9 @@ class URLConnectionTest {
} }
} }
val requestA = server.takeRequest() val requestA = server.takeRequest()
assertThat(requestA.path).isEqualTo("/a") assertThat(requestA.url.encodedPath).isEqualTo("/a")
val requestB = server.takeRequest() val requestB = server.takeRequest()
assertThat(requestB.path).isEqualTo("/b") assertThat(requestB.url.encodedPath).isEqualTo("/b")
assertThat(requestB.body.utf8()).isEqualTo(requestBody) assertThat(requestB.body.utf8()).isEqualTo(requestBody)
} }

View File

@ -596,9 +596,9 @@ class HttpOverHttp2Test {
val response = call.execute() val response = call.execute()
assertThat(response.body.string()).isEqualTo("This is the new location!") assertThat(response.body.string()).isEqualTo("This is the new location!")
val request1 = server.takeRequest() val request1 = server.takeRequest()
assertThat(request1.path).isEqualTo("/") assertThat(request1.url.encodedPath).isEqualTo("/")
val request2 = server.takeRequest() val request2 = server.takeRequest()
assertThat(request2.path).isEqualTo("/foo") assertThat(request2.url.encodedPath).isEqualTo("/foo")
} }
@ParameterizedTest @ParameterizedTest
@ -2158,11 +2158,11 @@ class HttpOverHttp2Test {
assertThat(call2Connect.sequenceNumber).isEqualTo(0) assertThat(call2Connect.sequenceNumber).isEqualTo(0)
val call2Get = server.takeRequest() val call2Get = server.takeRequest()
assertThat(call2Get.method).isEqualTo("GET") assertThat(call2Get.method).isEqualTo("GET")
assertThat(call2Get.path).isEqualTo("/call2") assertThat(call2Get.url.encodedPath).isEqualTo("/call2")
assertThat(call2Get.sequenceNumber).isEqualTo(0) assertThat(call2Get.sequenceNumber).isEqualTo(0)
val call1Get = server.takeRequest() val call1Get = server.takeRequest()
assertThat(call1Get.method).isEqualTo("GET") assertThat(call1Get.method).isEqualTo("GET")
assertThat(call1Get.path).isEqualTo("/call1") assertThat(call1Get.url.encodedPath).isEqualTo("/call1")
assertThat(call1Get.sequenceNumber).isEqualTo(1) assertThat(call1Get.sequenceNumber).isEqualTo(1)
assertThat(client.connectionPool.connectionCount()).isEqualTo(1) assertThat(client.connectionPool.connectionCount()).isEqualTo(1)
} }